| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- <template>
- <u-popup :show="visible" mode="bottom" :round="10" :closeOnClickOverlay="false" @close="cancel"
- class="accident-popup">
- <view class="popup-content">
- <view class="popup-header"><text class="popup-title">{{ dialogTitle }}</text>
- <view class="close-btn" @click="cancel">×</view>
- </view>
- <scroll-view class="popup-body" scroll-y>
- <view class="card-a">
- <!-- 事故事件信息 -->
- <view class="card-section">
- <view class="section-title">📋 事故事件信息</view>
- <u--form labelPosition="left" labelWidth="190rpx" :model="form" :rules="rules" ref="formRef">
- <u-form-item label="事故事件名称" prop="acdntName" borderBottom required>
- <u--input v-model="form.acdntName" placeholder="请输入" :disabled="isView" border="none"
- inputAlign="right" />
- </u-form-item>
- <u-form-item label="发生时间" prop="occurrenceTime" borderBottom required>
- <view class="picker-value" @click="!isView && showDateTimePicker('occurrenceTime')">
- {{ form.occurrenceTime || "请选择" }}
- </view>
- <u-icon slot="right" name="arrow-right" />
- </u-form-item>
- <u-form-item label="事故发生地点" prop="acdntPlace" borderBottom required>
- <u--input v-model="form.acdntPlace" placeholder="请输入" :disabled="isView" border="none"
- inputAlign="right" />
- </u-form-item>
- <u-form-item label="来源类型" borderBottom>
- <view class="picker-value" @click="!isView && showSourceTypePicker()">
- {{ getSourceTypeLabel(form.sourceType) || "请选择" }}
- </view>
- <u-icon slot="right" name="arrow-right" />
- </u-form-item>
- <u-form-item label="来源单据名称" borderBottom>
- <u--input v-model="form.sourceName" placeholder="请选择" readonly :disabled="isView"
- border="none" inputAlign="right" @click="addSource" />
- </u-form-item>
- <u-form-item label="事故事件经过" prop="acdntPass" borderBottom required>
- <u--textarea v-model="form.acdntPass" placeholder="请输入" :disabled="isView"
- height="120rpx" />
- </u-form-item>
- <!-- 修复:上报人使用 userOpen('report') -->
- <u-form-item label="上报人" prop="reportPersonName" borderBottom @click="userOpen('report')">
- <u--input v-model="form.reportPersonName" placeholder="请选择" :disabled="isView"
- border="none" inputAlign="right" />
- </u-form-item>
- <u-form-item label="上报部门" borderBottom>
- <u--input v-model="form.reportDeptName" disabled border="none" inputAlign="right" />
- </u-form-item>
- <u-form-item label="上报时间" prop="reportTime" borderBottom required>
- <view class="picker-value" @click="!isView && showDateTimePicker('reportTime')">
- {{ form.reportTime || "请选择" }}
- </view>
- <u-icon slot="right" name="arrow-right" />
- </u-form-item>
- </u--form>
- </view>
- <!-- 调查处理信息 -->
- <view class="card-section" v-if="!isView || form.acdntLevelId">
- <view class="section-title">🔍 调查处理信息</view>
- <u--form labelPosition="left" labelWidth="180rpx" :model="form" ref="form2Ref">
- <u-form-item label="事故级别" prop="acdntLevelId" borderBottom required>
- <DictSelection dictName="事故级别" clearable :disabled="isView"
- v-model="form.acdntLevelId" />
- </u-form-item>
- <u-form-item label="事故事件类型" prop="acdntTypeId" borderBottom required labelWidth="190rpx">
- <DictSelection dictName="事故事件类型" clearable :disabled="isView"
- v-model="form.acdntTypeId" />
- </u-form-item>
- <u-form-item label="事故原因" prop="acdntCauselText" borderBottom>
- <u--textarea v-model="form.acdntCauselText" placeholder="请输入" :disabled="isView"
- height="120rpx" />
- </u-form-item>
- <!-- 事故责任人 -->
- <u-form-item label="事故责任人" prop="dutyPersonName" borderBottom @click="userOpen('duty')">
- <u--input v-model="form.dutyPersonName" placeholder="请选择" :disabled="isView"
- border="none" inputAlign="right" />
- </u-form-item>
- <u-form-item label="责任单位" borderBottom>
- <u--input v-model="form.dutyUnitName" disabled border="none" inputAlign="right" />
- </u-form-item>
- <u-form-item label="间接经济损失(万元)" borderBottom>
- <u--input v-model="form.indirectEconomicLoss" type="number" placeholder="请输入"
- :disabled="isView" border="none" inputAlign="right" />
- </u-form-item>
- <u-form-item label="直接经济损失(万元)" borderBottom>
- <u--input v-model="form.directEconomicLoss" type="number" placeholder="请输入"
- :disabled="isView" border="none" inputAlign="right" />
- </u-form-item>
- </u--form>
- </view>
- <!-- ===== 伤亡人员列表(修改部分) ===== -->
- <view class="card-section">
- <view class="section-title">👥 伤亡人员列表
- <text class="add-btn" v-if="!isView" @click="userOpen('casualty')">+ 添加</text>
- </view>
- <view v-for="(p, idx) in form.ehsAccidentCasualtiesVOList" :key="idx" class="person-card">
- <!-- 第一行:姓名 + 部门 + 删除按钮 -->
- <view class="person-header">
- <view class="person-info">
- <text class="name">{{ p.userName || '-' }}</text>
- <text class="dept">{{ p.userDeptName || '-' }}</text>
- </view>
- <text class="delete-btn" v-if="!isView" @click="removeCasualty(idx)">✕</text>
- </view>
- <!-- 第二行:受伤程度(独占一行) -->
- <view class="field-row" @click="!isView && showInjuryPickerFn(idx)">
- <text class="field-label">受伤程度</text>
- <view class="field-value-wrapper">
- <text class="field-value" :class="{ placeholder: !getInjuryLabel(p.injuryDegree) }">
- {{ getInjuryLabel(p.injuryDegree) || '请选择' }}
- </text>
- <u-icon v-if="!isView" name="arrow-right" size="28" color="#999" />
- </view>
- </view>
- <!-- 第三行:损失工作日(独占一行) -->
- <view class="field-row">
- <text class="field-label">损失工作日</text>
- <view class="field-value-wrapper">
- <input class="days-input" v-model="p.lostWorkDays" type="number"
- placeholder="请输入" :disabled="isView" />
- </view>
- </view>
- </view>
- <view v-if="form.ehsAccidentCasualtiesVOList.length === 0" class="empty-tip">暂无伤亡人员</view>
- </view>
- </view>
- </scroll-view>
- <view class="popup-footer">
- <u-button type="default" @click="cancel">取消</u-button>
- <u-button v-if="!isView" type="primary" @click="save" :loading="loading">保存</u-button>
- </view>
- </view>
- <!-- 字典选择器 -->
- <u-action-sheet :show="showDictPopup" :actions="dictActions" @close="showDictPopup = false"
- @select="onDictSelect" />
- <!-- 受伤程度选择器(新增) -->
- <u-action-sheet :show="showInjuryPicker" :actions="injuryActions" title="请选择受伤程度"
- @close="showInjuryPicker = false" @select="onInjurySelect" />
- <!-- 日期时间选择器 -->
- <u-datetime-picker :show="showDateTimePopup" v-model="datetimeValue" mode="datetime"
- @confirm="onDateTimeConfirm" @cancel="showDateTimePopup = false" />
- <!-- 人员选择 -->
- <selectUserDialog ref="userSelectRef" @confirm="changePersonel" />
- <!-- 演练工单选择 -->
- <drillOrderSelect ref="drillOrderSelectRef" @confirm="onDrillOrderConfirm" />
- <u-toast ref="uToast" />
- </u-popup>
- </template>
- <script>
- import drillOrderSelect from "./drillOrderSelect.vue";
- import selectUserDialog from "@/components/selectUserDialog.vue";
- import {
- save,
- getById
- } from "@/api/accidentReport/index.js";
- import dictMixins from "@/mixins/dictMixins";
- import DictSelection from "@/components/Dict/DictSelection.vue";
- const defForm = {
- acdntName: "",
- occurrenceTime: "",
- acdntPlace: "",
- acdntPass: "",
- sourceType: "",
- sourceName: "",
- sourceId: "",
- reportPersonName: "",
- reportPersonUserId: "",
- reportDeptName: "",
- reportDeptId: "",
- reportTime: "",
- acdntLevelId: "",
- acdntTypeId: "",
- acdntCauselText: "",
- dutyUnitId: "",
- dutyUnitName: "",
- dutyPersonName: "",
- dutyPersonId: "",
- indirectEconomicLoss: undefined,
- directEconomicLoss: undefined,
- ehsAccidentCasualtiesVOList: [],
- };
- export default {
- components: {
- selectUserDialog,
- drillOrderSelect,
- DictSelection
- },
- mixins: [dictMixins],
- data() {
- return {
- visible: false,
- loading: false,
- dialogType: "add",
- userKey: "",
- form: JSON.parse(JSON.stringify(defForm)),
- // 受伤程度选项
- injuryDegreeOptions: [{
- value: "1",
- label: "轻微伤"
- },
- {
- value: "2",
- label: "轻伤二级"
- },
- {
- value: "3",
- label: "轻微一级"
- },
- {
- value: "4",
- label: "重伤二级"
- },
- {
- value: "5",
- label: "重伤一级"
- },
- ],
- // 受伤程度选择器
- showInjuryPicker: false,
- injuryActions: [],
- currentInjuryIndex: -1,
- // 字典选择器
- showDictPopup: false,
- dictActions: [],
- dictField: "",
- // 日期时间选择器
- showDateTimePopup: false,
- datetimeValue: 0,
- dateField: "",
- // 表单校验规则
- rules: {
- acdntName: {
- required: true,
- message: "请输入事故事件名称"
- },
- occurrenceTime: {
- required: true,
- message: "请选择发生时间"
- },
- acdntPlace: {
- required: true,
- message: "请输入事故发生地点"
- },
- acdntPass: {
- required: true,
- message: "请输入事故事件经过"
- },
- reportTime: {
- required: true,
- message: "请选择上报时间"
- },
- acdntLevelId: {
- required: true,
- message: "请选择事故级别"
- },
- acdntTypeId: {
- required: true,
- message: "请选择事故事件类型"
- },
- },
- };
- },
- computed: {
- dialogTitle() {
- const map = {
- add: "新增事故上报",
- edit: "编辑事故上报",
- view: "查看事故上报"
- };
- return map[this.dialogType] || "事故上报";
- },
- isView() {
- return this.dialogType === "view";
- },
- },
- methods: {
- // ===== 打开弹窗 =====
- async open(row, type = "add") {
- this.visible = true;
- this.dialogType = type;
-
- if (row && row.id) {
- const data = await getById(row.id);
- this.form = {
- ...JSON.parse(JSON.stringify(defForm)),
- ...data
- };
- if (!this.form.ehsAccidentCasualtiesVOList)
- this.form.ehsAccidentCasualtiesVOList = [];
- } else {
- this.form = JSON.parse(JSON.stringify(defForm));
- const userInfo = uni.getStorageSync("userInfo") || {};
- this.form.reportPersonName = userInfo.name || "";
- this.form.reportPersonUserId = userInfo.userId || "";
- this.form.reportDeptName = userInfo.groupName || "";
- this.form.reportDeptId = userInfo.groupId || "";
- }
- this.$nextTick(() => {
- if (this.$refs.formRef) this.$refs.formRef.setRules(this.rules);
- });
- },
- // ===== 关闭弹窗 =====
- cancel() {
- this.visible = false;
- this.form = JSON.parse(JSON.stringify(defForm));
- this.showInjuryPicker = false;
- this.showDictPopup = false;
- this.showDateTimePopup = false;
- },
- // ===== 日期时间选择器 =====
- showDateTimePicker(field) {
- if (this.isView) return;
- this.dateField = field;
- this.datetimeValue = this.form[field] ?
- new Date(this.form[field]).getTime() :
- Date.now();
- this.showDateTimePopup = true;
- },
- onDateTimeConfirm(e) {
- this.showDateTimePopup = false;
- this.form[this.dateField] = this.$u.timeFormat(
- e.value,
- "yyyy-mm-dd hh:MM:ss",
- );
- },
- // ===== 字典选择器 =====
- onDictSelect(e) {
- this.showDictPopup = false;
- this.form[this.dictField] = e.value;
- if (this.$refs.formRef) this.$refs.formRef.validateField(this.dictField);
- },
- // ===== 来源类型 =====
- getSourceTypeLabel(val) {
- const map = {
- 1: "应急演练工单"
- };
- return map[val] || "";
- },
- showSourceTypePicker() {
- if (this.isView) return;
- this.dictField = "sourceType";
- this.dictActions = [{
- name: "应急演练工单",
- value: "1"
- }];
- this.showDictPopup = true;
- },
- // ===== 来源单据 =====
- addSource() {
- if (this.isView) return;
- if (!this.form.sourceType) {
- this.$refs.uToast.show({
- type: "warning",
- message: "请先选择来源类型",
- });
- return;
- }
- if (this.form.sourceType == "1") this.$refs.drillOrderSelectRef.open();
- },
- onDrillOrderConfirm(data) {
- this.form.sourceName = data.name || "";
- this.form.sourceId = data.id || "";
- this.form.acdntPlace = data.planLocation || "";
- },
- // ===== 人员选择 =====
- userOpen(key) {
- if (this.isView || this.loading) return;
- this.userKey = key;
- if (key === "report" || key === "duty") {
- this.$refs.userSelectRef.open(2); // 单选
- }
- if (key === "casualty") {
- this.$refs.userSelectRef.open(1); // 多选
- }
- },
- changePersonel(data) {
- if (!data || data.length === 0) return;
- if (this.userKey === "report") {
- const person = data[0];
- this.form.reportPersonName = person.name || "";
- this.form.reportPersonUserId = person.id || "";
- this.form.reportDeptName = person.groupName || "";
- this.form.reportDeptId = person.groupId || "";
- } else if (this.userKey === "duty") {
- const person = data[0];
- this.form.dutyPersonName = person.name || "";
- this.form.dutyPersonId = person.id || "";
- this.form.dutyUnitName = person.groupName || "";
- this.form.dutyUnitId = person.groupId || "";
- } else if (this.userKey === "casualty") {
- data.forEach((person) => {
- this.form.ehsAccidentCasualtiesVOList.push({
- userId: person.id || "",
- userName: person.name || "",
- userDeptId: person.groupId || "",
- userDeptName: person.groupName || "",
- injuryDegree: "",
- lostWorkDays: undefined,
- accidentId: this.form.id || "",
- });
- });
- }
- },
- // ===== 伤亡人员 - 受伤程度(u-action-sheet) =====
- showInjuryPickerFn(index) {
- if (this.isView) return;
- this.currentInjuryIndex = index;
- this.injuryActions = this.injuryDegreeOptions.map((item) => ({
- name: item.label,
- value: item.value,
- }));
- this.showInjuryPicker = true;
- },
- onInjurySelect(e) {
- this.showInjuryPicker = false;
- if (this.currentInjuryIndex >= 0) {
- this.$set(
- this.form.ehsAccidentCasualtiesVOList[this.currentInjuryIndex],
- "injuryDegree",
- e.value,
- );
- }
- this.currentInjuryIndex = -1;
- },
- // ===== 伤亡人员 - 辅助方法 =====
- getInjuryLabel(val) {
- const item = this.injuryDegreeOptions.find((i) => i.value == val);
- return item ? item.label : "";
- },
- // ===== 伤亡人员 - 删除 =====
- removeCasualty(idx) {
- this.form.ehsAccidentCasualtiesVOList.splice(idx, 1);
- },
- // ===== 保存 =====
- async save() {
- try {
- await this.$refs.formRef.validate();
- // 填充分类名称
- this.form.acdntLevelName = this.getDictValue(
- "事故级别",
- this.form.acdntLevelId,
- );
- this.form.acdntTypeName = this.getDictValue(
- "事故事件类型",
- this.form.acdntTypeId,
- );
- this.loading = true;
- await save(this.form);
- this.$refs.uToast.show({
- type: "success",
- message: "保存成功"
- });
- this.cancel();
- this.$emit("reload");
- } catch (e) {
- if (e && e.message)
- this.$refs.uToast.show({
- type: "error",
- message: e.message
- });
- } finally {
- this.loading = false;
- }
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .accident-popup {
- /deep/ .u-popup__content {
- border-radius: 32rpx 32rpx 0 0;
- overflow: hidden;
- }
- }
- .popup-content {
- height: calc(100vh - 100px);
- display: flex;
- flex-direction: column;
- background: #eff2f7;
- }
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 30rpx 32rpx;
- background: #fff;
- border-bottom: 2rpx solid #eef2f6;
- flex-shrink: 0;
- .popup-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #1f2b3c;
- }
- .close-btn {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 52rpx;
- color: #8e9aae;
- }
- }
- .popup-body {
- flex: 1;
- overflow-y: auto;
- padding: 24rpx;
- }
- .card-a {
- background: #fff;
- border-radius: 48rpx;
- box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.05);
- overflow: hidden;
- }
- .card-section {
- padding: 30rpx 32rpx;
- &:not(:last-child) {
- border-bottom: 2rpx solid #f0f2f5;
- }
- }
- .section-title {
- font-size: 30rpx;
- font-weight: 700;
- color: #1f2a44;
- margin-bottom: 24rpx;
- padding-left: 16rpx;
- border-left: 6rpx solid #4caf50;
- display: flex;
- justify-content: space-between;
- align-items: center;
- .add-btn {
- font-size: 26rpx;
- color: #2979ff;
- font-weight: normal;
- padding: 4rpx 16rpx;
- background: #e8f0fe;
- border-radius: 30rpx;
- }
- }
- // ===== u--form 样式 =====
- /deep/ .u-form-item {
- padding: 12rpx 0;
- .u-form-item__body__left__label {
- font-size: 26rpx !important;
- color: #6c7a91 !important;
- }
- .u-input__content__field-wrapper__field {
- font-size: 26rpx !important;
- text-align: right;
- }
- }
- .picker-value {
- font-size: 26rpx;
- color: #1e2a3a;
- text-align: right;
- flex: 1;
- min-height: 44rpx;
- padding: 4rpx 0;
- }
- // ===== 伤亡人员卡片(新增样式) =====
- .person-card {
- background: #f5f7fb;
- border-radius: 16rpx;
- padding: 16rpx 20rpx;
- margin-bottom: 16rpx;
- &:last-child {
- margin-bottom: 0;
- }
- // 第一行:姓名 + 部门 + 删除
- .person-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 16rpx;
- .person-info {
- display: flex;
- align-items: center;
- gap: 20rpx;
- flex: 1;
- min-width: 0;
- .name {
- font-size: 28rpx;
- font-weight: 600;
- color: #1f2b3c;
- }
- .dept {
- font-size: 24rpx;
- color: #8e9aae;
- }
- }
- .delete-btn {
- color: #f56c6c;
- font-size: 32rpx;
- padding: 0 8rpx;
- flex-shrink: 0;
- }
- }
- // 字段行:受伤程度 / 损失工作日(各独占一行)
- .field-row {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 8rpx 0;
- .field-label {
- font-size: 26rpx;
- color: #6c7a91;
- flex-shrink: 0;
- width: 140rpx;
- }
- .field-value-wrapper {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: flex-end;
- gap: 8rpx;
- min-width: 0;
- .field-value {
- font-size: 26rpx;
- color: #1e2a3a;
- &.placeholder {
- color: #bbb;
- }
- }
- .days-input {
- width: 100%;
- background: #fff;
- border-radius: 30rpx;
- padding: 0 16rpx;
- height: 50rpx;
- font-size: 24rpx;
- border: 2rpx solid #e9edf2;
- text-align: right;
- &:disabled {
- background: #f5f5f5;
- color: #999;
- }
- }
- }
- }
- }
- .empty-tip {
- text-align: center;
- font-size: 26rpx;
- color: #aaa;
- padding: 30rpx 0;
- }
- .popup-footer {
- display: flex;
- padding: 16rpx 24rpx;
- background: #fff;
- border-top: 2rpx solid #eef2f6;
- gap: 16rpx;
- flex-shrink: 0;
- /deep/ .u-button {
- flex: 1;
- border-radius: 48rpx;
- height: 72rpx;
- }
- }
- </style>
|