| 4 小时以前 | zhangwencui | ![]() |
| 6 小时以前 | huminmin | ![]() |
| 6 小时以前 | liyong | ![]() |
| 6 小时以前 | liyong | ![]() |
| 8 小时以前 | yaowanxin | ![]() |
| 9 小时以前 | yaowanxin | ![]() |
| 12 小时以前 | zhangwencui | ![]() |
| src/views/basicData/product/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/basicData/supplierManage/filesDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/issueManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/procurementManagement/invoiceEntry/components/Modal.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/procurementManagement/procurementLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/processRoute/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productStructure/StructureEdit.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productStructure/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/invoiceRegistration/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/views/basicData/product/index.vue
@@ -235,6 +235,10 @@ const expandedKeys = ref([]); const tableColumn = ref([ { label: "产品规格编号", prop: "productCode", }, { label: "规格型号", prop: "model", }, src/views/basicData/supplierManage/filesDia.vue
@@ -1,45 +1,35 @@ <template> <div> <el-dialog v-model="dialogFormVisible" title="上传附件" width="50%" @close="closeDia" > <el-dialog v-model="dialogFormVisible" title="上传附件" width="50%" @close="closeDia"> <div style="margin-bottom: 10px;text-align: right"> <el-upload v-model:file-list="fileList" class="upload-demo" :action="uploadUrl" :on-success="handleUploadSuccess" :on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" style="display: inline;margin-right: 10px" > <el-upload v-model:file-list="fileList" class="upload-demo" :action="uploadUrl" :on-success="handleUploadSuccess" :on-error="handleUploadError" name="file" :show-file-list="false" :headers="headers" style="display: inline;margin-right: 10px"> <el-button type="primary">上传附件</el-button> </el-upload> <el-button type="danger" plain @click="handleDelete">删除</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> </div> <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :tableLoading="tableLoading" :isSelection="true" @selection-change="handleSelectionChange" height="500" > <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :tableLoading="tableLoading" :isSelection="true" :page="page" @pagination="paginationSearch" @selection-change="handleSelectionChange" height="500"> </PIMTable> <pagination style="margin: 10px 0" v-show="total > 0" @pagination="paginationSearch" :total="total" :page="page.current" :limit="page.size" /> <template #footer> <div class="dialog-footer"> <el-button @click="closeDia">取消</el-button> @@ -51,149 +41,151 @@ </template> <script setup> import {ref} from "vue"; import {ElMessageBox} from "element-plus"; import {getToken} from "@/utils/auth.js"; import filePreview from '@/components/filePreview/index.vue' import { fileAdd, fileDel, fileListPage } from "@/api/basicData/supplierManageFile.js"; import Pagination from "@/components/PIMTable/Pagination.vue"; const { proxy } = getCurrentInstance() const emit = defineEmits(['close']) import { ref } from "vue"; import { ElMessageBox } from "element-plus"; import { getToken } from "@/utils/auth.js"; import filePreview from "@/components/filePreview/index.vue"; import { fileAdd, fileDel, fileListPage, } from "@/api/basicData/supplierManageFile.js"; import Pagination from "@/components/PIMTable/Pagination.vue"; const { proxy } = getCurrentInstance(); const emit = defineEmits(["close"]); const dialogFormVisible = ref(false); const currentId = ref('') const selectedRows = ref([]); const filePreviewRef = ref() const tableColumn = ref([ { label: "文件名称", prop: "name", }, { dataType: "action", label: "操作", align: "center", operation: [ { name: "下载", type: "text", clickFun: (row) => { downLoadFile(row); const dialogFormVisible = ref(false); const currentId = ref(""); const selectedRows = ref([]); const filePreviewRef = ref(); const tableColumn = ref([ { label: "文件名称", prop: "name", }, { dataType: "action", label: "操作", align: "center", operation: [ { name: "下载", type: "text", clickFun: row => { downLoadFile(row); }, }, }, { name: "预览", type: "text", clickFun: (row) => { lookFile(row); { name: "预览", type: "text", clickFun: row => { lookFile(row); }, }, } ], }, ]); const page = reactive({ current: 1, size: 100, }); const total = ref(0); const tableData = ref([]); const fileList = ref([]); const tableLoading = ref(false); const headers = ref({ Authorization: "Bearer " + getToken(), }); const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 上传的图片服务器地址 ], }, ]); const page = reactive({ current: 1, size: 100, total: 0, }); // const total = ref(0); const tableData = ref([]); const fileList = ref([]); const tableLoading = ref(false); const headers = ref({ Authorization: "Bearer " + getToken(), }); const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); // 上传的图片服务器地址 // 打开弹框 const openDialog = (row) => { dialogFormVisible.value = true; currentId.value = row.id; getList() } const paginationSearch = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { fileListPage({supplierId: currentId.value, ...page}).then(res => { tableData.value = res.data.records; total.value = res.data.total; }) } // 表格选择数据 const handleSelectionChange = (selection) => { selectedRows.value = selection; }; // 打开弹框 const openDialog = row => { dialogFormVisible.value = true; currentId.value = row.id; getList(); }; const paginationSearch = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { fileListPage({ supplierId: currentId.value, ...page }).then(res => { tableData.value = res.data.records; page.total = res.data.total; }); }; // 表格选择数据 const handleSelectionChange = selection => { selectedRows.value = selection; }; // 关闭弹框 const closeDia = () => { dialogFormVisible.value = false; emit('close') }; // 上传成功处理 function handleUploadSuccess(res, file) { // 如果上传成功 if (res.code == 200) { const fileRow = {} fileRow.name = res.data.originalName fileRow.url = res.data.tempPath uploadFile(fileRow) } else { proxy.$modal.msgError("文件上传失败"); // 关闭弹框 const closeDia = () => { dialogFormVisible.value = false; emit("close"); }; // 上传成功处理 function handleUploadSuccess(res, file) { // 如果上传成功 if (res.code == 200) { const fileRow = {}; fileRow.name = res.data.originalName; fileRow.url = res.data.tempPath; uploadFile(fileRow); } else { proxy.$modal.msgError("文件上传失败"); } } } function uploadFile(file) { file.supplierId = currentId.value; fileAdd(file).then(res => { proxy.$modal.msgSuccess("文件上传成功"); getList() }) } // 上传失败处理 function handleUploadError() { proxy.$modal.msgError("文件上传失败"); } // 下载附件 const downLoadFile = (row) => { proxy.$download.name(row.url); } // 删除 const handleDelete = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map((item) => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }).then(() => { fileDel(ids).then((res) => { proxy.$modal.msgSuccess("删除成功"); function uploadFile(file) { file.supplierId = currentId.value; fileAdd(file).then(res => { proxy.$modal.msgSuccess("文件上传成功"); getList(); }); }).catch(() => { proxy.$modal.msg("已取消"); }); }; // 预览附件 const lookFile = (row) => { filePreviewRef.value.open(row.url) } } // 上传失败处理 function handleUploadError() { proxy.$modal.msgError("文件上传失败"); } // 下载附件 const downLoadFile = row => { proxy.$download.name(row.url); }; // 删除 const handleDelete = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { fileDel(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 预览附件 const lookFile = row => { filePreviewRef.value.open(row.url); }; defineExpose({ openDialog, }); defineExpose({ openDialog, }); </script> <style scoped> </style> src/views/inventoryManagement/issueManagement/index.vue
@@ -376,6 +376,9 @@ if (num <= 0 || num > currentRowNum.value) { return proxy.$modal.msgWarning("请填入有效数字"); } if (!form.value.nickName) { return proxy.$modal.msgWarning("请选择操作人"); } proxy.$refs["formRef"].validate(valid => { if (valid && currentRowId.value) { const typeMap = { production: 2, purchase: 1 }; src/views/procurementManagement/invoiceEntry/components/Modal.vue
@@ -1,638 +1,669 @@ <template> <el-dialog :title="modalOptions.title" v-model="visible" width="70%"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" label-position="top" > <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="采购合同号:" prop="purchaseLedgerNo"> <el-input v-model="form.purchaseLedgerNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" placeholder="自动填充" clearable disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="供应商名称:" prop="supplierName"> <el-input v-model="form.supplierName" placeholder="自动填充" clearable disabled /> </el-form-item> </el-col> <!-- <el-col :span="12">--> <!-- <el-form-item label="项目名称:" prop="projectName">--> <!-- <el-input--> <!-- v-model="form.projectName"--> <!-- placeholder="自动填充"--> <!-- clearable--> <!-- disabled--> <!-- />--> <!-- </el-form-item>--> <!-- </el-col>--> <el-col :span="12"> <el-form-item label="发票号:" prop="invoiceNumber"> <el-input v-model="form.invoiceNumber" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发票金额(元):" prop="invoiceAmount"> <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.invoiceAmount" placeholder="请输入发票金额" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入人:" prop="issUer"> <el-input v-model="form.issUer" placeholder="请输入" clearable disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="开票日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入日期:" prop="enterDate"> <el-date-picker style="width: 100%" v-model="form.enterDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="上传附件"> <FileUpload :showTip="false" accept="*" :autoUpload="true" :action="action" :headers="{ <el-dialog :title="modalOptions.title" v-model="visible" width="70%"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" label-position="top"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="采购合同号:" prop="purchaseLedgerNo"> <el-input v-model="form.purchaseLedgerNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" placeholder="自动填充" clearable disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="供应商名称:" prop="supplierName"> <el-input v-model="form.supplierName" placeholder="自动填充" clearable disabled /> </el-form-item> </el-col> <!-- <el-col :span="12">--> <!-- <el-form-item label="项目名称:" prop="projectName">--> <!-- <el-input--> <!-- v-model="form.projectName"--> <!-- placeholder="自动填充"--> <!-- clearable--> <!-- disabled--> <!-- />--> <!-- </el-form-item>--> <!-- </el-col>--> <el-col :span="12"> <el-form-item label="发票号:" prop="invoiceNumber"> <el-input v-model="form.invoiceNumber" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发票金额(元):" prop="invoiceAmount"> <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.invoiceAmount" placeholder="请输入发票金额" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入人:" prop="issUer"> <el-input v-model="form.issUer" placeholder="请输入" clearable disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="开票日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入日期:" prop="enterDate"> <el-date-picker style="width: 100%" v-model="form.enterDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="上传附件"> <FileUpload :showTip="false" accept="*" :autoUpload="true" :action="action" :headers="{ Authorization: 'Bearer ' + getToken(), }" :limit="10" @success="uploadSuccess" @remove="removeFile" /> </el-form-item> </el-col> </el-row> <el-form-item label="产品信息:"> </el-form-item> <el-table :data="form.productData" border show-summary :summary-method="summarizeChildrenTable" > <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="所属合同" prop="purchaseLedgerNo" width="200"> <template #default="{ row }"> <el-tag type="primary">{{ row.purchaseLedgerNo }}</el-tag> </template> </el-table-column> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="本次开票数" prop="ticketsNum" width="180"> <template #default="scope"> <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.ticketsNum" @change="invoiceNumBlur(scope.row)" /> </template> </el-table-column> <el-table-column label="本次开票金额(元)" prop="ticketsAmount" width="180" > <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.ticketsAmount" @change="invoiceAmountBlur(scope.row)" /> </template> </el-table-column> <el-table-column label="未来票数" prop="futureTickets" :formatter="formattedNumber" /> <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber" /> <el-table-column label="未来票数" prop="futureTickets" :formatter="formattedNumber" /> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber" /> </el-table> </el-form> <template #footer> <el-button type="primary" :loading="modalLoading" @click="submitForm"> 确认 </el-button> <el-button @click="closeModal">取消</el-button> </template> </el-dialog> :limit="10" @success="uploadSuccess" @remove="removeFile" /> </el-form-item> </el-col> </el-row> <el-form-item label="产品信息:"> </el-form-item> <el-table :data="form.productData" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="所属合同" prop="purchaseLedgerNo" width="200"> <template #default="{ row }"> <el-tag type="primary">{{ row.purchaseLedgerNo }}</el-tag> </template> </el-table-column> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="本次开票数" prop="ticketsNum" width="180"> <template #default="scope"> <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.ticketsNum" @change="invoiceNumBlur(scope.row)" /> </template> </el-table-column> <el-table-column label="本次开票金额(元)" prop="ticketsAmount" width="180"> <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.ticketsAmount" @change="invoiceAmountBlur(scope.row)" /> </template> </el-table-column> <el-table-column label="未来票数" prop="futureTickets" :formatter="formattedNumber" /> <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber" /> <el-table-column label="未来票数" prop="futureTickets" :formatter="formattedNumber" /> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber" /> </el-table> </el-form> <template #footer> <el-button type="primary" :loading="modalLoading" @click="submitForm"> 确认 </el-button> <el-button @click="closeModal">取消</el-button> </template> </el-dialog> </template> <script setup> import { ref, getCurrentInstance } from "vue"; import { defineEmits } from 'vue'; import { useModal } from "@/hooks/useModal"; import useFormData from "@/hooks/useFormData"; import FileUpload from "@/components/Upload/FileUpload.vue"; import { getPurchaseNoById, getInfo, addOrUpdateRegistration, } from "@/api/procurementManagement/invoiceEntry.js"; import { getPurchaseById } from "@/api/procurementManagement/procurementLedger.js"; import { getToken } from "@/utils/auth"; import useUserStore from "@/store/modules/user"; import dayjs from "dayjs"; import { ref, getCurrentInstance } from "vue"; import { defineEmits } from "vue"; import { useModal } from "@/hooks/useModal"; import useFormData from "@/hooks/useFormData"; import FileUpload from "@/components/Upload/FileUpload.vue"; import { getPurchaseNoById, getInfo, addOrUpdateRegistration, } from "@/api/procurementManagement/invoiceEntry.js"; import { getPurchaseById } from "@/api/procurementManagement/procurementLedger.js"; import { getToken } from "@/utils/auth"; import useUserStore from "@/store/modules/user"; import dayjs from "dayjs"; defineOptions({ name: "来票登记模态框", }); defineOptions({ name: "来票登记模态框", }); const userStore = useUserStore(); const action = import.meta.env.VITE_APP_BASE_API + "/file/upload"; const formRef = ref(); const { proxy } = getCurrentInstance(); const { form } = useFormData({ purchaseLedgerNo: undefined, // 采购合同号 salesContractNo: undefined, // 销售合同号 supplierName: undefined, // 供应商名称 projectName: undefined, // 项目名称 invoiceNumber: undefined, // 发票号 invoiceAmount: undefined, // 发票金额(元) issUerId: userStore.id, // 录入人 issUer: userStore.nickName, // 录入人 entryDate: undefined, // 开票日期 salesContractNoId: undefined, // 开票日期 enterDate: dayjs().format("YYYY-MM-DD"), productData: [], // 表格 tempFileIds: [], // 文件 }); const userStore = useUserStore(); const action = import.meta.env.VITE_APP_BASE_API + "/file/upload"; const formRef = ref(); const { proxy } = getCurrentInstance(); const { form } = useFormData({ purchaseLedgerNo: undefined, // 采购合同号 salesContractNo: undefined, // 销售合同号 supplierName: undefined, // 供应商名称 projectName: undefined, // 项目名称 invoiceNumber: undefined, // 发票号 invoiceAmount: undefined, // 发票金额(元) issUerId: userStore.id, // 录入人 issUer: userStore.nickName, // 录入人 entryDate: undefined, // 开票日期 salesContractNoId: undefined, // 开票日期 enterDate: dayjs().format("YYYY-MM-DD"), productData: [], // 表格 tempFileIds: [], // 文件 }); const selectedContracts = ref([]); // 存储选中的合同数据 const selectedContracts = ref([]); // 存储选中的合同数据 const rules = ref({ invoiceNumber: [ { required: true, message: "请输入发票号", trigger: "blur" }, { type: "string" }, ], invoiceAmount: [ { required: true, message: "请输入发票金额", trigger: "blur" }, ], entryDate: [{ required: true, message: "请选择开票日期", trigger: "change" }], enterDate: [{ required: true, message: "请选择录入日期", trigger: "change" }], }); const rules = ref({ invoiceNumber: [ { required: true, message: "请输入发票号", trigger: "blur" }, { type: "string" }, ], invoiceAmount: [ { required: true, message: "请输入发票金额", trigger: "blur" }, ], entryDate: [{ required: true, message: "请选择开票日期", trigger: "change" }], enterDate: [{ required: true, message: "请选择录入日期", trigger: "change" }], }); const { id, visible, loading: modalLoading, openModal, modalOptions, handleConfirm, closeModal, } = useModal({ title: "来票登记", }); const { id, visible, loading: modalLoading, openModal, modalOptions, handleConfirm, closeModal, } = useModal({ title: "来票登记", }); const emit = defineEmits(['refreshList']); const emit = defineEmits(["refreshList"]); const columns = [ { label: "产品大类", prop: "productCategory", width: 120, }, { label: "规格型号", prop: "specificationModel", width: 120, }, { label: "单位", prop: "unit", width: 80, }, { label: "数量", prop: "quantity", width: 80, }, { label: "税率(%)", prop: "taxRate", width: 80, }, { label: "录入日期", prop: "registerDate", width: 120, }, { label: "含税单价(元)", prop: "taxInclusiveUnitPrice", width: 150, formatData: (val) => { return val ? parseFloat(val).toFixed(2) : 0; }, }, { label: "含税总价(元)", prop: "taxInclusiveTotalPrice", width: 150, formatData: (val) => { return parseFloat(val).toFixed(2) ?? 0; }, }, { label: "不含税总价(元)", prop: "taxExclusiveTotalPrice", width: 150, formatData: (val) => { return parseFloat(val).toFixed(2) ?? 0; }, }, { label: "本次来票数", prop: "ticketsNum", dataType: "slot", slot: "ticketsNumRef", width: 180, align: "center", }, { label: "本次来票金额(元)", prop: "ticketsAmount", dataType: "slot", slot: "ticketsAmountRef", width: 180, align: "center", }, { label: "未来票数", prop: "futureTickets", width: 100, }, { label: "未来票金额(元)", prop: "futureTicketsAmount", width: 200, }, ]; const formattedNumber = (row, column, cellValue) => { if (cellValue == 0) { return parseFloat(cellValue).toFixed(2); } if (cellValue) { return parseFloat(cellValue).toFixed(2); } else { return cellValue; } }; const getTableData = async (type, selectedRows) => { if (type == "add") { // 检查所有选择的合同是否具有相同的供应商名称 const firstRow = selectedRows[0]; const isSameSupplier = selectedRows.every(row => row.supplierName === firstRow.supplierName ); if (!isSameSupplier) { proxy.$modal.msgError("请选择相同供应商名称的合同"); return; } // 允许不同的采购合同号批量处理,无需检查重复 // 清空表单数据 Object.keys(form).forEach(key => { if (key !== 'productData') { form[key] = undefined; } }); form.productData = []; // 加载所有选中合同的产品数据 const promises = selectedRows.map(row => getInfo({ id: row.id }) ); Promise.all(promises).then(results => { // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 const allProductData = []; results.forEach((result, index) => { const contract = selectedRows[index]; const contractId = contract.id; if (result.data && result.data.productData) { result.data.productData.forEach(item => { allProductData.push({ ...item, id: contractId, // 明确设置合同ID purchaseLedgerNo: contract.purchaseContractNumber, // 添加采购合同号 supplierName: contract.supplierName, // 添加供应商名称 projectName: contract.projectName // 添加项目名称 }); }); } }); // 设置表单数据(使用第一个合同的基本信息,采购合同号留空) form.purchaseLedgerNo = ""; // 采购合同号留空,因为会在产品表格中分别显示 form.invoiceAmount = 0; form.invoiceNumber = ""; form.entryDate = dayjs().format("YYYY-MM-DD"); form.enterDate = dayjs().format("YYYY-MM-DD"); form.salesContractNo = results[0].data.salesContractNo; form.projectName = results[0].data.projectName; form.supplierName = results[0].data.supplierName; // 保留录入人信息 form.issUerId = userStore.id; form.issUer = userStore.nickName; form.productData = allProductData; // 存储选中的合同数据 selectedContracts.value = selectedRows; }); } else if (type == "edit") { const id = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; const data = await getPurchaseById({ id, type: 2 }); form.purchaseLedgerNo = data.purchaseContractNumber; form.invoiceAmount = data.invoiceAmount; form.invoiceNumber = data.invoiceNumber; form.salesContractNo = data.salesContractNo; form.projectName = data.projectName; form.supplierName = data.supplierName; form.entryDate = data.entryDate; form.productData = data.productData; } }; // 子表合计方法 const summarizeChildrenTable = (param) => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "ticketsNum", "ticketsAmount", "ticketsAmountRef", "futureTickets", "futureTicketsAmount", ]); }; //本次来票数失焦操作 const invoiceNumBlur = (row) => { if (!row.ticketsNum || row.ticketsNum === "") { row.ticketsNum = 0; } if (Number(row.ticketsNum) > Number(row.tempFutureTickets)) { proxy.$modal.msgWarning("本次开票数不得大于未开票数"); row.ticketsNum = 0; return; } // 计算本次来票金额 row.ticketsAmount = (row.ticketsNum * row.taxInclusiveUnitPrice).toFixed(2) // 计算未来票数 row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2) // 计算未来票金额 row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2) calculateinvoiceAmount(); }; const columns = [ { label: "产品大类", prop: "productCategory", width: 120, }, { label: "规格型号", prop: "specificationModel", width: 120, }, { label: "单位", prop: "unit", width: 80, }, { label: "数量", prop: "quantity", width: 80, }, { label: "税率(%)", prop: "taxRate", width: 80, }, { label: "录入日期", prop: "registerDate", width: 120, }, { label: "含税单价(元)", prop: "taxInclusiveUnitPrice", width: 150, formatData: val => { return val ? parseFloat(val).toFixed(2) : 0; }, }, { label: "含税总价(元)", prop: "taxInclusiveTotalPrice", width: 150, formatData: val => { return parseFloat(val).toFixed(2) ?? 0; }, }, { label: "不含税总价(元)", prop: "taxExclusiveTotalPrice", width: 150, formatData: val => { return parseFloat(val).toFixed(2) ?? 0; }, }, { label: "本次来票数", prop: "ticketsNum", dataType: "slot", slot: "ticketsNumRef", width: 180, align: "center", }, { label: "本次来票金额(元)", prop: "ticketsAmount", dataType: "slot", slot: "ticketsAmountRef", width: 180, align: "center", }, { label: "未来票数", prop: "futureTickets", width: 100, }, { label: "未来票金额(元)", prop: "futureTicketsAmount", width: 200, }, ]; const formattedNumber = (row, column, cellValue) => { if (cellValue == 0) { return parseFloat(cellValue).toFixed(2); } if (cellValue) { return parseFloat(cellValue).toFixed(2); } else { return cellValue; } }; const getTableData = async (type, selectedRows) => { if (type == "add") { // 检查所有选择的合同是否具有相同的供应商名称 const firstRow = selectedRows[0]; const isSameSupplier = selectedRows.every( row => row.supplierName === firstRow.supplierName ); // 本次来票金额失焦操作 const invoiceAmountBlur = (row) => { if (!row.ticketsAmount) { row.ticketsAmount = 0; } // 计算是否超过来票总金额 if (row.ticketsAmount > row.tempFutureTicketsAmount) { proxy.$modal.msgWarning("本次来票金额不得大于未来票金额"); row.ticketsAmount = 0; } // 计算本次来票数 row.ticketsNum = Number( (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2) ); // 计算未来票数 row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2) // 计算未来票金额 row.futureTicketsAmount = (row.tempFutureTicketsAmount - row.ticketsAmount).toFixed(2) calculateinvoiceAmount(); }; if (!isSameSupplier) { proxy.$modal.msgError("请选择相同供应商名称的合同"); return; } const calculateinvoiceAmount = () => { let invoiceAmountTotal = 0; form.productData.forEach((item) => { if (item.ticketsAmount) { invoiceAmountTotal += Number(item.ticketsAmount); } }); form.invoiceAmount = invoiceAmountTotal.toFixed(2); }; // 允许不同的采购合同号批量处理,无需检查重复 const open = async (type, selectedRows) => { visible.value = true; // 如果是批量操作,设置标题 if (Array.isArray(selectedRows) && selectedRows.length > 1) { modalOptions.title = `批量新增 (${selectedRows.length}条)`; } else { modalOptions.title = type == "add" ? "新增" : "编辑"; } // 如果是单个操作,获取id if (!Array.isArray(selectedRows) || selectedRows.length === 1) { const idValue = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; id.value = idValue; } await getTableData(type, selectedRows); }; // 清空表单数据 Object.keys(form).forEach(key => { if (key !== "productData") { form[key] = undefined; } }); form.productData = []; const uploadSuccess = (response) => { form.tempFileIds.push(response.data.tempId); console.log(form); }; // 加载所有选中合同的产品数据 const promises = selectedRows.map(row => getInfo({ id: row.id })); const removeFile = (file) => { const { tempId } = file.response.data; form.tempFileIds = form.tempFileIds.filter((item) => item !== tempId); }; Promise.all(promises).then(results => { // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 const allProductData = []; results.forEach((result, index) => { const contract = selectedRows[index]; const contractId = contract.id; if (result.data && result.data.productData) { result.data.productData.forEach(item => { allProductData.push({ ...item, // id: contractId, // 明确设置合同ID purchaseLedgerNo: contract.purchaseContractNumber, // 添加采购合同号 supplierName: contract.supplierName, // 添加供应商名称 projectName: contract.projectName, // 添加项目名称 }); }); } }); const closeAndRefresh = () => { closeModal(); emit('refreshList'); }; // 设置表单数据(使用第一个合同的基本信息,采购合同号留空) form.purchaseLedgerNo = ""; // 采购合同号留空,因为会在产品表格中分别显示 form.invoiceAmount = 0; form.invoiceNumber = ""; form.entryDate = dayjs().format("YYYY-MM-DD"); form.enterDate = dayjs().format("YYYY-MM-DD"); form.salesContractNo = results[0].data.salesContractNo; form.projectName = results[0].data.projectName; form.supplierName = results[0].data.supplierName; // 保留录入人信息 form.issUerId = userStore.id; form.issUer = userStore.nickName; const submitForm = () => { proxy.$refs["formRef"].validate((valid) => { if (valid) { // 如果是批量操作,将所有合同的数据放在一个数组里,只调用一次接口 if (selectedContracts.value.length > 1) { // 创建包含所有合同数据的数组 const batchData = selectedContracts.value.map(contract => { // 筛选出属于当前合同的产品数据 const contractProductData = form.productData.filter(item => item.id === contract.id ); // 为每个采购合同创建独立的对象 return { // 基础表单数据 invoiceNumber: form.invoiceNumber, invoiceAmount: form.invoiceAmount, entryDate: form.entryDate, enterDate: form.enterDate, issUerId: form.issUerId, // 录入人id issUer: form.issUer, // 录入人 tempFileIds: form.tempFileIds, // 合同实际信息 purchaseLedgerId: contract.id, // 使用id作为字段名,值为purchaseLedgerId purchaseContractNumber: contract.purchaseContractNumber, // 使用实际的采购合同号 salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 supplierName: contract.supplierName, // 使用实际的供应商名称 projectName: contract.projectName, // 使用实际的项目名称 // 产品数据 productData: proxy.HaveJson(contractProductData), // 批量标识 isBatch: true, type: 4 }; }); // 只调用一次接口,传递包含所有合同数据的数组 modalLoading.value = true; addOrUpdateRegistration(batchData).then((res) => { modalLoading.value = false; if (res.code === 200) { proxy.$modal.msgSuccess("批量登记成功"); closeAndRefresh(); } }).catch(() => { modalLoading.value = false; proxy.$modal.msgError("批量登记失败"); }); } else { // 单个合同提交逻辑 - 以数组格式传递 const singleContract = selectedContracts.value[0]; const singleFormArray = [{ // 基础表单数据 invoiceNumber: form.invoiceNumber, invoiceAmount: form.invoiceAmount, entryDate: form.entryDate, enterDate: form.enterDate, issUerId: form.issUerId, // 录入人id issUer: form.issUer, // 录入人 tempFileIds: form.tempFileIds, // 合同实际信息 purchaseLedgerId: singleContract.id, // 使用id作为字段名,值为purchaseLedgerId purchaseContractNumber: singleContract.purchaseContractNumber, // 使用实际的采购合同号 salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 supplierName: singleContract.supplierName, // 使用实际的供应商名称 projectName: singleContract.projectName, // 使用实际的项目名称 // 产品数据 productData: proxy.HaveJson(form.productData), // 批量标识 isBatch: false, type: 4 }]; modalLoading.value = true; addOrUpdateRegistration(singleFormArray).then((res) => { modalLoading.value = false; if (res.code === 200) { proxy.$modal.msgSuccess("登记成功"); closeAndRefresh(); } }).catch(() => { modalLoading.value = false; proxy.$modal.msgError("登记失败"); }); } } }); }; form.productData = allProductData; defineExpose({ open, closeAndRefresh, }); // 存储选中的合同数据 selectedContracts.value = selectedRows; }); } else if (type == "edit") { const id = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; const data = await getPurchaseById({ id, type: 2 }); form.purchaseLedgerNo = data.purchaseContractNumber; form.invoiceAmount = data.invoiceAmount; form.invoiceNumber = data.invoiceNumber; form.salesContractNo = data.salesContractNo; form.projectName = data.projectName; form.supplierName = data.supplierName; form.entryDate = data.entryDate; form.productData = data.productData; } }; // 子表合计方法 const summarizeChildrenTable = param => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "ticketsNum", "ticketsAmount", "ticketsAmountRef", "futureTickets", "futureTicketsAmount", ]); }; //本次来票数失焦操作 const invoiceNumBlur = row => { if (!row.ticketsNum || row.ticketsNum === "") { row.ticketsNum = 0; } if (Number(row.ticketsNum) > Number(row.tempFutureTickets)) { proxy.$modal.msgWarning("本次开票数不得大于未开票数"); row.ticketsNum = 0; return; } // 计算本次来票金额 row.ticketsAmount = (row.ticketsNum * row.taxInclusiveUnitPrice).toFixed(2); // 计算未来票数 row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2); // 计算未来票金额 row.futureTicketsAmount = ( row.tempFutureTicketsAmount - row.ticketsAmount ).toFixed(2); calculateinvoiceAmount(); }; // 本次来票金额失焦操作 const invoiceAmountBlur = row => { if (!row.ticketsAmount) { row.ticketsAmount = 0; } // 计算是否超过来票总金额 if (row.ticketsAmount > row.tempFutureTicketsAmount) { proxy.$modal.msgWarning("本次来票金额不得大于未来票金额"); row.ticketsAmount = 0; } // 计算本次来票数 row.ticketsNum = Number( (row.ticketsAmount / row.taxInclusiveUnitPrice).toFixed(2) ); // 计算未来票数 row.futureTickets = (row.tempFutureTickets - row.ticketsNum).toFixed(2); // 计算未来票金额 row.futureTicketsAmount = ( row.tempFutureTicketsAmount - row.ticketsAmount ).toFixed(2); calculateinvoiceAmount(); }; const calculateinvoiceAmount = () => { let invoiceAmountTotal = 0; form.productData.forEach(item => { if (item.ticketsAmount) { invoiceAmountTotal += Number(item.ticketsAmount); } }); form.invoiceAmount = invoiceAmountTotal.toFixed(2); }; const open = async (type, selectedRows) => { visible.value = true; // 如果是批量操作,设置标题 if (Array.isArray(selectedRows) && selectedRows.length > 1) { modalOptions.title = `批量新增 (${selectedRows.length}条)`; } else { modalOptions.title = type == "add" ? "新增" : "编辑"; } // 如果是单个操作,获取id if (!Array.isArray(selectedRows) || selectedRows.length === 1) { const idValue = Array.isArray(selectedRows) ? selectedRows[0].id : selectedRows; id.value = idValue; } await getTableData(type, selectedRows); }; const uploadSuccess = response => { form.tempFileIds.push(response.data.tempId); console.log(form); }; const removeFile = file => { const { tempId } = file.response.data; form.tempFileIds = form.tempFileIds.filter(item => item !== tempId); }; const closeAndRefresh = () => { closeModal(); emit("refreshList"); }; const processProductData = products => { return products.map(product => { return { ...product, futureTickets: product.futureTickets ? Number(Number(product.futureTickets).toFixed(2)) : 0, futureTicketsAmount: product.futureTicketsAmount ? Number(Number(product.futureTicketsAmount).toFixed(2)) : 0, ticketsNum: product.ticketsNum ? Number(Number(product.ticketsNum).toFixed(2)) : 0, ticketsAmount: product.ticketsAmount ? Number(Number(product.ticketsAmount).toFixed(2)) : 0, }; }); }; const submitForm = () => { proxy.$refs["formRef"].validate(valid => { if (valid) { // 如果是批量操作,将所有合同的数据放在一个数组里,只调用一次接口 if (selectedContracts.value.length > 1) { // 创建包含所有合同数据的数组 const batchData = selectedContracts.value.map(contract => { // 筛选出属于当前合同的产品数据 const contractProductData = form.productData.filter( item => item.id === contract.id ); const processedProductData = processProductData(contractProductData); // 为每个采购合同创建独立的对象 return { // 基础表单数据 invoiceNumber: form.invoiceNumber, invoiceAmount: form.invoiceAmount, entryDate: form.entryDate, enterDate: form.enterDate, issUerId: form.issUerId, // 录入人id issUer: form.issUer, // 录入人 tempFileIds: form.tempFileIds, // 合同实际信息 purchaseLedgerId: contract.id, // 使用id作为字段名,值为purchaseLedgerId purchaseContractNumber: contract.purchaseContractNumber, // 使用实际的采购合同号 salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 supplierName: contract.supplierName, // 使用实际的供应商名称 projectName: contract.projectName, // 使用实际的项目名称 // 产品数据 productData: proxy.HaveJson(processedProductData), // 批量标识 isBatch: true, type: 4, }; }); // 只调用一次接口,传递包含所有合同数据的数组 modalLoading.value = true; console.log(batchData, "batchData"); addOrUpdateRegistration(batchData) .then(res => { modalLoading.value = false; if (res.code === 200) { proxy.$modal.msgSuccess("批量登记成功"); closeAndRefresh(); } }) .catch(() => { modalLoading.value = false; proxy.$modal.msgError("批量登记失败"); }); } else { // 单个合同提交逻辑 - 以数组格式传递 const singleContract = selectedContracts.value[0]; const processedProductData = processProductData(form.productData); const singleFormArray = [ { // 基础表单数据 invoiceNumber: form.invoiceNumber, invoiceAmount: form.invoiceAmount, entryDate: form.entryDate, enterDate: form.enterDate, issUerId: form.issUerId, // 录入人id issUer: form.issUer, // 录入人 tempFileIds: form.tempFileIds, // 合同实际信息 purchaseLedgerId: singleContract.id, // 使用id作为字段名,值为purchaseLedgerId purchaseContractNumber: singleContract.purchaseContractNumber, // 使用实际的采购合同号 salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 supplierName: singleContract.supplierName, // 使用实际的供应商名称 projectName: singleContract.projectName, // 使用实际的项目名称 // 产品数据 productData: proxy.HaveJson(processedProductData), // 批量标识 isBatch: false, type: 4, }, ]; modalLoading.value = true; console.log(singleFormArray, "singleFormArray"); addOrUpdateRegistration(singleFormArray) .then(res => { modalLoading.value = false; if (res.code === 200) { proxy.$modal.msgSuccess("登记成功"); closeAndRefresh(); } }) .catch(() => { modalLoading.value = false; proxy.$modal.msgError("登记失败"); }); } } }); }; defineExpose({ open, closeAndRefresh, }); </script> <style lang="scss" scoped></style> src/views/procurementManagement/procurementLedger/index.vue
@@ -2,477 +2,433 @@ <div class="app-container"> <div class="search_form"> <div> <el-form :model="searchForm" :inline="true"> <el-form :model="searchForm" :inline="true"> <el-form-item label="供应商名称:"> <el-input v-model="searchForm.supplierName" placeholder="请输入" clearable prefix-icon="Search" <el-input v-model="searchForm.supplierName" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item label="采购合同号:"> <el-input v-model="searchForm.purchaseContractNumber" style="width: 240px" placeholder="请输入" @change="handleQuery" clearable :prefix-icon="Search" /> <el-input v-model="searchForm.purchaseContractNumber" style="width: 240px" placeholder="请输入" @change="handleQuery" clearable :prefix-icon="Search" /> </el-form-item> <el-form-item label="销售合同号:"> <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item label="项目名称:"> <el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search" <el-input v-model="searchForm.projectName" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item label="录入日期:"> <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" placeholder="请选择" clearable @change="changeDaterange" /> <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" placeholder="请选择" clearable @change="changeDaterange" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> </el-form-item> </el-form> </div> </div> <div class="table_list"> <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> <el-button type="primary" @click="openForm('add')">新增台账</el-button> <el-button type="success" @click="openScanAddDialog">扫码新增</el-button> <el-button type="primary" @click="openForm('add')">新增台账</el-button> <el-button type="success" @click="openScanAddDialog">扫码新增</el-button> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> </div> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 19em)" :row-class-name="tableRowClassName" > <el-table-column align="center" type="selection" width="55" /> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 19em)" :row-class-name="tableRowClassName"> <el-table-column align="center" type="selection" width="55" /> <el-table-column type="expand"> <template #default="props"> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable" > <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> </el-table> </template> </el-table-column> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="采购合同号" prop="purchaseContractNumber" width="200" show-overflow-tooltip /> <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip /> <el-table-column label="订单状态" width="100" align="center"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="采购合同号" prop="purchaseContractNumber" width="200" show-overflow-tooltip /> <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip /> <el-table-column label="订单状态" width="100" align="center"> <template #default="scope"> <el-tag v-if="scope.row.isInvalid" type="danger" size="small">失效</el-tag> <el-tag v-else type="success" size="small">正常</el-tag> <el-tag v-if="scope.row.isInvalid" type="danger" size="small">失效</el-tag> <el-tag v-else type="success" size="small">正常</el-tag> </template> </el-table-column> <el-table-column label="项目名称" prop="projectName" width="420" show-overflow-tooltip /> <el-table-column label="审批状态" prop="approvalStatus" width="200" show-overflow-tooltip > <el-table-column label="项目名称" prop="projectName" width="420" show-overflow-tooltip /> <el-table-column label="审批状态" prop="approvalStatus" width="200" show-overflow-tooltip> <template #default="scope"> <el-tag size="small" > <el-tag size="small"> {{ approvalStatusText[scope.row.approvalStatus] || '未知状态' }} </el-tag> </template> </el-table-column> <el-table-column label="签订日期" prop="executionDate" width="100" show-overflow-tooltip /> <el-table-column label="付款方式" width="100" prop="paymentMethod" show-overflow-tooltip /> <el-table-column label="合同金额(元)" prop="contractAmount" width="200" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="录入人" prop="recorderName" width="120" show-overflow-tooltip /> <el-table-column label="录入日期" prop="entryDate" width="100" show-overflow-tooltip /> <el-table-column fixed="right" label="操作" width="180" align="center" > <el-table-column label="签订日期" prop="executionDate" width="100" show-overflow-tooltip /> <el-table-column label="付款方式" width="100" prop="paymentMethod" show-overflow-tooltip /> <el-table-column label="合同金额(元)" prop="contractAmount" width="200" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="录入人" prop="recorderName" width="120" show-overflow-tooltip /> <el-table-column label="录入日期" prop="entryDate" width="100" show-overflow-tooltip /> <el-table-column fixed="right" label="操作" width="180" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openForm('edit', scope.row)" >编辑</el-button > <el-button link type="success" size="small" @click="showQRCode(scope.row)" >生成二维码</el-button > <el-button link type="primary" size="small" @click="downLoadFile(scope.row)" >附件</el-button > <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button> <el-button link type="success" size="small" @click="showQRCode(scope.row)">生成二维码</el-button> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">附件</el-button> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增采购台账页面' : '编辑采购台账页面'" width="70%" @close="closeDia" > <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef" > <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增采购台账页面' : '编辑采购台账页面'" width="70%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="采购合同号:" prop="purchaseContractNumber"> <el-input v-model="form.purchaseContractNumber" placeholder="请输入" clearable /> <el-form-item label="采购合同号:" prop="purchaseContractNumber"> <el-input v-model="form.purchaseContractNumber" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesLedgerId"> <el-select v-model="form.salesLedgerId" placeholder="请选择" filterable clearable @change="salesLedgerChange" > <el-option v-for="item in salesContractList" :key="item.id" :label="item.salesContractNo" :value="item.id" /> <el-form-item label="销售合同号:" prop="salesLedgerId"> <el-select v-model="form.salesLedgerId" placeholder="请选择" filterable clearable @change="salesLedgerChange"> <el-option v-for="item in salesContractList" :key="item.id" :label="item.salesContractNo" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="供应商名称:" prop="supplierId"> <el-select v-model="form.supplierId" placeholder="请选择" filterable clearable > <el-option v-for="item in supplierList" :key="item.id" :label="item.supplierName" :value="item.id" /> <el-form-item label="供应商名称:" prop="supplierId"> <el-select v-model="form.supplierId" placeholder="请选择" filterable clearable> <el-option v-for="item in supplierList" :key="item.id" :label="item.supplierName" :value="item.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="项目名称" prop="projectName"> <el-input v-model="form.projectName" placeholder="请输入" clearable /> <el-col :span="12"> <el-form-item label="项目名称" prop="projectName"> <el-input v-model="form.projectName" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-col> </el-row> <el-row :gutter="30"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="付款方式"> <el-input v-model="form.paymentMethod" placeholder="请输入" clearable /> <el-input v-model="form.paymentMethod" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="签订日期:" prop="executionDate"> <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> </el-row> <el-col :span="12"> <el-form-item label="签订日期:" prop="executionDate"> <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="审批人:" prop="approverId"> <el-select v-model="form.approverId" placeholder="请选择审批人" clearable > <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> <el-form-item label="审批人:" prop="approverId"> <el-select v-model="form.approverId" placeholder="请选择审批人" clearable> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> <el-form-item label="录入人:" prop="recorderId" v-show="false"> <el-select v-model="form.recorderId" placeholder="请选择" clearable disabled > <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> <el-form-item label="录入人:" prop="recorderId" v-show="false"> <el-select v-model="form.recorderId" placeholder="请选择" clearable disabled> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> <el-form-item label="录入日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> </el-row> <el-row> <el-form-item label="产品信息:" prop="entryDate"> <el-button type="primary" @click="openProductForm('add')" >添加</el-button > <el-button plain type="danger" @click="deleteProduct" >删除</el-button > <el-form-item label="产品信息:" prop="entryDate"> <el-button type="primary" @click="openProductForm('add')">添加</el-button> <el-button plain type="danger" @click="deleteProduct">删除</el-button> </el-form-item> <div class="select-button-group" style="width: 220px; margin: 20px 0;" v-if="operationType === 'add'"> <el-select filterable allow-create :reserve-keyword="true" :default-first-option="false" v-model="templateName" :input-value="filterInputValue" @filter-change="onTemplateFilterChange" @change="onTemplateChange" style="width: 180px; border-right: none; border-radius: 4px 0 0 4px;" placeholder="请选择" class="no-arrow-select" > <el-option v-for="item in templateList" :key="item.value" :label="item.templateName" :value="item.templateName" ></el-option> <div class="select-button-group" style="width: 220px; margin: 20px 0;" v-if="operationType === 'add'"> <el-select filterable allow-create :reserve-keyword="true" :default-first-option="false" v-model="templateName" :input-value="filterInputValue" @filter-change="onTemplateFilterChange" @change="onTemplateChange" style="width: 180px; border-right: none; border-radius: 4px 0 0 4px;" placeholder="请选择" class="no-arrow-select"> <el-option v-for="item in templateList" :key="item.value" :label="item.templateName" :value="item.templateName"></el-option> </el-select> <!-- 按钮:与 Select 高度匹配,去掉左侧边框,无缝衔接 --> <el-button size="small" style="height: 32px; border-radius: 0 4px 4px 0; margin-left: -1px;" @click="handleButtonClick" :disabled="!templateName || templateName.trim() === '' || isTemplateNameDuplicate" > <el-button size="small" style="height: 32px; border-radius: 0 4px 4px 0; margin-left: -1px;" @click="handleButtonClick" :disabled="!templateName || templateName.trim() === '' || isTemplateNameDuplicate"> 保存 </el-button> </div> </el-row> <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeProTable" > <el-table-column align="center" type="selection" width="55" /> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="库存预警数量" prop="warnNum" width="120" show-overflow-tooltip /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column fixed="right" label="操作" min-width="60" align="center" > <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeProTable"> <el-table-column align="center" type="selection" width="55" /> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="库存预警数量" prop="warnNum" width="120" show-overflow-tooltip /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row, scope.$index)" >编辑</el-button > <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row, scope.$index)">编辑</el-button> </template> </el-table-column> </el-table> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="备注·:" prop="remark"> <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2" /> <el-form-item label="备注·:" prop="remark"> <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2" /> </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-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">上传</el-button> <template #tip> <div class="el-upload__tip"> @@ -487,335 +443,310 @@ </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">取消</el-button> </div> </template> </el-dialog> <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia" > <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef" > <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia"> <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef"> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="产品大类:" prop="productId"> <el-tree-select v-model="productForm.productId" placeholder="请选择" clearable check-strictly @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> <el-form-item label="产品大类:" prop="productId"> <el-tree-select v-model="productForm.productId" placeholder="请选择" clearable check-strictly @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="规格型号:" prop="productModelId"> <el-select v-model="productForm.productModelId" placeholder="请选择" clearable @change="getProductModel" > <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> <el-form-item label="规格型号:" prop="productModelId"> <el-select v-model="productForm.productModelId" placeholder="请选择" clearable @change="getProductModel"> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="单位:" prop="unit"> <el-input v-model="productForm.unit" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="税率(%):" prop="taxRate"> <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="mathNum" > <el-option label="1" value="1" /> <el-option label="6" value="6" /> <el-option label="13" value="13" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice"> <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="mathNum" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="数量:" prop="quantity"> <el-input-number :step="0.1" clearable :precision="2" style="width: 100%" v-model="productForm.quantity" placeholder="请输入" @change="mathNum" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice"> <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="reverseMathNum('taxInclusiveTotalPrice')" /> <el-form-item label="单位:" prop="unit"> <el-input v-model="productForm.unit" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice" > <el-input v-model="productForm.taxExclusiveTotalPrice" @change="reverseMathNum('taxExclusiveTotalPrice')" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="发票类型:" prop="invoiceType"> <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable > <el-option label="增普票" value="增普票" /> <el-option label="增专票" value="增专票" /> <el-form-item label="税率(%):" prop="taxRate"> <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="mathNum"> <el-option label="1" value="1" /> <el-option label="6" value="6" /> <el-option label="13" value="13" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="库存预警数量:" prop="warnNum"> <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice"> <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="mathNum" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="数量:" prop="quantity"> <el-input-number :step="0.1" clearable :precision="2" style="width: 100%" v-model="productForm.quantity" placeholder="请输入" @change="mathNum" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice"> <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" clearable style="width: 100%" @change="reverseMathNum('taxInclusiveTotalPrice')" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice"> <el-input v-model="productForm.taxExclusiveTotalPrice" @change="reverseMathNum('taxExclusiveTotalPrice')" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="发票类型:" prop="invoiceType"> <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable> <el-option label="增普票" value="增普票" /> <el-option label="增专票" value="增专票" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="库存预警数量:" prop="warnNum"> <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitProduct">确认</el-button> <el-button type="primary" @click="submitProduct">确认</el-button> <el-button @click="closeProductDia">取消</el-button> </div> </template> </el-dialog> <!-- 二维码显示对话框 --> <el-dialog v-model="qrCodeDialogVisible" title="采购合同号二维码" width="400px" center > <el-dialog v-model="qrCodeDialogVisible" title="采购合同号二维码" width="400px" center> <div style="text-align: center;"> <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" /> <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" /> <div style="margin: 20px;"> <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button> <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button> </div> </div> </el-dialog> <!-- 扫码新增对话框 --> <el-dialog v-model="scanAddDialogVisible" title="扫码新增采购台账" width="70%" @close="closeScanAddDialog" > <el-form :model="scanAddForm" label-width="140px" label-position="top" :rules="scanAddRules" ref="scanAddFormRef" > <el-dialog v-model="scanAddDialogVisible" title="扫码新增采购台账" width="70%" @close="closeScanAddDialog"> <el-form :model="scanAddForm" label-width="140px" label-position="top" :rules="scanAddRules" ref="scanAddFormRef"> <el-row :gutter="20"> <el-col :span="24"> <el-form-item label="扫码内容:"> <el-input v-model="scanAddForm.scanContent" type="textarea" :rows="3" placeholder="请扫描二维码或手动输入采购合同信息" @input="parseScanContent" /> <el-input v-model="scanAddForm.scanContent" type="textarea" :rows="3" placeholder="请扫描二维码或手动输入采购合同信息" @input="parseScanContent" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="采购合同号:" prop="purchaseContractNumber"> <el-input v-model="scanAddForm.purchaseContractNumber" placeholder="请输入" clearable /> <el-form-item label="采购合同号:" prop="purchaseContractNumber"> <el-input v-model="scanAddForm.purchaseContractNumber" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="供应商名称:" prop="supplierName"> <el-input v-model="scanAddForm.supplierName" placeholder="请输入" clearable /> <el-form-item label="供应商名称:" prop="supplierName"> <el-input v-model="scanAddForm.supplierName" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="项目名称:" prop="projectName"> <el-input v-model="scanAddForm.projectName" placeholder="请输入" clearable /> <el-form-item label="项目名称:" prop="projectName"> <el-input v-model="scanAddForm.projectName" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="合同金额(元):" prop="contractAmount"> <el-input-number v-model="scanAddForm.contractAmount" :precision="2" :step="0.1" clearable style="width: 100%" placeholder="请输入" /> <el-form-item label="合同金额(元):" prop="contractAmount"> <el-input-number v-model="scanAddForm.contractAmount" :precision="2" :step="0.1" clearable style="width: 100%" placeholder="请输入" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="付款方式:"> <el-input v-model="scanAddForm.paymentMethod" placeholder="请输入" clearable /> <el-input v-model="scanAddForm.paymentMethod" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入人:"> <el-input v-model="scanAddForm.recorderName" disabled /> <el-input v-model="scanAddForm.recorderName" disabled /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="24"> <el-form-item label="备注:"> <el-input v-model="scanAddForm.remark" type="textarea" :rows="2" placeholder="请输入备注信息" clearable /> <el-input v-model="scanAddForm.remark" type="textarea" :rows="2" placeholder="请输入备注信息" clearable /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitScanAdd">确认新增</el-button> <el-button type="primary" @click="submitScanAdd">确认新增</el-button> <el-button @click="closeScanAddDialog">取消</el-button> </div> </template> </el-dialog> <!-- 扫码登记对话框 --> <el-dialog v-model="scanDialogVisible" title="扫码登记" width="60%" @close="closeScanDialog" > <el-form :model="scanForm" label-width="120px" label-position="left" :rules="scanRules" ref="scanFormRef" > <el-dialog v-model="scanDialogVisible" title="扫码登记" width="60%" @close="closeScanDialog"> <el-form :model="scanForm" label-width="120px" label-position="left" :rules="scanRules" ref="scanFormRef"> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="采购合同号:"> <el-input v-model="scanForm.purchaseContractNumber" disabled /> <el-input v-model="scanForm.purchaseContractNumber" disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="供应商名称:"> <el-input v-model="scanForm.supplierName" disabled /> <el-input v-model="scanForm.supplierName" disabled /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="项目名称:"> <el-input v-model="scanForm.projectName" disabled /> <el-input v-model="scanForm.projectName" disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="扫码时间:"> <el-input v-model="scanForm.scanTime" disabled /> <el-input v-model="scanForm.scanTime" disabled /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="扫码人:"> <el-input v-model="scanForm.scannerName" disabled /> <el-input v-model="scanForm.scannerName" disabled /> </el-form-item> </el-col> <el-col :span="12"> @@ -829,30 +760,40 @@ <el-row :gutter="20"> <el-col :span="24"> <el-form-item label="扫码备注:"> <el-input v-model="scanForm.scanRemark" type="textarea" :rows="3" placeholder="请输入扫码备注信息" /> <el-input v-model="scanForm.scanRemark" type="textarea" :rows="3" placeholder="请输入扫码备注信息" /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="24"> <el-form-item label="扫码记录:"> <el-table :data="scanRecords" border style="width: 100%"> <el-table-column label="序号" type="index" width="60" align="center" /> <el-table-column label="扫码时间" prop="scanTime" width="180" /> <el-table-column label="扫码人" prop="scannerName" width="120" /> <el-table-column label="扫码状态" prop="scanStatus" width="100"> <el-table :data="scanRecords" border style="width: 100%"> <el-table-column label="序号" type="index" width="60" align="center" /> <el-table-column label="扫码时间" prop="scanTime" width="180" /> <el-table-column label="扫码人" prop="scannerName" width="120" /> <el-table-column label="扫码状态" prop="scanStatus" width="100"> <template #default="scope"> <el-tag :type="scope.row.scanStatus === '已扫码' ? 'success' : 'warning'"> {{ scope.row.scanStatus }} </el-tag> </template> </el-table-column> <el-table-column label="备注" prop="scanRemark" /> <el-table-column label="备注" prop="scanRemark" /> </el-table> </el-form-item> </el-col> @@ -860,706 +801,783 @@ </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitScan">确认扫码</el-button> <el-button type="primary" @click="submitScan">确认扫码</el-button> <el-button @click="closeScanDialog">取消</el-button> </div> </template> </el-dialog> <FileList ref="fileListRef" /> <FileList ref="fileListRef" /> </div> </template> <script setup> import {getToken} from "@/utils/auth"; import pagination from "@/components/PIMTable/Pagination.vue"; import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessageBox,ElMessage } from "element-plus"; import { userListNoPage } from "@/api/system/user.js"; import FileList from "./fileList.vue"; import { getSalesLedgerWithProducts, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInfoByContractNo, } from "@/api/salesManagement/salesLedger.js"; import { addOrEditPurchase, addPurchaseTemplate, createPurchaseNo, delPurchase, getSalesNo, purchaseListPage, productList, getPurchaseById, getOptions, getPurchaseTemplateList } from "@/api/procurementManagement/procurementLedger.js"; import useFormData from "@/hooks/useFormData.js"; import QRCode from "qrcode"; import { getToken } from "@/utils/auth"; import pagination from "@/components/PIMTable/Pagination.vue"; import { ref, onMounted, reactive, toRefs, getCurrentInstance, nextTick, } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessageBox, ElMessage } from "element-plus"; import { userListNoPage } from "@/api/system/user.js"; import FileList from "./fileList.vue"; import { getSalesLedgerWithProducts, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInfoByContractNo, } from "@/api/salesManagement/salesLedger.js"; import { addOrEditPurchase, addPurchaseTemplate, createPurchaseNo, delPurchase, getSalesNo, purchaseListPage, productList, getPurchaseById, getOptions, getPurchaseTemplateList, } from "@/api/procurementManagement/procurementLedger.js"; import useFormData from "@/hooks/useFormData.js"; import QRCode from "qrcode"; const { proxy } = getCurrentInstance(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const productSelectedRows = ref([]); const modelOptions = ref([]); const userList = ref([]); const productOptions = ref([]); const salesContractList = ref([]); const supplierList = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); const total = ref(0); const fileList = ref([]); import useUserStore from "@/store/modules/user"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const productSelectedRows = ref([]); const modelOptions = ref([]); const userList = ref([]); const productOptions = ref([]); const salesContractList = ref([]); const supplierList = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); const total = ref(0); const fileList = ref([]); import useUserStore from "@/store/modules/user"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import dayjs from "dayjs"; const userStore = useUserStore(); const userStore = useUserStore(); // 二维码相关变量 const qrCodeDialogVisible = ref(false); const qrCodeUrl = ref(""); // 二维码相关变量 const qrCodeDialogVisible = ref(false); const qrCodeUrl = ref(""); // 订单审批状态显示文本 const approvalStatusText = { 0: "审批中", 1: "审批通过", 2: "审批失败", }; // 订单审批状态显示文本 const approvalStatusText = { 0: '审批中', 1: '审批通过', 2: '审批失败' }; const templateName = ref(''); const filterInputValue = ref(''); const templateList = ref([]); const isTemplateNameDuplicate = ref(false); // 标记模板名称是否重复 // 检查模板名称是否重复 const checkTemplateNameDuplicate = (name) => { if (!name || name.trim() === '') { isTemplateNameDuplicate.value = false; return false; } const isDuplicate = templateList.value.some(item => item.templateName === name.trim()); isTemplateNameDuplicate.value = isDuplicate; return isDuplicate; }; // 防抖定时器 let duplicateCheckTimer = null; const onTemplateFilterChange = (val) => { filterInputValue.value = val ?? ''; // 清除之前的定时器 if (duplicateCheckTimer) { clearTimeout(duplicateCheckTimer); } // 实时检查模板名称是否重复(防抖处理,避免频繁提示) if (val && val.trim()) { duplicateCheckTimer = setTimeout(() => { const isDuplicate = checkTemplateNameDuplicate(val); if (isDuplicate) { ElMessage({ message: '模板名称已存在,请更换模板名称', type: 'warning', duration: 2000 }); } }, 300); // 300ms 防抖 } else { isTemplateNameDuplicate.value = false; } }; // allow-create 时,输入不存在的内容会作为 string 值返回;这里同步回输入框以确保文字不丢 const onTemplateChange = async (val) => { if (typeof val === 'string') { filterInputValue.value = val; // 选择或输入时检查重复 checkTemplateNameDuplicate(val); } // 过滤数据,查找匹配的模板 const matchedTemplate = templateList.value.find(item => item.templateName === val); if (matchedTemplate?.id) { // 如果找到模板,加载模板数据 form.value = { ...form.value, ...matchedTemplate, }; productData.value = matchedTemplate.productData || []; // 生成新的采购合同号 try { const res = await createPurchaseNo(); if (res?.data) { form.value.purchaseContractNumber = res.data; } } catch (error) { console.error('生成采购合同号失败:', error); } } else { // 如果没有找到模板,重置表单(保持当前表单状态) const currentFormData = { ...form.value }; const currentProductData = [...productData.value]; // 如果对话框未打开,先打开 if (!dialogFormVisible.value) { operationType.value = 'add'; dialogFormVisible.value = true; } // 等待下一个 tick 后恢复数据 await nextTick(); form.value = { ...form.value, ...currentFormData, }; productData.value = currentProductData; } }; // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { supplierName: "", // 供应商名称 purchaseContractNumber: "", // 采购合同编号 salesContractNo: "", // 销售合同编号 projectName: "", // 项目名称 entryDate: null, // 录入日期 entryDateStart: undefined, entryDateEnd: undefined, }, form: { purchaseContractNumber: "", salesLedgerId: "", projectName: "", recorderId: "", entryDate: "", productData: [], supplierName: "", supplierId: "", paymentMethod: "", executionDate: "", }, rules: { purchaseContractNumber: [ { required: true, message: "请输入", trigger: "blur" }, ], approverId:[{ required: true, message: "请选择审批人", trigger: "change" }], projectName:[{ required:true, message:"请输入项目名称", trigger:"blur"}], supplierId: [{ required: true, message: "请输入", trigger: "blur" }], entryDate: [{ required: true, message: "请选择", trigger: "change" }], executionDate: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { form, rules } = toRefs(data); const { form: searchForm } = useFormData({ ...data.searchForm, // 设置录入日期范围为当天 entryDate: [dayjs().startOf('day').format('YYYY-MM-DD'), dayjs().endOf('day').format('YYYY-MM-DD')], entryDateStart: dayjs().startOf('day').format('YYYY-MM-DD'), entryDateEnd: dayjs().endOf('day').format('YYYY-MM-DD') }); // 产品表单弹框数据 const productFormVisible = ref(false); const productOperationType = ref(""); const productOperationIndex = ref(""); const currentId = ref(""); const productFormData = reactive({ productForm: { productId: "", productCategory: "", productModelId: "", specificationModel: "", unit: "", quantity: "", taxInclusiveUnitPrice: "", taxRate: "", taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", warnNum: "", }, productRules: { productId: [{ required: true, message: "请选择", trigger: "change" }], productModelId: [{ required: true, message: "请选择", trigger: "change" }], unit: [{ required: true, message: "请输入", trigger: "blur" }], quantity: [{ required: true, message: "请输入", trigger: "blur" }], taxInclusiveUnitPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxRate: [{ required: true, message: "请选择", trigger: "change" }], warnNum: [{ required: true, message: "请选择", trigger: "change" }], taxInclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxExclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], invoiceType: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { productForm, productRules } = toRefs(productFormData); const upload = reactive({ // 上传的地址 url: import.meta.env.VITE_APP_BASE_API + "/file/upload", // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, }); const changeDaterange = (value) => { if (value) { searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); } else { searchForm.entryDateStart = undefined; searchForm.entryDateEnd = undefined; } handleQuery(); }; const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { page.current = 1; getList(); }; // 保存模板 const handleButtonClick = async () => { // 检查模板名称是否为空 if (!templateName.value || templateName.value.trim() === '') { ElMessage({ message: '请输入模板名称', type: 'warning', }); return; } const templateName = ref(""); const filterInputValue = ref(""); const templateList = ref([]); const isTemplateNameDuplicate = ref(false); // 标记模板名称是否重复 // 检查模板名称是否重复 const isDuplicate = checkTemplateNameDuplicate(templateName.value); if (isDuplicate) { ElMessage({ message: '模板名称已存在,请更换模板名称', type: 'warning', }); return; } // 检查供应商是否选择 if (!form.value.supplierId) { ElMessage({ message: '请先选择供应商', type: 'warning', }); return; } // 检查是否有产品数据 // if (!productData.value || productData.value.length === 0) { // ElMessage({ // message: '请先添加产品信息', // type: 'warning', // }); // return; // } try { let params = { productData: proxy.HaveJson(productData.value), supplierId: form.value.supplierId, paymentMethod: form.value.paymentMethod, recorderId: form.value.recorderId, approverId: form.value.approverId, templateName: templateName.value.trim() }; console.log(params); let res = await addPurchaseTemplate(params); if (res && res.code === 200) { ElMessage({ message: '模板保存成功', type: 'success', }); // 保存成功后重新获取模板列表 await getTemplateList(); // 清空模板名称输入 templateName.value = ''; filterInputValue.value = ''; const checkTemplateNameDuplicate = name => { if (!name || name.trim() === "") { isTemplateNameDuplicate.value = false; return false; } const isDuplicate = templateList.value.some( item => item.templateName === name.trim() ); isTemplateNameDuplicate.value = isDuplicate; return isDuplicate; }; // 防抖定时器 let duplicateCheckTimer = null; const onTemplateFilterChange = val => { filterInputValue.value = val ?? ""; // 清除之前的定时器 if (duplicateCheckTimer) { clearTimeout(duplicateCheckTimer); } // 实时检查模板名称是否重复(防抖处理,避免频繁提示) if (val && val.trim()) { duplicateCheckTimer = setTimeout(() => { const isDuplicate = checkTemplateNameDuplicate(val); if (isDuplicate) { ElMessage({ message: "模板名称已存在,请更换模板名称", type: "warning", duration: 2000, }); } }, 300); // 300ms 防抖 } else { isTemplateNameDuplicate.value = false; } }; // allow-create 时,输入不存在的内容会作为 string 值返回;这里同步回输入框以确保文字不丢 const onTemplateChange = async val => { if (typeof val === "string") { filterInputValue.value = val; // 选择或输入时检查重复 checkTemplateNameDuplicate(val); } // 过滤数据,查找匹配的模板 const matchedTemplate = templateList.value.find( item => item.templateName === val ); if (matchedTemplate?.id) { // 如果找到模板,加载模板数据 form.value = { ...form.value, ...matchedTemplate, }; productData.value = matchedTemplate.productData || []; // 生成新的采购合同号 try { const res = await createPurchaseNo(); if (res?.data) { form.value.purchaseContractNumber = res.data; } } catch (error) { console.error("生成采购合同号失败:", error); } } else { // 如果没有找到模板,重置表单(保持当前表单状态) const currentFormData = { ...form.value }; const currentProductData = [...productData.value]; // 如果对话框未打开,先打开 if (!dialogFormVisible.value) { operationType.value = "add"; dialogFormVisible.value = true; } // 等待下一个 tick 后恢复数据 await nextTick(); form.value = { ...form.value, ...currentFormData, }; productData.value = currentProductData; } }; // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { supplierName: "", // 供应商名称 purchaseContractNumber: "", // 采购合同编号 salesContractNo: "", // 销售合同编号 projectName: "", // 项目名称 entryDate: null, // 录入日期 entryDateStart: undefined, entryDateEnd: undefined, }, form: { purchaseContractNumber: "", salesLedgerId: "", projectName: "", recorderId: "", entryDate: "", productData: [], supplierName: "", supplierId: "", paymentMethod: "", executionDate: "", }, rules: { purchaseContractNumber: [ { required: true, message: "请输入", trigger: "blur" }, ], approverId: [ { required: true, message: "请选择审批人", trigger: "change" }, ], projectName: [ { required: true, message: "请输入项目名称", trigger: "blur" }, ], supplierId: [{ required: true, message: "请输入", trigger: "blur" }], entryDate: [{ required: true, message: "请选择", trigger: "change" }], executionDate: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { form, rules } = toRefs(data); const { form: searchForm } = useFormData({ ...data.searchForm, // 设置录入日期范围为当天 entryDate: [ dayjs().startOf("day").format("YYYY-MM-DD"), dayjs().endOf("day").format("YYYY-MM-DD"), ], entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"), entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"), }); // 产品表单弹框数据 const productFormVisible = ref(false); const productOperationType = ref(""); const productOperationIndex = ref(""); const currentId = ref(""); const productFormData = reactive({ productForm: { productId: "", productCategory: "", productModelId: "", specificationModel: "", unit: "", quantity: "", taxInclusiveUnitPrice: "", taxRate: "", taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", warnNum: "", }, productRules: { productId: [{ required: true, message: "请选择", trigger: "change" }], productModelId: [{ required: true, message: "请选择", trigger: "change" }], unit: [{ required: true, message: "请输入", trigger: "blur" }], quantity: [{ required: true, message: "请输入", trigger: "blur" }], taxInclusiveUnitPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxRate: [{ required: true, message: "请选择", trigger: "change" }], warnNum: [{ required: true, message: "请选择", trigger: "change" }], taxInclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxExclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], invoiceType: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { productForm, productRules } = toRefs(productFormData); const upload = reactive({ // 上传的地址 url: import.meta.env.VITE_APP_BASE_API + "/file/upload", // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, }); const changeDaterange = value => { if (value) { searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); } else { searchForm.entryDateStart = undefined; searchForm.entryDateEnd = undefined; } handleQuery(); }; const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { page.current = 1; getList(); }; // 保存模板 const handleButtonClick = async () => { // 检查模板名称是否为空 if (!templateName.value || templateName.value.trim() === "") { ElMessage({ message: res?.msg || '模板保存失败', type: 'error', message: "请输入模板名称", type: "warning", }); return; } // 检查模板名称是否重复 const isDuplicate = checkTemplateNameDuplicate(templateName.value); if (isDuplicate) { ElMessage({ message: "模板名称已存在,请更换模板名称", type: "warning", }); return; } // 检查供应商是否选择 if (!form.value.supplierId) { ElMessage({ message: "请先选择供应商", type: "warning", }); return; } // 检查是否有产品数据 // if (!productData.value || productData.value.length === 0) { // ElMessage({ // message: '请先添加产品信息', // type: 'warning', // }); // return; // } try { let params = { productData: proxy.HaveJson(productData.value), supplierId: form.value.supplierId, paymentMethod: form.value.paymentMethod, recorderId: form.value.recorderId, approverId: form.value.approverId, templateName: templateName.value.trim(), }; console.log(params); let res = await addPurchaseTemplate(params); if (res && res.code === 200) { ElMessage({ message: "模板保存成功", type: "success", }); // 保存成功后重新获取模板列表 await getTemplateList(); // 清空模板名称输入 templateName.value = ""; filterInputValue.value = ""; isTemplateNameDuplicate.value = false; } else { ElMessage({ message: res?.msg || "模板保存失败", type: "error", }); } } catch (error) { console.error("保存模板失败:", error); ElMessage({ message: "模板保存失败,请稍后重试", type: "error", }); } } catch (error) { console.error('保存模板失败:', error); ElMessage({ message: '模板保存失败,请稍后重试', type: 'error', }); } }; // 子表合计方法 const summarizeChildrenTable = (param) => { return proxy.summarizeTable( param, [ }; // 子表合计方法 const summarizeChildrenTable = param => { return proxy.summarizeTable( param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "ticketsNum", "ticketsAmount", "futureTickets", "futureTicketsAmount", ], { ticketsNum: { noDecimal: true }, // 不保留小数 futureTickets: { noDecimal: true }, // 不保留小数 } ); }; const paginationChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; const { entryDate, ...rest } = searchForm; purchaseListPage({ ...rest, ...page }) .then(res => { tableLoading.value = false; // tableData.value = res.data.records; tableData.value = res.data.records.map(record => ({ ...record, isInvalid: record.isWhite === 1, })); // 初始化子数据数组 tableData.value.forEach(item => { item.children = []; }); total.value = res.data.total; expandedRowKeys.value = []; }) .catch(() => { tableLoading.value = false; }); }; // 表格选择数据 const handleSelectionChange = selection => { selectedRows.value = selection; }; const productSelected = selectedRows => { productSelectedRows.value = selectedRows; }; const expandedRowKeys = ref([]); // 展开行 const expandChange = async (row, expandedRows) => { if (expandedRows.length > 0) { expandedRowKeys.value = []; try { const res = await productList({ salesLedgerId: row.id, type: 2 }); const index = tableData.value.findIndex(item => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data || []; expandedRowKeys.value.push(row.id); } } catch (error) { console.error("加载产品列表失败:", error); proxy.$modal.msgError("加载产品列表失败"); // 展开失败时,移除展开状态 const index = expandedRows.findIndex(item => item.id === row.id); if (index > -1) { expandedRows.splice(index, 1); } } } else { expandedRowKeys.value = []; } }; // 主表合计方法 const summarizeMainTable = param => { return proxy.summarizeTable(param, ["contractAmount"]); }; // 子表合计方法 const summarizeProTable = param => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "ticketsNum", "ticketsAmount", "futureTickets", "futureTicketsAmount", ], { ticketsNum: { noDecimal: true }, // 不保留小数 futureTickets: { noDecimal: true }, // 不保留小数 } ); }; const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; const { entryDate, ...rest } = searchForm; purchaseListPage({ ...rest, ...page }) .then((res) => { tableLoading.value = false; // tableData.value = res.data.records; tableData.value = res.data.records.map(record => ({ ...record, isInvalid: record.isWhite === 1 })); // 初始化子数据数组 tableData.value.forEach((item) => { item.children = []; }); total.value = res.data.total; expandedRowKeys.value = []; }) .catch(() => { tableLoading.value = false; }); }; // 表格选择数据 const handleSelectionChange = (selection) => { selectedRows.value = selection; }; const productSelected = (selectedRows) => { productSelectedRows.value = selectedRows; }; const expandedRowKeys = ref([]); // 展开行 const expandChange = async (row, expandedRows) => { if (expandedRows.length > 0) { expandedRowKeys.value = []; try { const res = await productList({ salesLedgerId: row.id, type: 2 }); const index = tableData.value.findIndex((item) => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data || []; expandedRowKeys.value.push(row.id); } } catch (error) { console.error('加载产品列表失败:', error); proxy.$modal.msgError('加载产品列表失败'); // 展开失败时,移除展开状态 const index = expandedRows.findIndex(item => item.id === row.id); if (index > -1) { expandedRows.splice(index, 1); } } } else { expandedRowKeys.value = []; } }; // 主表合计方法 const summarizeMainTable = (param) => { return proxy.summarizeTable(param, ["contractAmount"]); }; // 子表合计方法 const summarizeProTable = (param) => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ]); }; // 打开弹框 const openForm = async (type, row) => { await getTemplateList() operationType.value = type; form.value = {}; productData.value = []; fileList.value = []; templateName.value = ''; filterInputValue.value = ''; isTemplateNameDuplicate.value = false; try { // 并行加载基础数据 const [userRes, salesRes, supplierRes] = await Promise.all([ userListNoPage(), getSalesNo(), getOptions() ]); userList.value = userRes.data || []; salesContractList.value = salesRes || []; // 供应商过滤出isWhite=0 的数据 supplierList.value = (supplierRes.data || []).filter((item) => item.isWhite === 0); // 设置默认值 form.value.recorderId = userStore.id; form.value.entryDate = getCurrentDate(); if (type === "add") { // 新增时生成采购合同号 try { const purchaseNoRes = await createPurchaseNo(); if (purchaseNoRes?.data) { form.value.purchaseContractNumber = purchaseNoRes.data; } } catch (error) { console.error('生成采购合同号失败:', error); proxy.$modal.msgWarning('生成采购合同号失败'); } } else if (type === "edit" && row?.id) { // 编辑时加载数据 currentId.value = row.id; try { const purchaseRes = await getPurchaseById({ id: row.id, type: 2 }); form.value = { ...purchaseRes }; productData.value = purchaseRes.productData || []; fileList.value = purchaseRes.salesLedgerFiles || []; } catch (error) { console.error('加载采购台账数据失败:', error); proxy.$modal.msgError('加载数据失败'); return; } } dialogFormVisible.value = true; } catch (error) { console.error('打开表单失败:', error); proxy.$modal.msgError('加载基础数据失败'); } }; // 上传前校检 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) { file.tempId = res.data.tempId; proxy.$modal.msgSuccess("上传成功"); } else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload.handleRemove(file); } } // 移除文件 async function handleRemove(file) { if (!file?.id) { return; } console.log("handleRemove", file.id); if (file.size > 1024 * 1024 * 10) { // 仅前端清理,不调用删除接口和提示 return; } if (operationType.value === "edit" && file.id) { }; // 打开弹框 const openForm = async (type, row) => { await getTemplateList(); operationType.value = type; form.value = {}; productData.value = []; fileList.value = []; templateName.value = ""; filterInputValue.value = ""; isTemplateNameDuplicate.value = false; try { await delLedgerFile([file.id]); proxy.$modal.msgSuccess("删除成功"); // 并行加载基础数据 const [userRes, salesRes, supplierRes] = await Promise.all([ userListNoPage(), getSalesNo(), getOptions(), ]); userList.value = userRes.data || []; salesContractList.value = salesRes || []; // 供应商过滤出isWhite=0 的数据 supplierList.value = (supplierRes.data || []).filter( item => item.isWhite === 0 ); // 设置默认值 form.value.recorderId = userStore.id; form.value.entryDate = getCurrentDate(); if (type === "add") { // 新增时生成采购合同号 try { const purchaseNoRes = await createPurchaseNo(); if (purchaseNoRes?.data) { form.value.purchaseContractNumber = purchaseNoRes.data; } } catch (error) { console.error("生成采购合同号失败:", error); proxy.$modal.msgWarning("生成采购合同号失败"); } } else if (type === "edit" && row?.id) { // 编辑时加载数据 currentId.value = row.id; try { const purchaseRes = await getPurchaseById({ id: row.id, type: 2 }); form.value = { ...purchaseRes }; productData.value = purchaseRes.productData || []; fileList.value = purchaseRes.salesLedgerFiles || []; } catch (error) { console.error("加载采购台账数据失败:", error); proxy.$modal.msgError("加载数据失败"); return; } } dialogFormVisible.value = true; } catch (error) { console.error('删除文件失败:', error); proxy.$modal.msgError("删除文件失败"); console.error("打开表单失败:", error); proxy.$modal.msgError("加载基础数据失败"); } }; // 上传前校检 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) { file.tempId = res.data.tempId; proxy.$modal.msgSuccess("上传成功"); } else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload.handleRemove(file); } } } // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate((valid) => { if (valid) { if (productData.value.length > 0) { form.value.productData = proxy.HaveJson(productData.value); } else { proxy.$modal.msgWarning("请添加产品信息"); return; } let tempFileIds = []; if (fileList.value.length > 0) { tempFileIds = fileList.value.map((item) => item.tempId); } form.value.tempFileIds = tempFileIds; form.value.type = 2; // 如果salesLedgerId为空,则不传递salesContractNo if (!form.value.salesLedgerId) { form.value.salesContractNo = '' } addOrEditPurchase(form.value).then((res) => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); }); // 移除文件 async function handleRemove(file) { if (!file?.id) { return; } }); }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; // 打开产品弹框 const openProductForm = (type, row, index) => { productOperationType.value = type; productOperationIndex.value = index; productForm.value = {}; proxy.resetForm("productFormRef"); if (type === "edit") { productForm.value = { ...row }; } productFormVisible.value = true; getProductOptions(); }; const getProductOptions = () => { productTreeList().then((res) => { productOptions.value = convertIdToValue(res); }); }; const getModels = (value) => { if (value) { productForm.value.productCategory = findNodeById(productOptions.value, value) || ""; modelList({ id: value }).then((res) => { modelOptions.value = res; }); } else { productForm.value.productCategory = ""; modelOptions.value = []; } }; const getProductModel = (value) => { const index = modelOptions.value.findIndex((item) => item.id === value); if (index !== -1) { productForm.value.specificationModel = modelOptions.value[index].model; productForm.value.unit = modelOptions.value[index].unit; } else { productForm.value.specificationModel = null; productForm.value.unit = null; } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].value === productId) { return nodes[i].label; // 找到节点,返回该节点的label } if (nodes[i].children && nodes[i].children.length > 0) { const foundNode = findNodeById(nodes[i].children, productId); if (foundNode) { return foundNode; // 在子节点中找到,直接返回(已经是label字符串) } } } return null; // 没有找到节点,返回null }; 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); console.log("handleRemove", file.id); if (file.size > 1024 * 1024 * 10) { // 仅前端清理,不调用删除接口和提示 return; } return newItem; }); } // 提交产品表单 const submitProduct = () => { proxy.$refs["productFormRef"].validate((valid) => { if (valid) { if (operationType.value === "edit") { submitProductEdit(); } else { if (productOperationType.value === "add") { productData.value.push({ ...productForm.value }); console.log("productData.value---", productData.value); } else { productData.value[productOperationIndex.value] = { ...productForm.value, }; } closeProductDia(); if (operationType.value === "edit" && file.id) { try { await delLedgerFile([file.id]); proxy.$modal.msgSuccess("删除成功"); } catch (error) { console.error("删除文件失败:", error); proxy.$modal.msgError("删除文件失败"); } } }); }; const submitProductEdit = () => { productForm.value.salesLedgerId = currentId.value; productForm.value.type = 2; addOrUpdateSalesLedgerProduct(productForm.value).then((res) => { proxy.$modal.msgSuccess("提交成功"); closeProductDia(); getPurchaseById({ id: currentId.value, type: 2 }).then((res) => { productData.value = res.productData; }); }); }; // 删除产品 const deleteProduct = () => { if (productSelectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择数据"); return; } if (operationType.value === "add") { productSelectedRows.value.forEach((selectedRow) => { const index = productData.value.findIndex( (product) => product.id === selectedRow.id ); if (index !== -1) { productData.value.splice(index, 1); // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate(valid => { if (valid) { if (productData.value.length > 0) { form.value.productData = proxy.HaveJson(productData.value); } else { proxy.$modal.msgWarning("请添加产品信息"); return; } let tempFileIds = []; if (fileList.value.length > 0) { tempFileIds = fileList.value.map(item => item.tempId); } form.value.tempFileIds = tempFileIds; form.value.type = 2; // 如果salesLedgerId为空,则不传递salesContractNo if (!form.value.salesLedgerId) { form.value.salesContractNo = ""; } addOrEditPurchase(form.value).then(res => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); }); } }); } else { }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; // 打开产品弹框 const openProductForm = (type, row, index) => { productOperationType.value = type; productOperationIndex.value = index; productForm.value = {}; proxy.resetForm("productFormRef"); if (type === "edit") { productForm.value = { ...row }; } productFormVisible.value = true; getProductOptions(); }; const getProductOptions = () => { productTreeList().then(res => { productOptions.value = convertIdToValue(res); }); }; const getModels = value => { if (value) { productForm.value.productCategory = findNodeById(productOptions.value, value) || ""; modelList({ id: value }).then(res => { modelOptions.value = res; }); } else { productForm.value.productCategory = ""; modelOptions.value = []; } }; const getProductModel = value => { const index = modelOptions.value.findIndex(item => item.id === value); if (index !== -1) { productForm.value.specificationModel = modelOptions.value[index].model; productForm.value.unit = modelOptions.value[index].unit; } else { productForm.value.specificationModel = null; productForm.value.unit = null; } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].value === productId) { return nodes[i].label; // 找到节点,返回该节点的label } if (nodes[i].children && nodes[i].children.length > 0) { const foundNode = findNodeById(nodes[i].children, productId); if (foundNode) { return foundNode; // 在子节点中找到,直接返回(已经是label字符串) } } } return null; // 没有找到节点,返回null }; 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 submitProduct = () => { proxy.$refs["productFormRef"].validate(valid => { if (valid) { if (operationType.value === "edit") { submitProductEdit(); } else { if (productOperationType.value === "add") { productData.value.push({ ...productForm.value }); console.log("productData.value---", productData.value); } else { productData.value[productOperationIndex.value] = { ...productForm.value, }; } closeProductDia(); } } }); }; const submitProductEdit = () => { productForm.value.salesLedgerId = currentId.value; productForm.value.type = 2; addOrUpdateSalesLedgerProduct(productForm.value).then(res => { proxy.$modal.msgSuccess("提交成功"); closeProductDia(); getPurchaseById({ id: currentId.value, type: 2 }).then(res => { productData.value = res.productData; }); }); }; // 删除产品 const deleteProduct = () => { if (productSelectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择数据"); return; } if (operationType.value === "add") { productSelectedRows.value.forEach(selectedRow => { const index = productData.value.findIndex( product => product.id === selectedRow.id ); if (index !== -1) { productData.value.splice(index, 1); } }); } else { let ids = []; if (productSelectedRows.value.length > 0) { ids = productSelectedRows.value.map(item => item.id); } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { delProduct(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 2 }).then( res => { productData.value = res.productData; } ); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); } }; // 关闭产品弹框 const closeProductDia = () => { proxy.resetForm("productFormRef"); productFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/purchase/ledger/export", {}, "采购台账.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 删除 const handleDelete = () => { let ids = []; if (productSelectedRows.value.length > 0) { ids = productSelectedRows.value.map((item) => item.id); if (selectedRows.value.length > 0) { // 检查是否有他人维护的数据 const unauthorizedData = selectedRows.value.filter( item => item.recorderName !== userStore.nickName ); if (unauthorizedData.length > 0) { proxy.$modal.msgWarning("不可删除他人维护的数据"); return; } ids = selectedRows.value.map(item => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", @@ -1567,388 +1585,347 @@ type: "warning", }) .then(() => { delProduct(ids).then((res) => { delPurchase(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 2 }).then( (res) => { productData.value = res.productData; } ); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 获取当前日期并格式化为 YYYY-MM-DD function getCurrentDate() { const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始 const day = String(today.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } }; // 关闭产品弹框 const closeProductDia = () => { proxy.resetForm("productFormRef"); productFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/purchase/ledger/export", {}, "采购台账.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 删除 const handleDelete = () => { let ids = []; if (selectedRows.value.length > 0) { // 检查是否有他人维护的数据 const unauthorizedData = selectedRows.value.filter(item => item.recorderName !== userStore.nickName); if (unauthorizedData.length > 0) { proxy.$modal.msgWarning("不可删除他人维护的数据"); return; } ids = selectedRows.value.map((item) => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { delPurchase(ids).then((res) => { proxy.$modal.msgSuccess("删除成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 获取当前日期并格式化为 YYYY-MM-DD function getCurrentDate() { const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始 const day = String(today.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } const mathNum = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (!productForm.value.taxInclusiveUnitPrice) { return; } if (!productForm.value.quantity) { return; } // 含税总价计算 productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice( productForm.value.taxInclusiveUnitPrice, productForm.value.quantity ); if (productForm.value.taxRate) { // 不含税总价计算 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } }; const reverseMathNum = (field) => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } const taxRate = Number(productForm.value.taxRate); if (!taxRate) return; if (field === 'taxInclusiveTotalPrice') { // 已知含税总价和数量,反算含税单价 if (productForm.value.quantity) { productForm.value.taxInclusiveUnitPrice = (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2); } // 已知含税总价和含税单价,反算数量 else if (productForm.value.taxInclusiveUnitPrice) { productForm.value.quantity = (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2); } // 反算不含税总价 productForm.value.taxExclusiveTotalPrice = (Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100)).toFixed(2); } else if (field === 'taxExclusiveTotalPrice') { // 反算含税总价 productForm.value.taxInclusiveTotalPrice = (Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100)).toFixed(2); // 已知数量,反算含税单价 if (productForm.value.quantity) { productForm.value.taxInclusiveUnitPrice = (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity)).toFixed(2); } // 已知含税单价,反算数量 else if (productForm.value.taxInclusiveUnitPrice) { productForm.value.quantity = (Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice)).toFixed(2); } } }; // 销售合同选择改变方法 const salesLedgerChange = async (row) => { console.log("row", row); var index = salesContractList.value.findIndex((item) => item.id == row); console.log("index", index); if (index > -1) { await querygProductInfoByContractNo(); } }; const querygProductInfoByContractNo = async () => { const { code, data } = await getProductInfoByContractNo({ contractNo: form.value.salesLedgerId, }); if (code == 200) { productData.value = data; } }; const fileListRef = ref(null) const downLoadFile = (row) => { fileListRef.value.open(row.salesLedgerFiles) } // 显示二维码 const showQRCode = async (row) => { try { // 构建二维码内容,只包含采购合同号(纯文本) const qrContent = row.purchaseContractNumber || ''; // 检查内容是否为空 if (!qrContent || qrContent.trim() === '') { proxy.$modal.msgWarning("该行没有采购合同号,无法生成二维码"); const mathNum = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } qrCodeUrl.value = await QRCode.toDataURL(qrContent, { width: 200, margin: 2, color: { dark: '#000000', light: '#FFFFFF' if (!productForm.value.taxInclusiveUnitPrice) { return; } if (!productForm.value.quantity) { return; } // 含税总价计算 productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice( productForm.value.taxInclusiveUnitPrice, productForm.value.quantity ); if (productForm.value.taxRate) { // 不含税总价计算 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } }; const reverseMathNum = field => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } const taxRate = Number(productForm.value.taxRate); if (!taxRate) return; if (field === "taxInclusiveTotalPrice") { // 已知含税总价和数量,反算含税单价 if (productForm.value.quantity) { productForm.value.taxInclusiveUnitPrice = ( Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity) ).toFixed(2); } // 已知含税总价和含税单价,反算数量 else if (productForm.value.taxInclusiveUnitPrice) { productForm.value.quantity = ( Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice) ).toFixed(2); } // 反算不含税总价 productForm.value.taxExclusiveTotalPrice = ( Number(productForm.value.taxInclusiveTotalPrice) / (1 + taxRate / 100) ).toFixed(2); } else if (field === "taxExclusiveTotalPrice") { // 反算含税总价 productForm.value.taxInclusiveTotalPrice = ( Number(productForm.value.taxExclusiveTotalPrice) * (1 + taxRate / 100) ).toFixed(2); // 已知数量,反算含税单价 if (productForm.value.quantity) { productForm.value.taxInclusiveUnitPrice = ( Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.quantity) ).toFixed(2); } // 已知含税单价,反算数量 else if (productForm.value.taxInclusiveUnitPrice) { productForm.value.quantity = ( Number(productForm.value.taxInclusiveTotalPrice) / Number(productForm.value.taxInclusiveUnitPrice) ).toFixed(2); } } }; // 销售合同选择改变方法 const salesLedgerChange = async row => { console.log("row", row); var index = salesContractList.value.findIndex(item => item.id == row); console.log("index", index); if (index > -1) { await querygProductInfoByContractNo(); } }; const querygProductInfoByContractNo = async () => { const { code, data } = await getProductInfoByContractNo({ contractNo: form.value.salesLedgerId, }); if (code == 200) { productData.value = data; } }; const fileListRef = ref(null); const downLoadFile = row => { fileListRef.value.open(row.salesLedgerFiles); }; // 显示二维码 const showQRCode = async row => { try { // 构建二维码内容,只包含采购合同号(纯文本) const qrContent = row.purchaseContractNumber || ""; // 检查内容是否为空 if (!qrContent || qrContent.trim() === "") { proxy.$modal.msgWarning("该行没有采购合同号,无法生成二维码"); return; } qrCodeUrl.value = await QRCode.toDataURL(qrContent, { width: 200, margin: 2, color: { dark: "#000000", light: "#FFFFFF", }, }); qrCodeDialogVisible.value = true; } catch (error) { console.error("生成二维码失败:", error); proxy.$modal.msgError("生成二维码失败:" + error.message); } }; // 下载二维码 const downloadQRCode = () => { if (!qrCodeUrl.value) { proxy.$modal.msgWarning("二维码未生成"); return; } const a = document.createElement("a"); a.href = qrCodeUrl.value; a.download = `采购合同号二维码_${new Date().getTime()}.png`; document.body.appendChild(a); a.click(); document.body.removeChild(a); proxy.$modal.msgSuccess("下载成功"); }; // 扫码新增对话框相关变量 const scanAddDialogVisible = ref(false); const scanAddForm = reactive({ scanContent: "", purchaseContractNumber: "", supplierName: "", projectName: "", contractAmount: "", paymentMethod: "", recorderName: "", scanRemark: "", }); const scanAddRules = { purchaseContractNumber: [ { required: true, message: "请输入采购合同号", trigger: "blur" }, ], supplierName: [ { required: true, message: "请输入供应商名称", trigger: "blur" }, ], projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }], }; // 扫码登记对话框相关变量 const scanDialogVisible = ref(false); const scanForm = reactive({ purchaseContractNumber: "", supplierName: "", projectName: "", scanTime: "", scannerName: "", scanStatus: "未扫码", scanRemark: "", }); const scanRules = { scanRemark: [{ required: true, message: "请输入扫码备注", trigger: "blur" }], }; const scanRecords = ref([]); // 打开扫码新增对话框 const openScanAddDialog = () => { scanAddForm.scanContent = ""; scanAddForm.purchaseContractNumber = ""; scanAddForm.supplierName = ""; scanAddForm.projectName = ""; scanAddForm.contractAmount = ""; scanAddForm.paymentMethod = ""; scanAddForm.recorderName = userStore.nickName; scanAddForm.scanRemark = ""; scanAddDialogVisible.value = true; }; // 解析扫码内容(模拟解析二维码数据) const parseScanContent = content => { if (!content) return; // 模拟解析二维码内容,这里可以根据实际需求调整解析逻辑 // 假设扫码内容格式为:合同号|供应商|金额|付款方式 const parts = content.split("|"); if (parts.length >= 2) { scanAddForm.purchaseContractNumber = parts[0] || ""; scanAddForm.supplierName = parts[1] || ""; scanAddForm.contractAmount = parts[2] || ""; scanAddForm.paymentMethod = parts[3] || ""; scanAddForm.projectName = parts[4] || ""; // scanAddForm.contractAmount = parts[3] || ""; // scanAddForm.paymentMethod = parts[4] || ""; } }; // 关闭扫码新增对话框 const closeScanAddDialog = () => { scanAddDialogVisible.value = false; proxy.resetForm("scanAddFormRef"); }; // 提交扫码新增 const submitScanAdd = () => { proxy.$refs["scanAddFormRef"].validate(valid => { if (valid) { // 构建新增数据 const newData = { purchaseContractNumber: scanAddForm.purchaseContractNumber, supplierName: scanAddForm.supplierName, projectName: scanAddForm.projectName, contractAmount: scanAddForm.contractAmount, paymentMethod: scanAddForm.paymentMethod, recorderName: scanAddForm.recorderName, entryDate: getCurrentDate(), remark: scanAddForm.scanRemark, type: 2, }; // 模拟新增成功 proxy.$modal.msgSuccess("扫码新增成功!"); closeScanAddDialog(); // 可以选择是否刷新列表 // getList(); } }); qrCodeDialogVisible.value = true; } catch (error) { console.error('生成二维码失败:', error); proxy.$modal.msgError("生成二维码失败:" + error.message); }; // 打开扫码登记对话框 const openScanDialog = row => { scanForm.purchaseContractNumber = row.purchaseContractNumber; scanForm.supplierName = row.supplierName; scanForm.projectName = row.projectName; scanForm.scanTime = getCurrentDateTime(); scanForm.scannerName = userStore.nickName; scanForm.scanStatus = "未扫码"; scanForm.scanRemark = ""; scanRecords.value = []; scanDialogVisible.value = true; }; // 关闭扫码登记对话框 const closeScanDialog = () => { scanDialogVisible.value = false; proxy.resetForm("scanFormRef"); }; // 提交扫码登记 const submitScan = () => { proxy.$refs["scanFormRef"].validate(valid => { if (valid) { // 添加扫码记录 scanRecords.value.push({ ...scanForm, id: Date.now(), // 模拟ID scanTime: getCurrentDateTime(), }); scanForm.scanStatus = "已扫码"; scanForm.scanRemark = scanForm.scanRemark || "无"; proxy.$modal.msgSuccess("扫码登记成功!"); closeScanDialog(); } }); }; // 获取当前日期时间 function getCurrentDateTime() { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, "0"); const day = String(now.getDate()).padStart(2, "0"); const hours = String(now.getHours()).padStart(2, "0"); const minutes = String(now.getMinutes()).padStart(2, "0"); const seconds = String(now.getSeconds()).padStart(2, "0"); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } }; // 下载二维码 const downloadQRCode = () => { if (!qrCodeUrl.value) { proxy.$modal.msgWarning("二维码未生成"); return; } const a = document.createElement('a'); a.href = qrCodeUrl.value; a.download = `采购合同号二维码_${new Date().getTime()}.png`; document.body.appendChild(a); a.click(); document.body.removeChild(a); proxy.$modal.msgSuccess("下载成功"); }; // 添加行类名方法 const tableRowClassName = ({ row }) => { return row.isInvalid ? "invalid-row" : ""; }; // 扫码新增对话框相关变量 const scanAddDialogVisible = ref(false); const scanAddForm = reactive({ scanContent: "", purchaseContractNumber: "", supplierName: "", projectName: "", contractAmount: "", paymentMethod: "", recorderName: "", scanRemark: "", }); const scanAddRules = { purchaseContractNumber: [{ required: true, message: "请输入采购合同号", trigger: "blur" }], supplierName: [{ required: true, message: "请输入供应商名称", trigger: "blur" }], projectName: [{ required: true, message: "请输入项目名称", trigger: "blur" }], }; // 扫码登记对话框相关变量 const scanDialogVisible = ref(false); const scanForm = reactive({ purchaseContractNumber: "", supplierName: "", projectName: "", scanTime: "", scannerName: "", scanStatus: "未扫码", scanRemark: "", }); const scanRules = { scanRemark: [{ required: true, message: "请输入扫码备注", trigger: "blur" }], }; const scanRecords = ref([]); // 打开扫码新增对话框 const openScanAddDialog = () => { scanAddForm.scanContent = ""; scanAddForm.purchaseContractNumber = ""; scanAddForm.supplierName = ""; scanAddForm.projectName = ""; scanAddForm.contractAmount = ""; scanAddForm.paymentMethod = ""; scanAddForm.recorderName = userStore.nickName; scanAddForm.scanRemark = ""; scanAddDialogVisible.value = true; }; // 解析扫码内容(模拟解析二维码数据) const parseScanContent = (content) => { if (!content) return; // 模拟解析二维码内容,这里可以根据实际需求调整解析逻辑 // 假设扫码内容格式为:合同号|供应商|金额|付款方式 const parts = content.split('|'); if (parts.length >= 2) { scanAddForm.purchaseContractNumber = parts[0] || ""; scanAddForm.supplierName = parts[1] || ""; scanAddForm.contractAmount = parts[2] || ""; scanAddForm.paymentMethod = parts[3] || ""; scanAddForm.projectName = parts[4] || ""; // scanAddForm.contractAmount = parts[3] || ""; // scanAddForm.paymentMethod = parts[4] || ""; } }; // 关闭扫码新增对话框 const closeScanAddDialog = () => { scanAddDialogVisible.value = false; proxy.resetForm("scanAddFormRef"); }; // 提交扫码新增 const submitScanAdd = () => { proxy.$refs["scanAddFormRef"].validate((valid) => { if (valid) { // 构建新增数据 const newData = { purchaseContractNumber: scanAddForm.purchaseContractNumber, supplierName: scanAddForm.supplierName, projectName: scanAddForm.projectName, contractAmount: scanAddForm.contractAmount, paymentMethod: scanAddForm.paymentMethod, recorderName: scanAddForm.recorderName, entryDate: getCurrentDate(), remark: scanAddForm.scanRemark, type: 2 }; // 模拟新增成功 proxy.$modal.msgSuccess("扫码新增成功!"); closeScanAddDialog(); // 可以选择是否刷新列表 // getList(); // 获取模板信息 const getTemplateList = async () => { let res = await getPurchaseTemplateList(); if (res && res.code === 200 && Array.isArray(res.data)) { templateList.value = res.data; } }; onMounted(() => { getList(); getTemplateList(); }); }; // 打开扫码登记对话框 const openScanDialog = (row) => { scanForm.purchaseContractNumber = row.purchaseContractNumber; scanForm.supplierName = row.supplierName; scanForm.projectName = row.projectName; scanForm.scanTime = getCurrentDateTime(); scanForm.scannerName = userStore.nickName; scanForm.scanStatus = "未扫码"; scanForm.scanRemark = ""; scanRecords.value = []; scanDialogVisible.value = true; }; // 关闭扫码登记对话框 const closeScanDialog = () => { scanDialogVisible.value = false; proxy.resetForm("scanFormRef"); }; // 提交扫码登记 const submitScan = () => { proxy.$refs["scanFormRef"].validate((valid) => { if (valid) { // 添加扫码记录 scanRecords.value.push({ ...scanForm, id: Date.now(), // 模拟ID scanTime: getCurrentDateTime(), }); scanForm.scanStatus = "已扫码"; scanForm.scanRemark = scanForm.scanRemark || "无"; proxy.$modal.msgSuccess("扫码登记成功!"); closeScanDialog(); } }); }; // 获取当前日期时间 function getCurrentDateTime() { const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, "0"); const day = String(now.getDate()).padStart(2, "0"); const hours = String(now.getHours()).padStart(2, "0"); const minutes = String(now.getMinutes()).padStart(2, "0"); const seconds = String(now.getSeconds()).padStart(2, "0"); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } // 添加行类名方法 const tableRowClassName = ({ row }) => { return row.isInvalid ? 'invalid-row' : ''; }; // 获取模板信息 const getTemplateList =async ()=>{ let res = await getPurchaseTemplateList() if(res && res.code===200 && Array.isArray(res.data)){ templateList.value = res.data } } onMounted(() => { getList(); getTemplateList(); }); </script> <style scoped lang="scss"> .invalid-row { opacity: 0.6; background-color: #f5f7fa; } .el-row{ justify-content: space-between; align-items: center } .no-arrow-select { --el-select-suffix-icon-color: transparent; /* 隐藏默认下拉箭头 */ } .select-button-group { display: flex; align-items: center; } .invalid-row { opacity: 0.6; background-color: #f5f7fa; } .el-row { justify-content: space-between; align-items: center; } .no-arrow-select { --el-select-suffix-icon-color: transparent; /* 隐藏默认下拉箭头 */ } .select-button-group { display: flex; align-items: center; } </style> src/views/productionManagement/processRoute/index.vue
@@ -66,6 +66,10 @@ const { searchForm } = toRefs(data); const tableColumn = ref([ { label: "工艺路线编号", prop: "processRouteCode", }, { label: "产品名称", prop: "productName", }, src/views/productionManagement/productStructure/StructureEdit.vue
@@ -19,130 +19,147 @@ @click="cancelEdit" style="margin-bottom: 10px">取消 </el-button> <el-form ref="form" :model="dataValue"> <el-table :data="dataValue.dataList" style="width: 100%"> <el-table-column prop="productName" label="产品" width="150" /> <el-table-column prop="model" label="规格" width="150"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :prop="`dataList.${$index}.model`" :rules="[{ required: true, message: '请选择规格', trigger: ['blur','change'] }]" style="margin: 0"> <el-select v-model="row.model" placeholder="请选择产品" clearable :disabled="!dataValue.isEdit" style="width: 100%" @visible-change="(v) => { if (v) openDialog($index) }"> <el-option v-if="row.model" :label="row.model" :value="row.model" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="processId" label="消耗工序" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.processId`" :rules="[{ required: true, message: '请选择消耗工序', trigger: 'change' }]" style="margin: 0"> <el-select v-model="row.processId" placeholder="请选择" filterable clearable style="width: 100%" :disabled="!dataValue.isEdit"> <el-option v-for="item in dataValue.processOptions" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="unitQuantity" label="单位产出所需数量" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.unitQuantity`" :rules="[{ required: true, message: '请输入单位产出所需数量', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.unitQuantity" :min="0" :precision="2" :step="1" controls-position="right" <el-table :data="tableData" border :preserve-expanded-content="false" style="width: 100%" > <el-table-column type="expand"> <template #default="props"> <el-form ref="form" :model="dataValue"> <el-table :data="dataValue.dataList" style="width: 100%"> <el-table-column prop="productName" label="产品" width="150" /> <el-table-column prop="model" label="规格" width="150"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :prop="`dataList.${$index}.model`" :rules="[{ required: true, message: '请选择规格', trigger: ['blur','change'] }]" style="margin: 0"> <el-select v-model="row.model" placeholder="请选择产品" clearable :disabled="!dataValue.isEdit" style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="demandedQuantity" label="需求总量" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.demandedQuantity`" :rules="[{ required: true, message: '请输入需求总量', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.demandedQuantity" :min="0" :precision="2" :step="1" controls-position="right" @visible-change="(v) => { if (v) openDialog($index) }"> <el-option v-if="row.model" :label="row.model" :value="row.model" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="processId" label="消耗工序" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.processId`" :rules="[{ required: true, message: '请选择消耗工序', trigger: 'change' }]" style="margin: 0"> <el-select v-model="row.processId" placeholder="请选择" filterable clearable style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="unit" label="单位" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.unit`" :rules="[{ required: true, message: '请输入单位', trigger: ['blur','change'] }]" style="margin: 0"> <el-input v-model="row.unit" placeholder="请输入单位" clearable :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="diskQuantity" label="盘数(盘)" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.diskQuantity`" :rules="[{ required: true, message: '请输入盘数', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.diskQuantity" :min="0" :precision="0" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column label="操作"> <template #default="{ row, $index }"> <el-button type="danger" text @click="dataValue.dataList.splice($index, 1)">删除 </el-button> </template> </el-table-column> </el-table> </el-form> :disabled="!dataValue.isEdit"> <el-option v-for="item in dataValue.processOptions" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="unitQuantity" label="单位产出所需数量" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.unitQuantity`" :rules="[{ required: true, message: '请输入单位产出所需数量', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.unitQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="demandedQuantity" label="需求总量" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.demandedQuantity`" :rules="[{ required: true, message: '请输入需求总量', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.demandedQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="unit" label="单位" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.unit`" :rules="[{ required: true, message: '请输入单位', trigger: ['blur','change'] }]" style="margin: 0"> <el-input v-model="row.unit" placeholder="请输入单位" clearable :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column prop="diskQuantity" label="盘数(盘)" width="150"> <template #default="{ row, $index }"> <el-form-item :prop="`dataList.${$index}.diskQuantity`" :rules="[{ required: true, message: '请输入盘数', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.diskQuantity" :min="0" :precision="0" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit" /> </el-form-item> </template> </el-table-column> <el-table-column label="操作"> <template #default="{ row, $index }"> <el-button type="danger" text @click="dataValue.dataList.splice($index, 1)">删除 </el-button> </template> </el-table-column> </el-table> </el-form> </template> </el-table-column> <el-table-column label="产品编码" prop="productCode" /> <el-table-column label="产品名称" prop="productName" /> <el-table-column label="规格型号" prop="model" /> <el-table-column label="单位" prop="unit" /> </el-table> <product-select-dialog v-if="dataValue.showProductDialog" v-model:model-value="dataValue.showProductDialog" @confirm="handleProduct" /> @@ -187,8 +204,8 @@ type: Boolean, default: false, }, productModelId: { type: Number, record: { type: Object, required: true, }, }); @@ -213,18 +230,27 @@ isEdit: false, }); const tableData = [ { productName: props.record.productName, model: props.record.model, unit: props.record.unit, productCode: props.record.productCode, } ] const openDialog = index => { dataValue.currentRowIndex = index; dataValue.showProductDialog = true; }; const fetchData = async () => { const { data } = await queryList(props.productModelId); const { data } = await queryList(props.record.id); dataValue.dataList = data; }; const fetchProcessOptions = async () => { const { data } = await list(props.productModelId); const { data } = await list(props.record.id); dataValue.processOptions = data; }; @@ -245,7 +271,7 @@ dataValue.loading = true; if (valid) { add({ parentId: props.productModelId, parentId: props.record.id, productStructureList: dataValue.dataList || [], }).then(res => { ElMessage.success("保存成功"); src/views/productionManagement/productStructure/index.vue
@@ -15,14 +15,14 @@ type="primary" text @click="() =>{ currentRowId = row.id; currentRow = row; showEdit = true; }" >{{ row.productName }} </el-button> </template> </PIMTable> <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :product-model-id="currentRowId"/> <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow"/> </div> </template> @@ -33,6 +33,11 @@ const StructureEdit = defineAsyncComponent(() => import('@/views/productionManagement/productStructure/StructureEdit.vue')) const tableColumn = ref([ { label: "产品编码", prop: "productCode", slot: "detail" }, { label: "产品名称", prop: "productName", @@ -52,7 +57,7 @@ const tableLoading = ref(false); const showEdit = ref(false); const selectedRows = ref([]); const currentRowId = ref(0); const currentRow = ref({}); const page = reactive({ current: 1, size: 10, src/views/salesManagement/invoiceRegistration/index.vue
@@ -1,356 +1,331 @@ <template> <div class="app-container"> <div class="search_form"> <el-form :inline="true" :model="searchForm"> <el-form-item label="客户名称"> <el-input v-model="searchForm.customerName" style="width: 240px" placeholder="请输入名称搜索" clearable :prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item> <el-checkbox v-model="searchForm.status" label="不显示未开票金额为0" @change="handleQuery" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> <el-button @click="resetForm"> 重置 </el-button> <el-button @click="handleExport" style="margin-right: 10px">导出</el-button> </el-form-item> </el-form> </div> <div class="table_list"> <div class="flex justify-between"> <div></div> <div> <el-button type="primary" @click="openForm" style="margin-bottom: 8px"> 新增登记 </el-button> </div> </div> <el-table :data="tableData" :border="true" height="calc(100vh - 21em)" v-loading="tableLoading" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" @expand-change="expandChange" @selection-change="handleSelectionChange" > <el-table-column align="center" type="selection" width="55" /> <el-table-column type="expand"> <template #default="props"> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable" > <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="开票数" prop="invoiceNum" :formatter="formattedNumber" /> <el-table-column label="开票金额(元)" prop="invoiceAmount" :formatter="formattedNumber" /> <el-table-column label="未开票数" prop="noInvoiceNum" :formatter="formattedNumber" /> <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" :formatter="formattedNumber" /> </el-table> </template> </el-table-column> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> <!-- <el-table-column--> <!-- label="客户合同号"--> <!-- prop="customerContractNo"--> <!-- width="200"--> <!-- show-overflow-tooltip--> <!-- />--> <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip /> <el-table-column label="业务员" prop="salesman" show-overflow-tooltip/> <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="已开票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="未开票金额(元)" prop="noInvoiceAmountTotal" show-overflow-tooltip width="120" > <template #default="{ row, column }"> <el-text type="danger"> {{ formattedNumber(row, column, row.noInvoiceAmountTotal) }} </el-text> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <el-dialog v-model="dialogFormVisible" title="新增开票登记页面" width="85%" @close="closeDia" > <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef" > <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="客户名称:" prop="customerName"> <el-input v-model="form.customerName" placeholder="自动填充" disabled ></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="业务员:" prop="salesman"> <el-input v-model="form.salesman" placeholder="自动填充" disabled /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="录入人" prop="createUer"> <el-input v-model="form.createUer" placeholder="请输入录入人" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="开票日期" prop="issueDate"> <el-date-picker style="width: 100%" v-model="form.issueDate" type="date" placeholder="请选择" clearable format="YYYY-MM-DD" value-format="YYYY-MM-DD" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="录入日期:" prop="createTime"> <el-date-picker style="width: 100%" v-model="form.createTime" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发票号码:" prop="invoiceNo"> <el-input v-model="form.invoiceNo" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> <el-row> <el-form-item label="产品信息:" prop="entryDate"> </el-form-item> </el-row> <el-table :data="productData" border show-summary :summary-method="summarizeChildrenTable" > <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="所属合同" prop="salesContractNo" width="200"> <template #default="{ row }"> <el-tag type="primary">{{ row.salesContractNo }}</el-tag> </template> </el-table-column> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="200" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="200" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="本次开票数" prop="currentInvoiceNum" width="180"> <template #default="scope"> <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceNum" @change="invoiceNumBlur(scope.row)" ></el-input-number> </template> </el-table-column> <el-table-column label="本次开票金额(元)" prop="currentInvoiceAmount" width="180" > <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceAmount" @change="invoiceAmountBlur(scope.row)" ></el-input-number> </template> </el-table-column> <el-table-column label="未开票数" prop="noInvoiceNum" width="120"> <template #default="scope"> <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceNum" ></el-input> </template> </el-table-column> <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" width="200" > <template #default="scope"> <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceAmount" :formatter="formattedInputNumber" :precision="2" :step="0.01" ></el-input> </template> </el-table-column> <el-table-column label="登记人" prop="register" width="100"> <!-- <template #default="{ row }"> <div class="app-container"> <div class="search_form"> <el-form :inline="true" :model="searchForm"> <el-form-item label="客户名称"> <el-input v-model="searchForm.customerName" style="width: 240px" placeholder="请输入名称搜索" clearable :prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item> <el-checkbox v-model="searchForm.status" label="不显示未开票金额为0" @change="handleQuery" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> <el-button @click="resetForm"> 重置 </el-button> <el-button @click="handleExport" style="margin-right: 10px">导出</el-button> </el-form-item> </el-form> </div> <div class="table_list"> <div class="flex justify-between"> <div></div> <div> <el-button type="primary" @click="openForm" style="margin-bottom: 8px"> 新增登记 </el-button> </div> </div> <el-table :data="tableData" :border="true" height="calc(100vh - 21em)" v-loading="tableLoading" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" @expand-change="expandChange" @selection-change="handleSelectionChange"> <el-table-column align="center" type="selection" width="55" /> <el-table-column type="expand"> <template #default="props"> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" width="70" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="开票数" prop="invoiceNum" :formatter="formattedNumber" /> <el-table-column label="开票金额(元)" prop="invoiceAmount" :formatter="formattedNumber" /> <el-table-column label="未开票数" prop="noInvoiceNum" :formatter="formattedNumber" /> <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" :formatter="formattedNumber" /> </el-table> </template> </el-table-column> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip /> <!-- <el-table-column--> <!-- label="客户合同号"--> <!-- prop="customerContractNo"--> <!-- width="200"--> <!-- show-overflow-tooltip--> <!-- />--> <el-table-column label="客户名称" prop="customerName" show-overflow-tooltip /> <el-table-column label="业务员" prop="salesman" show-overflow-tooltip /> <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="已开票金额(元)" prop="invoiceTotal" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="未开票金额(元)" prop="noInvoiceAmountTotal" show-overflow-tooltip width="120"> <template #default="{ row, column }"> <el-text type="danger"> {{ formattedNumber(row, column, row.noInvoiceAmountTotal) }} </el-text> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <el-dialog v-model="dialogFormVisible" title="新增开票登记页面" width="85%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" disabled placeholder="多合同批量处理(具体合同号见产品列表)"></el-input> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="客户名称:" prop="customerName"> <el-input v-model="form.customerName" placeholder="自动填充" disabled></el-input> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="业务员:" prop="salesman"> <el-input v-model="form.salesman" placeholder="自动填充" disabled /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="录入人" prop="createUer"> <el-input v-model="form.createUer" placeholder="请输入录入人" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="开票日期" prop="issueDate"> <el-date-picker style="width: 100%" v-model="form.issueDate" type="date" placeholder="请选择" clearable format="YYYY-MM-DD" value-format="YYYY-MM-DD" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="录入日期:" prop="createTime"> <el-date-picker style="width: 100%" v-model="form.createTime" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="发票号码:" prop="invoiceNo"> <el-input v-model="form.invoiceNo" placeholder="请输入" clearable /> </el-form-item> </el-col> </el-row> <el-row> <el-form-item label="产品信息:" prop="entryDate"> </el-form-item> </el-row> <el-table :data="productData" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="所属合同" prop="salesContractNo" width="200"> <template #default="{ row }"> <el-tag type="primary">{{ row.salesContractNo }}</el-tag> </template> </el-table-column> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" width="150" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" width="70" /> <el-table-column label="税率(%)" prop="taxRate" width="80" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" width="200" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="200" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> <el-table-column label="本次开票数" prop="currentInvoiceNum" width="180"> <template #default="scope"> <el-input-number :step="0.1" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceNum" @change="invoiceNumBlur(scope.row)"></el-input-number> </template> </el-table-column> <el-table-column label="本次开票金额(元)" prop="currentInvoiceAmount" width="180"> <template #default="scope"> <el-input-number :step="0.01" :min="0" style="width: 100%" :precision="2" v-model="scope.row.currentInvoiceAmount" @change="invoiceAmountBlur(scope.row)"></el-input-number> </template> </el-table-column> <el-table-column label="未开票数" prop="noInvoiceNum" width="120"> <template #default="scope"> <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceNum"></el-input> </template> </el-table-column> <el-table-column label="未开票金额(元)" prop="noInvoiceAmount" width="200"> <template #default="scope"> <el-input type="number" min="0" disabled v-model="scope.row.noInvoiceAmount" :formatter="formattedInputNumber" :precision="2" :step="0.01"></el-input> </template> </el-table-column> <el-table-column label="登记人" prop="register" width="100"> <!-- <template #default="{ row }"> <el-input v-model="row.register" placeholder="请输入登记人" disabled /> </template> --> </el-table-column> <el-table-column label="登记日期" prop="registerDate" width="150"> <!-- <template #default="{ row }"> </el-table-column> <el-table-column label="登记日期" prop="registerDate" width="150"> <!-- <template #default="{ row }"> <el-date-picker style="width: 100%" v-model="row.registerDate" @@ -362,410 +337,446 @@ disabled /> </template> --> </el-table-column> </el-table> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">取消</el-button> </div> </template> </el-dialog> </div> </el-table-column> </el-table> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">取消</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import pagination from "@/components/PIMTable/Pagination.vue"; import { onMounted, ref } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessageBox } from "element-plus"; // import {userListNoPage} from "@/api/system/user.js"; import { getSalesLedgerWithProducts, ledgerListPage, productList, } from "@/api/salesManagement/salesLedger.js"; import { invoiceRegistrationSave } from "@/api/salesManagement/invoiceRegistration.js"; import useFormData from "@/hooks/useFormData"; import useUserStore from "@/store/modules/user"; import dayjs from "dayjs"; import pagination from "@/components/PIMTable/Pagination.vue"; import { onMounted, ref } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessageBox } from "element-plus"; // import {userListNoPage} from "@/api/system/user.js"; import { getSalesLedgerWithProducts, ledgerListPage, productList, } from "@/api/salesManagement/salesLedger.js"; import { invoiceRegistrationSave } from "@/api/salesManagement/invoiceRegistration.js"; import useFormData from "@/hooks/useFormData"; import useUserStore from "@/store/modules/user"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance(); const userStore = useUserStore(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); const total = ref(0); // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { customerName: "", status: false, customerContractNo: undefined, // 客户合同号 projectName: undefined, // 项目名称 createUer: undefined, // 登记人 issueDate: undefined, // 开票日期 createTime: undefined, // 录入日期: productCategory: "", isInvoice: 1 }, form: { salesLedgerId: "", customerName: "", salesman: "", projectName: "", productData: [], invoiceNo: "", createUer: userStore.nickName, issueDate: dayjs().format("YYYY-MM-DD"), selectedContractIds: [], // 新增:存储所有选中的合同ID isBatch: false // 新增:标识是否为批量操作 }, rules: { createUer: [{ required: true, message: "请选择", trigger: "blur" }], issueDate: [{ required: true, message: "请选择", trigger: "change" }], invoiceNo: [{ required: true, message: "请输入", trigger: "change" }], createTime: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { form, rules } = toRefs(data); const { form: searchForm, resetForm } = useFormData(data.searchForm); const { proxy } = getCurrentInstance(); const userStore = useUserStore(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); const total = ref(0); // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { customerName: "", status: false, customerContractNo: undefined, // 客户合同号 projectName: undefined, // 项目名称 createUer: undefined, // 登记人 issueDate: undefined, // 开票日期 createTime: undefined, // 录入日期: productCategory: "", isInvoice: 1, }, form: { salesLedgerId: "", customerName: "", salesman: "", projectName: "", productData: [], invoiceNo: "", createUer: userStore.nickName, issueDate: dayjs().format("YYYY-MM-DD"), selectedContractIds: [], // 新增:存储所有选中的合同ID isBatch: false, // 新增:标识是否为批量操作 }, rules: { createUer: [{ required: true, message: "请选择", trigger: "blur" }], issueDate: [{ required: true, message: "请选择", trigger: "change" }], invoiceNo: [{ required: true, message: "请输入", trigger: "change" }], createTime: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { form, rules } = toRefs(data); const { form: searchForm, resetForm } = useFormData(data.searchForm); const formattedNumber = (row, column, cellValue) => { if (cellValue == 0) { return parseFloat(cellValue).toFixed(2); } if (cellValue) { return parseFloat(cellValue).toFixed(2); } else { return cellValue; } }; const formattedNumber = (row, column, cellValue) => { if (cellValue == 0) { return parseFloat(cellValue).toFixed(2); } if (cellValue) { return parseFloat(cellValue).toFixed(2); } else { return cellValue; } }; const formattedInputNumber = (value) => { return value ? parseFloat(value).toFixed(2) : 0; }; const formattedInputNumber = value => { return value ? parseFloat(value).toFixed(2) : 0; }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { page.current = 1; getList(); }; const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; ledgerListPage({ ...searchForm, ...page }).then((res) => { tableLoading.value = false; tableData.value = res.records; total.value = res.total; expandedRowKeys.value = []; }); }; // 表格选择数据 const handleSelectionChange = (selection) => { console.log("selection", selection); selectedRows.value = selection.filter( (item) => item.salesContractNo !== undefined ); }; const expandedRowKeys = ref([]); // 展开行 const expandChange = (row, expandedRows) => { if (expandedRows.length > 0) { expandedRowKeys.value = []; try { productList({ salesLedgerId: row.id, type: 1 }).then((res) => { const index = tableData.value.findIndex((item) => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data; } expandedRowKeys.value.push(row.id); }); } catch (error) { console.log(error); } } else { expandedRowKeys.value = []; } }; // 主表合计方法 const summarizeMainTable = (param) => { return proxy.summarizeTable(param, [ "contractAmount", "invoiceTotal", "noInvoiceAmountTotal", ]); }; // 子表合计方法 const summarizeChildrenTable = (param) => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "invoiceNum", "invoiceAmount", "currentInvoiceAmount", "noInvoiceNum", "noInvoiceAmount", "currentInvoiceNum", ]); }; // 打开弹框 const openForm = () => { // 判断是否选择了合同 if (selectedRows.value.length === 0) { proxy.$modal.msgError("请至少选择一条合同"); return; } // 检查所有选择的合同是否具有相同的客户名称 const firstRow = selectedRows.value[0]; const isSameCustomer = selectedRows.value.every(row => row.customerName === firstRow.customerName ); if (!isSameCustomer) { proxy.$modal.msgError("请选择相同客户名称的合同"); return; } // 允许不同的销售合同号批量处理,无需检查重复 form.value = {}; productData.value = []; // 加载所有选中合同的产品数据 const promises = selectedRows.value.map(row => getSalesLedgerWithProducts({ id: row.id }) ); Promise.all(promises).then(results => { // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 const allProductData = []; results.forEach((result, index) => { const contract = selectedRows.value[index]; const contractId = contract.id; if (result.productData) { result.productData.forEach(item => { allProductData.push({ ...item, id: contractId, // 明确设置合同ID salesContractNo: contract.salesContractNo, // 添加销售合同号 customerName: contract.customerName, // 添加客户名称 customerContractNo: contract.customerContractNo // 添加客户合同号 }); }); } }); // 设置表单数据(使用第一个合同的基本信息,销售合同号留空) form.value = { ...results[0] }; form.value.createTime = dayjs().format("YYYY-MM-DD"); form.value.issueDate = dayjs().format("YYYY-MM-DD"); form.value.createUer = userStore.nickName; form.value.selectedContractIds = selectedRows.value.map(row => row.id); // 存储所有选中的合同ID form.value.salesContractNo = ""; // 销售合同号留空,因为会在产品表格中分别显示 productData.value = allProductData; dialogFormVisible.value = true; console.log("productData.value ", productData.value); }); }; // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate((valid) => { if (valid) { // 如果是批量操作,将所有合同的数据放在一个数组里,只调用一次接口 if (selectedRows.value.length > 1) { // 创建包含所有合同数据的数组 const batchData = selectedRows.value.map(contract => { // 筛选出属于当前合同的产品数据 const contractProductData = productData.value.filter(item => item.salesLedgerId === contract.id ); // 为每个销售合同号创建独立的对象 return { // 基础表单数据 issueDate: form.value.issueDate, createTime: form.value.createTime, createUer: form.value.createUer, invoiceNo: form.value.invoiceNo, // 合同实际信息 id: contract.id, // 使用id作为字段名,值为salesLedgerId salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 customerName: contract.customerName, // 使用实际的客户名称 customerId: contract.customerId, // 添加客户ID customerContractNo: contract.customerContractNo, // 使用实际的客户合同号 projectName: contract.projectName, // 使用实际的项目名称 salesman: contract.salesman, // 使用实际的业务员 // 产品数据 productData: proxy.HaveJson(contractProductData), // 批量标识 isBatch: true }; }); // 只调用一次接口,传递包含所有合同数据的数组 invoiceRegistrationSave(batchData).then(() => { proxy.$modal.msgSuccess("批量新增成功"); closeDia(); getList(); }); } else { // 单个合同提交逻辑 - 也以数组形式传递 const singleContract = selectedRows.value[0]; const singleFormArray = [ { // 基础表单数据 issueDate: form.value.issueDate, createTime: form.value.createTime, createUer: form.value.createUer, invoiceNo: form.value.invoiceNo, // 合同实际信息 id: singleContract.id, // 使用id作为字段名,值为salesLedgerId salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 customerName: singleContract.customerName, // 使用实际的客户名称 customerId: singleContract.customerId, // 添加客户ID customerContractNo: singleContract.customerContractNo, // 使用实际的客户合同号 projectName: singleContract.projectName, // 使用实际的项目名称 salesman: singleContract.salesman, // 使用实际的业务员 // 产品数据 productData: proxy.HaveJson(productData.value), // 批量标识 isBatch: false } ]; invoiceRegistrationSave(singleFormArray).then((res) => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); }); } } }); }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/invoiceRegistration/export", {}, "开票登记信息.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { page.current = 1; getList(); }; const paginationChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; ledgerListPage({ ...searchForm, ...page }).then(res => { tableLoading.value = false; tableData.value = res.records; total.value = res.total; expandedRowKeys.value = []; }); }; // 表格选择数据 const handleSelectionChange = selection => { console.log("selection", selection); selectedRows.value = selection.filter( item => item.salesContractNo !== undefined ); }; const expandedRowKeys = ref([]); // 展开行 const expandChange = (row, expandedRows) => { if (expandedRows.length > 0) { expandedRowKeys.value = []; try { productList({ salesLedgerId: row.id, type: 1 }).then(res => { const index = tableData.value.findIndex(item => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data; } expandedRowKeys.value.push(row.id); }); } catch (error) { console.log(error); } } else { expandedRowKeys.value = []; } }; // 主表合计方法 const summarizeMainTable = param => { return proxy.summarizeTable(param, [ "contractAmount", "invoiceTotal", "noInvoiceAmountTotal", ]); }; // 子表合计方法 const summarizeChildrenTable = param => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", "invoiceNum", "invoiceAmount", "currentInvoiceAmount", "noInvoiceNum", "noInvoiceAmount", "currentInvoiceNum", ]); }; // 打开弹框 const openForm = () => { // 判断是否选择了合同 if (selectedRows.value.length === 0) { proxy.$modal.msgError("请至少选择一条合同"); return; } // 导出销售台账 const handleExport = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/sales/ledger/exportOne", { ...searchForm, ...page }, "开票登记.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 检查所有选择的合同是否具有相同的客户名称 const firstRow = selectedRows.value[0]; const isSameCustomer = selectedRows.value.every( row => row.customerName === firstRow.customerName ); //本次开票失焦操作 const invoiceNumBlur = (row) => { if (!row.currentInvoiceNum) { row.currentInvoiceNum = 0; } if (row.currentInvoiceNum > row.tempNoInvoiceNum) { proxy.$modal.msgWarning("本次开票数不得大于未开票数"); row.currentInvoiceNum = 0; } // 计算本次开票金额 row.currentInvoiceAmount = ( row.currentInvoiceNum * row.taxInclusiveUnitPrice ).toFixed(2); // 计算未开票数 row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // 计算未开票金额 row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); }; // 本次开票金额失焦操作 const invoiceAmountBlur = (row) => { if (!row.currentInvoiceAmount) { row.currentInvoiceAmount = 0; } // 计算是否超过开票总金额 if (row.currentInvoiceAmount > row.tempnoInvoiceAmount) { proxy.$modal.msgWarning("本次开票金额不得大于未开票金额"); row.currentInvoiceAmount = 0; } // 计算本次开票数 row.currentInvoiceNum = ( row.currentInvoiceAmount / row.taxInclusiveUnitPrice ).toFixed(2); console.log("row.currentInvoiceNum ", row.currentInvoiceNum); console.log(" row.originalNoInvoiceNum ", row.originalNoInvoiceNum); // 计算未开票数 row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // 计算未开票金额 row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); }; if (!isSameCustomer) { proxy.$modal.msgError("请选择相同客户名称的合同"); return; } onMounted(() => { getList(); }); // 允许不同的销售合同号批量处理,无需检查重复 form.value = {}; productData.value = []; // 加载所有选中合同的产品数据 const promises = selectedRows.value.map(row => getSalesLedgerWithProducts({ id: row.id }) ); Promise.all(promises).then(results => { // 合并所有合同的产品数据,并为每个产品添加对应的合同信息 const allProductData = []; results.forEach((result, index) => { const contract = selectedRows.value[index]; const contractId = contract.id; console.log("result.productData", result.productData); if (result.productData) { result.productData.forEach(item => { allProductData.push({ ...item, // id: contractId, // 明确设置合同ID salesContractNo: contract.salesContractNo, // 添加销售合同号 customerName: contract.customerName, // 添加客户名称 customerContractNo: contract.customerContractNo, // 添加客户合同号 }); }); } }); console.log("allProductData", allProductData); // 设置表单数据(使用第一个合同的基本信息,销售合同号留空) form.value = { ...results[0] }; form.value.createTime = dayjs().format("YYYY-MM-DD"); form.value.issueDate = dayjs().format("YYYY-MM-DD"); form.value.createUer = userStore.nickName; form.value.selectedContractIds = selectedRows.value.map(row => row.id); // 存储所有选中的合同ID form.value.salesContractNo = ""; // 销售合同号留空,因为会在产品表格中分别显示 productData.value = allProductData; dialogFormVisible.value = true; console.log("productData.value ", productData.value); }); }; const processProductData = products => { return products.map(product => { return { ...product, currentInvoiceNum: product.currentInvoiceNum ? Number(Number(product.currentInvoiceNum).toFixed(2)) : 0, currentInvoiceAmount: product.currentInvoiceAmount ? Number(Number(product.currentInvoiceAmount).toFixed(2)) : 0, noInvoiceNum: product.noInvoiceNum ? Number(Number(product.noInvoiceNum).toFixed(2)) : 0, noInvoiceAmount: product.noInvoiceAmount ? Number(Number(product.noInvoiceAmount).toFixed(2)) : 0, }; }); }; // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate(valid => { if (valid) { // 处理产品数据,将 currentInvoiceNum 和 currentInvoiceAmount 转换为数字 // 如果是批量操作,将所有合同的数据放在一个数组里,只调用一次接口 if (selectedRows.value.length > 1) { // 创建包含所有合同数据的数组 const batchData = selectedRows.value.map(contract => { // 筛选出属于当前合同的产品数据 const contractProductData = productData.value.filter( item => item.salesLedgerId === contract.id ); // 处理产品数据,转换为数字格式 const processedProductData = processProductData(contractProductData); // 为每个销售合同号创建独立的对象 return { // 基础表单数据 issueDate: form.value.issueDate, createTime: form.value.createTime, createUer: form.value.createUer, invoiceNo: form.value.invoiceNo, // 合同实际信息 id: contract.id, // 使用id作为字段名,值为salesLedgerId salesContractNo: contract.salesContractNo, // 使用实际的销售合同号 customerName: contract.customerName, // 使用实际的客户名称 customerId: contract.customerId, // 添加客户ID customerContractNo: contract.customerContractNo, // 使用实际的客户合同号 projectName: contract.projectName, // 使用实际的项目名称 salesman: contract.salesman, // 使用实际的业务员 // 产品数据 productData: proxy.HaveJson(processedProductData), // 批量标识 isBatch: true, }; }); // 只调用一次接口,传递包含所有合同数据的数组 invoiceRegistrationSave(batchData).then(() => { proxy.$modal.msgSuccess("批量新增成功"); closeDia(); getList(); }); } else { // 单个合同提交逻辑 - 也以数组形式传递 const singleContract = selectedRows.value[0]; // 处理产品数据,转换为数字格式 const processedProductData = processProductData(productData.value); console.log("processedProductData ", processedProductData); const singleFormArray = [ { // 基础表单数据 issueDate: form.value.issueDate, createTime: form.value.createTime, createUer: form.value.createUer, invoiceNo: form.value.invoiceNo, // 合同实际信息 id: singleContract.id, // 使用id作为字段名,值为salesLedgerId salesContractNo: singleContract.salesContractNo, // 使用实际的销售合同号 customerName: singleContract.customerName, // 使用实际的客户名称 customerId: singleContract.customerId, // 添加客户ID customerContractNo: singleContract.customerContractNo, // 使用实际的客户合同号 projectName: singleContract.projectName, // 使用实际的项目名称 salesman: singleContract.salesman, // 使用实际的业务员 // 产品数据 productData: proxy.HaveJson(processedProductData), // 批量标识 isBatch: false, }, ]; console.log("singleFormArray ", singleFormArray); invoiceRegistrationSave(singleFormArray).then(res => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); }); } } }); }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/invoiceRegistration/export", {}, "开票登记信息.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 导出销售台账 const handleExport = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download( "/sales/ledger/exportOne", { ...searchForm, ...page }, "开票登记.xlsx" ); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; //本次开票失焦操作 const invoiceNumBlur = row => { if (!row.currentInvoiceNum) { row.currentInvoiceNum = 0; } if (row.currentInvoiceNum > row.tempNoInvoiceNum) { proxy.$modal.msgWarning("本次开票数不得大于未开票数"); row.currentInvoiceNum = 0; } // 计算本次开票金额 row.currentInvoiceAmount = ( row.currentInvoiceNum * row.taxInclusiveUnitPrice ).toFixed(2); // 计算未开票数 row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // 计算未开票金额 row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); }; // 本次开票金额失焦操作 const invoiceAmountBlur = row => { if (!row.currentInvoiceAmount) { row.currentInvoiceAmount = 0; } // 计算是否超过开票总金额 if (row.currentInvoiceAmount > row.tempnoInvoiceAmount) { proxy.$modal.msgWarning("本次开票金额不得大于未开票金额"); row.currentInvoiceAmount = 0; } // 计算本次开票数 row.currentInvoiceNum = ( row.currentInvoiceAmount / row.taxInclusiveUnitPrice ).toFixed(2); // 计算未开票数 row.noInvoiceNum = (row.originalNoInvoiceNum - row.currentInvoiceNum).toFixed( 2 ); // 计算未开票金额 row.noInvoiceAmount = ( row.tempnoInvoiceAmount - row.currentInvoiceAmount ).toFixed(2); }; onMounted(() => { getList(); }); </script> <style scoped lang="scss"> .table_list { margin-top: unset; } .flex { display: flex; } .justify-between { justify-content: space-between; } ::v-deep(.el-checkbox__label) { font-weight: bold; } .table_list { margin-top: unset; } .flex { display: flex; } .justify-between { justify-content: space-between; } ::v-deep(.el-checkbox__label) { font-weight: bold; } </style> src/views/salesManagement/salesLedger/index.vue
@@ -1,21 +1,34 @@ <template> <div class="app-container"> <div class="search_form"> <el-form :model="searchForm" :inline="true"> <el-form :model="searchForm" :inline="true"> <el-form-item label="客户名称:"> <el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> <el-input v-model="searchForm.customerName" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item label="销售合同号:"> <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> <el-input v-model="searchForm.salesContractNo" placeholder="请输入" clearable prefix-icon="Search" @change="handleQuery" /> </el-form-item> <el-form-item label="录入日期:"> <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" placeholder="请选择" clearable @change="changeDaterange" /> <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" placeholder="请选择" clearable @change="changeDaterange" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> <el-button type="primary" @click="handleQuery"> 搜索 </el-button> </el-form-item> </el-form> </div> @@ -23,130 +36,257 @@ <div class="actions"> <div></div> <div> <el-button type="primary" @click="openForm('add')"> <el-button type="primary" @click="openForm('add')"> 新增台账 </el-button> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> <el-button type="primary" plain @click="handlePrint">打印</el-button> <el-button type="danger" plain @click="handleDelete">删除</el-button> <el-button type="primary" plain @click="handlePrint">打印</el-button> </div> </div> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary style="width: 100%" :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 21em)"> <el-table-column align="center" type="selection" width="55" /> <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary style="width: 100%" :summary-method="summarizeMainTable" @expand-change="expandChange" height="calc(100vh - 21em)"> <el-table-column align="center" type="selection" width="55" /> <el-table-column type="expand"> <template #default="props"> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="生产状态" width="100px" align="center"> <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <el-table-column label="单位" prop="unit" /> <el-table-column label="生产状态" width="100px" align="center"> <template #default="scope"> <el-tag v-if="scope.row.productionStatus === '已完成'" type="success">已完成</el-tag> <el-tag v-if="scope.row.productionStatus === '生产中'" type="warning">生产中</el-tag> <el-tag v-if="scope.row.productionStatus === '未开始'" type="danger">未开始</el-tag> <el-tag v-if="!scope.row.productionStatus" type="info">暂无状态</el-tag> <el-tag v-if="scope.row.productionStatus === '已完成'" type="success">已完成</el-tag> <el-tag v-if="scope.row.productionStatus === '生产中'" type="warning">生产中</el-tag> <el-tag v-if="scope.row.productionStatus === '未开始'" type="danger">未开始</el-tag> <el-tag v-if="!scope.row.productionStatus" type="info">暂无状态</el-tag> </template> </el-table-column> <el-table-column label="产品状态" width="100px" align="center"> <el-table-column label="产品状态" width="100px" align="center"> <template #default="scope"> <el-tag v-if="scope.row.approveStatus === 0" type="info">未出库</el-tag> <el-tag v-if="scope.row.approveStatus === 1" type="success">已出库</el-tag> <el-tag v-if="scope.row.approveStatus === 2" type="warning">审核中</el-tag> <el-tag v-if="scope.row.approveStatus === 3" type="success">审核成功</el-tag> <el-tag v-if="scope.row.approveStatus === 4" type="danger">审核失败</el-tag> <el-tag v-if="scope.row.approveStatus === 0" type="info">未出库</el-tag> <el-tag v-if="scope.row.approveStatus === 1" type="success">已出库</el-tag> <el-tag v-if="scope.row.approveStatus === 2" type="warning">审核中</el-tag> <el-tag v-if="scope.row.approveStatus === 3" type="success">审核成功</el-tag> <el-tag v-if="scope.row.approveStatus === 4" type="danger">审核失败</el-tag> </template> </el-table-column> <el-table-column label="发货车牌" minWidth="100px" align="center"> <el-table-column label="发货车牌" minWidth="100px" align="center"> <template #default="scope"> <div> <el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag> <el-tag v-else type="info">未发货</el-tag> <el-tag type="success" v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</el-tag> <el-tag v-else type="info">未发货</el-tag> </div> </template> </el-table-column> <el-table-column label="发货日期" minWidth="100px" align="center"> <el-table-column label="发货日期" minWidth="100px" align="center"> <template #default="scope"> <div> <div v-if="scope.row.shippingDate">{{ scope.row.shippingDate }}</div> <el-tag v-else type="info">未发货</el-tag> <el-tag v-else type="info">未发货</el-tag> </div> </template> </el-table-column> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <!--操作--> <el-table-column Width="60px" label="操作" align="center"> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <!--操作--> <el-table-column Width="60px" label="操作" align="center"> <template #default="scope"> <el-button :disabled="scope.row.approveStatus!==1" link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button> <el-button :disabled="scope.row.approveStatus!==1" link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button> </template> </el-table-column> </el-table> </template> </el-table-column> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="销售合同号" prop="salesContractNo" width="180" show-overflow-tooltip /> <el-table-column label="客户合同号" prop="customerContractNo" width="180" show-overflow-tooltip /> <el-table-column label="客户名称" prop="customerName" width="300" show-overflow-tooltip /> <el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip /> <el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip /> <el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip /> <el-table-column label="合同金额(元)" prop="contractAmount" width="220" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip /> <el-table-column label="发货车牌" prop="shippingCarNumber" width="120" show-overflow-tooltip> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="销售合同号" prop="salesContractNo" width="180" show-overflow-tooltip /> <el-table-column label="客户名称" prop="customerName" width="300" show-overflow-tooltip /> <el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip /> <el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip /> <el-table-column label="合同金额(元)" prop="contractAmount" width="220" show-overflow-tooltip :formatter="formattedNumber" /> <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip /> <el-table-column label="发货车牌" prop="shippingCarNumber" width="120" show-overflow-tooltip> <template #default="scope"> <div> <div v-if="scope.row.shippingCarNumber">{{ scope.row.shippingCarNumber }}</div> <el-tag v-else type="warning">未发货</el-tag> <el-tag v-else type="warning">未发货</el-tag> </div> </template> </el-table-column> <el-table-column label="发货日期" prop="shippingDate" width="120" show-overflow-tooltip /> <el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip /> <el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip /> <el-table-column fixed="right" label="操作" min-width="100" align="center"> <el-table-column label="发货日期" prop="shippingDate" width="120" show-overflow-tooltip /> <el-table-column label="录入日期" prop="entryDate" width="120" show-overflow-tooltip /> <el-table-column label="签订日期" prop="executionDate" width="120" show-overflow-tooltip /> <el-table-column fixed="right" label="操作" min-width="100" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button> <!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详情</el-button>--> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">附件</el-button> <!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>--> <el-button link type="primary" size="small" @click="openForm('edit', scope.row)">编辑</el-button> <!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详情</el-button>--> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">附件</el-button> <!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">发货</el-button>--> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" width="70%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-dialog v-model="dialogFormVisible" :title="operationType === 'add' ? '新增销售台账页面' : '编辑销售台账页面'" width="70%" @close="closeDia"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" placeholder="自动生成" clearable disabled /> <el-form-item label="销售合同号:" prop="salesContractNo"> <el-input v-model="form.salesContractNo" placeholder="自动生成" clearable disabled /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="业务员:" prop="salesman"> <el-select v-model="form.salesman" filterable <el-form-item label="业务员:" prop="salesman"> <el-select v-model="form.salesman" filterable default-first-option :reserve-keyword="false" placeholder="请选择" clearable :disabled="operationType === 'view'"> <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName" /> :reserve-keyword="false" placeholder="请选择" clearable :disabled="operationType === 'view'"> <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="客户名称:" prop="customerId"> <el-select v-model="form.customerId" placeholder="请选择" clearable :disabled="operationType === 'view'" filterable> <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id"> <el-form-item label="客户名称:" prop="customerId"> <el-select v-model="form.customerId" placeholder="请选择" clearable :disabled="operationType === 'view'" filterable> <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id"> {{ item.customerName + "——" + item.taxpayerIdentificationNumber }} @@ -154,77 +294,150 @@ </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="签订日期:" prop="executionDate"> <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="签订日期:" prop="executionDate"> <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="录入人:" prop="entryPerson"> <el-select v-model="form.entryPerson" filterable default-first-option :reserve-keyword="false" placeholder="请选择" clearable @change="changs"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> <el-form-item label="录入人:" prop="entryPerson"> <el-select v-model="form.entryPerson" filterable default-first-option :reserve-keyword="false" placeholder="请选择" clearable @change="changs"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="录入日期:" prop="entryDate"> <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="付款方式"> <el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" /> <el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" /> </el-form-item> </el-col> </el-row> <el-row> <el-form-item label="产品信息:" prop="entryDate"> <el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">添加</el-button> <el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct" >删除</el-button> <el-form-item label="产品信息:" prop="entryDate"> <el-button v-if="operationType !== 'view'" type="primary" @click="openProductForm('add')">添加</el-button> <el-button v-if="operationType !== 'view'" plain type="danger" @click="deleteProduct">删除</el-button> </el-form-item> </el-row> <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeMainTable"> <el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'" /> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <!-- <el-table-column label="绑定机器" prop="speculativeTradingName" />--> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column fixed="right" label="操作" min-width="60" align="center" v-if="operationType !== 'view'"> <el-table :data="productData" border @selection-change="productSelected" show-summary :summary-method="summarizeMainTable"> <el-table-column align="center" type="selection" width="55" v-if="operationType !== 'view'" /> <el-table-column align="center" label="序号" type="index" width="60" /> <el-table-column label="产品大类" prop="productCategory" /> <el-table-column label="规格型号" prop="specificationModel" /> <!-- <el-table-column label="绑定机器" prop="speculativeTradingName" />--> <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" :formatter="formattedNumber" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> <el-table-column fixed="right" label="操作" min-width="60" align="center" v-if="operationType !== 'view'"> <template #default="scope"> <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row,scope.$index)">编辑</el-button> <el-button link type="primary" size="small" @click="openProductForm('edit', scope.row,scope.$index)">编辑</el-button> </template> </el-table-column> </el-table> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="备注·:" prop="remark"> <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" /> <el-form-item label="备注·:" prop="remark"> <el-input v-model="form.remark" placeholder="请输入" clearable type="textarea" :rows="2" :disabled="operationType === 'view'" /> </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'"> <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 @@ -237,91 +450,148 @@ </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">取消</el-button> </div> </template> </el-dialog> <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia"> <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef"> <el-dialog v-model="productFormVisible" :title="productOperationType === 'add' ? '新增产品' : '编辑产品'" width="40%" @close="closeProductDia"> <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef"> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="产品大类:" prop="productCategory"> <el-form-item label="产品大类:" prop="productId"> <!-- <el-select v-model="productForm.productCategory" placeholder="请选择" clearable> <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/> </el-select> --> <el-tree-select v-model="productForm.productCategory" placeholder="请选择" clearable check-strictly @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> <el-tree-select v-model="productForm.productId" placeholder="请选择" clearable check-strictly @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="规格型号:" prop="productModelId"> <el-select v-model="productForm.productModelId" placeholder="请选择" clearable @change="getProductModel" filterable> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> <el-form-item label="规格型号:" prop="productModelId"> <el-select v-model="productForm.productModelId" placeholder="请选择" clearable @change="getProductModel" filterable> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> </el-select> </el-form-item> </el-col> </el-row> <!-- <el-row :gutter="30">--> <!-- <el-col :span="24">--> <!-- <el-form-item label="绑定机器:">--> <!-- <el-input v-model="productForm.speculativeTradingName" placeholder="请先选择规格型号" clearable disabled />--> <!-- </el-form-item>--> <!-- </el-col>--> <!-- </el-row>--> <!-- <el-row :gutter="30">--> <!-- <el-col :span="24">--> <!-- <el-form-item label="绑定机器:">--> <!-- <el-input v-model="productForm.speculativeTradingName" placeholder="请先选择规格型号" clearable disabled />--> <!-- </el-form-item>--> <!-- </el-col>--> <!-- </el-row>--> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="单位:" prop="unit"> <el-input v-model="productForm.unit" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="税率(%):" prop="taxRate"> <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="calculateFromTaxRate"> <el-option label="1" value="1" /> <el-option label="6" value="6" /> <el-option label="13" value="13" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice"> <el-input-number :step="0.01" :min="0" v-model="productForm.taxInclusiveUnitPrice" style="width: 100%" :precision="2" placeholder="请输入" clearable @change="calculateFromUnitPrice" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="数量:" prop="quantity"> <el-input-number :step="0.1" :min="0" v-model="productForm.quantity" placeholder="请输入" clearable :precision="2" @change="calculateFromQuantity" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice"> <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromTotalPrice" /> <el-form-item label="单位:" prop="unit"> <el-input v-model="productForm.unit" placeholder="请输入" clearable /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice"> <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromExclusiveTotalPrice" /> <el-form-item label="税率(%):" prop="taxRate"> <el-select v-model="productForm.taxRate" placeholder="请选择" clearable @change="calculateFromTaxRate"> <el-option label="1" value="1" /> <el-option label="6" value="6" /> <el-option label="13" value="13" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="发票类型:" prop="invoiceType"> <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable> <el-option label="增普票" value="增普票" /> <el-option label="增专票" value="增专票" /> <el-form-item label="含税单价(元):" prop="taxInclusiveUnitPrice"> <el-input-number :step="0.01" :min="0" v-model="productForm.taxInclusiveUnitPrice" style="width: 100%" :precision="2" placeholder="请输入" clearable @change="calculateFromUnitPrice" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="数量:" prop="quantity"> <el-input-number :step="0.1" :min="0" v-model="productForm.quantity" placeholder="请输入" clearable :precision="2" @change="calculateFromQuantity" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="含税总价(元):" prop="taxInclusiveTotalPrice"> <el-input v-model="productForm.taxInclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromTotalPrice" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="不含税总价(元):" prop="taxExclusiveTotalPrice"> <el-input v-model="productForm.taxExclusiveTotalPrice" placeholder="请输入" clearable @change="calculateFromExclusiveTotalPrice" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="发票类型:" prop="invoiceType"> <el-select v-model="productForm.invoiceType" placeholder="请选择" clearable> <el-option label="增普票" value="增普票" /> <el-option label="增专票" value="增专票" /> </el-select> </el-form-item> </el-col> @@ -329,651 +599,719 @@ </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitProduct">确认</el-button> <el-button type="primary" @click="submitProduct">确认</el-button> <el-button @click="closeProductDia">取消</el-button> </div> </template> </el-dialog> <!-- 打印预览弹窗 --> <el-dialog v-model="printPreviewVisible" title="打印预览" width="90%" :close-on-click-modal="false" class="print-preview-dialog" > <div class="print-preview-container"> <div class="print-preview-header"> <el-button type="primary" @click="executePrint">执行打印</el-button> <el-button @click="printPreviewVisible = false">关闭预览</el-button> </div> <div class="print-preview-content"> <div v-if="printData.length === 0" style="text-align: center; padding: 50px; color: #999;"> 暂无打印数据 </div> <div v-else style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;"> 共 {{ printData.length }} 条数据待打印 </div> <div v-for="(item, index) in printData" :key="index" class="print-page"> <div class="delivery-note"> <div class="header"> <div class="company-name">海川开心食品有限公司</div> <div class="document-title">零售发货单</div> </div> <div class="info-section"> <div class="info-row"> <div> <span class="label">发货日期:</span> <span class="value">{{ formatDate(item.createTime) }}</span> </div> <div> <span class="label">发货车牌号:</span> <span class="value">{{ item.shippingCarNumber }}</span> </div> </div> <div class="info-row"> <div> <span class="label">客户名称:</span> <span class="value">{{ item.customerName || '张爱有' }}</span> </div> <span class="label">单号:</span> <span class="value">{{ item.salesContractNo }}</span> </div> </div> <div class="table-section"> <table class="product-table"> <thead> <tr> <th>产品名称</th> <th>规格型号</th> <th>单位</th> <th>单价</th> <th>零售数量</th> <th>零售金额</th> </tr> </thead> <tbody> <tr v-for="product in item.products" :key="product.id"> <td>{{ product.productCategory || '' }}</td> <td>{{ product.specificationModel || '' }}</td> <td>{{ product.unit || '' }}</td> <td>{{ product.taxInclusiveUnitPrice || '0' }}</td> <td>{{ product.quantity || '0' }}</td> <td>{{ product.taxInclusiveTotalPrice || '0' }}</td> </tr> <tr v-if="!item.products || item.products.length === 0"> <td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td> </tr> </tbody> <tfoot> <tr> <td class="label">合计</td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value">{{ getTotalQuantity(item.products) }}</td> <td class="total-value">{{ getTotalAmount(item.products) }}</td> </tr> </tfoot> </table> </div> <div class="footer-section"> <div class="footer-row"> <div class="footer-item"> <span class="label">收货电话:</span> <span class="value"></span> </div> <div class="footer-item"> <span class="label">收货人:</span> <span class="value"></span> </div> <div class="footer-item address-item"> <span class="label">收货地址:</span> <span class="value address-value"></span> </div> </div> <div class="footer-row"> <div class="footer-item"> <span class="label">操作员:</span> <span class="value">{{ userStore.nickName || '撕开前' }}</span> </div> <div class="footer-item"> <span class="label">打印日期:</span> <span class="value">{{ formatDateTime(new Date()) }}</span> </div> </div> </div> </div> </div> </div> </div> </el-dialog> <!-- 发货弹框 --> <el-dialog v-model="deliveryFormVisible" title="发货信息" width="40%" @close="closeDeliveryDia" > <el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef"> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="发货日期:" prop="shippingDate"> <el-date-picker style="width: 100%" v-model="deliveryForm.shippingDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择发货日期" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="发货车牌号:" prop="shippingCarNumber"> <el-input v-model="deliveryForm.shippingCarNumber" placeholder="请输入发货车牌号" clearable /> </el-form-item> </el-col> </el-row> <!-- 打印预览弹窗 --> <el-dialog v-model="printPreviewVisible" title="打印预览" width="90%" :close-on-click-modal="false" class="print-preview-dialog"> <div class="print-preview-container"> <div class="print-preview-header"> <el-button type="primary" @click="executePrint">执行打印</el-button> <el-button @click="printPreviewVisible = false">关闭预览</el-button> </div> <div class="print-preview-content"> <div v-if="printData.length === 0" style="text-align: center; padding: 50px; color: #999;"> 暂无打印数据 </div> <div v-else style="text-align: center; padding: 10px; color: #666; font-size: 14px; background: #e8f4fd; margin-bottom: 10px;"> 共 {{ printData.length }} 条数据待打印 </div> <div v-for="(item, index) in printData" :key="index" class="print-page"> <div class="delivery-note"> <div class="header"> <div class="company-name">{{ currentFactoryName }}</div> <div class="document-title">零售发货单</div> </div> <div class="info-section"> <div class="info-row"> <div> <span class="label">发货日期:</span> <span class="value">{{ formatDate(item.createTime) }}</span> </div> <div> <span class="label">发货车牌号:</span> <span class="value">{{ item.shippingCarNumber }}</span> </div> </div> <div class="info-row"> <div> <span class="label">客户名称:</span> <span class="value">{{ item.customerName || '张爱有' }}</span> </div> <span class="label">单号:</span> <span class="value">{{ item.salesContractNo }}</span> </div> </div> <div class="table-section"> <table class="product-table"> <thead> <tr> <th>产品名称</th> <th>规格型号</th> <th>单位</th> <th>单价</th> <th>零售数量</th> <th>零售金额</th> </tr> </thead> <tbody> <tr v-for="product in item.products" :key="product.id"> <td>{{ product.productCategory || '' }}</td> <td>{{ product.specificationModel || '' }}</td> <td>{{ product.unit || '' }}</td> <td>{{ product.taxInclusiveUnitPrice || '0' }}</td> <td>{{ product.quantity || '0' }}</td> <td>{{ product.taxInclusiveTotalPrice || '0' }}</td> </tr> <tr v-if="!item.products || item.products.length === 0"> <td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td> </tr> </tbody> <tfoot> <tr> <td class="label">合计</td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value">{{ getTotalQuantity(item.products) }}</td> <td class="total-value">{{ getTotalAmount(item.products) }}</td> </tr> </tfoot> </table> </div> <div class="footer-section"> <div class="footer-row"> <div class="footer-item"> <span class="label">收货电话:</span> <span class="value"></span> </div> <div class="footer-item"> <span class="label">收货人:</span> <span class="value"></span> </div> <div class="footer-item address-item"> <span class="label">收货地址:</span> <span class="value address-value"></span> </div> </div> <div class="footer-row"> <div class="footer-item"> <span class="label">操作员:</span> <span class="value">{{ userStore.nickName || '撕开前' }}</span> </div> <div class="footer-item"> <span class="label">打印日期:</span> <span class="value">{{ formatDateTime(new Date()) }}</span> </div> </div> </div> </div> </div> </div> </div> </el-dialog> <!-- 发货弹框 --> <el-dialog v-model="deliveryFormVisible" title="发货信息" width="40%" @close="closeDeliveryDia"> <el-form :model="deliveryForm" label-width="120px" label-position="top" :rules="deliveryRules" ref="deliveryFormRef"> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="审批人:" prop="approverId"> <el-select v-model="deliveryForm.approverId" placeholder="请选择审批人" clearable :disabled="operationType === 'view'"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> <el-form-item label="发货日期:" prop="shippingDate"> <el-date-picker style="width: 100%" v-model="deliveryForm.shippingDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="请选择发货日期" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="发货车牌号:" prop="shippingCarNumber"> <el-input v-model="deliveryForm.shippingCarNumber" placeholder="请输入发货车牌号" clearable /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="审批人:" prop="approverId"> <el-select v-model="deliveryForm.approverId" placeholder="请选择审批人" clearable :disabled="operationType === 'view'"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> </el-select> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitDelivery">确认发货</el-button> <el-button @click="closeDeliveryDia">取消</el-button> </div> </template> </el-dialog> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitDelivery">确认发货</el-button> <el-button @click="closeDeliveryDia">取消</el-button> </div> </template> </el-dialog> <FileList ref="fileListRef" /> </div> </template> <script setup> import { getToken } from "@/utils/auth"; import pagination from "@/components/PIMTable/Pagination.vue"; import {onMounted, ref} from "vue"; import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js"; import {ElMessage, ElMessageBox} from "element-plus"; import useUserStore from "@/store/modules/user"; import { userListNoPage } from "@/api/system/user.js"; import FileList from "./fileList.vue"; import { ledgerListPage, productList, customerList, addOrUpdateSalesLedger, getSalesLedgerWithProducts, delLedger, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInventory, } from "@/api/salesManagement/salesLedger.js"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import useFormData from "@/hooks/useFormData.js"; import dayjs from "dayjs"; import { getToken } from "@/utils/auth"; import pagination from "@/components/PIMTable/Pagination.vue"; import { onMounted, ref } from "vue"; import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js"; import { ElMessage, ElMessageBox } from "element-plus"; import useUserStore from "@/store/modules/user"; import { userListNoPage } from "@/api/system/user.js"; import FileList from "./fileList.vue"; import { ledgerListPage, productList, customerList, addOrUpdateSalesLedger, getSalesLedgerWithProducts, delLedger, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInventory, } from "@/api/salesManagement/salesLedger.js"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import useFormData from "@/hooks/useFormData.js"; import dayjs from "dayjs"; const userStore = useUserStore(); const { proxy } = getCurrentInstance(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const productSelectedRows = ref([]); const userList = ref([]); const customerOption = ref([]); const productOptions = ref([]); const modelOptions = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); const total = ref(0); const fileList = ref([]); // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { customerName: "", // 客户名称 salesContractNo: "", // 销售合同编号 entryDate: null, // 录入日期 entryDateStart: undefined, entryDateEnd: undefined, }, form: { salesContractNo: "", salesman: "", customerContractNo: "", customerId: "", projectName: "", entryPerson: "", entryDate: "", maintenanceTime: "", productData: [], executionDate: "", }, rules: { salesman: [{ required: true, message: "请选择", trigger: "change" }], customerContractNo: [ { required: true, message: "请输入", trigger: "blur" }, ], customerId: [{ required: true, message: "请选择", trigger: "change" }], projectName: [{ required: true, message: "请输入", trigger: "blur" }], entryPerson: [{ required: true, message: "请选择", trigger: "change" }], entryDate: [{ required: true, message: "请选择", trigger: "change" }], executionDate: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { form, rules } = toRefs(data); const { form: searchForm } = useFormData(data.searchForm); // 产品表单弹框数据 const productFormVisible = ref(false); const productOperationType = ref(""); const currentId = ref(""); const productFormData = reactive({ productForm: { productCategory: "", specificationModel: "", unit: "", quantity: "", taxInclusiveUnitPrice: "", taxRate: "", taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", speculativeTradingName: "", }, productRules: { productCategory: [{ required: true, message: "请选择", trigger: "change" }], productModelId: [{ required: true, message: "请选择", trigger: "change" }], specificationModel: [ { required: true, message: "请选择", trigger: "change" }, ], unit: [{ required: true, message: "请输入", trigger: "blur" }], quantity: [{ required: true, message: "请输入", trigger: "blur" }], taxInclusiveUnitPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxRate: [{ required: true, message: "请选择", trigger: "change" }], taxInclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxExclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], invoiceType: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { productForm, productRules } = toRefs(productFormData); // 防止循环计算的标志 const isCalculating = ref(false); const upload = reactive({ // 上传的地址 url: import.meta.env.VITE_APP_BASE_API + "/file/upload", // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, }); // 打印相关 const printPreviewVisible = ref(false); const printData = ref([]); // 发货相关 const deliveryFormVisible = ref(false); const currentDeliveryRow = ref(null); const deliveryFormData = reactive({ deliveryForm: { shippingDate: "", shippingCarNumber: "", }, deliveryRules: { shippingDate: [ { required: true, message: "请选择发货日期", trigger: "change" } ], shippingCarNumber: [ { required: true, message: "请输入发货车牌号", trigger: "blur" } ], approverId:[ { required: true,message: "", } ] }, }); const { deliveryForm, deliveryRules } = toRefs(deliveryFormData); const changeDaterange = (value) => { if (value) { searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); } else { searchForm.entryDateStart = undefined; searchForm.entryDateEnd = undefined; } handleQuery(); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { // 只有在点击搜索按钮时才重置页码到第一页 // 避免表单字段change事件干扰分页 if (arguments.length === 0) { page.current = 1; } expandedRowKeys.value = []; getList(); }; const paginationChange = (obj) => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList =async () => { let userLists = await userListNoPage(); userList.value = userLists.data; tableLoading.value = true; const { entryDate, ...rest } = searchForm; ledgerListPage({ ...rest, ...page }) .then((res) => { tableLoading.value = false; tableData.value = res.records; tableData.value.map((item) => { item.children = []; }); total.value = res.total; }) .catch(() => { tableLoading.value = false; }); }; // 获取产品大类tree数据 const getProductOptions = () => { productTreeList().then((res) => { productOptions.value = convertIdToValue(res); const userStore = useUserStore(); const { proxy } = getCurrentInstance(); const tableData = ref([]); const productData = ref([]); const selectedRows = ref([]); const productSelectedRows = ref([]); const userList = ref([]); const customerOption = ref([]); const productOptions = ref([]); const modelOptions = ref([]); const tableLoading = ref(false); const page = reactive({ current: 1, size: 100, }); }; const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 获取tree子数据 const getModels = (value) => { productForm.value.productCategory = findNodeById(productOptions.value, value); modelList({ id: value }).then((res) => { modelOptions.value = res; }); }; const getProductModel = (value) => { console.log("value", value); const index = modelOptions.value.findIndex((item) => item.id === value); if (index !== -1) { productForm.value.specificationModel = modelOptions.value[index].model; productForm.value.unit = modelOptions.value[index].unit; // productForm.value.speculativeTradingName = modelOptions.value[index].speculativeTradingName || ""; } else { productForm.value.specificationModel = null; productForm.value.unit = null; productForm.value.speculativeTradingName = ""; } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].value === productId) { return nodes[i].label; // 找到节点,返回该节点 } if (nodes[i].children && nodes[i].children.length > 0) { const foundNode = findNodeById(nodes[i].children, productId); if (foundNode) { return foundNode; // 在子节点中找到,返回该节点 } } } return null; // 没有找到节点,返回null }; 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); } const total = ref(0); const fileList = ref([]); return newItem; // 用户信息表单弹框数据 const operationType = ref(""); const dialogFormVisible = ref(false); const data = reactive({ searchForm: { customerName: "", // 客户名称 salesContractNo: "", // 销售合同编号 entryDate: null, // 录入日期 entryDateStart: undefined, entryDateEnd: undefined, }, form: { salesContractNo: "", salesman: "", customerContractNo: "", customerId: "", projectName: "", entryPerson: "", entryDate: "", maintenanceTime: "", productData: [], executionDate: "", }, rules: { salesman: [{ required: true, message: "请选择", trigger: "change" }], customerContractNo: [ { required: true, message: "请输入", trigger: "blur" }, ], customerId: [{ required: true, message: "请选择", trigger: "change" }], projectName: [{ required: true, message: "请输入", trigger: "blur" }], entryPerson: [{ required: true, message: "请选择", trigger: "change" }], entryDate: [{ required: true, message: "请选择", trigger: "change" }], executionDate: [{ required: true, message: "请选择", trigger: "change" }], }, }); } // 表格选择数据 const handleSelectionChange = (selection) => { // 过滤掉子数据 selectedRows.value = selection.filter((item) => item.children !== undefined); console.log("selection", selectedRows.value); }; const productSelected = (selectedRows) => { productSelectedRows.value = selectedRows; }; const expandedRowKeys = ref([]); // 展开行(始终只展开一行) const expandChange = (row) => { const rowKey = row.id; const isExpanded = expandedRowKeys.value.includes(rowKey); const { form, rules } = toRefs(data); const { form: searchForm } = useFormData(data.searchForm); // 产品表单弹框数据 const productFormVisible = ref(false); const productOperationType = ref(""); const currentId = ref(""); const productFormData = reactive({ productForm: { productCategory: "", productId: "", specificationModel: "", unit: "", quantity: "", taxInclusiveUnitPrice: "", taxRate: "", taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", speculativeTradingName: "", }, productRules: { productCategory: [{ required: true, message: "请选择", trigger: "change" }], productModelId: [{ required: true, message: "请选择", trigger: "change" }], specificationModel: [ { required: true, message: "请选择", trigger: "change" }, ], unit: [{ required: true, message: "请输入", trigger: "blur" }], quantity: [{ required: true, message: "请输入", trigger: "blur" }], taxInclusiveUnitPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxRate: [{ required: true, message: "请选择", trigger: "change" }], taxInclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], taxExclusiveTotalPrice: [ { required: true, message: "请输入", trigger: "blur" }, ], invoiceType: [{ required: true, message: "请选择", trigger: "change" }], }, }); const { productForm, productRules } = toRefs(productFormData); // 防止循环计算的标志 const isCalculating = ref(false); const upload = reactive({ // 上传的地址 url: import.meta.env.VITE_APP_BASE_API + "/file/upload", // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, }); // 打印相关 const printPreviewVisible = ref(false); const printData = ref([]); if (isExpanded) { // 当前行已展开 -> 收起 // 发货相关 const deliveryFormVisible = ref(false); const currentDeliveryRow = ref(null); const deliveryFormData = reactive({ deliveryForm: { shippingDate: "", shippingCarNumber: "", }, deliveryRules: { shippingDate: [ { required: true, message: "请选择发货日期", trigger: "change" }, ], shippingCarNumber: [ { required: true, message: "请输入发货车牌号", trigger: "blur" }, ], approverId: [ { required: true, message: "", }, ], }, }); const { deliveryForm, deliveryRules } = toRefs(deliveryFormData); const changeDaterange = value => { if (value) { searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); } else { searchForm.entryDateStart = undefined; searchForm.entryDateEnd = undefined; } handleQuery(); }; // 查询列表 /** 搜索按钮操作 */ const handleQuery = () => { // 只有在点击搜索按钮时才重置页码到第一页 // 避免表单字段change事件干扰分页 if (arguments.length === 0) { page.current = 1; } expandedRowKeys.value = []; return; } getList(); }; const paginationChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = async () => { let userLists = await userListNoPage(); userList.value = userLists.data; tableLoading.value = true; const { entryDate, ...rest } = searchForm; ledgerListPage({ ...rest, ...page }) .then(res => { tableLoading.value = false; tableData.value = res.records; tableData.value.map(item => { item.children = []; }); total.value = res.total; }) .catch(() => { tableLoading.value = false; }); }; const currentFactoryName = ref(""); const getcurrentFactoryName = async () => { let res = await userStore.getInfo(); currentFactoryName.value = res.user.currentFactoryName; }; // 获取产品大类tree数据 const getProductOptions = () => { productTreeList().then(res => { productOptions.value = convertIdToValue(res); }); }; const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 获取tree子数据 const getModels = value => { productForm.value.productCategory = findNodeById(productOptions.value, value); modelList({ id: value }).then(res => { modelOptions.value = res; }); }; const getProductModel = value => { console.log("value", value); const index = modelOptions.value.findIndex(item => item.id === value); if (index !== -1) { productForm.value.specificationModel = modelOptions.value[index].model; productForm.value.unit = modelOptions.value[index].unit; // productForm.value.speculativeTradingName = modelOptions.value[index].speculativeTradingName || ""; } else { productForm.value.specificationModel = null; productForm.value.unit = null; productForm.value.speculativeTradingName = ""; } }; const findNodeById = (nodes, productId) => { for (let i = 0; i < nodes.length; i++) { if (nodes[i].value === productId) { return nodes[i].label; // 找到节点,返回该节点 } if (nodes[i].children && nodes[i].children.length > 0) { const foundNode = findNodeById(nodes[i].children, productId); if (foundNode) { return foundNode; // 在子节点中找到,返回该节点 } } } return null; // 没有找到节点,返回null }; 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); } // 展开当前行前,先收起其它行 expandedRowKeys.value = []; return newItem; }); } // 表格选择数据 const handleSelectionChange = selection => { // 过滤掉子数据 selectedRows.value = selection.filter(item => item.children !== undefined); console.log("selection", selectedRows.value); }; const productSelected = selectedRows => { productSelectedRows.value = selectedRows; }; const expandedRowKeys = ref([]); // 展开行(始终只展开一行) const expandChange = row => { const rowKey = row.id; const isExpanded = expandedRowKeys.value.includes(rowKey); try { productList({ salesLedgerId: row.id, type: 1 }).then((res) => { const index = tableData.value.findIndex((item) => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data; } // 只保留当前这一行处于展开状态 expandedRowKeys.value = [rowKey]; if (isExpanded) { // 当前行已展开 -> 收起 expandedRowKeys.value = []; return; } // 展开当前行前,先收起其它行 expandedRowKeys.value = []; try { productList({ salesLedgerId: row.id, type: 1 }).then(res => { const index = tableData.value.findIndex(item => item.id === row.id); if (index > -1) { tableData.value[index].children = res.data; } // 只保留当前这一行处于展开状态 expandedRowKeys.value = [rowKey]; }); } catch (error) { console.log(error); } }; // 主表合计方法 const summarizeMainTable = param => { return proxy.summarizeTable(param, [ "contractAmount", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ]); }; // 子表合计方法 const summarizeChildrenTable = param => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ]); }; // 打开弹框 const openForm = async (type, row) => { operationType.value = type; form.value = {}; productData.value = []; let userLists = await userListNoPage(); userList.value = userLists.data; customerList().then(res => { customerOption.value = res; }); } catch (error) { console.log(error); } }; // 主表合计方法 const summarizeMainTable = (param) => { return proxy.summarizeTable(param, [ "contractAmount", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ]); }; // 子表合计方法 const summarizeChildrenTable = (param) => { return proxy.summarizeTable(param, [ "taxInclusiveUnitPrice", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ]); }; // 打开弹框 const openForm = async (type, row) => { operationType.value = type; form.value = {}; productData.value = []; let userLists = await userListNoPage(); userList.value = userLists.data; customerList().then((res) => { customerOption.value = res; }); form.value.entryPerson = userStore.id; if (type !== "add") { currentId.value = row.id; getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => { form.value = { ...res }; form.value.entryPerson = Number(res.entryPerson); productData.value = form.value.productData; fileList.value = form.value.salesLedgerFiles; }); } // let userAll = await userStore.getInfo() // userList.value.forEach(element => { // if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) { // form.value.entryPerson = userAll.user.userId // 设置默认业务员为当前用户 // } // }); form.value.entryDate = getCurrentDate(); // 设置默认录入日期为当前日期 dialogFormVisible.value = true; }; function changs(val) { console.log(val); } // 上传前校检 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) { file.tempId = 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("删除成功"); }); } } // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate((valid) => { if (valid) { console.log('productData.value--', productData.value) if (productData.value !== null && productData.value.length > 0) { form.value.productData = proxy.HaveJson(productData.value); } else { proxy.$modal.msgWarning("请添加产品信息"); return; } let tempFileIds = []; if (fileList.value !== null && fileList.value.length > 0) { tempFileIds = fileList.value.map((item) => item.tempId); } form.value.tempFileIds = tempFileIds; form.value.type = 1; addOrUpdateSalesLedger(form.value).then((res) => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); form.value.entryPerson = userStore.id; if (type !== "add") { currentId.value = row.id; getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => { form.value = { ...res }; form.value.entryPerson = Number(res.entryPerson); productData.value = form.value.productData; fileList.value = form.value.salesLedgerFiles; }); } }); }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; const productIndex = ref(0); // 打开产品弹框 const openProductForm = (type, row,index) => { productOperationType.value = type; productForm.value = {}; proxy.resetForm("productFormRef"); if (type === "edit") { productForm.value = { ...row }; productIndex.value = index; // let userAll = await userStore.getInfo() // userList.value.forEach(element => { // if(userAll.user.nickName === element.nickName && userAll.user.userName === element.userName) { // form.value.entryPerson = userAll.user.userId // 设置默认业务员为当前用户 // } // }); form.value.entryDate = getCurrentDate(); // 设置默认录入日期为当前日期 dialogFormVisible.value = true; }; function changs(val) { console.log(val); } productFormVisible.value = true; getProductOptions(); }; // 提交产品表单 const submitProduct = () => { proxy.$refs["productFormRef"].validate((valid) => { if (valid) { if (operationType.value === "edit") { submitProductEdit(); } else { if(productOperationType.value === "add"){ productData.value.push({ ...productForm.value }); }else{ productData.value[productIndex.value] = { ...productForm.value } } closeProductDia(); } // 上传前校检 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) { file.tempId = res.data.tempId; proxy.$modal.msgSuccess("上传成功"); } else { proxy.$modal.msgError(res.msg); proxy.$refs.fileUpload.handleRemove(file); } }); }; const submitProductEdit = () => { productForm.value.salesLedgerId = currentId.value; productForm.value.type = 1 addOrUpdateSalesLedgerProduct(productForm.value).then((res) => { proxy.$modal.msgSuccess("提交成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then((res) => { productData.value = res.productData; }); }); }; // 删除产品 const deleteProduct = () => { if (productSelectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择数据"); return; } if (operationType.value === "add") { productSelectedRows.value.forEach((selectedRow) => { const index = productData.value.findIndex( (product) => product.id === selectedRow.id ); if (index !== -1) { productData.value.splice(index, 1); // 移除文件 function handleRemove(file) { if (operationType.value === "edit") { let ids = []; ids.push(file.id); delLedgerFile(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); }); } } // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate(valid => { if (valid) { console.log("productData.value--", productData.value); if (productData.value !== null && productData.value.length > 0) { form.value.productData = proxy.HaveJson(productData.value); } else { proxy.$modal.msgWarning("请添加产品信息"); return; } let tempFileIds = []; if (fileList.value !== null && fileList.value.length > 0) { tempFileIds = fileList.value.map(item => item.tempId); } form.value.tempFileIds = tempFileIds; form.value.type = 1; addOrUpdateSalesLedger(form.value).then(res => { proxy.$modal.msgSuccess("提交成功"); closeDia(); getList(); }); } }); } else { }; // 关闭弹框 const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; }; const productIndex = ref(0); // 打开产品弹框 const openProductForm = (type, row, index) => { productOperationType.value = type; productForm.value = {}; proxy.resetForm("productFormRef"); if (type === "edit") { productForm.value = { ...row }; productIndex.value = index; } productFormVisible.value = true; getProductOptions(); }; // 提交产品表单 const submitProduct = () => { proxy.$refs["productFormRef"].validate(valid => { if (valid) { if (operationType.value === "edit") { submitProductEdit(); } else { if (productOperationType.value === "add") { productData.value.push({ ...productForm.value }); } else { productData.value[productIndex.value] = { ...productForm.value }; } closeProductDia(); } } }); }; const submitProductEdit = () => { productForm.value.salesLedgerId = currentId.value; productForm.value.type = 1; addOrUpdateSalesLedgerProduct(productForm.value).then(res => { proxy.$modal.msgSuccess("提交成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then(res => { productData.value = res.productData; }); }); }; // 删除产品 const deleteProduct = () => { if (productSelectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择数据"); return; } if (operationType.value === "add") { productSelectedRows.value.forEach(selectedRow => { const index = productData.value.findIndex( product => product.id === selectedRow.id ); if (index !== -1) { productData.value.splice(index, 1); } }); } else { let ids = []; if (productSelectedRows.value.length > 0) { ids = productSelectedRows.value.map(item => item.id); } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { delProduct(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then( res => { productData.value = res.productData; } ); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); } }; // 关闭产品弹框 const closeProductDia = () => { proxy.resetForm("productFormRef"); productFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/sales/ledger/export", {}, "销售台账.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 删除 const handleDelete = () => { let ids = []; if (productSelectedRows.value.length > 0) { ids = productSelectedRows.value.map((item) => item.id); if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", @@ -981,847 +1319,839 @@ type: "warning", }) .then(() => { delProduct(ids).then((res) => { delLedger(ids).then(res => { proxy.$modal.msgSuccess("删除成功"); closeProductDia(); getSalesLedgerWithProducts({ id: currentId.value, type: 1 }).then( (res) => { productData.value = res.productData; } ); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); } }; // 关闭产品弹框 const closeProductDia = () => { proxy.resetForm("productFormRef"); productFormVisible.value = false; }; // 导出 const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { proxy.download("/sales/ledger/export", {}, "销售台账.xlsx"); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 删除 const handleDelete = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map((item) => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被删除,是否确认删除?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { delLedger(ids).then((res) => { proxy.$modal.msgSuccess("删除成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 打印功能 const handlePrint = async () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择要打印的数据"); return; } // 显示加载状态 proxy.$modal.loading("正在获取产品数据,请稍候..."); try { // 为每个选中的销售台账记录查询对应的产品数据 const printDataWithProducts = []; for (const row of selectedRows.value) { try { // 调用productList接口查询产品数据 const productRes = await productList({ salesLedgerId: row.id, type: 1 }); // 将产品数据整合到销售台账记录中 const rowWithProducts = { ...row, products: productRes.data || [] }; printDataWithProducts.push(rowWithProducts); } catch (error) { console.error(`获取销售台账 ${row.id} 的产品数据失败:`, error); // 即使某个记录的产品数据获取失败,也要包含该记录 printDataWithProducts.push({ ...row, products: [] }); } } printData.value = printDataWithProducts; console.log('打印数据(包含产品):', printData.value); printPreviewVisible.value = true; } catch (error) { console.error('获取产品数据失败:', error); proxy.$modal.msgError("获取产品数据失败,请重试"); } finally { proxy.$modal.closeLoading(); } }; // 执行打印 const executePrint = () => { console.log('开始执行打印,数据条数:', printData.value.length); console.log('打印数据:', printData.value); // 创建一个新的打印窗口 const printWindow = window.open('', '_blank', 'width=800,height=600'); // 构建打印内容 let printContent = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>打印预览</title> <style> body { margin: 0; padding: 0; font-family: "SimSun", serif; background: white; } .print-page { width: 200mm; height: 75mm; padding: 10mm; padding-left: 20mm; background: white; box-sizing: border-box; page-break-after: always; page-break-inside: avoid; } .print-page:last-child { page-break-after: avoid; } .delivery-note { width: 100%; height: 100%; font-size: 12px; line-height: 1.2; display: flex; flex-direction: column; color: #000; } .header { text-align: center; margin-bottom: 8px; } .company-name { font-size: 18px; font-weight: bold; margin-bottom: 4px; } .document-title { font-size: 16px; font-weight: bold; } .info-section { margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; } .info-row { line-height: 20px; } .label { font-weight: bold; width: 60px; font-size: 12px; } .value { margin-right: 20px; min-width: 80px; font-size: 12px; } .table-section { margin-bottom: 40px; // flex: 0.6; } .product-table { width: 100%; border-collapse: collapse; border: 1px solid #000; } .product-table th, .product-table td { border: 1px solid #000; padding: 6px; text-align: center; font-size: 12px; line-height: 1.4; } .product-table th { font-weight: bold; } .total-value { font-weight: bold; } .footer-section { margin-top: auto; } .footer-row { display: flex; margin-bottom: 3px; line-height: 22px; justify-content: space-between; } .footer-item { display: flex; margin-right: 20px; } .footer-item .label { font-weight: bold; width: 80px; font-size: 12px; } .footer-item .value { min-width: 80px; font-size: 12px; } .address-item .address-value { min-width: 200px; } @media print { body { margin: 0; padding: 0; } .print-page { margin: 0; padding: 10mm; /* padding-left: 20mm; */ page-break-inside: avoid; page-break-after: always; } .print-page:last-child { page-break-after: avoid; } } </style> </head> <body> `; // 为每条数据生成打印页面 printData.value.forEach((item, index) => { printContent += ` <div class="print-page"> <div class="delivery-note"> <div class="header"> <div class="company-name">海川开心食品有限公司</div> <div class="document-title">零售发货单</div> </div> <div class="info-section"> <div class="info-row"> <div> <span class="label">发货日期:</span> <span class="value">${formatDate(item.createTime)}</span> </div> <div> <span class="label">客户名称:</span> <span class="value">${item.customerName || '张爱有'}</span> </div> </div> <div class="info-row"> <span class="label">单号:</span> <span class="value">${item.salesContractNo || ''}</span> </div> </div> <div class="table-section"> <table class="product-table"> <thead> <tr> <th>产品名称</th> <th>规格型号</th> <th>单位</th> <th>单价</th> <th>零售数量</th> <th>零售金额</th> </tr> </thead> <tbody> ${item.products && item.products.length > 0 ? item.products.map(product => ` <tr> <td>${product.productCategory || ''}</td> <td>${product.specificationModel || ''}</td> <td>${product.unit || ''}</td> <td>${product.taxInclusiveUnitPrice || '0'}</td> <td>${product.quantity || '0'}</td> <td>${product.taxInclusiveTotalPrice || '0'}</td> </tr> `).join('') : '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>' } </tbody> <tfoot> <tr> <td class="label">合计</td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value">${getTotalQuantityForPrint(item.products)}</td> <td class="total-value">${getTotalAmountForPrint(item.products)}</td> </tr> </tfoot> </table> </div> <div class="footer-section"> <div class="footer-row"> <div class="footer-item"> <span class="label">收货电话:</span> <span class="value"></span> </div> <div class="footer-item"> <span class="label">收货人:</span> <span class="value"></span> </div> <div class="footer-item address-item"> <span class="label">收货地址:</span> <span class="value address-value"></span> </div> </div> <div class="footer-row"> <div class="footer-item"> <span class="label">操作员:</span> <span class="value">${userStore.nickName || '撕开前'}</span> </div> <div class="footer-item"> <span class="label">打印日期:</span> <span class="value">${formatDateTime(new Date())}</span> </div> </div> </div> </div> </div> `; }); printContent += ` </body> </html> `; // 写入内容到新窗口 printWindow.document.write(printContent); printWindow.document.close(); // 等待内容加载完成后打印 printWindow.onload = () => { setTimeout(() => { printWindow.print(); printWindow.close(); printPreviewVisible.value = false; }, 500); }; }; // 格式化日期 const formatDate = (dateString) => { if (!dateString) return getCurrentDate(); const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}/${month}/${day}`; }; // 格式化日期时间 const formatDateTime = (date) => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); const seconds = String(date.getSeconds()).padStart(2, "0"); return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; }; // 获取当前日期并格式化为 YYYY-MM-DD function getCurrentDate() { const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始 const day = String(today.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } // 计算产品总数量 const getTotalQuantity = (products) => { if (!products || products.length === 0) return '0'; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.quantity) || 0); }, 0); return total.toFixed(2); }; // 计算产品总金额 const getTotalAmount = (products) => { if (!products || products.length === 0) return '0'; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); }, 0); return total.toFixed(2); }; // 用于打印的计算函数 const getTotalQuantityForPrint = (products) => { if (!products || products.length === 0) return '0'; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.quantity) || 0); }, 0); return total.toFixed(2); }; const getTotalAmountForPrint = (products) => { if (!products || products.length === 0) return '0'; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); }, 0); return total.toFixed(2); }; const mathNum = () => { console.log("productForm.value", productForm.value); if (!productForm.value.taxInclusiveUnitPrice) { return; } if (!productForm.value.quantity) { return; } // 含税总价计算 productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice( productForm.value.taxInclusiveUnitPrice, productForm.value.quantity ); if (productForm.value.taxRate) { // 不含税总价计算 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } }; // 根据含税总价计算含税单价和数量 const calculateFromTotalPrice = () => { if (isCalculating.value) return; const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice); const quantity = parseFloat(productForm.value.quantity); if (!totalPrice || !quantity || quantity <= 0) { return; } isCalculating.value = true; // 计算含税单价 = 含税总价 / 数量 productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( totalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据不含税总价计算含税单价和数量 const calculateFromExclusiveTotalPrice = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const exclusiveTotalPrice = parseFloat(productForm.value.taxExclusiveTotalPrice); const quantity = parseFloat(productForm.value.quantity); const taxRate = parseFloat(productForm.value.taxRate); if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) { return; } isCalculating.value = true; // 先计算含税总价 = 不含税总价 / (1 - 税率/100) const taxRateDecimal = taxRate / 100; const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal); productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2); // 计算含税单价 = 含税总价 / 数量 productForm.value.taxInclusiveUnitPrice = (inclusiveTotalPrice / quantity).toFixed(2); isCalculating.value = false; }; // 根据数量变化计算总价 const calculateFromQuantity = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const quantity = parseFloat(productForm.value.quantity); const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); if (!quantity || quantity <= 0 || !unitPrice) { return; } isCalculating.value = true; // 计算含税总价 productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据含税单价变化计算总价 const calculateFromUnitPrice = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const quantity = parseFloat(productForm.value.quantity); const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); if (!quantity || quantity <= 0 || !unitPrice) { return; } isCalculating.value = true; // 计算含税总价 productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据税率变化计算不含税总价 const calculateFromTaxRate = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const inclusiveTotalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice); const taxRate = parseFloat(productForm.value.taxRate); if (!inclusiveTotalPrice || !taxRate) { return; } isCalculating.value = true; // 计算不含税总价 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( inclusiveTotalPrice, taxRate ); isCalculating.value = false; }; /** * 下载文件 * * @param row 下载文件的相关信息对象 */ const fileListRef = ref(null) const downLoadFile = (row) => { getSalesLedgerWithProducts({ id: row.id, type: 1 }).then((res) => { fileListRef.value.open(res.salesLedgerFiles) }); } // 打开发货弹框 const openDeliveryForm = (row) => { currentDeliveryRow.value = row; deliveryForm.value = { shippingDate: "", // 移除默认值设置 shippingCarNumber: "", }; deliveryFormVisible.value = true; }; // 提交发货表单 const submitDelivery = () => { proxy.$refs["deliveryFormRef"].validate((valid) => { if (valid) { addShippingInfo({ approverId:deliveryForm.value.approverId, salesLedgerId: currentDeliveryRow.value.salesLedgerId, salesLedgerProductId: currentDeliveryRow.value.id, shippingDate: deliveryForm.value.shippingDate, shippingCarNumber: deliveryForm.value.shippingCarNumber, }) .then(() => { proxy.$modal.msgSuccess("发货成功"); closeDeliveryDia(); getList(); }) .catch(() => { proxy.$modal.msgError("发货失败,请重试"); }); // 打印功能 const handlePrint = async () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("请选择要打印的数据"); return; } // 显示加载状态 proxy.$modal.loading("正在获取产品数据,请稍候..."); try { // 为每个选中的销售台账记录查询对应的产品数据 const printDataWithProducts = []; for (const row of selectedRows.value) { try { // 调用productList接口查询产品数据 const productRes = await productList({ salesLedgerId: row.id, type: 1, }); // 将产品数据整合到销售台账记录中 const rowWithProducts = { ...row, products: productRes.data || [], }; printDataWithProducts.push(rowWithProducts); } catch (error) { console.error(`获取销售台账 ${row.id} 的产品数据失败:`, error); // 即使某个记录的产品数据获取失败,也要包含该记录 printDataWithProducts.push({ ...row, products: [], }); } } printData.value = printDataWithProducts; console.log("打印数据(包含产品):", printData.value); printPreviewVisible.value = true; } catch (error) { console.error("获取产品数据失败:", error); proxy.$modal.msgError("获取产品数据失败,请重试"); } finally { proxy.$modal.closeLoading(); } }; // 执行打印 const executePrint = () => { console.log("开始执行打印,数据条数:", printData.value.length); console.log("打印数据:", printData.value); // 创建一个新的打印窗口 const printWindow = window.open("", "_blank", "width=800,height=600"); // 构建打印内容 let printContent = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>打印预览</title> <style> body { margin: 0; padding: 0; font-family: "SimSun", serif; background: white; } .print-page { width: 200mm; height: 75mm; padding: 10mm; padding-left: 20mm; background: white; box-sizing: border-box; page-break-after: always; page-break-inside: avoid; } .print-page:last-child { page-break-after: avoid; } .delivery-note { width: 100%; height: 100%; font-size: 12px; line-height: 1.2; display: flex; flex-direction: column; color: #000; } .header { text-align: center; margin-bottom: 8px; } .company-name { font-size: 18px; font-weight: bold; margin-bottom: 4px; } .document-title { font-size: 16px; font-weight: bold; } .info-section { margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; } .info-row { line-height: 20px; } .label { font-weight: bold; width: 60px; font-size: 12px; } .value { margin-right: 20px; min-width: 80px; font-size: 12px; } .table-section { margin-bottom: 40px; // flex: 0.6; } .product-table { width: 100%; border-collapse: collapse; border: 1px solid #000; } .product-table th, .product-table td { border: 1px solid #000; padding: 6px; text-align: center; font-size: 12px; line-height: 1.4; } .product-table th { font-weight: bold; } .total-value { font-weight: bold; } .footer-section { margin-top: auto; } .footer-row { display: flex; margin-bottom: 3px; line-height: 22px; justify-content: space-between; } .footer-item { display: flex; margin-right: 20px; } .footer-item .label { font-weight: bold; width: 80px; font-size: 12px; } .footer-item .value { min-width: 80px; font-size: 12px; } .address-item .address-value { min-width: 200px; } @media print { body { margin: 0; padding: 0; } .print-page { margin: 0; padding: 10mm; /* padding-left: 20mm; */ page-break-inside: avoid; page-break-after: always; } .print-page:last-child { page-break-after: avoid; } } </style> </head> <body> `; // 为每条数据生成打印页面 printData.value.forEach((item, index) => { printContent += ` <div class="print-page"> <div class="delivery-note"> <div class="header"> <div class="company-name">${ currentFactoryName.value }</div> <div class="document-title">零售发货单</div> </div> <div class="info-section"> <div class="info-row"> <div> <span class="label">发货日期:</span> <span class="value">${formatDate( item.createTime )}</span> </div> <div> <span class="label">客户名称:</span> <span class="value">${ item.customerName || "张爱有" }</span> </div> </div> <div class="info-row"> <span class="label">单号:</span> <span class="value">${ item.salesContractNo || "" }</span> </div> </div> <div class="table-section"> <table class="product-table"> <thead> <tr> <th>产品名称</th> <th>规格型号</th> <th>单位</th> <th>单价</th> <th>零售数量</th> <th>零售金额</th> </tr> </thead> <tbody> ${ item.products && item.products.length > 0 ? item.products .map( product => ` <tr> <td>${ product.productCategory || "" }</td> <td>${ product.specificationModel || "" }</td> <td>${product.unit || ""}</td> <td>${ product.taxInclusiveUnitPrice || "0" }</td> <td>${ product.quantity || "0" }</td> <td>${ product.taxInclusiveTotalPrice || "0" }</td> </tr> ` ) .join("") : '<tr><td colspan="6" style="text-align: center; color: #999;">暂无产品数据</td></tr>' } </tbody> <tfoot> <tr> <td class="label">合计</td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value"></td> <td class="total-value">${getTotalQuantityForPrint( item.products )}</td> <td class="total-value">${getTotalAmountForPrint( item.products )}</td> </tr> </tfoot> </table> </div> <div class="footer-section"> <div class="footer-row"> <div class="footer-item"> <span class="label">收货电话:</span> <span class="value"></span> </div> <div class="footer-item"> <span class="label">收货人:</span> <span class="value"></span> </div> <div class="footer-item address-item"> <span class="label">收货地址:</span> <span class="value address-value"></span> </div> </div> <div class="footer-row"> <div class="footer-item"> <span class="label">操作员:</span> <span class="value">${ userStore.nickName || "撕开前" }</span> </div> <div class="footer-item"> <span class="label">打印日期:</span> <span class="value">${formatDateTime( new Date() )}</span> </div> </div> </div> </div> </div> `; }); printContent += ` </body> </html> `; // 写入内容到新窗口 printWindow.document.write(printContent); printWindow.document.close(); // 等待内容加载完成后打印 printWindow.onload = () => { setTimeout(() => { printWindow.print(); printWindow.close(); printPreviewVisible.value = false; }, 500); }; }; // 格式化日期 const formatDate = dateString => { if (!dateString) return getCurrentDate(); const date = new Date(dateString); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); return `${year}/${month}/${day}`; }; // 格式化日期时间 const formatDateTime = date => { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDate()).padStart(2, "0"); const hours = String(date.getHours()).padStart(2, "0"); const minutes = String(date.getMinutes()).padStart(2, "0"); const seconds = String(date.getSeconds()).padStart(2, "0"); return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; }; // 获取当前日期并格式化为 YYYY-MM-DD function getCurrentDate() { const today = new Date(); const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, "0"); // 月份从0开始 const day = String(today.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; } // 计算产品总数量 const getTotalQuantity = products => { if (!products || products.length === 0) return "0"; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.quantity) || 0); }, 0); return total.toFixed(2); }; // 计算产品总金额 const getTotalAmount = products => { if (!products || products.length === 0) return "0"; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); }, 0); return total.toFixed(2); }; // 用于打印的计算函数 const getTotalQuantityForPrint = products => { if (!products || products.length === 0) return "0"; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.quantity) || 0); }, 0); return total.toFixed(2); }; const getTotalAmountForPrint = products => { if (!products || products.length === 0) return "0"; const total = products.reduce((sum, product) => { return sum + (parseFloat(product.taxInclusiveTotalPrice) || 0); }, 0); return total.toFixed(2); }; const mathNum = () => { console.log("productForm.value", productForm.value); if (!productForm.value.taxInclusiveUnitPrice) { return; } if (!productForm.value.quantity) { return; } // 含税总价计算 productForm.value.taxInclusiveTotalPrice = proxy.calculateTaxIncludeTotalPrice( productForm.value.taxInclusiveUnitPrice, productForm.value.quantity ); if (productForm.value.taxRate) { // 不含税总价计算 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } }; // 根据含税总价计算含税单价和数量 const calculateFromTotalPrice = () => { if (isCalculating.value) return; const totalPrice = parseFloat(productForm.value.taxInclusiveTotalPrice); const quantity = parseFloat(productForm.value.quantity); if (!totalPrice || !quantity || quantity <= 0) { return; } isCalculating.value = true; // 计算含税单价 = 含税总价 / 数量 productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( totalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据不含税总价计算含税单价和数量 const calculateFromExclusiveTotalPrice = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const exclusiveTotalPrice = parseFloat( productForm.value.taxExclusiveTotalPrice ); const quantity = parseFloat(productForm.value.quantity); const taxRate = parseFloat(productForm.value.taxRate); if (!exclusiveTotalPrice || !quantity || quantity <= 0 || !taxRate) { return; } isCalculating.value = true; // 先计算含税总价 = 不含税总价 / (1 - 税率/100) const taxRateDecimal = taxRate / 100; const inclusiveTotalPrice = exclusiveTotalPrice / (1 - taxRateDecimal); productForm.value.taxInclusiveTotalPrice = inclusiveTotalPrice.toFixed(2); // 计算含税单价 = 含税总价 / 数量 productForm.value.taxInclusiveUnitPrice = ( inclusiveTotalPrice / quantity ).toFixed(2); isCalculating.value = false; }; // 根据数量变化计算总价 const calculateFromQuantity = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const quantity = parseFloat(productForm.value.quantity); const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); if (!quantity || quantity <= 0 || !unitPrice) { return; } isCalculating.value = true; // 计算含税总价 productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据含税单价变化计算总价 const calculateFromUnitPrice = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const quantity = parseFloat(productForm.value.quantity); const unitPrice = parseFloat(productForm.value.taxInclusiveUnitPrice); if (!quantity || quantity <= 0 || !unitPrice) { return; } isCalculating.value = true; // 计算含税总价 productForm.value.taxInclusiveTotalPrice = (unitPrice * quantity).toFixed(2); // 如果有税率,计算不含税总价 if (productForm.value.taxRate) { productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice( productForm.value.taxInclusiveTotalPrice, productForm.value.taxRate ); } isCalculating.value = false; }; // 根据税率变化计算不含税总价 const calculateFromTaxRate = () => { if (!productForm.value.taxRate) { proxy.$modal.msgWarning("请先选择税率"); return; } if (isCalculating.value) return; const inclusiveTotalPrice = parseFloat( productForm.value.taxInclusiveTotalPrice ); const taxRate = parseFloat(productForm.value.taxRate); if (!inclusiveTotalPrice || !taxRate) { return; } isCalculating.value = true; // 计算不含税总价 productForm.value.taxExclusiveTotalPrice = proxy.calculateTaxExclusiveTotalPrice(inclusiveTotalPrice, taxRate); isCalculating.value = false; }; /** * 下载文件 * * @param row 下载文件的相关信息对象 */ const fileListRef = ref(null); const downLoadFile = row => { getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => { fileListRef.value.open(res.salesLedgerFiles); }); }; // 打开发货弹框 const openDeliveryForm = row => { currentDeliveryRow.value = row; deliveryForm.value = { shippingDate: "", // 移除默认值设置 shippingCarNumber: "", }; deliveryFormVisible.value = true; }; // 提交发货表单 const submitDelivery = () => { proxy.$refs["deliveryFormRef"].validate(valid => { if (valid) { addShippingInfo({ approverId: deliveryForm.value.approverId, salesLedgerId: currentDeliveryRow.value.salesLedgerId, salesLedgerProductId: currentDeliveryRow.value.id, shippingDate: deliveryForm.value.shippingDate, shippingCarNumber: deliveryForm.value.shippingCarNumber, }) .then(() => { proxy.$modal.msgSuccess("发货成功"); closeDeliveryDia(); getList(); }) .catch(() => { proxy.$modal.msgError("发货失败,请重试"); }); } }); }; // 关闭发货弹框 const closeDeliveryDia = () => { proxy.resetForm("deliveryFormRef"); deliveryFormVisible.value = false; currentDeliveryRow.value = null; }; onMounted(() => { // 设置录入日期范围默认值为当天 const today = dayjs().format("YYYY-MM-DD"); searchForm.entryDate = [today, today]; // 设置范围日期字段的起始和结束时间 searchForm.entryDateStart = today; searchForm.entryDateEnd = today; getList(); getcurrentFactoryName(); }); }; // 关闭发货弹框 const closeDeliveryDia = () => { proxy.resetForm("deliveryFormRef"); deliveryFormVisible.value = false; currentDeliveryRow.value = null; }; onMounted(() => { // 设置录入日期范围默认值为当天 const today = dayjs().format('YYYY-MM-DD'); searchForm.entryDate = [today, today]; // 设置范围日期字段的起始和结束时间 searchForm.entryDateStart = today; searchForm.entryDateEnd = today; getList(); }); </script> <style scoped lang="scss"> .ml-10 { margin-left: 10px; } .ml-10 { margin-left: 10px; } .table_list { margin-top: unset; } .table_list { margin-top: unset; } .actions { display: flex; justify-content: space-between; margin-bottom: 10px; } .print-preview-dialog { .el-dialog__body { padding: 0; max-height: 80vh; overflow-y: auto; } } .actions { display: flex; justify-content: space-between; margin-bottom: 10px; } .print-preview-dialog { .el-dialog__body { padding: 0; max-height: 80vh; overflow-y: auto; } } .print-preview-container { .print-preview-header { padding: 15px; border-bottom: 1px solid #e4e7ed; text-align: center; .el-button { margin: 0 10px; } } .print-preview-content { padding: 20px; background-color: #f5f5f5; min-height: 400px; } } .print-preview-container { .print-preview-header { padding: 15px; border-bottom: 1px solid #e4e7ed; text-align: center; .print-page { width: 220mm; height: 90mm; padding: 10mm; margin: 0 auto; background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); margin-bottom: 10px; box-sizing: border-box; } .el-button { margin: 0 10px; } } .delivery-note { width: 100%; height: 100%; font-family: "SimSun", serif; font-size: 10px; line-height: 1.2; display: flex; flex-direction: column; } .print-preview-content { padding: 20px; background-color: #f5f5f5; min-height: 400px; } } .header { text-align: center; margin-bottom: 8px; .company-name { font-size: 18px; font-weight: bold; margin-bottom: 4px; } .document-title { font-size: 16px; font-weight: bold; } } .print-page { width: 220mm; height: 90mm; padding: 10mm; margin: 0 auto; background: white; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); margin-bottom: 10px; box-sizing: border-box; } .info-section { margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; .info-row { line-height: 20px; .label { font-weight: bold; width: 60px; font-size: 14px; } .value { margin-right: 20px; min-width: 80px; font-size: 14px; } } } .delivery-note { width: 100%; height: 100%; font-family: "SimSun", serif; font-size: 10px; line-height: 1.2; display: flex; flex-direction: column; } .table-section { margin-bottom: 4px; flex: 1; .product-table { width: 100%; border-collapse: collapse; border: 1px solid #000; th, td { border: 1px solid #000; padding: 6px; text-align: center; font-size: 14px; line-height: 1.4; } th { font-weight: bold; } .total-label { text-align: right; font-weight: bold; } .total-value { font-weight: bold; } } } .header { text-align: center; margin-bottom: 8px; .footer-section { .footer-row { display: flex; margin-bottom: 3px; line-height: 20px; justify-content: space-between; .footer-item { display: flex; margin-right: 20px; .label { font-weight: bold; width: 80px; font-size: 14px; } .value { min-width: 80px; font-size: 14px; } &.address-item { .address-value { min-width: 200px; } } } } } .company-name { font-size: 18px; font-weight: bold; margin-bottom: 4px; } @media print { .app-container { display: none; } .print-page { box-shadow: none; margin: 0; padding: 10mm; padding-left: 20mm; page-break-inside: avoid; page-break-after: always; } .print-page:last-child { page-break-after: avoid; } } .document-title { font-size: 16px; font-weight: bold; } } .info-section { margin-bottom: 8px; display: flex; justify-content: space-between; align-items: center; .info-row { line-height: 20px; .label { font-weight: bold; width: 60px; font-size: 14px; } .value { margin-right: 20px; min-width: 80px; font-size: 14px; } } } .table-section { margin-bottom: 4px; flex: 1; .product-table { width: 100%; border-collapse: collapse; border: 1px solid #000; th, td { border: 1px solid #000; padding: 6px; text-align: center; font-size: 14px; line-height: 1.4; } th { font-weight: bold; } .total-label { text-align: right; font-weight: bold; } .total-value { font-weight: bold; } } } .footer-section { .footer-row { display: flex; margin-bottom: 3px; line-height: 20px; justify-content: space-between; .footer-item { display: flex; margin-right: 20px; .label { font-weight: bold; width: 80px; font-size: 14px; } .value { min-width: 80px; font-size: 14px; } &.address-item { .address-value { min-width: 200px; } } } } } @media print { .app-container { display: none; } .print-page { box-shadow: none; margin: 0; padding: 10mm; padding-left: 20mm; page-break-inside: avoid; page-break-after: always; } .print-page:last-child { page-break-after: avoid; } } </style>