| | |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? '新增审批流程' : '编辑审批流程'" |
| | | :title="operationType === 'approval' ? '审批' : '详情'" |
| | | width="700px" |
| | | @close="closeDia" |
| | | > |
| | |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="申请部门:" prop="approveDeptId"> |
| | | <el-form-item label="申请部门:"> |
| | | <el-select |
| | | disabled |
| | | v-model="form.approveDeptId" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-row v-if="!isQuotationApproval && !isPurchaseApproval"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="审批事由:" prop="approveReason"> |
| | | <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> |
| | | |
| | | <!-- 用印审批:展示用印申请详情 --> |
| | | <div v-if="isSealApproval" style="margin: 10px 0 18px;"> |
| | | <el-divider content-position="left">用印详情</el-divider> |
| | | <el-skeleton :loading="sealLoading" animated> |
| | | <template #template> |
| | | <el-skeleton-item variant="h3" style="width: 30%" /> |
| | | <el-skeleton-item variant="text" style="width: 100%" /> |
| | | </template> |
| | | <template #default> |
| | | <el-empty v-if="!currentSeal || !currentSeal.applicationNum" description="未查询到对应用印申请详情" /> |
| | | <template v-else> |
| | | <el-descriptions :column="2" border> |
| | | <el-descriptions-item label="申请编号">{{ currentSeal.applicationNum }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请标题">{{ currentSeal.title }}</el-descriptions-item> |
| | | <el-descriptions-item label="用印类型">{{ getSealTypeText(currentSeal.sealType) }}</el-descriptions-item> |
| | | <el-descriptions-item label="紧急程度">{{ getUrgencyText(currentSeal.urgency) }}</el-descriptions-item> |
| | | <el-descriptions-item label="申请原因" :span="2">{{ currentSeal.reason }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | <div v-if="currentSeal.commonFileList?.length" style="margin-top: 20px;"> |
| | | <h4>附件</h4> |
| | | <el-table :data="currentSeal.commonFileList" border style="width: 100%"> |
| | | <el-table-column label="附件名称" show-overflow-tooltip> |
| | | <template #default="scope">{{ scope.row.name }}</template> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="previewSealFile(scope.row)">预览</el-button> |
| | | <el-button link type="primary" size="small" @click="downloadSealFile(scope.row)">下载</el-button> |
| | | </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-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)" |
| | | v-for="(group, gIndex) in stepGroups" |
| | | :key="gIndex" |
| | | finish-status="success" |
| | | :title="getNodeTitle(gIndex, stepGroups.length)" |
| | | :icon="getNodeIcon(group)" |
| | | > |
| | | <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 #icon> |
| | | <el-icon v-if="group.some(a => a.approveNodeStatus === 2)" color="red" :size="22"><WarningFilled /></el-icon> |
| | | <el-icon v-else-if="group.some(a => a.isShen)" color="#1890ff" :size="22"><Edit /></el-icon> |
| | | <el-icon v-else-if="group.every(a => a.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> |
| | | <span style="color: #000000">{{ getNodeTitle(gIndex, stepGroups.length) }}</span> |
| | | <el-tag :type="group[0]?.approveMode === 'and' ? 'warning' : 'info'" size="small" style="margin-left: 6px">{{ group[0]?.approveMode === 'and' ? '会签' : '或签' }}</el-tag> |
| | | </template> |
| | | <template #description> |
| | | <div class="node-user"> |
| | | <div class="avatar-wrapper"> |
| | | <img :src="userStore.avatar" class="user-avatar" alt=""/> |
| | | <div v-for="(activity, aIndex) in group" :key="activity.id || aIndex" class="node-user-item"> |
| | | <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> |
| | | <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 v-if="!activity.isShen" class="node-reason"> |
| | | <span>审批意见:</span>{{ activity.approveNodeReason }} |
| | | </div> |
| | | <div v-else-if="activity.isShen"> |
| | | <el-form-item |
| | | :prop="'activities.' + getActivityIndex(activity) + '.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> |
| | | </div> |
| | | </template> |
| | | </el-step> |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { getCurrentInstance, reactive, ref, toRefs } from "vue"; |
| | | 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"; |
| | | import { getSealDetail } from "@/api/collaborativeApproval/sealManagement.js"; |
| | | import FilePreview from '@/components/filePreview/index.vue' |
| | | const emit = defineEmits(['close']) |
| | | const { proxy } = getCurrentInstance() |
| | | |
| | | const props = defineProps({ |
| | | approveType: { |
| | | type: [Number, String], |
| | | default: 0 |
| | | } |
| | | }) |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = 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 sealLoading = ref(false) |
| | | const currentSeal = ref({}) |
| | | const filePreviewRef = ref() |
| | | const isQuotationApproval = computed(() => Number(props.approveType) === 6) |
| | | const isPurchaseApproval = computed(() => Number(props.approveType) === 5) |
| | | const isSealApproval = computed(() => Number(props.approveType) === 9) |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | approveTime: "", |
| | | approveId: "", |
| | | approveUser: "", |
| | | approveDeptId: "", |
| | | approveReason: "", |
| | | checkResult: "", |
| | |
| | | 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); |
| | | const idx = stepGroups.value.findIndex(group => group.some(a => a.isShen === true)); |
| | | if (idx === -1) return stepGroups.value.length; |
| | | return idx; |
| | | }; |
| | | // 步骤icon |
| | | const getNodeIcon = (activity, index) => { |
| | | if (activity.approveNodeStatus === 2) return 'el-icon-warning'; // 不通过 |
| | | if (activity.isShen) return 'Edit'; |
| | | // 步骤icon(组级:任一人驳回/任一人待审) |
| | | const getNodeIcon = (group) => { |
| | | if (group.some(a => a.approveNodeStatus === 2)) return 'el-icon-warning'; // 不通过 |
| | | if (group.some(a => a.isShen)) return 'Edit'; |
| | | return ''; |
| | | }; |
| | | // 审批节点分组(同一 approveNodeOrder = 同一节点的多名审批人,或签/会签) |
| | | const stepGroups = computed(() => { |
| | | const map = new Map(); |
| | | (activities.value || []).forEach(a => { |
| | | const order = a.approveNodeOrder; |
| | | if (!map.has(order)) map.set(order, []); |
| | | map.get(order).push(a); |
| | | }); |
| | | return Array.from(map.values()); |
| | | }); |
| | | // 获取节点成员在 activities 中的索引(用于表单校验 prop) |
| | | const getActivityIndex = (activity) => { |
| | | return activities.value.findIndex(a => a.id === activity.id); |
| | | }; |
| | | |
| | | // 打开弹框 |
| | | const openDialog = (type, row) => { |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | currentQuotation.value = {} |
| | | currentPurchase.value = {} |
| | | form.value = {...row} |
| | | getProductOptions() |
| | | // 立即清除表单验证状态(因为字段是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 |
| | | }) |
| | | } |
| | | } |
| | | |
| | | // 用印审批:按审批流程 DB 主键(row.id)查用印申请详情 |
| | | if (isSealApproval.value) { |
| | | sealLoading.value = true |
| | | getSealDetail(row.id).then((res) => { |
| | | currentSeal.value = res.data || {} |
| | | }).catch((err) => { |
| | | console.error('查询用印详情失败:', err) |
| | | proxy.$modal.msgError('查询用印详情失败') |
| | | }).finally(() => { |
| | | sealLoading.value = false |
| | | }) |
| | | } |
| | | |
| | | approveProcessDetails(row.approveId).then((res) => { |
| | | activities.value = res.data |
| | | // 增加isApproval字段 |
| | |
| | | }) |
| | | } |
| | | const getProductOptions = () => { |
| | | getDept().then((res) => { |
| | | return getDept().then((res) => { |
| | | productOptions.value = res.data; |
| | | }); |
| | | }; |
| | | // 用印类型文本 |
| | | const getSealTypeText = (sealType) => { |
| | | const map = { official: '公章', contract: '合同专用章', finance: '财务专用章', legal: '法人章' } |
| | | return map[sealType] || sealType || '未知' |
| | | } |
| | | // 紧急程度文本 |
| | | const getUrgencyText = (urgency) => { |
| | | const map = { normal: '普通', urgent: '紧急', 'very-urgent': '特急' } |
| | | return map[urgency] || urgency || '未知' |
| | | } |
| | | // 预览附件(URL 为完整地址,原样打开,不拼 host) |
| | | const previewSealFile = (row) => { |
| | | const url = row.previewURL || row.previewUrl || row.url |
| | | if (url && filePreviewRef.value) { |
| | | filePreviewRef.value.openUrl(url) |
| | | } else { |
| | | proxy.$modal.msgWarning('文件地址无效,无法预览') |
| | | } |
| | | } |
| | | // 下载附件(锚点方式,URL 为完整地址) |
| | | const downloadSealFile = (row) => { |
| | | const url = row.downloadURL || row.downloadUrl || row.url |
| | | if (url) { |
| | | const filename = row.originalFilename || row.name || row.fileName || 'download' |
| | | const a = document.createElement('a') |
| | | a.href = url |
| | | a.download = filename |
| | | a.target = '_blank' |
| | | a.rel = 'noopener noreferrer' |
| | | document.body.appendChild(a) |
| | | a.click() |
| | | document.body.removeChild(a) |
| | | } else { |
| | | proxy.$modal.msgWarning('文件地址无效,无法下载') |
| | | } |
| | | } |
| | | // 提交审批 |
| | | const submitForm = (status) => { |
| | | const filteredActivities = activities.value.filter(activity => activity.isShen); |
| | | filteredActivities[0].approveNodeStatus = status; |
| | | // 判断是否为最后一步 |
| | | const isLast = activities.value.findIndex(a => a.isShen) === activities.value.length-1; |
| | | updateApproveNode({ ...filteredActivities[0], isLast }).then(() => { |
| | | if (!filteredActivities || filteredActivities.length === 0) { |
| | | proxy.$modal.msgError("未找到待审批的节点"); |
| | | return; |
| | | } |
| | | const currentActivity = filteredActivities[0]; |
| | | if (!currentActivity) { |
| | | proxy.$modal.msgError("未找到待审批的节点"); |
| | | return; |
| | | } |
| | | currentActivity.approveNodeStatus = status; |
| | | // 流转判断由后端完成,前端不再传 isLast |
| | | updateApproveNode({ ...currentActivity }).then(() => { |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | closeDia(); |
| | | }); |
| | |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | quotationLoading.value = false |
| | | currentQuotation.value = {} |
| | | purchaseLoading.value = false |
| | | currentPurchase.value = {} |
| | | sealLoading.value = false |
| | | currentSeal.value = {} |
| | | emit('close') |
| | | }; |
| | | defineExpose({ |
| | |
| | | align-items: center; |
| | | gap: 8px; |
| | | } |
| | | .node-user-item { |
| | | margin: 8px 0; |
| | | } |
| | | .node-status { |
| | | color: #1890ff; |
| | | margin-left: 8px; |