| | |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 审批人信息 --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"> |
| | | <UserFilled/> |
| | | </el-icon> |
| | | <span class="card-title">审批人选择</span> |
| | | <el-button type="primary" size="small" @click="addApproverNode" class="header-btn"> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | 新增节点 |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | <div class="form-content"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item> |
| | | <div class="approver-nodes-container"> |
| | | <div |
| | | v-for="(node, index) in approverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item" |
| | | > |
| | | <div class="approver-node-label"> |
| | | <span class="node-step">{{ index + 1 }}</span> |
| | | <span class="node-text">审批人</span> |
| | | <el-icon class="arrow-icon"> |
| | | <ArrowRight/> |
| | | </el-icon> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | | placeholder="选择人员" |
| | | class="approver-select" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" |
| | | /> |
| | | </el-select> |
| | | <el-button |
| | | type="danger" |
| | | size="small" |
| | | :icon="Delete" |
| | | @click="removeApproverNode(index)" |
| | | v-if="approverNodes.length > 1" |
| | | class="remove-btn" |
| | | >删除 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 产品信息 --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | |
| | | <FormDialog v-model="importDialogVisible" title="导入报价单" width="85%" :close-on-click-modal="false" |
| | | @close="importDialogVisible = false" @confirm="handleImportSubmit" |
| | | @cancel="importDialogVisible = false"> |
| | | <!-- 审批人信息 --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"> |
| | | <UserFilled/> |
| | | </el-icon> |
| | | <span class="card-title">审批人选择</span> |
| | | <el-button type="primary" size="small" @click="addImportApproverNode" class="header-btn"> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | 新增节点 |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | <div class="form-content"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item> |
| | | <div class="approver-nodes-container"> |
| | | <div |
| | | v-for="(node, index) in importApproverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item" |
| | | > |
| | | <div class="approver-node-label"> |
| | | <span class="node-step">{{ index + 1 }}</span> |
| | | <span class="node-text">审批人</span> |
| | | <el-icon class="arrow-icon"> |
| | | <ArrowRight/> |
| | | </el-icon> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | | placeholder="选择人员" |
| | | class="approver-select" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" |
| | | /> |
| | | </el-select> |
| | | <el-button |
| | | type="danger" |
| | | size="small" |
| | | :icon="Delete" |
| | | @click="removeImportApproverNode(index)" |
| | | v-if="importApproverNodes.length > 1" |
| | | class="remove-btn" |
| | | >删除 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </el-card> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | |
| | | const importDialogVisible = ref(false) |
| | | const viewDialogVisible = ref(false) |
| | | const importFileList = ref([]) |
| | | const importApproverNodes = ref([ |
| | | {id: 1, userId: null} |
| | | ]) |
| | | let nextImportApproverId = 2 |
| | | |
| | | const fileUpload = ref(null) |
| | | |
| | |
| | | const userList = ref([]); |
| | | const customerOption = ref([]); |
| | | |
| | | // 审批人节点相关 |
| | | const approverNodes = ref([ |
| | | {id: 1, userId: null} |
| | | ]) |
| | | let nextApproverId = 2 |
| | | |
| | | const isEdit = ref(false) |
| | | const showDetail = ref(false) |
| | | const editId = ref(null) |
| | | const currentQuotation = ref({}) |
| | | const formRef = ref() |
| | | |
| | | // 添加审批人节点 |
| | | function addApproverNode() { |
| | | approverNodes.value.push({id: nextApproverId++, userId: null}) |
| | | } |
| | | |
| | | // 删除审批人节点 |
| | | function removeApproverNode(index) { |
| | | approverNodes.value.splice(index, 1) |
| | | } |
| | | |
| | | // 导入弹窗审批人节点相关 |
| | | function addImportApproverNode() { |
| | | importApproverNodes.value.push({id: nextImportApproverId++, userId: null}) |
| | | } |
| | | |
| | | function removeImportApproverNode(index) { |
| | | importApproverNodes.value.splice(index, 1) |
| | | } |
| | | |
| | | function triggerRemoveImportFile(file) { |
| | | const index = importFileList.value.indexOf(file) |
| | |
| | | return |
| | | } |
| | | |
| | | const hasEmptyApprover = importApproverNodes.value.some(node => !node.userId) |
| | | if (hasEmptyApprover) { |
| | | ElMessage.error('请为所有审批节点选择审批人!') |
| | | return |
| | | } |
| | | |
| | | const selectedFile = importFileList.value[0] |
| | | const rawFile = selectedFile?.raw || selectedFile |
| | | if (!validateImportFile(rawFile)) { |
| | |
| | | |
| | | const formData = new FormData() |
| | | formData.append('file', rawFile) |
| | | |
| | | // 审核人 IDs,以逗号分割 |
| | | const approveUserIds = importApproverNodes.value.map(node => node.userId).join(',') |
| | | formData.append('approveUserIdsJson', approveUserIds) |
| | | |
| | | loading.value = true |
| | | try { |
| | |
| | | const handleImport = async () => { |
| | | importFileList.value = [] |
| | | |
| | | // ✅ 清空“导入用”的审批人 |
| | | importApproverNodes.value = [{id: 1, userId: null}] |
| | | nextImportApproverId = 2 |
| | | |
| | | let userLists = await userListNoPage(); |
| | | importDialogVisible.value = true |
| | | |
| | |
| | | dialogTitle.value = '新增报价' |
| | | isEdit.value = false |
| | | resetForm() |
| | | // 重置审批人节点 |
| | | approverNodes.value = [{id: 1, userId: null}] |
| | | nextApproverId = 2 |
| | | dialogVisible.value = true |
| | | let userLists = await userListNoPage(); |
| | | // 只复制需要的字段,避免将组件引用放入响应式对象 |
| | |
| | | form.discountAmount = row.discountAmount || 0 |
| | | form.totalAmount = row.totalAmount || 0 |
| | | |
| | | // 反显审批人 |
| | | if (row.approveUserIds) { |
| | | const userIds = row.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 |
| | | } |
| | | |
| | | // 加载用户列表 |
| | | let userLists = await userListNoPage(); |
| | | userList.value = (userLists.data || []).map(item => ({ |
| | |
| | | return |
| | | } |
| | | |
| | | // 审批人必填校验 |
| | | const hasEmptyApprover = approverNodes.value.some(node => !node.userId) |
| | | if (hasEmptyApprover) { |
| | | ElMessage.error('请为所有审批节点选择审批人!') |
| | | return |
| | | } |
| | | |
| | | // 收集所有节点的审批人id |
| | | form.approveUserIds = approverNodes.value.map(node => node.userId).join(',') |
| | | |
| | | // 计算所有产品的单价总和 |
| | | form.totalAmount = form.products.reduce((sum, product) => { |
| | | const price = Number(product.unitPrice) || 0 |
| | |
| | | validDate: item.validDate || '', |
| | | paymentMethod: item.paymentMethod || '', |
| | | status: item.status || '草稿', |
| | | // 审批人(用于编辑时反显) |
| | | approveUserIds: item.approveUserIds || '', |
| | | remark: item.remark || '', |
| | | products: item.products ? item.products.map(product => ({ |
| | | productId: product.productId || '', |