| src/views/safeProduction/safeWorkApproval/components/approvalDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/safeWorkApproval/fileList.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/safeWorkApproval/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/safeProduction/safeWorkApproval/index1.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/views/safeProduction/safeWorkApproval/components/approvalDia.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,530 @@ <template> <div> <el-dialog v-model="dialogFormVisible" :title="operationType === 'approval' ? '审æ¹' : '详æ '" width="700px" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" ref="formRef"> <el-row> <el-col :span="24"> <el-form-item label="æµç¨ç¼å·ï¼" prop="approveId"> <el-input v-model="form.approveId" placeholder="èªå¨ç¼å·" clearable disabled /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="ç³è¯·é¨é¨ï¼"> <el-select disabled v-model="form.approveDeptId" placeholder="éæ©é¨é¨"> <el-option v-for="user in productOptions" :key="user.deptId" :label="user.deptName" :value="user.deptId" /> </el-select> </el-form-item> </el-col> </el-row> <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> <el-col :span="24"> <el-form-item :label="props.approveType == 5 ? 'éè´ååå·ï¼' : '审æ¹äºç±ï¼'" prop="approveReason"> <el-input v-model="form.approveReason" placeholder="请è¾å ¥" clearable type="textarea" disabled /> </el-form-item> </el-col> </el-row> <!-- 审æ¹äººéæ©ï¼å¨æèç¹ï¼ --> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="ç³è¯·äººï¼" prop="approveUser"> <el-select v-model="form.approveUser" placeholder="éæ©äººå" disabled> <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="ç³è¯·æ¥æï¼" prop="approveTime"> <el-date-picker v-model="form.approveTime" type="date" placeholder="è¯·éæ©æ¥æ" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" disabled /> </el-form-item> </el-col> </el-row> </el-form> <!-- æ¥ä»·å®¡æ¹ï¼å±ç¤ºæ¥ä»·è¯¦æ ï¼å¤ç¨é宿¥ä»·"æ¥ç详æ å¯¹è¯æ¡"å å®¹ç»æï¼ --> <div v-if="isQuotationApproval" style="margin: 10px 0 18px;"> <el-divider content-position="left">æ¥ä»·è¯¦æ </el-divider> <el-skeleton :loading="quotationLoading" animated> <template #template> <el-skeleton-item variant="h3" style="width: 30%" /> <el-skeleton-item variant="text" style="width: 100%" /> <el-skeleton-item variant="text" style="width: 100%" /> </template> <template #default> <el-empty v-if="!currentQuotation || !currentQuotation.quotationNo" description="æªæ¥è¯¢å°å¯¹åºæ¥ä»·è¯¦æ " /> <template v-else> <el-descriptions :column="2" border> <el-descriptions-item label="æ¥ä»·åå·">{{ currentQuotation.quotationNo }}</el-descriptions-item> <el-descriptions-item label="客æ·åç§°">{{ currentQuotation.customer }}</el-descriptions-item> <el-descriptions-item label="ä¸å¡å">{{ currentQuotation.salesperson }}</el-descriptions-item> <el-descriptions-item label="æ¥ä»·æ¥æ">{{ currentQuotation.quotationDate }}</el-descriptions-item> <el-descriptions-item label="æææè³">{{ currentQuotation.validDate }}</el-descriptions-item> <el-descriptions-item label="仿¬¾æ¹å¼">{{ currentQuotation.paymentMethod }}</el-descriptions-item> <el-descriptions-item label="æ¥ä»·æ»é¢" :span="2"> <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> Â¥{{ Number(currentQuotation.totalAmount ?? 0).toFixed(2) }} </span> </el-descriptions-item> </el-descriptions> <div style="margin-top: 20px;"> <h4>产åæç»</h4> <el-table :data="currentQuotation.products || []" border style="width: 100%"> <el-table-column prop="product" label="产ååç§°" /> <el-table-column prop="specification" label="è§æ ¼åå·" /> <el-table-column prop="unit" label="åä½" /> <el-table-column prop="unitPrice" label="åä»·"> <template #default="scope">Â¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template> </el-table-column> </el-table> </div> <div v-if="currentQuotation.remark" style="margin-top: 20px;"> <h4>夿³¨</h4> <p>{{ currentQuotation.remark }}</p> </div> </template> </template> </el-skeleton> </div> <!-- éè´å®¡æ¹ï¼å±ç¤ºéè´è¯¦æ --> <div v-if="isPurchaseApproval" style="margin: 10px 0 18px;"> <el-divider content-position="left">éè´è¯¦æ </el-divider> <el-skeleton :loading="purchaseLoading" animated> <template #template> <el-skeleton-item variant="h3" style="width: 30%" /> <el-skeleton-item variant="text" style="width: 100%" /> <el-skeleton-item variant="text" style="width: 100%" /> </template> <template #default> <el-empty v-if="!currentPurchase || !currentPurchase.purchaseContractNumber" description="æªæ¥è¯¢å°å¯¹åºéè´è¯¦æ " /> <template v-else> <el-descriptions :column="2" border> <el-descriptions-item label="éè´ååå·">{{ currentPurchase.purchaseContractNumber }}</el-descriptions-item> <el-descriptions-item label="ä¾åºååç§°">{{ currentPurchase.supplierName }}</el-descriptions-item> <el-descriptions-item label="项ç®åç§°">{{ currentPurchase.projectName }}</el-descriptions-item> <el-descriptions-item label="éå®ååå·">{{ currentPurchase.salesContractNo }}</el-descriptions-item> <el-descriptions-item label="ç¾è®¢æ¥æ">{{ currentPurchase.executionDate }}</el-descriptions-item> <el-descriptions-item label="å½å ¥æ¥æ">{{ currentPurchase.entryDate }}</el-descriptions-item> <el-descriptions-item label="仿¬¾æ¹å¼">{{ currentPurchase.paymentMethod }}</el-descriptions-item> <el-descriptions-item label="ååéé¢" :span="2"> <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> Â¥{{ Number(currentPurchase.contractAmount ?? 0).toFixed(2) }} </span> </el-descriptions-item> </el-descriptions> <div style="margin-top: 20px;"> <h4>产åæç»</h4> <el-table :data="currentPurchase.productData || []" border style="width: 100%"> <el-table-column prop="productCategory" label="产ååç§°" /> <el-table-column prop="specificationModel" label="è§æ ¼åå·" /> <el-table-column prop="unit" label="åä½" /> <el-table-column prop="quantity" label="æ°é" /> <el-table-column prop="taxInclusiveUnitPrice" label="å«ç¨åä»·"> <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveUnitPrice ?? 0).toFixed(2) }}</template> </el-table-column> <el-table-column prop="taxInclusiveTotalPrice" label="å«ç¨æ»ä»·"> <template #default="scope">Â¥{{ Number(scope.row.taxInclusiveTotalPrice ?? 0).toFixed(2) }}</template> </el-table-column> </el-table> </div> </template> </template> </el-skeleton> </div> <el-form :model="{ activities }" ref="formRef" label-position="top"> <el-steps :active="getActiveStep()" finish-status="success" process-status="process" align-center direction="vertical"> <el-step v-for="(activity, index) in activities" :key="index" finish-status="success" :title="getNodeTitle(index, activities.length)" :description="activity.approveNodeUser" :icon="getNodeIcon(activity, index)"> <template #icon> <el-icon v-if="activity.approveNodeStatus === 2" color="red" :size="22"> <WarningFilled /> </el-icon> <el-icon v-else-if="activity.isShen" color="#1890ff" :size="22"> <Edit /> </el-icon> <el-icon v-else-if="activity.approveNodeStatus === 1" color="#67C23A" :size="26"> <Check /> </el-icon> <el-icon v-else color="#C0C4CC" :size="22"> <MoreFilled /> </el-icon> </template> <template #title> <span style="color: #000000">{{ getNodeTitle(index, activities.length) }}</span> </template> <template #description> <div class="node-user"> <div class="avatar-wrapper"> <img :src="userStore.avatar" class="user-avatar" alt="" /> </div> <span style="color: #000000">{{ activity.approveNodeUser }}-{{activity.isApproval}}</span> </div> <div v-if="!activity.isShen" class="node-reason"> <span>å®¡æ¹æè§ï¼</span>{{ activity.approveNodeReason }} </div> <div v-if="!activity.isShen" class="node-reason"> <span>ç¾åï¼</span> <img :src="activity.urlTem" class="signImg" alt="" v-if="activity.urlTem" /> </div> <div v-else-if="activity.isShen"> <el-form-item :prop="'activities.' + index + '.approveNodeReason'" :rules="[{ required: true, message: 'å®¡æ¹æè§ä¸è½ä¸ºç©º', trigger: 'blur' }]"> <el-input v-model="activity.approveNodeReason" clearable type="textarea" :disabled="operationType === 'view'"></el-input> </el-form-item> </div> </template> </el-step> </el-steps> </el-form> <template #footer v-if="operationType === 'approval'"> <div class="dialog-footer"> <el-button type="primary" @click="submitForm(2)">ä¸éè¿</el-button> <el-button type="primary" @click="submitForm(1)">éè¿</el-button> <el-button @click="closeDia">åæ¶</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import { computed, getCurrentInstance, nextTick, reactive, ref, toRefs, } from "vue"; import { approveProcessDetails, getDept, updateApproveNode, } from "@/api/collaborativeApproval/approvalProcess.js"; import useUserStore from "@/store/modules/user.js"; import { userListNoPageByTenantId } from "@/api/system/user.js"; import { WarningFilled, Edit, Check, MoreFilled, } from "@element-plus/icons-vue"; import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; import { getPurchaseByCode } from "@/api/procurementManagement/procurementLedger.js"; const emit = defineEmits(["close"]); const { proxy } = getCurrentInstance(); const props = defineProps({ approveType: { type: [Number, String], default: 0, }, }); const dialogFormVisible = ref(false); const operationType = ref(""); const activities = ref([]); const formRef = ref(null); const userStore = useUserStore(); const productOptions = ref([]); const userList = ref([]); const quotationLoading = ref(false); const currentQuotation = ref({}); const purchaseLoading = ref(false); const currentPurchase = ref({}); const isQuotationApproval = computed(() => Number(props.approveType) === 6); const isPurchaseApproval = computed(() => Number(props.approveType) === 5); const data = reactive({ form: { approveTime: "", approveId: "", approveUser: "", approveDeptId: "", approveReason: "", checkResult: "", }, }); const { form } = toRefs(data); // èç¹æ é¢ const getNodeTitle = (index, len) => { if (index === len - 1) return "ç»æ"; return "审æ¹"; }; // è·åå½åæ¿æ´»æ¥éª¤ const getActiveStep = () => { // å¦æææ isShen é½ä¸º falseï¼è¿åæåä¸ä¸ªæ¥éª¤ï¼å ¨é¨å®æï¼ const hasActive = activities.value.some(a => a.isShen === true); if (!hasActive) return activities.value.length; // å½åèç¹ç´¢å¼ return activities.value.findIndex(a => a.isShen == true); }; // æ¥éª¤icon const getNodeIcon = (activity, index) => { if (activity.approveNodeStatus === 2) return "el-icon-warning"; // ä¸éè¿ if (activity.isShen) return "Edit"; return ""; }; // æå¼å¼¹æ¡ const openDialog = (type, row) => { operationType.value = type; dialogFormVisible.value = true; currentQuotation.value = {}; currentPurchase.value = {}; userListNoPageByTenantId().then(res => { userList.value = res.data; }); form.value = { ...row }; // ç«å³æ¸ é¤è¡¨åéªè¯ç¶æï¼å ä¸ºåæ®µæ¯disabledçï¼ä¸éè¦éªè¯ï¼ nextTick(() => { if (formRef.value) { formRef.value.clearValidate(); } }); // ç¡®ä¿é项å è½½å®æååå¹é å¼ç±»å getProductOptions().then(() => { // ç¡®ä¿å¼ç±»åå¹é ï¼å¦æé项已å è½½ï¼ if (productOptions.value.length > 0 && form.value.approveDeptId) { const matchedOption = productOptions.value.find( opt => opt.deptId == form.value.approveDeptId || String(opt.deptId) === String(form.value.approveDeptId) ); if (matchedOption) { form.value.approveDeptId = matchedOption.deptId; } } // 忬¡æ¸ é¤éªè¯ï¼ç¡®ä¿é项å è½½åå¼å¹é æ£ç¡® nextTick(() => { if (formRef.value) { formRef.value.clearValidate(); } }); }); // æ¥ä»·å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"æ¥ä»·åå·"廿¥æ¥ä»·å表 if (isQuotationApproval.value) { const quotationNo = row?.approveReason; if (quotationNo) { quotationLoading.value = true; getQuotationList({ quotationNo }) .then(res => { const records = res?.data?.records || []; currentQuotation.value = records[0] || {}; }) .finally(() => { quotationLoading.value = false; }); } } // éè´å®¡æ¹ï¼ç¨å®¡æ¹äºç±å段æ¿è½½ç"éè´ååå·"廿¥éè´è¯¦æ if (isPurchaseApproval.value) { const purchaseContractNumber = row?.approveReason; if (purchaseContractNumber) { purchaseLoading.value = true; getPurchaseByCode({ purchaseContractNumber }) .then(res => { currentPurchase.value = res; }) .catch(err => { console.error("æ¥è¯¢éè´è¯¦æ 失败:", err); proxy.$modal.msgError("æ¥è¯¢éè´è¯¦æ 失败"); }) .finally(() => { purchaseLoading.value = false; }); } } approveProcessDetails(row.approveId).then(res => { activities.value = res.data; // å¢å isApprovalåæ®µ activities.value.forEach(item => { if (item.url && item.url.includes("word")) { item.urlTem = item.url.replaceAll("word", "img"); } else { item.urlTem = item.url; } if (item.approveNodeStatus === 2) { item.isApproval = "已驳å"; } else if (item.approveNodeStatus === 1) { item.isApproval = "å·²åæ"; } else { item.isApproval = "æªå®¡æ¹"; } }); }); }; const getProductOptions = () => { return getDept().then(res => { productOptions.value = res.data; }); }; // æäº¤å®¡æ¹ const submitForm = status => { const filteredActivities = activities.value.filter( activity => activity.isShen ); if (!filteredActivities || filteredActivities.length === 0) { proxy.$modal.msgError("æªæ¾å°å¾ 审æ¹çèç¹"); return; } const currentActivity = filteredActivities[0]; if (!currentActivity) { proxy.$modal.msgError("æªæ¾å°å¾ 审æ¹çèç¹"); return; } currentActivity.approveNodeStatus = status; // 夿æ¯å¦ä¸ºæå䏿¥ const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length - 1; updateApproveNode({ ...currentActivity, isLast }).then(() => { proxy.$modal.msgSuccess("æäº¤æå"); closeDia(); }); }; // å ³éå¼¹æ¡ const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; quotationLoading.value = false; currentQuotation.value = {}; purchaseLoading.value = false; currentPurchase.value = {}; emit("close"); }; defineExpose({ openDialog, }); </script> <style scoped> .node-user { margin: 10px 0; font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 8px; } .node-status { color: #1890ff; margin-left: 8px; font-size: 14px; } .node-reason { font-size: 15px; color: #333; margin: 10px 0; } .user-avatar { cursor: pointer; width: 30px; height: 30px; border-radius: 50px; } .signImg { cursor: pointer; width: 200px; height: 60px; } </style> src/views/safeProduction/safeWorkApproval/components/infoFormDia.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,486 @@ <template> <div> <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? 'æ°å¢å®¡æ¹æµç¨' : 'ç¼è¾å®¡æ¹æµç¨'" width="50%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row> <el-col :span="24"> <el-form-item label="æµç¨ç¼å·ï¼" prop="approveId"> <el-input v-model="form.approveId" placeholder="èªå¨ç¼å·" clearable disabled /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="ç³è¯·é¨é¨ï¼" prop="approveDeptName"> <!-- <el-input v-model="form.approveDeptName" placeholder="请è¾å ¥" clearable/>--> <el-select v-model="form.approveDeptId" placeholder="éæ©é¨é¨" @change="handleDeptChange"> <el-option v-for="user in productOptions" :key="user.deptId" :label="user.deptName" :value="user.deptId" /> </el-select> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item :label="props.approveType == 5 ? 'éè´ååå·ï¼' : '审æ¹äºç±ï¼'" prop="approveReason"> <el-input v-model="form.approveReason" placeholder="请è¾å ¥" clearable type="textarea" /> </el-form-item> </el-col> </el-row> <!-- è¯·åæ¶é´ï¼ä» å½ approveType 为 2 æ¶æ¾ç¤ºï¼ --> <el-row :gutter="30" v-if="props.approveType == 2"> <el-col :span="12"> <el-form-item label="请åå¼å§æ¶é´ï¼" prop="startDate"> <el-date-picker v-model="form.startDate" type="date" placeholder="è¯·éæ©å¼å§æ¥æ" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="请åç»ææ¶é´ï¼" prop="endDate"> <el-date-picker v-model="form.endDate" type="date" placeholder="è¯·éæ©ç»ææ¥æ" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> <!-- æ¥ééé¢ï¼ä» å½ approveType 为 4 æ¶æ¾ç¤ºï¼ --> <el-row v-if="props.approveType == 4"> <el-col :span="24"> <el-form-item label="æ¥ééé¢ï¼" prop="price"> <el-input-number v-model="form.price" placeholder="请è¾å ¥æ¥ééé¢" :min="0" :precision="2" :step="0.01" style="width: 100%" clearable /> </el-form-item> </el-col> </el-row> <!-- åºå·®å°ç¹ï¼ä» å½ approveType 为 3 æ¶æ¾ç¤ºï¼ --> <el-row v-if="props.approveType == 3"> <el-col :span="24"> <el-form-item label="åºå·®å°ç¹ï¼" prop="location"> <el-input v-model="form.location" placeholder="请è¾å ¥åºå·®å°ç¹" clearable /> </el-form-item> </el-col> </el-row> <!-- 审æ¹äººéæ©ï¼å¨æèç¹ï¼ --> <el-row> <el-col :span="24"> <el-form-item> <template #label> <span>审æ¹äººéæ©ï¼</span> <el-button type="primary" @click="addApproverNode" style="margin-left: 8px;">æ°å¢èç¹</el-button> </template> <div style="display: flex; align-items: flex-end; flex-wrap: wrap;"> <div v-for="(node, index) in approverNodes" :key="node.id" style="margin-right: 30px; text-align: center; margin-bottom: 10px;"> <div> <span>审æ¹äºº</span> â </div> <el-select v-model="node.userId" placeholder="éæ©äººå" style="width: 120px; margin-bottom: 8px;"> <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> </el-select> <div> <el-button type="danger" size="small" @click="removeApproverNode(index)" v-if="approverNodes.length > 1">å é¤</el-button> </div> </div> </div> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="ç³è¯·äººï¼" prop="approveUser"> <el-select v-model="form.approveUser" placeholder="éæ©äººå" filterable default-first-option :reserve-keyword="false"> <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="ç³è¯·æ¥æï¼" prop="approveTime"> <el-date-picker v-model="form.approveTime" type="date" placeholder="è¯·éæ©æ¥æ" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="éä»¶ææï¼" prop="remark"> <el-upload v-model:file-list="fileList" :action="upload.url" multiple ref="fileUpload" auto-upload :headers="upload.headers" :before-upload="handleBeforeUpload" :on-error="handleUploadError" :on-success="handleUploadSuccess" :on-remove="handleRemove"> <el-button type="primary" v-if="operationType !== 'view'">ä¸ä¼ </el-button> <template #tip v-if="operationType !== 'view'"> <div class="el-upload__tip"> æä»¶æ ¼å¼æ¯æ docï¼docxï¼xlsï¼xlsxï¼pptï¼pptxï¼pdfï¼txtï¼xmlï¼jpgï¼jpegï¼pngï¼gifï¼bmpï¼rarï¼zipï¼7z </div> </template> </el-upload> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">åæ¶</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, toRefs, getCurrentInstance } from "vue"; import { approveProcessAdd, approveProcessGetInfo, approveProcessUpdate, getDept, } from "@/api/collaborativeApproval/approvalProcess.js"; import { delLedgerFile } from "@/api/salesManagement/salesLedger.js"; import { userListNoPageByTenantId } from "@/api/system/user.js"; import { getToken } from "@/utils/auth"; const { proxy } = getCurrentInstance(); const emit = defineEmits(["close"]); import useUserStore from "@/store/modules/user"; import { getCurrentDate } from "@/utils/index.js"; import log from "@/views/monitor/job/log.vue"; const userStore = useUserStore(); const dialogFormVisible = ref(false); const operationType = ref(""); const fileList = ref([]); const upload = reactive({ // ä¸ä¼ çå°å url: import.meta.env.VITE_APP_BASE_API + "/file/upload", // 设置ä¸ä¼ ç请æ±å¤´é¨ headers: { Authorization: "Bearer " + getToken() }, }); const data = reactive({ form: { approveTime: "", approveId: "", approveUser: "", approveDeptId: "", approveDeptName: "", approveReason: "", checkResult: "", tempFileIds: [], approverList: [], // æ°å¢å段ï¼å卿æèç¹ç审æ¹äººid startDate: "", // 请åå¼å§æ¶é´ endDate: "", // 请åç»ææ¶é´ price: null, // æ¥ééé¢ location: "", // åºå·®å°ç¹ }, rules: { approveTime: [{ required: false, message: "请è¾å ¥", trigger: "change" }], approveId: [{ required: false, message: "请è¾å ¥", trigger: "blur" }], approveUser: [{ required: false, message: "请è¾å ¥", trigger: "blur" }], approveDeptName: [{ required: true, message: "请è¾å ¥", trigger: "blur" }], approveReason: [{ required: true, message: "请è¾å ¥", trigger: "blur" }], checkResult: [{ required: false, message: "请è¾å ¥", trigger: "blur" }], startDate: [ { required: true, message: "è¯·éæ©è¯·åå¼å§æ¶é´", trigger: "change" }, ], endDate: [ { required: true, message: "è¯·éæ©è¯·åç»ææ¶é´", trigger: "change" }, ], price: [{ required: true, message: "请è¾å ¥æ¥ééé¢", trigger: "blur" }], location: [{ required: true, message: "请è¾å ¥åºå·®å°ç¹", trigger: "blur" }], }, }); const { form, rules } = toRefs(data); const productOptions = ref([]); const currentApproveStatus = ref(0); const props = defineProps({ approveType: { type: [Number, String], default: 0, }, }); // 审æ¹äººèç¹ç¸å ³ const approverNodes = ref([{ id: 1, userId: null }]); let nextApproverId = 2; const userList = ref([]); function addApproverNode() { approverNodes.value.push({ id: nextApproverId++, userId: null }); } function removeApproverNode(index) { approverNodes.value.splice(index, 1); } // å¤çé¨é¨éæ©åå const handleDeptChange = deptId => { if (deptId) { const selectedDept = productOptions.value.find( dept => dept.deptId === deptId ); if (selectedDept) { form.value.approveDeptName = selectedDept.deptName; } } else { form.value.approveDeptName = ""; } }; // æå¼å¼¹æ¡ const openDialog = (type, row) => { operationType.value = type; dialogFormVisible.value = true; userListNoPageByTenantId().then(res => { userList.value = res.data; }); form.value = {}; approverNodes.value = [{ id: 1, userId: null }]; form.value.approveUser = userStore.id; form.value.approveTime = getCurrentDate(); // è·åå½åç¨æ·ä¿¡æ¯å¹¶è®¾ç½®é¨é¨ID form.value.approveDeptId = userStore.currentDeptId; // å è½½é¨é¨é项ï¼å¹¶å¨å è½½å®æå设置é¨é¨åç§° getProductOptions(); if (operationType.value === "edit") { fileList.value = row.commonFileList; form.value.tempFileIds = fileList.value.map(file => file.id); currentApproveStatus.value = row.approveStatus; approveProcessGetInfo({ id: row.approveId, approveReason: "1" }).then( res => { form.value = { ...res.data }; // 忾审æ¹äºº if (res.data && res.data.approveUserIds) { const userIds = res.data.approveUserIds.split(","); approverNodes.value = userIds.map((userId, idx) => ({ id: idx + 1, userId: parseInt(userId.trim()), })); nextApproverId = userIds.length + 1; } else { approverNodes.value = [{ id: 1, userId: null }]; nextApproverId = 2; } } ); } }; const getProductOptions = () => { return getDept().then(res => { productOptions.value = res.data; // 妿已æé¨é¨IDï¼èªå¨è®¾ç½®é¨é¨åç§°ï¼ç¨äºéªè¯ï¼ if (form.value.approveDeptId && productOptions.value.length > 0) { const matchedDept = productOptions.value.find( dept => dept.deptId == form.value.approveDeptId || String(dept.deptId) === String(form.value.approveDeptId) ); if (matchedDept) { form.value.approveDeptName = matchedDept.deptName; } } }); }; function convertIdToValue(data) { return data.map(item => { const { id, children, ...rest } = item; const newItem = { ...rest, value: id, // å° id æ¹ä¸º value }; if (children && children.length > 0) { newItem.children = convertIdToValue(children); } return newItem; }); } // æäº¤äº§å表å const submitForm = () => { // æ¶éææèç¹ç审æ¹äººid form.value.approveUserIds = approverNodes.value .map(node => node.userId) .join(","); form.value.approveType = props.approveType; // 审æ¹äººå¿ å¡«æ ¡éª const hasEmptyApprover = approverNodes.value.some(node => !node.userId); if (hasEmptyApprover) { proxy.$modal.msgError("请为ææå®¡æ¹èç¹éæ©å®¡æ¹äººï¼"); return; } // å½ approveType 为 2 æ¶ï¼æ ¡éªè¯·åæ¶é´ if (props.approveType == 2) { if (!form.value.startDate) { proxy.$modal.msgError("è¯·éæ©è¯·åå¼å§æ¶é´ï¼"); return; } if (!form.value.endDate) { proxy.$modal.msgError("è¯·éæ©è¯·åç»ææ¶é´ï¼"); return; } // æ ¡éªç»ææ¶é´ä¸è½æ©äºå¼å§æ¶é´ if (new Date(form.value.endDate) < new Date(form.value.startDate)) { proxy.$modal.msgError("请åç»ææ¶é´ä¸è½æ©äºå¼å§æ¶é´ï¼"); return; } } // å½ approveType 为 3 æ¶ï¼æ ¡éªåºå·®å°ç¹ if (props.approveType == 3) { if (!form.value.location || form.value.location.trim() === "") { proxy.$modal.msgError("请è¾å ¥åºå·®å°ç¹ï¼"); return; } } // å½ approveType 为 4 æ¶ï¼æ ¡éªæ¥ééé¢ if (props.approveType == 4) { if (!form.value.price || form.value.price <= 0) { proxy.$modal.msgError("请è¾å ¥ææçæ¥ééé¢ï¼"); return; } } proxy.$refs.formRef.validate(valid => { if (valid) { if (operationType.value === "add" || currentApproveStatus.value == 3) { approveProcessAdd(form.value).then(res => { proxy.$modal.msgSuccess("æäº¤æå"); closeDia(); }); } else { approveProcessUpdate(form.value).then(res => { proxy.$modal.msgSuccess("æäº¤æå"); closeDia(); }); } } }); }; // å ³éå¼¹æ¡ const closeDia = () => { fileList.value = []; proxy.resetForm("formRef"); dialogFormVisible.value = false; emit("close"); }; // ä¸ä¼ åæ ¡æ£ function handleBeforeUpload(file) { // æ ¡æ£æä»¶å¤§å° // if (file.size > 1024 * 1024 * 10) { // proxy.$modal.msgError("ä¸ä¼ æä»¶å¤§å°ä¸è½è¶ è¿10MB!"); // return false; // } proxy.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); return true; } // ä¸ä¼ 失败 function handleUploadError(err) { proxy.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); proxy.$modal.closeLoading(); } // ä¸ä¼ æååè° function handleUploadSuccess(res, file, uploadFiles) { proxy.$modal.closeLoading(); if (res.code === 200) { // ç¡®ä¿ tempFileIds åå¨ä¸ä¸ºæ°ç» if (!form.value.tempFileIds) { form.value.tempFileIds = []; } form.value.tempFileIds.push(res.data.tempId); proxy.$modal.msgSuccess("ä¸ä¼ æå"); } else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload.handleRemove(file); } } // ç§»é¤æä»¶ function handleRemove(file) { if (operationType.value === "edit") { let ids = []; ids.push(file.id); delLedgerFile(ids).then(res => { proxy.$modal.msgSuccess("å 餿å"); }); } } defineExpose({ openDialog, }); </script> <style scoped> </style> src/views/safeProduction/safeWorkApproval/fileList.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,67 @@ <template> <el-dialog v-model="dialogVisible" title="éä»¶" width="40%" :before-close="handleClose" draggable> <el-table :data="tableData" border height="40vh"> <el-table-column label="éä»¶åç§°" prop="name" min-width="400" show-overflow-tooltip /> <el-table-column fixed="right" label="æä½" width="150" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">ä¸è½½</el-button> <el-button link type="primary" size="small" @click="lookFile(scope.row)">é¢è§</el-button> <el-button link type="danger" size="small" @click="handleDelete(scope.row)">å é¤</el-button> </template> </el-table-column> </el-table> </el-dialog> <filePreview ref="filePreviewRef" /> </template> <script setup> import { ref } from 'vue' import filePreview from '@/components/filePreview/index.vue' import { ElMessageBox, ElMessage } from 'element-plus' import { delCommonFile } from '@/api/publicApi/commonFile.js' const dialogVisible = ref(false) const tableData = ref([]) const { proxy } = getCurrentInstance(); const filePreviewRef = ref() const handleClose = () => { dialogVisible.value = false } const open = (list) => { dialogVisible.value = true tableData.value = list } const downLoadFile = (row) => { proxy.$download.name(row.url); } const lookFile = (row) => { filePreviewRef.value.open(row.url) } // å é¤éä»¶ const handleDelete = (row) => { ElMessageBox.confirm(`确认å é¤éä»¶"${row.name}"åï¼`, 'æç¤º', { confirmButtonText: 'ç¡®å®', cancelButtonText: 'åæ¶', type: 'warning' }).then(() => { delCommonFile([row.id]).then(() => { ElMessage.success('å 餿å') // ä»å表ä¸ç§»é¤å·²å é¤çéä»¶ const index = tableData.value.findIndex(item => item.id === row.id) if (index !== -1) { tableData.value.splice(index, 1) } }).catch(() => { ElMessage.error('å é¤å¤±è´¥') }) }).catch(() => { ElMessage.info('已忶å é¤') }) } defineExpose({ open }) </script> <style></style> src/views/safeProduction/safeWorkApproval/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,371 @@ <template> <div class="app-container"> <!-- æ ç¾é¡µåæ¢ä¸åç审æ¹ç±»å --> <div class="search_form"> <div> <span class="search_title">æµç¨ç¼å·ï¼</span> <el-input v-model="searchForm.approveId" style="width: 240px" placeholder="请è¾å ¥æµç¨ç¼å·æç´¢" @change="handleQuery" clearable :prefix-icon="Search" /> <span class="search_title ml10">审æ¹ç¶æï¼</span> <el-select v-model="searchForm.approveStatus" clearable @change="handleQuery" style="width: 240px"> <el-option label="å¾ å®¡æ ¸" :value="0" /> <el-option label="å®¡æ ¸ä¸" :value="1" /> <el-option label="å®¡æ ¸å®æ" :value="2" /> <el-option label="å®¡æ ¸æªéè¿" :value="3" /> <el-option label="已鿰æäº¤" :value="4" /> </el-select> <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> </div> <div> <el-button type="primary" @click="openForm('add')">æ°å¢</el-button> <el-button @click="handleOut">导åº</el-button> <el-button type="danger" plain @click="handleDelete">å é¤</el-button> </div> </div> <div class="table_list"> <PIMTable rowKey="id" :column="tableColumnCopy" :tableData="tableData" :page="page" :isSelection="true" @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination" :total="page.total"></PIMTable> </div> <info-form-dia ref="infoFormDia" @close="handleQuery" :approveType="currentApproveType"></info-form-dia> <approval-dia ref="approvalDia" @close="handleQuery" :approveType="currentApproveType"></approval-dia> <FileList ref="fileListRef" /> </div> </template> <script setup> import FileList from "./fileList.vue"; import { Search } from "@element-plus/icons-vue"; import { onMounted, ref, computed, reactive, toRefs, nextTick, getCurrentInstance, } from "vue"; import { ElMessageBox } from "element-plus"; import { useRoute } from "vue-router"; import InfoFormDia from "@/views/collaborativeApproval/approvalProcess/components/infoFormDia.vue"; import ApprovalDia from "@/views/collaborativeApproval/approvalProcess/components/approvalDia.vue"; import { approveProcessDelete, approveProcessListPage, } from "@/api/collaborativeApproval/approvalProcess.js"; import useUserStore from "@/store/modules/user"; const userStore = useUserStore(); const route = useRoute(); // å½å审æ¹ç±»åï¼æ ¹æ®éä¸çæ ç¾é¡µè®¡ç® const currentApproveType = computed(() => { return Number(8); }); // æ ç¾é¡µåæ¢å¤ç const handleTabChange = tabName => { // 忢æ ç¾é¡µæ¶éç½®æç´¢æ¡ä»¶åå页ï¼å¹¶éæ°å è½½æ°æ® searchForm.value.approveId = ""; searchForm.value.approveStatus = ""; page.current = 1; getList(); }; const data = reactive({ searchForm: { approveId: "", approveStatus: "", }, }); const { searchForm } = toRefs(data); // å¨æè¡¨æ ¼åé ç½®ï¼æ ¹æ®å®¡æ¹ç±»åçæå const tableColumnCopy = computed(() => { // åºç¡åé ç½® const baseColumns = [ { label: "审æ¹ç¶æ", prop: "approveStatus", dataType: "tag", width: 100, formatData: params => { if (params == 0) { return "å¾ å®¡æ ¸"; } else if (params == 1) { return "å®¡æ ¸ä¸"; } else if (params == 2) { return "å®¡æ ¸å®æ"; } else if (params == 4) { return "已鿰æäº¤"; } else { return "ä¸éè¿"; } }, formatType: params => { if (params == 0) { return "warning"; } else if (params == 1) { return "primary"; } else if (params == 2) { return "success"; } else if (params == 4) { return "info"; } else { return "danger"; } }, }, { label: "æµç¨ç¼å·", prop: "approveId", width: 170, }, { label: "ç³è¯·é¨é¨", prop: "approveDeptName", width: 220, }, { label: "审æ¹äºç±", prop: "approveReason", width: 200, }, { label: "ç³è¯·äºº", prop: "approveUserName", width: 120, }, ]; // æ¥æåï¼æ ¹æ®ç±»å卿é ç½®ï¼ baseColumns.push( { label: "ç³è¯·æ¥æ", prop: "approveTime", width: 200, }, { label: "ç»ææ¥æ", prop: "approveOverTime", width: 120, } ); // å½å审æ¹äººå baseColumns.push({ label: "å½å审æ¹äºº", prop: "approveUserCurrentName", width: 120, }); // æä½å baseColumns.push({ dataType: "action", label: "æä½", align: "center", fixed: "right", width: 230, operation: [ { name: "ç¼è¾", type: "text", clickFun: row => { openForm("edit", row); }, disabled: row => row.approveStatus == 2 || row.approveStatus == 1 || row.approveStatus == 4, }, { name: "å®¡æ ¸", type: "text", clickFun: row => { openApprovalDia("approval", row); }, disabled: row => row.approveUserCurrentId == null || row.approveStatus == 2 || row.approveStatus == 3 || row.approveStatus == 4 || row.approveUserCurrentId !== userStore.id, }, { name: "详æ ", type: "text", clickFun: row => { openApprovalDia("view", row); }, }, { name: "éä»¶", type: "text", clickFun: row => { downLoadFile(row); }, }, ], }); return baseColumns; }); const tableData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, total: 0, }); const infoFormDia = ref(); const approvalDia = ref(); const { proxy } = getCurrentInstance(); // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); }; const fileListRef = ref(null); const downLoadFile = row => { fileListRef.value.open(row.commonFileList); }; const pagination = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; approveProcessListPage({ ...page, ...searchForm.value, approveType: currentApproveType.value, }) .then(res => { tableLoading.value = false; tableData.value = res.data.records; page.total = res.data.total; }) .catch(err => { tableLoading.value = false; }); }; // å¯¼åº const handleOut = () => { const type = currentApproveType.value; const urlMap = { 0: "/approveProcess/exportZero", 1: "/approveProcess/exportOne", 2: "/approveProcess/exportTwo", 3: "/approveProcess/exportThree", 4: "/approveProcess/exportFour", 5: "/approveProcess/exportFive", 6: "/approveProcess/exportSix", 7: "/approveProcess/exportSeven", 8: "/approveProcess/exportEight", }; const url = urlMap[type] || urlMap[0]; const nameMap = { 0: "åå审æ¹ç®¡ç表", 1: "å ¬åºç®¡ç审æ¹è¡¨", 2: "请å管ç审æ¹è¡¨", 3: "åºå·®ç®¡ç审æ¹è¡¨", 4: "æ¥é管ç审æ¹è¡¨", 5: "éè´ç³è¯·å®¡æ¹è¡¨", 6: "æ¥ä»·å®¡æ¹è¡¨", 7: "å货审æ¹è¡¨", 8: "å±é©ä½ä¸å®¡æ¹è¡¨", }; const fileName = nameMap[type] || nameMap[0]; proxy.download(url, {}, `${fileName}.xlsx`); }; // è¡¨æ ¼éæ©æ°æ® const handleSelectionChange = selection => { selectedRows.value = selection; }; // æå¼æ°å¢ãç¼è¾å¼¹æ¡ const openForm = (type, row) => { nextTick(() => { infoFormDia.value?.openDialog(type, row); }); }; // æå¼æ°å¢æ£éªå¼¹æ¡ const openApprovalDia = (type, row) => { nextTick(() => { approvalDia.value?.openDialog(type, row); }); }; // å é¤ const handleDelete = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.approveId); } else { proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); return; } ElMessageBox.confirm("éä¸çå 容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) .then(() => { approveProcessDelete(ids).then(res => { proxy.$modal.msgSuccess("å 餿å"); getList(); }); }) .catch(() => { proxy.$modal.msg("已忶"); }); }; onMounted(() => { const approveId = route.query.approveId; if (approveId) { // 设置æµç¨ç¼å·æ¥è¯¢æ¡ä»¶ searchForm.value.approveId = String(approveId); } // æ¥è¯¢å表 getList(); }); </script> <style scoped> .approval-tabs { margin-bottom: 10px; } </style> src/views/safeProduction/safeWorkApproval/index1.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,22 @@ <template> <div class="container"> <!-- å¼å ¥index.vueç»ä»¶å¹¶ä¼ éåæ° --> <ApprovalProcessIndex :approveType="1" /> </div> </template> <script setup> import ApprovalProcessIndex from "./index.vue"; // å®ä¹ç»ä»¶åç§° defineOptions({ name: "ApprovalProcessIndex1", }); </script> <style scoped> .container { width: 100%; height: 100%; } </style>