| | |
| | | <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">新增台账</el-button> |
| | | <el-button type="primary" plain @click="handleImport">导入</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | @click="handleImport">导入</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | |
| | | prop="availableQuality" /> |
| | | <el-table-column label="退货数量" |
| | | prop="returnQuality" /> |
| | | |
| | | <el-table-column label="税率(%)" |
| | | prop="taxRate" /> |
| | | <el-table-column label="含税单价(元)" |
| | |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag |
| | | :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }} |
| | | </el-tag> |
| | |
| | | <template #label> |
| | | <div style="display: flex; align-items: center; justify-content: space-between; width: 100%;"> |
| | | <span>审批人选择:</span> |
| | | <el-button type="primary" size="small" @click="addApproverNode" icon="Plus">新增节点</el-button> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="addApproverNode" |
| | | icon="Plus">新增节点</el-button> |
| | | </div> |
| | | </template> |
| | | <div class="approver-nodes-container"> |
| | | <div |
| | | v-for="(node, index) in approverNodes" |
| | | <div v-for="(node, index) in approverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item" |
| | | > |
| | | class="approver-node-item"> |
| | | <div class="approver-node-header"> |
| | | <span class="approver-node-label">审批节点 {{ index + 1 }}</span> |
| | | <el-button |
| | | v-if="approverNodes.length > 1" |
| | | <el-button v-if="approverNodes.length > 1" |
| | | type="danger" |
| | | size="small" |
| | | text |
| | | @click="removeApproverNode(index)" |
| | | icon="Delete" |
| | | >删除</el-button> |
| | | icon="Delete">删除</el-button> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | | <el-select v-model="node.userId" |
| | | placeholder="请选择审批人" |
| | | filterable |
| | | style="width: 100%;" |
| | | > |
| | | <el-option |
| | | v-for="user in userList" |
| | | style="width: 100%;"> |
| | | <el-option v-for="user in userListApprove" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" |
| | | /> |
| | | :label="user.userName" |
| | | :value="user.userId" /> |
| | | </el-select> |
| | | </div> |
| | | </div> |
| | |
| | | :value="item.templateName"> |
| | | <div style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <span>{{ item.templateName }}</span> |
| | | <el-icon |
| | | v-if="item.id" |
| | | <el-icon v-if="item.id" |
| | | class="delete-icon" |
| | | @click.stop="handleDeleteTemplate(item)" |
| | | style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;"> |
| | |
| | | </el-form> |
| | | </FormDialog> |
| | | <!-- 导入弹窗 --> |
| | | <FormDialog |
| | | v-model="importUpload.open" |
| | | <FormDialog v-model="importUpload.open" |
| | | :title="importUpload.title" |
| | | :width="'600px'" |
| | | @close="importUpload.open = false" |
| | | @confirm="submitImportFile" |
| | | @cancel="importUpload.open = false" |
| | | > |
| | | <el-upload |
| | | ref="importUploadRef" |
| | | @cancel="importUpload.open = false"> |
| | | <el-upload ref="importUploadRef" |
| | | :limit="1" |
| | | accept=".xlsx,.xls" |
| | | :action="importUpload.url" |
| | |
| | | :on-progress="importUpload.onProgress" |
| | | :on-change="importUpload.onChange" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | drag> |
| | | <i class="el-icon-upload"></i> |
| | | <div class="el-upload__text"> |
| | | 将文件拖到此处,或<em>点击上传</em> |
| | |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | 仅支持 xls/xlsx,大小不超过 10MB。 |
| | | <el-button link type="primary" @click="downloadTemplate">下载导入模板</el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="downloadTemplate">下载导入模板</el-button> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="附件列表" |
| | | /> |
| | | title="附件列表" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { Search, Delete } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import { approveUserList } from "@/api/collaborativeApproval/approvalProcess.js"; |
| | | |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { |
| | | getSalesLedgerWithProducts, |
| | | addOrUpdateSalesLedgerProduct, |
| | |
| | | const productSelectedRows = ref([]); |
| | | const modelOptions = ref([]); |
| | | const userList = ref([]); |
| | | const userListApprove = ref([]); |
| | | const productOptions = ref([]); |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | |
| | | const addApproverNode = () => { |
| | | approverNodes.value.push({ id: nextApproverId++, userId: null }); |
| | | }; |
| | | const removeApproverNode = (index) => { |
| | | const removeApproverNode = index => { |
| | | approverNodes.value.splice(index, 1); |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | // 获取审批状态标签类型 |
| | | const getApprovalStatusType = (status) => { |
| | | const getApprovalStatusType = status => { |
| | | const typeMap = { |
| | | 1: "info", // 待审核 - 灰色 |
| | | 2: "warning", // 审批中 - 橙色 |
| | |
| | | form.value.paymentMethod = matchedTemplate.paymentMethod; |
| | | } |
| | | // 模板数据中的产品字段是 productList,需要转换为 productData |
| | | productData.value = matchedTemplate.productList || matchedTemplate.productData || []; |
| | | productData.value = |
| | | matchedTemplate.productList || matchedTemplate.productData || []; |
| | | } else { |
| | | // 未匹配到已有模板,视为新模板 |
| | | currentTemplateId.value = null; |
| | |
| | | url: import.meta.env.VITE_APP_BASE_API + "/purchase/ledger/import", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | isUploading: false, |
| | | beforeUpload: (file) => { |
| | | beforeUpload: file => { |
| | | const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls"); |
| | | const isLt10M = file.size / 1024 / 1024 < 10; |
| | | if (!isExcel) { |
| | |
| | | |
| | | // 下载导入模板(如后端路径不同,可在此处调整) |
| | | const downloadTemplate = () => { |
| | | proxy.download("/purchase/ledger/exportTemplate", {}, "采购台账导入模板.xlsx"); |
| | | proxy.download( |
| | | "/purchase/ledger/exportTemplate", |
| | | {}, |
| | | "采购台账导入模板.xlsx" |
| | | ); |
| | | }; |
| | | |
| | | const submitImportFile = () => { |
| | |
| | | // 检查是否有产品数据 |
| | | if (!productData.value || productData.value.length === 0) { |
| | | ElMessage({ |
| | | message: '请先添加产品信息', |
| | | type: 'warning', |
| | | message: "请先添加产品信息", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | |
| | | approveUserIds: approveUserIds, |
| | | templateName: templateName.value.trim(), |
| | | }; |
| | | console.log("template params ===>", params, "currentTemplateId:", currentTemplateId.value); |
| | | console.log( |
| | | "template params ===>", |
| | | params, |
| | | "currentTemplateId:", |
| | | currentTemplateId.value |
| | | ); |
| | | |
| | | // 如果 currentTemplateId 有值,说明当前是“编辑已有模板” → 调用更新接口 |
| | | // 否则为“新建模板” → 调用新增接口 |
| | |
| | | getSalesNo(), |
| | | getOptions(), |
| | | ]); |
| | | |
| | | approveUserList({ approveType: 5 }).then(res => { |
| | | userListApprove.value = res.data; |
| | | }); |
| | | userList.value = userRes.data || []; |
| | | salesContractList.value = salesRes || []; |
| | | // 供应商过滤出isWhite=0 的数据 |
| | |
| | | const approverIds = purchaseRes.approveUserIds.split(","); |
| | | approverNodes.value = approverIds.map((id, index) => ({ |
| | | id: index + 1, |
| | | userId: Number(id) |
| | | userId: Number(id), |
| | | })); |
| | | nextApproverId = approverIds.length + 1; |
| | | } |
| | |
| | | proxy.$modal.msgError("请为所有审批节点选择审批人!"); |
| | | return; |
| | | } |
| | | const approveUserIds = approverNodes.value.map(node => node.userId).join(","); |
| | | const approveUserIds = approverNodes.value |
| | | .map(node => node.userId) |
| | | .join(","); |
| | | |
| | | if (productData.value.length > 0) { |
| | | // 新增时,需要从每个产品对象中删除 id 字段 |
| | |
| | | return nodes[i].value; |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const found = findProductIdByCategory(nodes[i].children, categoryName); |
| | | const found = findProductIdByCategory( |
| | | nodes[i].children, |
| | | categoryName |
| | | ); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const productId = findProductIdByCategory(productOptions.value, productForm.value.productCategory); |
| | | const productId = findProductIdByCategory( |
| | | productOptions.value, |
| | | productForm.value.productCategory |
| | | ); |
| | | if (productId) { |
| | | productForm.value.productId = productId; |
| | | // 获取型号列表并等待完成 |
| | |
| | | await nextTick(); |
| | | |
| | | // 根据 specificationModel 查找 productModelId |
| | | if (productForm.value.specificationModel && modelOptions.value.length > 0) { |
| | | if ( |
| | | productForm.value.specificationModel && |
| | | modelOptions.value.length > 0 |
| | | ) { |
| | | const modelItem = modelOptions.value.find( |
| | | item => item.model === productForm.value.specificationModel |
| | | ); |
| | |
| | | delProduct(ids).then(res => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | closeProductDia(); |
| | | getPurchaseById({ id: currentId.value, type: 2 }).then( |
| | | res => { |
| | | getPurchaseById({ id: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.productData; |
| | | } |
| | | ); |
| | | }); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | |
| | | }; |
| | | |
| | | // 删除模板 |
| | | const handleDeleteTemplate = async (item) => { |
| | | const handleDeleteTemplate = async item => { |
| | | if (!item.id) { |
| | | proxy.$modal.msgWarning("无法删除该模板"); |
| | | return; |