| | |
| | | <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"> |
| | | <!-- 申请部门:校验使用部门ID,便于下拉选择后立即通过校验 --> |
| | | <el-form-item label="申请部门:" prop="approveDeptId"> |
| | | <!-- <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> |
| | | <el-dialog v-model="visible" :title="operationType === 'add' ? `新增${typeName}` : `编辑${typeName}`" width="760px" @close="closeDialog"> |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-form-item label="流程编号"> |
| | | <el-input v-model="form.approveId" disabled placeholder="提交后自动生成" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item v-if="approveTypeNumber === 3" label="销售合同" prop="businessId"> |
| | | <el-select v-model="form.businessId" filterable placeholder="请选择销售合同" style="width: 100%" @change="handleContractChange"> |
| | | <el-option v-for="item in contractOptions" :key="item.id" :value="item.id" |
| | | :label="`${item.salesContractNo || '-'} / ${item.customerName || '-'} / ¥${item.contractAmount || 0}`" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item v-if="approveTypeNumber === 3 && selectedContract" label="合同信息"> |
| | | <el-descriptions :column="2" border style="width: 100%"> |
| | | <el-descriptions-item label="客户">{{ selectedContract.customerName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="项目">{{ selectedContract.projectName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="业务员">{{ selectedContract.salesman || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="合同金额">¥{{ selectedContract.contractAmount || 0 }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-form-item> |
| | | |
| | | <el-form-item v-if="[1, 5].includes(approveTypeNumber)" label="审批标题" prop="businessTitle"> |
| | | <el-input v-model="form.businessTitle" maxlength="200" show-word-limit /> |
| | | </el-form-item> |
| | | |
| | | <template v-if="approveTypeNumber === 1"> |
| | | <el-form-item label="事项类型" prop="category"> |
| | | <el-select v-model="form.category" style="width: 100%"> |
| | | <el-option label="临时费用报销" value="临时费用报销" /> |
| | | <el-option label="部门协作" value="部门协作" /> |
| | | <el-option label="其他" value="其他" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="涉及金额"> |
| | | <el-input-number v-model="form.amount" :min="0" :precision="2" style="width: 100%" /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | |
| | | <template v-if="approveTypeNumber === 5"> |
| | | <el-row :gutter="16"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="采购类别" prop="category"><el-input v-model="form.category" /></el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="紧急程度" prop="urgency"> |
| | | <el-select v-model="form.urgency" style="width: 100%"> |
| | | <el-option label="普通" value="普通" /><el-option label="紧急" value="紧急" /><el-option label="特急" value="特急" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="采购内容" prop="purchaseContent"><el-input v-model="form.purchaseContent" type="textarea" /></el-form-item> |
| | | <el-row :gutter="16"> |
| | | <el-col :span="8"><el-form-item label="数量" prop="quantity"><el-input-number v-model="form.quantity" :min="0.01" :precision="2" style="width: 100%" /></el-form-item></el-col> |
| | | <el-col :span="8"><el-form-item label="单位" prop="unit"><el-input v-model="form.unit" /></el-form-item></el-col> |
| | | <el-col :span="8"><el-form-item label="预算金额" prop="amount"><el-input-number v-model="form.amount" :min="0.01" :precision="2" style="width: 100%" /></el-form-item></el-col> |
| | | </el-row> |
| | | <el-form-item label="期望到货日期" prop="expectedDate"> |
| | | <el-date-picker v-model="form.expectedDate" type="date" value-format="YYYY-MM-DD" style="width: 100%" /> |
| | | </el-form-item> |
| | | </template> |
| | | |
| | | <el-row v-if="approveTypeNumber === 2" :gutter="16"> |
| | | <el-col :span="12"><el-form-item label="请假开始日期" prop="startDate"><el-date-picker v-model="form.startDate" type="date" value-format="YYYY-MM-DD" 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" value-format="YYYY-MM-DD" style="width: 100%" /></el-form-item></el-col> |
| | | </el-row> |
| | | <el-form-item v-if="approveTypeNumber === 4" label="报销金额" prop="amount"> |
| | | <el-input-number v-model="form.amount" :min="0.01" :precision="2" style="width: 100%" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="申请事由" prop="approveReason"> |
| | | <el-input v-model="form.approveReason" type="textarea" :rows="3" maxlength="1000" show-word-limit /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="申请部门" prop="approveDeptId"> |
| | | <el-select v-model="form.approveDeptId" style="width: 100%"> |
| | | <el-option v-for="dept in departmentOptions" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item v-if="[3, 5].includes(approveTypeNumber) && flowOptions.length" label="预设审批流程"> |
| | | <el-select v-model="form.flowDefinitionId" clearable placeholder="请选择预设流程;留空可手动设置节点" style="width: 100%"> |
| | | <el-option v-for="flow in flowOptions" :key="flow.id" :label="flow.flowName" :value="flow.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-divider content-position="left">审批节点</el-divider> |
| | | <el-alert v-if="form.flowDefinitionId && operationType === 'add'" title="提交后将按预设流程生成审批节点" type="info" :closable="false" style="margin-bottom: 12px" /> |
| | | <div v-for="(node, index) in approverNodes" v-show="!form.flowDefinitionId || operationType === 'edit'" :key="node.key" class="node-row"> |
| | | <span class="node-order">{{ index + 1 }}</span> |
| | | <el-input v-model="node.nodeName" placeholder="节点名称" style="width: 150px" /> |
| | | <el-select v-model="node.userId" filterable placeholder="审批人" style="width: 150px"> |
| | | <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> |
| | | </el-select> |
| | | <el-select v-model="node.conditionOperator" style="width: 130px" @change="handleConditionChange(node)"> |
| | | <el-option label="始终执行" value="ALWAYS" /> |
| | | <el-option label="金额大于" value="GT" /> |
| | | <el-option label="金额大于等于" value="GTE" /> |
| | | <el-option label="金额小于" value="LT" /> |
| | | <el-option label="金额小于等于" value="LTE" /> |
| | | </el-select> |
| | | <el-input-number v-if="node.conditionOperator !== 'ALWAYS'" v-model="node.conditionValue" :min="0" :precision="2" style="width: 130px" /> |
| | | <el-button type="danger" link :disabled="approverNodes.length === 1" @click="removeNode(index)">删除</el-button> |
| | | <el-button link :disabled="index === 0" @click="moveNode(index, -1)">上移</el-button> |
| | | <el-button link :disabled="index === approverNodes.length - 1" @click="moveNode(index, 1)">下移</el-button> |
| | | </div> |
| | | <el-button v-if="!form.flowDefinitionId || operationType === 'edit'" type="primary" plain class="add-node" @click="addNode">新增审批节点</el-button> |
| | | |
| | | <el-form-item label="申请日期"> |
| | | <el-date-picker v-model="form.approveTime" type="date" value-format="YYYY-MM-DD" style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="附件材料"> |
| | | <el-upload v-model:file-list="fileList" :action="upload.url" :headers="upload.headers" multiple |
| | | :before-upload="beforeUpload" :on-success="uploadSuccess" :on-error="uploadError" :on-remove="removeFile"> |
| | | <el-button type="primary">上传文件</el-button> |
| | | </el-upload> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="closeDialog">取消</el-button> |
| | | <el-button type="primary" :loading="submitting" @click="submit">提交</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </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() |
| | | import { computed, getCurrentInstance, reactive, ref } from 'vue' |
| | | import { approveFlowDefinitionList, approveProcessAdd, approveProcessDetails, approveProcessGetInfo, approveProcessUpdate, getDept } from '@/api/collaborativeApproval/approvalProcess' |
| | | import { delLedgerFile, ledgerListNoPage } from '@/api/salesManagement/salesLedger' |
| | | import { userListNoPageByTenantId } from '@/api/system/user' |
| | | import { getToken } from '@/utils/auth' |
| | | import { getCurrentDate } from '@/utils' |
| | | import useUserStore from '@/store/modules/user' |
| | | |
| | | const props = defineProps({ approveType: { type: [Number, String], default: 1 } }) |
| | | 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 { proxy } = getCurrentInstance() |
| | | const userStore = useUserStore() |
| | | const approveTypeNumber = computed(() => Number(props.approveType)) |
| | | const typeName = computed(() => ({ 1: '自由协同审批', 3: '销售审批', 5: '采购审批' }[approveTypeNumber.value] || '审批流程')) |
| | | |
| | | 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" }], |
| | | // 使用部门ID做必填校验,避免名称未同步导致误报 |
| | | approveDeptId: [{ required: true, message: "请选择申请部门", trigger: "change" }], |
| | | 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 visible = ref(false) |
| | | const submitting = ref(false) |
| | | const operationType = ref('add') |
| | | const formRef = ref() |
| | | const userList = ref([]) |
| | | function addApproverNode() { |
| | | approverNodes.value.push({ id: nextApproverId++, userId: null }) |
| | | const departmentOptions = ref([]) |
| | | const contractOptions = ref([]) |
| | | const flowOptions = ref([]) |
| | | const selectedContract = ref(null) |
| | | const fileList = ref([]) |
| | | let nodeKey = 1 |
| | | const approverNodes = ref([]) |
| | | const upload = reactive({ url: import.meta.env.VITE_APP_BASE_API + '/file/upload', headers: { Authorization: 'Bearer ' + getToken() } }) |
| | | const emptyForm = () => ({ |
| | | id: null, approveId: '', approveUser: userStore.id, approveDeptId: userStore.currentDeptId, |
| | | approveTime: getCurrentDate(), approveReason: '', businessId: null, businessNo: '', businessTitle: '', |
| | | amount: null, businessData: '', flowDefinitionId: null, category: '', urgency: '普通', purchaseContent: '', quantity: null, |
| | | unit: '', expectedDate: '', startDate: '', endDate: '', tempFileIds: [] |
| | | }) |
| | | const form = ref(emptyForm()) |
| | | const rules = { |
| | | approveDeptId: [{ required: true, message: '请选择申请部门', trigger: 'change' }], |
| | | approveReason: [{ required: true, message: '请输入申请事由', trigger: 'blur' }], |
| | | businessId: [{ required: true, message: '请选择销售合同', trigger: 'change' }], |
| | | businessTitle: [{ required: true, message: '请输入审批标题', trigger: 'blur' }], |
| | | category: [{ required: true, message: '请输入或选择类别', trigger: 'blur' }], |
| | | urgency: [{ required: true, message: '请选择紧急程度', trigger: 'change' }], |
| | | purchaseContent: [{ required: true, message: '请输入采购内容', trigger: 'blur' }], |
| | | quantity: [{ required: true, message: '请输入数量', trigger: 'blur' }], |
| | | unit: [{ required: true, message: '请输入单位', trigger: 'blur' }], |
| | | amount: [{ required: true, message: '请输入预算金额', trigger: 'blur' }], |
| | | expectedDate: [{ required: true, message: '请选择期望到货日期', trigger: 'change' }], |
| | | startDate: [{ required: true, message: '请选择请假开始日期', trigger: 'change' }], |
| | | endDate: [{ required: true, message: '请选择请假结束日期', trigger: 'change' }] |
| | | } |
| | | function removeApproverNode(index) { |
| | | approverNodes.value.splice(index, 1) |
| | | |
| | | const createNode = (data = {}) => ({ key: nodeKey++, userId: data.userId || null, nodeName: data.nodeName || '审批', conditionField: data.conditionField || null, conditionOperator: data.conditionOperator || 'ALWAYS', conditionValue: data.conditionValue == null ? null : Number(data.conditionValue) }) |
| | | const addNode = () => approverNodes.value.push(createNode()) |
| | | const removeNode = index => approverNodes.value.splice(index, 1) |
| | | const moveNode = (index, offset) => { |
| | | const target = index + offset |
| | | if (target < 0 || target >= approverNodes.value.length) return |
| | | const item = approverNodes.value.splice(index, 1)[0] |
| | | approverNodes.value.splice(target, 0, item) |
| | | } |
| | | // 处理部门选择变化 |
| | | const handleDeptChange = (deptId) => { |
| | | if (deptId) { |
| | | const selectedDept = productOptions.value.find(dept => dept.deptId === deptId); |
| | | if (selectedDept) { |
| | | form.value.approveDeptName = selectedDept.deptName; |
| | | } |
| | | const handleConditionChange = node => { |
| | | node.conditionField = node.conditionOperator === 'ALWAYS' ? null : 'amount' |
| | | if (node.conditionOperator === 'ALWAYS') node.conditionValue = null |
| | | } |
| | | |
| | | const loadOptions = async () => { |
| | | const tasks = [userListNoPageByTenantId(), getDept()] |
| | | if (approveTypeNumber.value === 3) tasks.push(ledgerListNoPage({})) |
| | | const flowPromise = [3, 5].includes(approveTypeNumber.value) ? approveFlowDefinitionList({ approveType: approveTypeNumber.value }) : Promise.resolve({ data: [] }) |
| | | tasks.push(flowPromise) |
| | | const results = await Promise.all(tasks) |
| | | userList.value = results[0].data || [] |
| | | departmentOptions.value = results[1].data || [] |
| | | if (approveTypeNumber.value === 3) { |
| | | contractOptions.value = results[2]?.data || [] |
| | | flowOptions.value = results[3]?.data || [] |
| | | } else { |
| | | form.value.approveDeptName = ''; |
| | | contractOptions.value = [] |
| | | flowOptions.value = results[2]?.data || [] |
| | | } |
| | | }; |
| | | // 打开弹框 |
| | | const openDialog = (type, row) => { |
| | | operationType.value = type; |
| | | dialogFormVisible.value = true; |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | getProductOptions(); |
| | | form.value = {} |
| | | approverNodes.value = [ |
| | | { id: 1, userId: null } |
| | | ] |
| | | form.value.approveUser = userStore.id; |
| | | form.value.approveTime = getCurrentDate(); |
| | | |
| | | // 获取当前用户信息并设置部门ID |
| | | form.value.approveDeptId = userStore.currentDeptId |
| | | 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 defaultFlow = flowOptions.value.find(item => item.isDefault === 1 && item.enabled === 1) |
| | | if (defaultFlow && operationType.value === 'add') form.value.flowDefinitionId = defaultFlow.id |
| | | } |
| | | const getProductOptions = () => { |
| | | getDept().then((res) => { |
| | | productOptions.value = res.data; |
| | | }); |
| | | }; |
| | | 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 = () => { |
| | | |
| | | const openDialog = async (type, row) => { |
| | | operationType.value = type |
| | | visible.value = true |
| | | form.value = emptyForm() |
| | | approverNodes.value = [createNode()] |
| | | 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 = []; |
| | | selectedContract.value = null |
| | | await loadOptions() |
| | | if (type === 'edit' && row?.approveId) { |
| | | const [processRes, nodeRes] = await Promise.all([approveProcessGetInfo({ id: row.approveId }), approveProcessDetails(row.approveId)]) |
| | | const process = processRes.data || {} |
| | | let business = {} |
| | | try { business = process.businessData ? JSON.parse(process.businessData) : {} } catch (_) { business = {} } |
| | | form.value = { ...emptyForm(), ...process, ...business, tempFileIds: [] } |
| | | fileList.value = process.commonFileList || [] |
| | | approverNodes.value = (nodeRes.data || []).map(item => createNode({ |
| | | userId: item.approveNodeUserId, |
| | | nodeName: item.approveNodeName, |
| | | conditionField: item.conditionField, |
| | | conditionOperator: item.conditionOperator, |
| | | conditionValue: item.conditionValue |
| | | })) |
| | | if (!approverNodes.value.length) approverNodes.value = [createNode()] |
| | | if (approveTypeNumber.value === 3) { |
| | | selectedContract.value = contractOptions.value.find(item => item.id === process.businessId) || business |
| | | } |
| | | 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, |
| | | }); |
| | | const handleContractChange = id => { |
| | | selectedContract.value = contractOptions.value.find(item => item.id === id) || null |
| | | if (selectedContract.value) form.value.businessTitle = `销售合同审批-${selectedContract.value.salesContractNo || ''}` |
| | | } |
| | | |
| | | const buildBusinessData = () => { |
| | | if (approveTypeNumber.value === 5) return JSON.stringify({ category: form.value.category, urgency: form.value.urgency, purchaseContent: form.value.purchaseContent, quantity: form.value.quantity, unit: form.value.unit, expectedDate: form.value.expectedDate }) |
| | | if (approveTypeNumber.value === 1) return JSON.stringify({ category: form.value.category }) |
| | | if (approveTypeNumber.value === 2) return JSON.stringify({ startDate: form.value.startDate, endDate: form.value.endDate }) |
| | | if (approveTypeNumber.value === 4) return JSON.stringify({ amount: form.value.amount }) |
| | | return form.value.businessData || '' |
| | | } |
| | | |
| | | const submit = async () => { |
| | | await formRef.value.validate() |
| | | if (approveTypeNumber.value === 2 && new Date(form.value.endDate) < new Date(form.value.startDate)) return proxy.$modal.msgError('请假结束日期不能早于开始日期') |
| | | const usePresetFlow = operationType.value === 'add' && !!form.value.flowDefinitionId |
| | | if (!usePresetFlow && approverNodes.value.some(item => !item.userId || !item.nodeName)) return proxy.$modal.msgError('请完整填写审批节点') |
| | | if (!usePresetFlow && approverNodes.value.some((item, index) => index > 0 && item.userId === approverNodes.value[index - 1].userId)) return proxy.$modal.msgError('相邻审批节点不能选择同一审批人') |
| | | if (!usePresetFlow && approverNodes.value.some(item => item.conditionOperator !== 'ALWAYS' && item.conditionValue == null)) return proxy.$modal.msgError('请填写节点条件金额') |
| | | const nodes = usePresetFlow ? [] : approverNodes.value.map(item => ({ userId: item.userId, nodeName: item.nodeName, conditionField: item.conditionOperator === 'ALWAYS' ? null : 'amount', conditionOperator: item.conditionOperator, conditionValue: item.conditionValue == null ? null : String(item.conditionValue) })) |
| | | const payload = { ...form.value, approveType: approveTypeNumber.value, approveUser: userStore.id, nodes, approveUserIds: nodes.map(item => item.userId).join(','), businessData: buildBusinessData() } |
| | | submitting.value = true |
| | | try { |
| | | if (operationType.value === 'add') await approveProcessAdd(payload) |
| | | else await approveProcessUpdate(payload) |
| | | proxy.$modal.msgSuccess('提交成功') |
| | | closeDialog() |
| | | } finally { |
| | | submitting.value = false |
| | | } |
| | | } |
| | | |
| | | const beforeUpload = () => { proxy.$modal.loading('正在上传文件,请稍候...'); return true } |
| | | const uploadSuccess = (res, file) => { |
| | | proxy.$modal.closeLoading() |
| | | if (res.code === 200) form.value.tempFileIds.push(res.data.tempId) |
| | | else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload?.handleRemove(file) } |
| | | } |
| | | const uploadError = () => { proxy.$modal.closeLoading(); proxy.$modal.msgError('上传失败') } |
| | | const removeFile = file => { |
| | | if (file.id) delLedgerFile([file.id]) |
| | | if (file.response?.data?.tempId) form.value.tempFileIds = form.value.tempFileIds.filter(id => id !== file.response.data.tempId) |
| | | } |
| | | const closeDialog = () => { visible.value = false; emit('close') } |
| | | |
| | | defineExpose({ openDialog }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | .node-row { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; } |
| | | .node-order { display: inline-flex; width: 26px; height: 26px; align-items: center; justify-content: center; border-radius: 50%; color: #fff; background: #409eff; } |
| | | .add-node { margin: 0 0 20px 120px; } |
| | | </style> |