交办、整改责任人修改
This commit is contained in:
@@ -57,6 +57,10 @@
|
||||
<text class="text-gray">检查形式:</text>
|
||||
<text>{{ SOURCE_OPTIONS[hazardPayload.formData.source]?.title || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患来源:</text>
|
||||
<text>{{ hazardPayload.formData.hazardSourceName || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患位置:</text>
|
||||
<text>{{ hazardPayload.address || '-' }}</text>
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
<text class="readonly-label">检查形式</text>
|
||||
<text class="readonly-value">{{ item.source }}</text>
|
||||
</view>
|
||||
<view v-if="item.hazardSource" class="readonly-row readonly-row--stack">
|
||||
<text class="readonly-label">隐患来源</text>
|
||||
<text class="readonly-value">{{ item.hazardSource }}</text>
|
||||
</view>
|
||||
<view v-if="item.hazardAddress" class="readonly-row readonly-row--stack">
|
||||
<text class="readonly-label">隐患位置</text>
|
||||
<text class="readonly-value">{{ item.hazardAddress }}</text>
|
||||
@@ -156,6 +160,10 @@
|
||||
<text class="text-gray">检查形式:</text>
|
||||
<text>{{ SOURCE_OPTIONS[answerList[index].hazardPayload.formData.source]?.title || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患来源:</text>
|
||||
<text>{{ answerList[index].hazardPayload.formData.hazardSourceName || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患位置:</text>
|
||||
<text>{{ answerList[index].hazardPayload.address || '-' }}</text>
|
||||
@@ -337,7 +345,7 @@ const viewHazardDetail = (item) => {
|
||||
return;
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/view?hazardId=${item.hazardId}`
|
||||
url: `/pages/hiddendanger/detail2?hazardId=${item.hazardId}&assignId=${item.assignId || ''}`
|
||||
});
|
||||
};
|
||||
|
||||
@@ -407,13 +415,20 @@ const buildAnswerFromTask = (item) => {
|
||||
|
||||
if (item.result === 2 && item.hazardName) {
|
||||
const sourceIndex = SOURCE_OPTIONS.findIndex((o) => o.title === item.source);
|
||||
const hazardSourceCode = item.hazardSourceCode ?? (
|
||||
item.hazardSource != null && item.hazardSource !== '' && !Number.isNaN(Number(item.hazardSource))
|
||||
? Number(item.hazardSource)
|
||||
: null
|
||||
);
|
||||
answer.hazardPayload = {
|
||||
...createEmptyHazardPayload(),
|
||||
formData: {
|
||||
...createEmptyHazardPayload().formData,
|
||||
title: item.hazardName || '',
|
||||
description: item.hazardDesc || '',
|
||||
source: sourceIndex >= 0 ? sourceIndex : 0
|
||||
source: sourceIndex >= 0 ? sourceIndex : 0,
|
||||
hazardSourceCode,
|
||||
hazardSourceName: item.hazardSourceName || ''
|
||||
},
|
||||
address: item.hazardAddress || ''
|
||||
};
|
||||
|
||||
@@ -77,6 +77,31 @@
|
||||
<up-textarea v-model="formData.treatmentResult" placeholder="请输入隐患治理完成情况"></up-textarea>
|
||||
<view class="margin-bottom margin-top">隐患治理责任单位自行验收的情况</view>
|
||||
<up-textarea v-model="formData.selfVerifyContent" placeholder="请输入隐患治理责任单位自行验收的情况"></up-textarea>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">下一步流程</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">隐患销号审批</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">下一步处理人</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">部门、企业管理员</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">短信提醒</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-radio-group v-model="sendMsgFlagRadio" placement="row" activeColor="#2667e9">
|
||||
<up-radio
|
||||
label="是"
|
||||
name="yes"
|
||||
:customStyle="{ marginRight: '48rpx' }"
|
||||
></up-radio>
|
||||
<up-radio label="否" name="no"></up-radio>
|
||||
</up-radio-group>
|
||||
</scroll-view>
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
|
||||
@@ -98,7 +123,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { getMyWriteOffList, applyDelete, getAcceptanceList, getHiddenDangerDetail, getRectifyDetail, generateWriteoffContent } from '@/request/api.js';
|
||||
|
||||
// 弹窗控制
|
||||
@@ -117,6 +142,10 @@
|
||||
|
||||
// AI生成状态
|
||||
const aiGenerating = ref(false);
|
||||
|
||||
// 短信提醒
|
||||
const sendMsgFlagRadio = ref('yes');
|
||||
const sendMsgFlag = computed(() => sendMsgFlagRadio.value === 'yes');
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
@@ -202,6 +231,7 @@
|
||||
formData.mainTreatmentContent = '';
|
||||
formData.treatmentResult = '';
|
||||
formData.selfVerifyContent = '';
|
||||
sendMsgFlagRadio.value = 'yes';
|
||||
};
|
||||
|
||||
// AI生成销号方案
|
||||
@@ -274,7 +304,8 @@
|
||||
responsiblePerson: formData.responsiblePerson || '', // 主要负责人
|
||||
mainTreatmentContent: formData.mainTreatmentContent || '', // 主要治理内容
|
||||
treatmentResult: formData.treatmentResult || '', // 隐患治理完成内容
|
||||
selfVerifyContent: formData.selfVerifyContent || '' // 责任单位自行验收情况
|
||||
selfVerifyContent: formData.selfVerifyContent || '', // 责任单位自行验收情况
|
||||
sendMsgFlag: sendMsgFlag.value // 是否短信提醒
|
||||
};
|
||||
|
||||
console.log('提交数据:', params);
|
||||
@@ -471,4 +502,15 @@
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.static-field {
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
@@ -19,6 +19,9 @@
|
||||
<view class="text-gray margin-bottom margin-top">隐患治理完成内容</view>
|
||||
<up-textarea v-model="formData.governanceCompleteContent" placeholder="暂无" disabled autoHeight></up-textarea>
|
||||
|
||||
<view class="text-gray margin-bottom margin-top">隐患治理责任单位自行验收的情况</view>
|
||||
<up-textarea v-model="formData.selfAcceptanceStatus" placeholder="暂无" disabled autoHeight></up-textarea>
|
||||
|
||||
<view class="text-gray margin-bottom margin-top">状态</view>
|
||||
<up-input :modelValue="statusText" placeholder="暂无" disabled></up-input>
|
||||
|
||||
@@ -64,6 +67,7 @@
|
||||
mainPerson: '',
|
||||
mainGovernanceContent: '',
|
||||
governanceCompleteContent: '',
|
||||
selfAcceptanceStatus: '',
|
||||
status: '',
|
||||
rejectReason: ''
|
||||
})
|
||||
@@ -111,6 +115,7 @@
|
||||
formData.mainPerson = data.mainPerson || ''
|
||||
formData.mainGovernanceContent = data.mainGovernanceContent || ''
|
||||
formData.governanceCompleteContent = data.governanceCompleteContent || ''
|
||||
formData.selfAcceptanceStatus = data.selfAcceptanceStatus || data.selfVerifyContent || ''
|
||||
formData.status = data.status ?? ''
|
||||
formData.rejectReason = data.rejectReason || ''
|
||||
applySignature(data.signPath)
|
||||
|
||||
@@ -50,18 +50,10 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="fixed-add-btn" @click="openAddPopup">
|
||||
<view class="fixed-add-btn" @click="goToAdd">
|
||||
<text class="cuIcon-add"></text>
|
||||
<text>新增</text>
|
||||
</view>
|
||||
|
||||
<HazardFormPopup
|
||||
v-model:show="showAddPopup"
|
||||
title="新增隐患排查"
|
||||
mode="direct"
|
||||
:extra-params="hazardExtraParams"
|
||||
@success="onHazardAddSuccess"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -73,16 +65,10 @@
|
||||
getCheckTaskDetail,
|
||||
getMyHiddenDangerList
|
||||
} from '@/request/api.js'
|
||||
import HazardFormPopup from '@/components/hazard/HazardFormPopup.vue'
|
||||
|
||||
const showAddPopup = ref(false)
|
||||
const taskId = ref('')
|
||||
const checkPointId = ref('')
|
||||
|
||||
const hazardExtraParams = computed(() => ({
|
||||
taskId: taskId.value,
|
||||
checkPointId: checkPointId.value
|
||||
}))
|
||||
const oneTableId = ref('')
|
||||
|
||||
const userRole = ref('')
|
||||
const canAcceptance = computed(() => {
|
||||
@@ -120,6 +106,7 @@
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.id) {
|
||||
oneTableId.value = options.id
|
||||
fetchTaskInfo(options.id)
|
||||
}
|
||||
})
|
||||
@@ -149,13 +136,22 @@
|
||||
fetchHiddenDangerList()
|
||||
})
|
||||
|
||||
const openAddPopup = () => {
|
||||
showAddPopup.value = true;
|
||||
};
|
||||
|
||||
const onHazardAddSuccess = () => {
|
||||
showAddPopup.value = false
|
||||
fetchHiddenDangerList()
|
||||
const goToAdd = () => {
|
||||
let url = '/pages/hiddendanger/add'
|
||||
const params = []
|
||||
if (oneTableId.value) {
|
||||
params.push(`id=${oneTableId.value}`)
|
||||
}
|
||||
if (taskId.value) {
|
||||
params.push(`taskId=${taskId.value}`)
|
||||
}
|
||||
if (checkPointId.value) {
|
||||
params.push(`checkPointId=${checkPointId.value}`)
|
||||
}
|
||||
if (params.length) {
|
||||
url += `?${params.join('&')}`
|
||||
}
|
||||
uni.navigateTo({ url })
|
||||
}
|
||||
|
||||
const details = (item) => {
|
||||
|
||||
@@ -27,9 +27,13 @@
|
||||
<view style="color: #999; margin-bottom: 10rpx;">实际投资资金:</view>
|
||||
<view style="word-break: break-all; line-height: 1.6; color: #333;">{{ formatMoney(rectifyData.actualCost) }}</view>
|
||||
</view>
|
||||
<view class="margin-top">
|
||||
<view style="color: #999; margin-bottom: 10rpx;">安全管理人员:</view>
|
||||
<view style="word-break: break-all; line-height: 1.6; color: #333;">{{ formatPersonNames(rectifyData.managerNames) }}</view>
|
||||
</view>
|
||||
<view class="margin-top">
|
||||
<view style="color: #999; margin-bottom: 10rpx;">整改责任人:</view>
|
||||
<view style="word-break: break-all; line-height: 1.6; color: #333;">{{ rectifyData.rectifierName || '暂无' }}</view>
|
||||
<view style="word-break: break-all; line-height: 1.6; color: #333;">{{ formatPersonNames(rectifyData.memberNames) }}</view>
|
||||
</view>
|
||||
<view class="margin-top">
|
||||
<view style="color: #999; margin-bottom: 10rpx;">完成情况:</view>
|
||||
@@ -63,8 +67,35 @@
|
||||
<!-- 隐藏的 Canvas,用于渲染防作弊时间戳水印 -->
|
||||
<canvas canvas-id="watermarkCanvas" :width="canvasWidth" :height="canvasHeight" :style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', position: 'fixed', left: '-9999px', top: '-9999px' }"></canvas>
|
||||
|
||||
<!-- 电子签名部分 -->
|
||||
<view class="flex justify-between margin-bottom margin-top-sm align-center">
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">下一步流程</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">申请隐患销号</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">下一步处理人</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">部门、企业管理员</view>
|
||||
|
||||
<!-- 短信提醒(暂不使用)
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">短信提醒</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-radio-group v-model="sendMsgFlagRadio" placement="row" activeColor="#2667e9">
|
||||
<up-radio
|
||||
label="是"
|
||||
name="yes"
|
||||
:customStyle="{ marginRight: '48rpx' }"
|
||||
></up-radio>
|
||||
<up-radio label="否" name="no"></up-radio>
|
||||
</up-radio-group>
|
||||
-->
|
||||
|
||||
<!-- 电子签名(表单最底部) -->
|
||||
<view class="flex justify-between margin-bottom margin-top align-center">
|
||||
<view class="text-gray flex align-center">
|
||||
电子签名
|
||||
<view class="text-red">*</view>
|
||||
@@ -139,10 +170,23 @@
|
||||
rectifyResult: '',
|
||||
planCost: null,
|
||||
actualCost: null,
|
||||
rectifierName: '',
|
||||
managerNames: [],
|
||||
memberNames: [],
|
||||
rectifyStatusName: ''
|
||||
});
|
||||
|
||||
const formatPersonNames = (names) => {
|
||||
if (!names) return '暂无';
|
||||
if (Array.isArray(names)) {
|
||||
const text = names.filter(Boolean).join('、');
|
||||
return text || '暂无';
|
||||
}
|
||||
if (typeof names === 'string') {
|
||||
return names.trim() || '暂无';
|
||||
}
|
||||
return '暂无';
|
||||
};
|
||||
|
||||
const formatMoney = (value) => {
|
||||
if (value === null || value === undefined || value === '') {
|
||||
return '暂无';
|
||||
@@ -164,6 +208,10 @@
|
||||
});
|
||||
|
||||
const fileList1 = ref([]);
|
||||
|
||||
// 短信提醒(暂不使用)
|
||||
// const sendMsgFlagRadio = ref('yes');
|
||||
// const sendMsgFlag = computed(() => sendMsgFlagRadio.value === 'yes');
|
||||
|
||||
// 防作弊时间戳水印 Canvas 大小配置
|
||||
const canvasWidth = ref(300);
|
||||
@@ -245,6 +293,7 @@
|
||||
signatureLocalPath: signatureLocalPath.value,
|
||||
showCanvas: showCanvas.value,
|
||||
signaturePaths: signaturePaths.value
|
||||
// sendMsgFlagRadio: sendMsgFlagRadio.value
|
||||
}),
|
||||
hasContent: acceptDraftHasContent,
|
||||
applyPayload: (data) => {
|
||||
@@ -264,6 +313,7 @@
|
||||
signatureLocalPath.value = '';
|
||||
isSignatureEmpty.value = true;
|
||||
}
|
||||
// sendMsgFlagRadio.value = data.sendMsgFlagRadio === 'no' ? 'no' : 'yes';
|
||||
},
|
||||
clearForm: () => {
|
||||
formData.result = 1;
|
||||
@@ -277,6 +327,7 @@
|
||||
if (signatureRef.value) {
|
||||
signatureRef.value.clear();
|
||||
}
|
||||
// sendMsgFlagRadio.value = 'yes';
|
||||
},
|
||||
canSave: () => !!rectifyId.value,
|
||||
requireInitialized: true,
|
||||
@@ -303,6 +354,7 @@
|
||||
signatureLocalPath.value,
|
||||
showCanvas.value,
|
||||
signaturePaths.value
|
||||
// sendMsgFlagRadio.value
|
||||
]);
|
||||
|
||||
// 获取完整图片路径
|
||||
@@ -349,7 +401,8 @@
|
||||
rectifyData.rectifyResult = rectify.rectifyResult || '';
|
||||
rectifyData.planCost = rectify.planCost ?? null;
|
||||
rectifyData.actualCost = rectify.actualCost ?? null;
|
||||
rectifyData.rectifierName = rectify.rectifierName || '';
|
||||
rectifyData.managerNames = rectify.managerNames || [];
|
||||
rectifyData.memberNames = rectify.memberNames || [];
|
||||
rectifyData.rectifyStatusName = rectify.rectifyStatusName || '';
|
||||
rectifyAttachments.value = rectify.attachments || [];
|
||||
};
|
||||
@@ -447,6 +500,7 @@
|
||||
verifyRemark: formData.verifyRemark || '',
|
||||
attachments: attachments,
|
||||
signPath: signatureServerPath.value || '' // 电子签名路径
|
||||
// sendMsgFlag: sendMsgFlag.value
|
||||
};
|
||||
|
||||
console.log('提交验收参数:', params);
|
||||
@@ -645,6 +699,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.static-field {
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// 签名相关样式
|
||||
.signature-box {
|
||||
width: 100%;
|
||||
|
||||
142
pages/hiddendanger/add.vue
Normal file
142
pages/hiddendanger/add.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<HazardFormPanel
|
||||
ref="formRef"
|
||||
page-mode
|
||||
title="新增隐患排查"
|
||||
mode="direct"
|
||||
:extra-params="hazardExtraParams"
|
||||
:show-draft-banner="showRestoreBanner"
|
||||
canvas-id="hazardAddWatermarkCanvas"
|
||||
@success="onSubmitSuccess"
|
||||
@clear-draft="clearDraft(true)"
|
||||
@draft-change="draftSnapshot = $event"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, nextTick } from 'vue'
|
||||
import { onLoad, onHide } from '@dcloudio/uni-app'
|
||||
import { enterCheckPlan, getCheckTaskDetail } from '@/request/api.js'
|
||||
import HazardFormPanel from '@/components/hazard/HazardFormPanel.vue'
|
||||
import { buildDraftKey, DRAFT_NS, removeDraft } from '@/utils/draftCache.js'
|
||||
import { useDraftCache } from '@/utils/useDraftCache.js'
|
||||
import { hasHazardFormContent } from '@/components/hazard/hazardForm.js'
|
||||
|
||||
const formRef = ref(null)
|
||||
const taskId = ref('')
|
||||
const checkPointId = ref('')
|
||||
const oneTableId = ref('')
|
||||
const draftSnapshot = ref(null)
|
||||
const draftInitialized = ref(false)
|
||||
|
||||
const hazardExtraParams = computed(() => ({
|
||||
taskId: taskId.value,
|
||||
checkPointId: checkPointId.value,
|
||||
locationDraftKey: buildDraftKey(
|
||||
DRAFT_NS.HAZARD_ADD,
|
||||
'location',
|
||||
oneTableId.value,
|
||||
taskId.value,
|
||||
checkPointId.value
|
||||
)
|
||||
}))
|
||||
|
||||
const getDraftKey = () => buildDraftKey(
|
||||
DRAFT_NS.HAZARD_ADD,
|
||||
oneTableId.value,
|
||||
taskId.value,
|
||||
checkPointId.value
|
||||
)
|
||||
|
||||
const {
|
||||
showRestoreBanner,
|
||||
clear: clearDraft,
|
||||
restore: restoreDraft,
|
||||
save: saveDraft,
|
||||
bindAutoSave
|
||||
} = useDraftCache({
|
||||
getKey: getDraftKey,
|
||||
getPayload: () => formRef.value?.getPayload?.() || {},
|
||||
hasContent: hasHazardFormContent,
|
||||
applyPayload: (data) => {
|
||||
nextTick(() => {
|
||||
formRef.value?.applyPayload?.(data)
|
||||
})
|
||||
},
|
||||
clearForm: () => {
|
||||
formRef.value?.resetForm?.()
|
||||
},
|
||||
canSave: () => draftInitialized.value,
|
||||
requireInitialized: true,
|
||||
showRestoreToast: false,
|
||||
onAfterRestore: (data) => {
|
||||
draftSnapshot.value = data
|
||||
}
|
||||
})
|
||||
|
||||
const fetchTaskInfo = async (tableId) => {
|
||||
try {
|
||||
const startRes = await enterCheckPlan(tableId)
|
||||
if (startRes.code === 0 && startRes.data) {
|
||||
const tid = startRes.data.taskId
|
||||
const detailRes = await getCheckTaskDetail(tid)
|
||||
if (detailRes.code === 0 && detailRes.data) {
|
||||
taskId.value = detailRes.data.taskId
|
||||
checkPointId.value = detailRes.data.checkPointId
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取任务信息失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const clearLocationPickerDraft = () => {
|
||||
removeDraft(hazardExtraParams.value.locationDraftKey)
|
||||
}
|
||||
|
||||
const restoreFormDraft = async () => {
|
||||
await nextTick()
|
||||
restoreDraft()
|
||||
}
|
||||
|
||||
const onSubmitSuccess = () => {
|
||||
clearLocationPickerDraft()
|
||||
clearDraft(false)
|
||||
}
|
||||
|
||||
bindAutoSave(() => draftSnapshot.value)
|
||||
|
||||
const initPage = async (options = {}) => {
|
||||
if (options.taskId) {
|
||||
taskId.value = options.taskId
|
||||
}
|
||||
if (options.checkPointId) {
|
||||
checkPointId.value = options.checkPointId
|
||||
}
|
||||
if (options.id) {
|
||||
oneTableId.value = options.id
|
||||
if (!options.taskId || !options.checkPointId) {
|
||||
await fetchTaskInfo(options.id)
|
||||
}
|
||||
}
|
||||
draftInitialized.value = true
|
||||
await restoreFormDraft()
|
||||
}
|
||||
|
||||
onLoad(async (options) => {
|
||||
await initPage(options)
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
saveDraft()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #ebf2fc;
|
||||
}
|
||||
</style>
|
||||
@@ -10,6 +10,12 @@
|
||||
<text class="text-blue text-bold" style="cursor: pointer; padding: 0 10rpx; color: #2667E9; font-weight: bold;" @click="clearDraft(true)">清空草稿</text>
|
||||
</view>
|
||||
<view class="flex margin-bottom">
|
||||
<view class="text-gray">下一步流程</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">隐患整改</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">整改责任人</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
@@ -81,6 +87,19 @@
|
||||
@cancel="showDatePicker = false"
|
||||
@close="showDatePicker = false"
|
||||
></up-datetime-picker>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">短信提醒</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-radio-group v-model="sendMsgFlagRadio" placement="row" activeColor="#2667e9">
|
||||
<up-radio
|
||||
label="是"
|
||||
name="yes"
|
||||
:customStyle="{ marginRight: '48rpx' }"
|
||||
></up-radio>
|
||||
<up-radio label="否" name="no"></up-radio>
|
||||
</up-radio-group>
|
||||
|
||||
<view class="btn-group margin-top-xl">
|
||||
<button class="btn-cancel" @click="handleCancel">取消</button>
|
||||
@@ -93,7 +112,8 @@
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { getDepartmentPersonUsers,assignHiddenDanger } from '@/request/api.js';
|
||||
// import { getDepartmentPersonUsers, assignHiddenDanger } from '@/request/api.js';
|
||||
import { getRelatedDeptUsers, assignHiddenDanger } from '@/request/api.js';
|
||||
import { buildDraftKey, DRAFT_NS } from '@/utils/draftCache.js';
|
||||
import { useDraftCache } from '@/utils/useDraftCache.js';
|
||||
|
||||
@@ -165,6 +185,10 @@
|
||||
const dateValue = ref(Date.now());
|
||||
const selectedDate = ref('');
|
||||
|
||||
// 短信提醒
|
||||
const sendMsgFlagRadio = ref('yes');
|
||||
const sendMsgFlag = computed(() => sendMsgFlagRadio.value === 'yes');
|
||||
|
||||
// 草稿(仅缓存整改期限,不缓存人员选择)
|
||||
const {
|
||||
showRestoreBanner,
|
||||
@@ -175,26 +199,32 @@
|
||||
getKey: () => buildDraftKey(DRAFT_NS.ASSIGN, hazardId.value),
|
||||
getPayload: () => ({
|
||||
selectedDate: selectedDate.value,
|
||||
dateValue: dateValue.value
|
||||
dateValue: dateValue.value,
|
||||
sendMsgFlagRadio: sendMsgFlagRadio.value
|
||||
}),
|
||||
hasContent: (payload) => !!payload.selectedDate,
|
||||
hasContent: (payload) => !!(payload.selectedDate || payload.sendMsgFlagRadio === 'no'),
|
||||
applyPayload: (payload) => {
|
||||
selectedDate.value = payload.selectedDate || '';
|
||||
dateValue.value = payload.dateValue || Date.now();
|
||||
sendMsgFlagRadio.value = payload.sendMsgFlagRadio === 'no' ? 'no' : 'yes';
|
||||
},
|
||||
clearForm: () => {
|
||||
selectedDate.value = '';
|
||||
dateValue.value = Date.now();
|
||||
sendMsgFlagRadio.value = 'yes';
|
||||
},
|
||||
canSave: () => !!hazardId.value
|
||||
});
|
||||
|
||||
bindAutoSave(() => [selectedDate.value]);
|
||||
bindAutoSave(() => [selectedDate.value, sendMsgFlagRadio.value]);
|
||||
|
||||
// 获取部门人员列表
|
||||
const fetchDeptUsers = async () => {
|
||||
try {
|
||||
const res = await getDepartmentPersonUsers();
|
||||
// const res = await getDepartmentPersonUsers();
|
||||
const res = await getRelatedDeptUsers({
|
||||
type:1
|
||||
});
|
||||
if (res.code === 0 && res.data) {
|
||||
deptList.value = res.data;
|
||||
console.log('部门人员树:', deptList.value);
|
||||
@@ -235,7 +265,8 @@
|
||||
hazardId: Number(hazardId.value), // 隐患ID
|
||||
assigneeId: Number(selectedUserId.value), // 被指派人ID
|
||||
deadline: selectedDate.value, // 处理期限
|
||||
assignRemark: '' // 交办备注(可选)
|
||||
assignRemark: '', // 交办备注(可选)
|
||||
sendMsgFlag: sendMsgFlag.value // 是否短信提醒
|
||||
};
|
||||
|
||||
console.log('提交数据:', params);
|
||||
@@ -303,6 +334,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
.static-field {
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.user-popup {
|
||||
background: #fff;
|
||||
|
||||
|
||||
@@ -165,11 +165,12 @@
|
||||
<scroll-view class="cascader-col user-col" scroll-y :key="'dept-users-' + activeDeptIndex">
|
||||
<view v-if="currentDeptUsers.length === 0" class="empty-tip">该部门暂无人员</view>
|
||||
<view v-else>
|
||||
<view class="user-item" v-for="user in currentDeptUsers" :key="'user-' + user.userId">
|
||||
<view class="user-item" v-for="user in currentDeptUsers" :key="'user-' + user.userId" :class="{ 'user-item-locked': isLockedUser(user.userId) }">
|
||||
<up-checkbox
|
||||
usedAlone
|
||||
:checked="userPickerSelectedSet.has(String(user.userId))"
|
||||
:label="formatUserDisplayName(user)"
|
||||
:label="formatUserPickerLabel(user)"
|
||||
:disabled="isLockedUser(user.userId)"
|
||||
activeColor="#2667E9"
|
||||
shape="square"
|
||||
@change="(checked) => onUserCheckChange(user.userId, checked)"
|
||||
@@ -199,7 +200,40 @@
|
||||
:height="canvasHeight"
|
||||
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', position: 'fixed', left: '-9999px', top: '-9999px' }"
|
||||
></canvas>
|
||||
<!-- 电子签名 -->
|
||||
<canvas
|
||||
v-if="!showUserPopup && !showManagerPopup && !showRectifyTimePicker"
|
||||
canvas-id="watermarkCanvas"
|
||||
:width="canvasWidth"
|
||||
:height="canvasHeight"
|
||||
:style="{ width: canvasWidth + 'px', height: canvasHeight + 'px', position: 'fixed', left: '-9999px', top: '-9999px' }"
|
||||
></canvas>
|
||||
|
||||
<view class="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">下一步流程</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">隐患验收</view>
|
||||
|
||||
<view class="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">下一步处理人</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="static-field">企业管理员</view>
|
||||
|
||||
<view class="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">短信提醒</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-radio-group v-model="sendMsgFlagRadio" placement="row" activeColor="#2667e9">
|
||||
<up-radio
|
||||
label="是"
|
||||
name="yes"
|
||||
:customStyle="{ marginRight: '48rpx' }"
|
||||
></up-radio>
|
||||
<up-radio label="否" name="no"></up-radio>
|
||||
</up-radio-group>
|
||||
|
||||
<!-- 电子签名(表单最底部) -->
|
||||
<view class="form-label margin-bottom margin-top flex justify-between align-center" style="width: 100%;">
|
||||
<view class="flex align-center">
|
||||
<view class="text-gray">电子签名</view>
|
||||
@@ -253,7 +287,15 @@
|
||||
<script setup>
|
||||
import {ref,reactive,computed,nextTick,getCurrentInstance} from 'vue'
|
||||
import {onLoad, onHide} from '@dcloudio/uni-app'
|
||||
import {submitRectification,getDepartmentPersonUsers,getRectifyDetail,getDeptUsersWithSubordinates,getHiddenDangerDetail,generateRectifyPlan} from '@/request/api.js'
|
||||
import {
|
||||
submitRectification,
|
||||
// getDepartmentPersonUsers,
|
||||
// getDeptUsersWithSubordinates,
|
||||
getRelatedDeptUsers,
|
||||
getRectifyDetail,
|
||||
getHiddenDangerDetail,
|
||||
generateRectifyPlan
|
||||
} from '@/request/api.js'
|
||||
import { buildDraftKey, buildDraftKeyCompact, DRAFT_NS } from '@/utils/draftCache.js';
|
||||
import { useDraftCache } from '@/utils/useDraftCache.js';
|
||||
import {
|
||||
@@ -415,6 +457,10 @@
|
||||
const rectifyTimeValue = ref(Date.now());
|
||||
const selectedRectifyTime = ref('');
|
||||
|
||||
// 短信提醒
|
||||
const sendMsgFlagRadio = ref('yes');
|
||||
const sendMsgFlag = computed(() => sendMsgFlagRadio.value === 'yes');
|
||||
|
||||
const formatDateValue = (timestamp) => {
|
||||
if (!timestamp) return '';
|
||||
const date = new Date(timestamp);
|
||||
@@ -458,7 +504,18 @@
|
||||
deptName: ''
|
||||
});
|
||||
}
|
||||
selectedUserIds.value = [id];
|
||||
if (!lockedUserIds.value.includes(id)) {
|
||||
lockedUserIds.value = [...lockedUserIds.value, id];
|
||||
}
|
||||
selectedUserIds.value = mergeLockedUserIds([id]);
|
||||
syncSelectedUsersFromIds(selectedUserIds.value);
|
||||
};
|
||||
|
||||
const setLockedDefaultUsers = (ids) => {
|
||||
const normalized = parseIdList(ids);
|
||||
if (!normalized.length) return;
|
||||
lockedUserIds.value = normalized;
|
||||
selectedUserIds.value = mergeLockedUserIds(selectedUserIds.value);
|
||||
syncSelectedUsersFromIds(selectedUserIds.value);
|
||||
};
|
||||
|
||||
@@ -529,7 +586,7 @@
|
||||
showRectifyTimePicker.value = false;
|
||||
};
|
||||
|
||||
// 人员列表(安全管理人员:本部门及上级;整改责任人:隐患关联部门)
|
||||
// 人员列表(安全管理人员、整改责任人:关联部门及人员,type=2)
|
||||
const managerDeptList = ref([])
|
||||
const deptList = ref([])
|
||||
const detailPersonPool = ref([])
|
||||
@@ -541,9 +598,25 @@
|
||||
const showUserPopup = ref(false)
|
||||
const selectedUserIds = ref([])
|
||||
const selectedUsers = ref([])
|
||||
const lockedUserIds = ref([])
|
||||
const activeDeptIndex = ref(0)
|
||||
const userPickerSelectedIds = ref([])
|
||||
|
||||
const isLockedUser = (userId) => lockedUserIds.value.includes(String(userId));
|
||||
|
||||
const mergeLockedUserIds = (ids) => {
|
||||
const merged = new Set([
|
||||
...(ids || []).map((id) => String(id)),
|
||||
...lockedUserIds.value.map((id) => String(id))
|
||||
]);
|
||||
return [...merged];
|
||||
};
|
||||
|
||||
const formatUserPickerLabel = (user) => {
|
||||
const name = formatUserDisplayName(user);
|
||||
return isLockedUser(user.userId) ? `${name}(默认)` : name;
|
||||
};
|
||||
|
||||
const formatUserDisplayName = (user) => {
|
||||
if (user.postName) {
|
||||
return `${user.nickName}_${user.postName}`;
|
||||
@@ -647,6 +720,10 @@
|
||||
|
||||
function onUserCheckChange(userId, checked) {
|
||||
const id = String(userId);
|
||||
if (!checked && isLockedUser(id)) {
|
||||
uni.showToast({ title: '默认整改责任人不可取消', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (checked) {
|
||||
if (!userPickerSelectedSet.value.has(id)) {
|
||||
userPickerSelectedIds.value = [...userPickerSelectedIds.value, id];
|
||||
@@ -668,7 +745,7 @@
|
||||
};
|
||||
|
||||
const openUserPopup = () => {
|
||||
userPickerSelectedIds.value = [...selectedUserIds.value];
|
||||
userPickerSelectedIds.value = mergeLockedUserIds(selectedUserIds.value);
|
||||
const firstDeptWithUsers = deptList.value.findIndex((dept) => dept.users?.length > 0);
|
||||
activeDeptIndex.value = firstDeptWithUsers >= 0 ? firstDeptWithUsers : 0;
|
||||
showUserPopup.value = true;
|
||||
@@ -687,45 +764,65 @@
|
||||
|
||||
// 确认选择整改责任人
|
||||
const confirmUserSelect = () => {
|
||||
userPickerSelectedIds.value = mergeLockedUserIds(userPickerSelectedIds.value);
|
||||
selectedUserIds.value = userPickerSelectedIds.value.map((id) => String(id));
|
||||
syncSelectedUsersFromIds(selectedUserIds.value);
|
||||
showUserPopup.value = false;
|
||||
};
|
||||
|
||||
// 获取安全管理人员候选列表(本部门及上级部门)
|
||||
const fetchManagerDeptUsers = async () => {
|
||||
// 获取关联部门及人员列表(全部上级部门、本部门、全部下级部门)
|
||||
const fetchRelatedDeptUsers = async () => {
|
||||
try {
|
||||
const res = await getDepartmentPersonUsers();
|
||||
const res = await getRelatedDeptUsers({ type: 2 });
|
||||
if (res.code === 0 && res.data) {
|
||||
managerDeptList.value = res.data;
|
||||
deptList.value = res.data;
|
||||
if (selectedManagerIds.value.length > 0) {
|
||||
syncSelectedManagersFromIds(selectedManagerIds.value);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取安全管理人员列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取整改责任人候选列表(隐患关联部门人员)
|
||||
const fetchRectifyDeptUsers = async () => {
|
||||
console.log('当前hazardId:', hazardId.value);
|
||||
try {
|
||||
const res = await getDeptUsersWithSubordinates({ hazardId: hazardId.value });
|
||||
if (res.code === 0 && res.data) {
|
||||
deptList.value = res.data;
|
||||
if (selectedUserIds.value.length > 0) {
|
||||
syncSelectedUsersFromIds(selectedUserIds.value);
|
||||
}
|
||||
console.log('整改责任人部门树:', deptList.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取整改责任人列表失败:', error);
|
||||
console.error('获取关联部门人员列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取安全管理人员候选列表(本部门及上级部门)
|
||||
// const fetchManagerDeptUsers = async () => {
|
||||
// try {
|
||||
// const res = await getDepartmentPersonUsers();
|
||||
// if (res.code === 0 && res.data) {
|
||||
// managerDeptList.value = res.data;
|
||||
// if (selectedManagerIds.value.length > 0) {
|
||||
// syncSelectedManagersFromIds(selectedManagerIds.value);
|
||||
// }
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('获取安全管理人员列表失败:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// 获取整改责任人候选列表(隐患关联部门人员)
|
||||
// const fetchRectifyDeptUsers = async () => {
|
||||
// console.log('当前hazardId:', hazardId.value);
|
||||
// try {
|
||||
// const res = await getDeptUsersWithSubordinates({ hazardId: hazardId.value });
|
||||
// if (res.code === 0 && res.data) {
|
||||
// deptList.value = res.data;
|
||||
// if (selectedUserIds.value.length > 0) {
|
||||
// syncSelectedUsersFromIds(selectedUserIds.value);
|
||||
// }
|
||||
// console.log('整改责任人部门树:', deptList.value);
|
||||
// }
|
||||
// } catch (error) {
|
||||
// console.error('获取整改责任人列表失败:', error);
|
||||
// }
|
||||
// };
|
||||
|
||||
const fetchPersonnelLists = async () => {
|
||||
await Promise.all([fetchManagerDeptUsers(), fetchRectifyDeptUsers()]);
|
||||
await fetchRelatedDeptUsers();
|
||||
if (selectedManagerIds.value.length > 0) {
|
||||
syncSelectedManagersFromIds(selectedManagerIds.value);
|
||||
}
|
||||
@@ -763,7 +860,8 @@
|
||||
manageIds: selectedManagerIds.value.map((id) => Number(id)),
|
||||
memberIds: selectedUserIds.value.map((id) => Number(id)),
|
||||
rectifyTime: selectedRectifyTime.value || formatDateValue(rectifyTimeValue.value),
|
||||
signPath: signatureServerPath.value || ''
|
||||
signPath: signatureServerPath.value || '',
|
||||
sendMsgFlag: sendMsgFlag.value
|
||||
};
|
||||
|
||||
// 编辑模式需要传递rectifyId
|
||||
@@ -1037,6 +1135,11 @@
|
||||
} else if (data.rectifierId) {
|
||||
selectedUserIds.value = [String(data.rectifierId)];
|
||||
}
|
||||
if (data.assigneeId) {
|
||||
setLockedDefaultUsers(data.assigneeId);
|
||||
} else if (data.rectifierId) {
|
||||
setLockedDefaultUsers(data.rectifierId);
|
||||
}
|
||||
await fetchPersonnelLists();
|
||||
|
||||
// 回显附件
|
||||
@@ -1138,7 +1241,8 @@
|
||||
signatureUrl: signatureUrl.value,
|
||||
signatureLocalPath: signatureLocalPath.value,
|
||||
showCanvas: showCanvas.value,
|
||||
signaturePaths: signaturePaths.value
|
||||
signaturePaths: signaturePaths.value,
|
||||
sendMsgFlagRadio: sendMsgFlagRadio.value
|
||||
}),
|
||||
hasContent: rectifyDraftHasContent,
|
||||
applyPayload: (data) => {
|
||||
@@ -1158,6 +1262,7 @@
|
||||
} else if (data.showCanvas === false) {
|
||||
showCanvas.value = false;
|
||||
}
|
||||
sendMsgFlagRadio.value = data.sendMsgFlagRadio === 'no' ? 'no' : 'yes';
|
||||
},
|
||||
clearForm: () => {
|
||||
formData.rectifyPlan = '';
|
||||
@@ -1175,6 +1280,7 @@
|
||||
if (signatureRef.value) {
|
||||
signatureRef.value.clear();
|
||||
}
|
||||
sendMsgFlagRadio.value = 'yes';
|
||||
},
|
||||
canSave: () => !!(hazardId.value || rectifyId.value),
|
||||
onAfterRestore: (data) => {
|
||||
@@ -1203,7 +1309,8 @@
|
||||
signatureUrl.value,
|
||||
signatureLocalPath.value,
|
||||
showCanvas.value,
|
||||
signaturePaths.value
|
||||
signaturePaths.value,
|
||||
sendMsgFlagRadio.value
|
||||
]);
|
||||
|
||||
onHide(() => {
|
||||
@@ -1328,6 +1435,17 @@
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.static-field {
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
// 选择触发器样式
|
||||
.select-trigger {
|
||||
@@ -1479,6 +1597,10 @@
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.user-item-locked {
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
|
||||
@@ -175,14 +175,18 @@
|
||||
<text style="color: #333333;">{{ item.createdAt }}</text>
|
||||
</view>
|
||||
<!-- 操作按钮 -->
|
||||
<view class="margin-top flex justify-end" style="gap: 16rpx;">
|
||||
<button class="cu-btn round lg light bg-blue" @click.stop="viewHazardDetail(item)">查看详情</button>
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="cu-btn round lg bg-blue" @click.stop="goRectification(item)">立即整改</button>
|
||||
<button v-if="item.statusName === '待验收' && canAcceptance"
|
||||
class="cu-btn round lg bg-blue" @click.stop="goAcceptance(item)">立即验收</button>
|
||||
<button v-if="item.statusName === '待交办'"
|
||||
class="cu-btn round lg bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
|
||||
<view class="flex justify-end danger-card-actions">
|
||||
<button class="round cu-btn light bg-blue" @click.stop="viewHazardDetail(item)">查看详情</button>
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="round cu-btn light bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="round cu-btn bg-blue" @click.stop="goRectification(item)">立即整改</button>
|
||||
<button v-if="item.statusName === '待验收' && item.canEdit"
|
||||
class="round cu-btn light bg-blue" @click.stop="editRectification(item)">编辑整改信息</button>
|
||||
<button v-if="item.statusName === '待验收' && canAcceptance"
|
||||
class="round cu-btn bg-blue" @click.stop="goAcceptance(item)">立即验收</button>
|
||||
<button v-if="item.statusName === '待交办'"
|
||||
class="round cu-btn bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -937,4 +941,21 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-card-actions {
|
||||
margin-top: 20rpx;
|
||||
gap: 10rpx;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.cu-btn {
|
||||
padding: 0 24rpx !important;
|
||||
font-size: 26rpx !important;
|
||||
height: 60rpx !important;
|
||||
line-height: 60rpx !important;
|
||||
white-space: nowrap !important;
|
||||
flex-shrink: 0 !important;
|
||||
width: auto !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user