<!-- 分包申请详情 --> <script lang="ts" setup> import { ElLoading, ElMessage, ElMessageBox } from 'element-plus' import type { FormInstance, FormRules } from 'element-plus' import { ref } from 'vue' import type { IApplyDetail, ISampleList } from '../subpackage-interface' import selectProjectApprove from '../apply/components/selectProjectApprove.vue' import selectSample from './components/selectSample.vue' import type { dictType } from './apply-interface' import { UploadFile } from '@/api/measure/file' import ApprovalDialog from '@/components/Approval/ApprovalDialog.vue' import type { TableColumn } from '@/components/NormalTable/table_interface' import { addApply, detail, failUpdateApply, submit, updateApply } from '@/api/business/subpackage/apply' import { cancelApproval, fetchApproval, submitApproval } from '@/api/approval' import showPhoto from '@/views/system/tool/showPhoto.vue' import { getDictByCode } from '@/api/system/dict' import useUserStore from '@/store/modules/user' const user = useUserStore() // 用户信息 const textMap: { [key: string]: string } = { edit: '编辑', add: '新建', detail: '详情', }// 字典 const { proxy } = getCurrentInstance() as any const $router = useRouter() // 关闭页面使用 const $route = useRoute() const query = $route.query const approvalDialog = ref() // 审批对话ref const pageType = ref('add') // 页面类型: add, edit, detail const infoId = ref('') // 列表id const submitId = ref('') // 新建提交时所用的id const outsourceReasonMap = ref<dictType[]>([]) // 分包原因 const ruleFormRef = ref<FormInstance>() as any const detailForm = ref<IApplyDetail>({ projectNo: '', // 分包项目编号 formId: query.formId as string, applicantTime: '', // 申请时间 applyMinioFileName: '', // 申请文件名称 applyProcessId: '', // 流程实例id applyRemark: '', // 申请备注 createUser: '', // 申请人 createUserName: '', // 申请人名称 orderSampleList: [] as any, // 订单列表 outsourceReason: '', // 分包原因 outsourceReasonName: '', // 原因名称 outsourcerId: '', // 分包方id outsourcerNo: '', // 分包方编号 outsourcerName: '', // 公司名称 preCost: '', // 预计费用 preEndTime: '', // 预计结束时间 preStartTime: '', // 预计开始时间 projectName: '', // 分包项目名称 sampleList: [] as any, // 样品列表 rejectRemark: '', // 历次原因 }) // 自定义校验规则--要求预计结束时间大于预计开始时间 const requireOverTimeValid = (rule: any, value: any, callback: any) => { if (!value) { return callback(new Error('预计结束时间必填')) } if (new Date(detailForm.value.preEndTime).getTime() <= new Date(detailForm.value.preStartTime).getTime()) { return callback(new Error('不能小于预计开始时间')) } callback() } // 校验规则 const formRules = ref<FormRules>({ projectName: [{ required: true, message: '分包项目名称必填', trigger: ['blur', 'change'] }], outsourcerNo: [{ required: true, message: '分包方编号必填', trigger: ['blur', 'change'] }], // outsourcerName: [{ required: true, message: '要求公司名称必填', trigger: ['blur', 'change'] }], outsourceReason: [{ required: true, message: '分包原因必填', trigger: ['blur', 'change'] }], // preCost: [{ required: true, message: '预计费用必填', trigger: ['blur', 'change'] }, // { pattern: /(^-?\d\d*\.\d*$)|(^-?\d\d*$)|(^-?\.\d\d*$)/, message: '预计费用只能为数字', trigger: ['blur', 'change'] }], preStartTime: [{ required: true, message: '预计开始时间必填', trigger: ['blur', 'change'] }], // preEndTime: [{ required: true, message: '预计结束时间必填', trigger: ['blur', 'change'] }], preEndTime: [{ required: true, type: 'date', validator: requireOverTimeValid, trigger: 'change' }], }) const list = ref<ISampleList[]>([])// 表格数据 // 表头 const columns = ref<TableColumn[]>([ { text: '样品编号', value: 'sampleNo', align: 'center', width: '230' }, { text: '样品名称', value: 'sampleName', align: 'center' }, { text: '型号', value: 'sampleModel', align: 'center' }, { text: '出厂编号', value: 'manufacturingNo', align: 'center' }, { text: '委托单编号', value: 'orderCode', align: 'center' }, { text: '委托单位', value: 'customerName', align: 'center' }, ]) // 从路由中获取页面类型参数 if ($route.params && $route.params.type) { pageType.value = $route.params.type as string console.log(pageType.value) if ($route.params.id) { infoId.value = $route.params.id as string } } // 获取字典值 function getDict() { // 分包原因 getDictByCode('outsourceReason').then((response) => { outsourceReasonMap.value = response.data }) } // 获取详情信息 const getDetail = () => { const loading = ElLoading.service({ lock: true, background: 'rgba(255, 255, 255, 0.8)', }) detail({ id: $route.params.id as string }).then((res) => { loading.close() detailForm.value = res.data detailForm.value.createUserName = res.data.applicantName || user.name list.value = res.data.sampleList.filter((item: ISampleList) => { return item !== null }) }).catch(() => { loading.close() }) } // 关闭新增页面的回调 const close = () => { $router.back() } // 保存 const handleSave = () => { const tempList = list.value.filter(item => item.sampleNo) if (!tempList.length) { ElMessage.warning('样品信息不能为空') return } ruleFormRef.value.validate((valid: boolean) => { if (valid) { const loading = ElLoading.service({ lock: true, background: 'rgba(255, 255, 255, 0.8)', }) // 样品&委托单列表(保存/编辑草稿接口入参使用) const temList = [] as any // 临时数组 console.log('保存中的数组', list.value) list.value.forEach((item: any) => { if ((item.orderId && item.id) || (item.orderId && item.sampleId)) { temList.push({ orderId: item.orderId, sampleId: item.id || item.sampleId, }) } }) detailForm.value.orderSampleList = temList if (pageType.value === 'add') { // 新建 addApply(detailForm.value).then((res) => { submitId.value = res.data.id detailForm.value.projectNo = res.data.projectNo // 分包项目编号 ElMessage.success('保存成功') loading.close() }).catch(() => { loading.close() }) } else if (pageType.value === 'edit') { // 编辑 if (query.approvalStatusName === '未通过-驳回') { // 未通过-驳回 failUpdateApply(detailForm.value).then((res) => { ElMessage.success('保存成功') loading.close() close() }).catch(() => { loading.close() }) } else { // 草稿箱和已取消 updateApply(detailForm.value).then((res) => { ElMessage.success('保存成功') loading.close() close() }).catch(() => { loading.close() }) } } } }) } // 提交 const handleSubmit = () => { if (submitId.value) { const loading = ElLoading.service({ lock: true, background: 'rgba(255, 255, 255, 0.8)', }) const params = { id: submitId.value, formId: query.formId, // 表单id } submit(params).then(() => { ElMessage.success('提交成功') loading.close() close() }).catch(() => { loading.close() }) } else { ElMessage.warning('请先保存!') } } // 增加行 const addRow = () => { const index = list.value.findIndex(item => !item.sampleNo) if (index !== -1) { ElMessage.warning('请完善上一条样品信息') return } list.value.push({ orderCode: '', // 原始记录单编号 sampleName: '', // 样品名称 sampleNo: '', // 样品编号 customerNo: '', // 委托方id customerName: '', // 委托方名称 startTime: '', endTime: '', }) } const sampleVisible = ref(false) const projectVisible = ref(false) const isMulti = ref(false) const selectIndex = ref(0) // 点击选择 const handleSelect = (index: number, row: ISampleList) => { sampleVisible.value = true // 选择设备对话框显隐 isMulti.value = false // 是否单选, false单选、true表格多选 selectIndex.value = index } // 点击批量添加 const multiAdd = () => { sampleVisible.value = true // 打开选择样品的对话框 isMulti.value = true } const checkoutList = ref([]) // 选中的行 // 修改委托方对话框显隐 const changeSampleVisible = (val: boolean) => { sampleVisible.value = val } // 修改项目选择对话框显隐 const changeProjectVisible = (val: boolean) => { projectVisible.value = val } // 选好样品 const clickConfirmSample = (val: any) => { if (val && val.length) { if (isMulti.value) { val.forEach((item: ISampleList) => { // 只添加列表里不存在的 const index = list.value.findIndex((i: ISampleList) => item.sampleNo === i.sampleNo) if (index === -1) { list.value.push(item) } }) } else { const index = list.value.findIndex((i: ISampleList) => val[0].sampleNo === i.sampleNo) if (index !== -1) { ElMessage.warning('此样品已添加过') return } list.value.splice(selectIndex.value, 1, val[0]) } } } // 选择分包方 const clickConfirmProject = (val: any) => { detailForm.value.outsourcerId = val[0].id // 分包方id detailForm.value.outsourcerNo = val[0].outsourcerNo // 分包方编号 detailForm.value.outsourcerName = val[0].outsourcerName // 公司名称 // detailForm.value.applyProcessId = val[0].processId // 流程实例id } // 选中行 const handleSelectionChange = (e: any) => { checkoutList.value = e } // 删除行 const delRow = () => { checkoutList.value.forEach((item: ISampleList) => { list.value.forEach((element, index) => { if (element.sampleNo === item.sampleNo) { list.value.splice(index, 1) } }) }) } // ---------------------------------文件上传------------------------------------------- const fileRef = ref() const onFileChange = (event: any) => { // 原生上传 if (event.target.files?.length !== 0) { // 创建formdata对象 const fd = new FormData() fd.append('multipartFile', event.target.files[0]) const loading = ElLoading.service({ lock: true, background: 'rgba(255, 255, 255, 0.8)', }) UploadFile(fd).then((res) => { if (res.code === 200) { detailForm.value.applyMinioFileName = res.data[0] // 重置当前验证 ElMessage.success('文件上传成功') loading.close() } else { ElMessage.error(res.message) loading.close() } }) } } const upload = () => { fileRef.value.click() } // ------------------------------------------审批----------------------------------------- const approvalRecordData = ref([]) // 审批流程数据 // 查询审批记录 function getApprovalRecord(processId: string) { if (pageType.value !== 'add') { if (processId) { fetchApproval(processId).then((res) => { approvalRecordData.value = res.data }) } else { ElMessage.warning('流程实例id为空') } } } // 审批结束回调 const approvalSuccess = () => { close() // 返回上一页 } // 审批 const handleApprove = (val: string, title = '') => { if (val === '取消') { const params = { processInstanceId: detailForm.value.applyProcessId!, comments: '', } ElMessageBox.confirm( '确认取消该审批吗?', '提示', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }, ) .then(() => { cancelApproval(params).then((res) => { ElMessage({ type: 'success', message: '取消成功', }) close() }) }) } else if (val === '同意') { approvalDialog.value.initDialog('agree', query.taskId) } else if (val === '驳回') { approvalDialog.value.initDialog('reject', query.taskId) } else if (val === '拒绝') { approvalDialog.value.initDialog('refuse', query.taskId) } } // ------------------------------------------------------------------------------------- onMounted(async () => { await getDict() detailForm.value.applyProcessId = query.applyProcessId as string // 流程实例 if (pageType.value !== 'add') { // 编辑、详情 getDetail() if (query.approvalStatusName !== '草稿箱') { getApprovalRecord(detailForm.value.applyProcessId) // 获取审批流程 } } else { // 新建 detailForm.value.createUser = user.id // 申请人id detailForm.value.createUserName = user.name // 申请人名字 detailForm.value.applicantTime = proxy.dayjs().format('YYYY-MM-DD HH:mm:ss') // 申请时间 } }) // 监听到驳回原因 const giveRejectRemark = (reason: string) => { if (detailForm.value.rejectRemark) { const lastIndex = detailForm.value.rejectRemark.lastIndexOf(reason) if (lastIndex === -1) { // 本次原因和上次最后一次原因不同才去拼接 detailForm.value.rejectRemark = `${detailForm.value.rejectRemark};${reason}` } } else { detailForm.value.rejectRemark = reason } } </script> <template> <app-container style="overflow: hidden;"> <detail-page :title="`分包项目申请-${textMap[pageType]}`"> <template #btns> <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批'" type="primary" @click="handleApprove('同意')"> 同意 </el-button> <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批' && query.decisionItem !== '3'" type="primary" @click="handleApprove('驳回')"> 驳回 </el-button> <el-button v-if="pageType === 'detail' && query.approvalStatusName === '待审批' && query.decisionItem !== '2'" type="danger" @click="handleApprove('拒绝')"> 拒绝 </el-button> <el-button v-if="pageType === 'add'" type="primary" @click="handleSubmit"> 提交 </el-button> <el-button v-if="pageType !== 'detail'" type="primary" @click="handleSave"> 保存 </el-button> <!-- <el-button v-if="pageType === 'detail'" type="primary"> 打印 </el-button> --> <el-button v-if="pageType === 'detail' && query.approvalStatusName === '审批中'" type="info" @click="handleApprove('取消')"> 取消 </el-button> <el-button type="info" @click="close"> 关闭 </el-button> </template> <el-form ref="ruleFormRef" :model="detailForm" label-width="140" label-position="right" :rules="formRules" > <el-row :gutter="24"> <el-col :span="6"> <el-form-item label="分包项目编号:" prop="id"> <el-input v-model="detailForm.projectNo" disabled placeholder="系统自动生成" /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="分包项目名称:" prop="projectName"> <el-input v-model="detailForm.projectName" :placeholder="pageType === 'detail' ? '' : '请输入分包项目名称'" :disabled="pageType === 'detail'" /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="申请人:"> <el-input v-model="detailForm.createUserName" disabled /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="申请时间:" prop="applicantTime"> <el-input v-model="detailForm.applicantTime" disabled /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="分包方编号:" prop="outsourcerNo"> <el-input v-model="detailForm.outsourcerNo" disabled :placeholder="pageType === 'detail' ? '' : '请选择分包方编号'" > <template v-if="pageType !== 'detail'" #append> <el-button size="small" @click="changeProjectVisible(true)" > 选择 </el-button> </template> </el-input> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="公司名称:" prop="outsourcerName"> <el-input v-model="detailForm.outsourcerName" :placeholder="pageType === 'detail' ? '' : '请输入公司名称'" disabled /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="分包原因:" prop="outsourceReason"> <el-select v-model="detailForm.outsourceReason" :placeholder="pageType === 'detail' ? '' : '请选择分包原因'" :disabled="pageType === 'detail'" class="full-width-input"> <el-option v-for="i in outsourceReasonMap" :key="i.value" :label="i.name" :value="i.value" /> </el-select> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="预计费用(元):" prop="preCost"> <el-input v-model="detailForm.preCost" placeholder="请输入预计费用" :disabled="pageType === 'detail'" /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="预计开始时间:" prop="preStartTime"> <el-date-picker v-model="detailForm.preStartTime" type="datetime" placeholder="请选择" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" :disabled="pageType === 'detail'" /> </el-form-item> </el-col> <el-col :span="6"> <el-form-item label="预计结束时间:" prop="preEndTime"> <el-date-picker v-model="detailForm.preEndTime" type="datetime" placeholder="请选择" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" :disabled="pageType === 'detail'" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="备注:" prop="applyRemark"> <el-input v-model="detailForm.applyRemark" :disabled="pageType === 'detail'" /> </el-form-item> </el-col> </el-row> <el-row :gutter="24"> <el-col :span="24"> <el-form-item label="附件:" prop="applyMinioFileName"> <input v-show="pageType === ''" ref="fileRef" multiple type="file" @change="onFileChange"> <span v-if="pageType === 'detail' && !detailForm.applyMinioFileName">无</span> <div v-else style="display: flex;"> <show-photo :minio-file-name="detailForm.applyMinioFileName || ''" style="display: inline-block;" /> </div> <el-button v-if="pageType !== 'detail'" type="primary" :disabled="pageType === 'detail'" @click="upload"> {{ detailForm.applyMinioFileName ? '更换' : '上传' }} </el-button> </el-form-item> </el-col> </el-row> <el-row v-if="query.approvalStatusName === '未通过-驳回'" :gutter="20"> <el-col :span="24"> <el-form-item label="历次驳回原因:"> <el-input v-model.trim="detailForm.rejectRemark" :placeholder="pageType === 'detail' ? '' : '历次驳回原因'" class="full-width-input" clearable type="textarea" autosize disabled /> </el-form-item> </el-col> </el-row> </el-form> </detail-page> <detail-block title="样品信息"> <template v-if="pageType !== 'detail'" #btns> <el-button type="primary" @click="multiAdd"> 批量添加 </el-button> <el-button type="primary" @click="addRow"> 增加行 </el-button> <el-button type="info" @click="delRow"> 删除行 </el-button> </template> <el-table :data="list" border style="width: 100%;" max-height="600" @selection-change="handleSelectionChange" > <el-table-column v-if="pageType !== 'detail'" type="selection" width="38" /> <el-table-column align="center" label="序号" width="80" type="index" /> <el-table-column v-for="item in columns" :key="item.value" :prop="item.value" :label="item.text" :width="item.width" show-overflow-tooltip align="center" > <template v-if="item.value === 'sampleNo' && (pageType === 'add' || pageType === 'edit')" #default="scope"> <el-input v-model="scope.row.sampleNo" placeholder="请选择设备" class="input" disabled> <template #append> <el-button size="small" @click="handleSelect(scope.$index, scope.row)"> 选择 </el-button> </template> </el-input> </template> </el-table-column> </el-table> </detail-block> <detail-block v-if="query.approvalStatusName !== '草稿箱' && pageType !== 'add'" title="审批流程"> <!-- 审批流程 --> <approval-record ref="approvalRecord" :approval-record-data="approvalRecordData" @give-reject-remark="giveRejectRemark" /> </detail-block> <!-- 样品增加弹窗 --> <select-sample v-model:visible="sampleVisible" :is-use-customer-no="false" :is-multi="isMulti" @click-confirm-sample="clickConfirmSample" @change-visible="changeSampleVisible" /> <!-- 项目选择 --> <select-project-approve v-model:visible="projectVisible" :form-id="detailForm.formId" @click-confirm-project="clickConfirmProject" @change-visible="changeProjectVisible(false)" /> <!-- 审批弹窗 --> <approval-dialog ref="approvalDialog" @on-success="approvalSuccess" /> </app-container> </template> <style lang="scss" scoped> // 样式 </style>