src/api/basicData/product.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/utils/summarizeTable.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/basicData/product/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/procurementManagement/invoiceEntry/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/procurementManagement/procurementLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/basicData/product.js
@@ -8,4 +8,44 @@ method: 'get', params: query }) } // 产品树新增修改 export function addOrEditProduct(query) { return request({ url: '/basic/product/addOrEditProduct', method: 'post', data: query }) } // 规格型号新增修改 export function addOrEditProductModel(query) { return request({ url: '/basic/product/addOrEditProductModel', method: 'post', data: query }) } // 产品树删除 export function delProduct(query) { return request({ url: '/basic/product/delProduct', method: 'delete', data: query }) } // 规格型号删除 export function delProductModel(query) { return request({ url: '/basic/product/delProductModel', method: 'delete', data: query }) } // 规格型号查询 export function modelList(query) { return request({ url: '/basic/product/modelList', method: 'get', params: query }) } src/utils/summarizeTable.js
@@ -1,12 +1,11 @@ /** * 通用的表格合计方法 * @param {Object} param * @param {Array} param.columns 表格列配置 * @param {Array} param.data 数据源 * @param {Array<string>} summaryProps 需要汇总的字段名数组 * @param {Object} param - 包含表格列配置和数据源的对象 * @param {Array<string>} summaryProps - 需要汇总的字段名数组 * @param {Object} specialFormat - 特殊格式化规则:字段名 -> 格式化选项(如是否去掉小数) * @returns {Array} 合计行数据 */ const summarizeTable = (param, summaryProps) => { const summarizeTable = (param, summaryProps, specialFormat = {}) => { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { @@ -20,7 +19,13 @@ // 只对有效数字进行求和 if (!values.every(isNaN)) { const sum = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0); sums[index] = parseFloat(sum).toFixed(2); if (specialFormat[prop] && specialFormat[prop].noDecimal) { // 如果指定了不需要保留小数,则直接转换为整数 sums[index] = Math.round(sum).toString(); } else { // 默认保留两位小数 sums[index] = parseFloat(sum).toFixed(specialFormat[prop]?.decimalPlaces ?? 2); } } else { sums[index] = ''; } @@ -30,6 +35,5 @@ }); return sums; }; // 导出函数供其他文件使用 export { summarizeTable }; src/views/basicData/product/index.vue
@@ -14,9 +14,10 @@ <el-button type="primary" @click="openProDia('add')" style="margin-left: 10px">新增产品</el-button> </div> <div> <el-tree ref="tree" v-loading="treeLoad" :data="list" <el-tree ref="tree" v-loading="treeLoad" :data="list" @node-click="handleNodeClick" :expand-on-click-node="false" :default-expanded-keys="expandedKeys" :draggable="true" :filter-node-method="filterNode" :props="{ children: 'children', label: 'label' }" highlight-current node-key="label" :props="{ children: 'children', label: 'label' }" highlight-current node-key="id" style="height: calc(100vh - 190px);overflow-y: scroll;scrollbar-width: none;"> <template #default="{ node, data }"> <div class="custom-tree-node"> @@ -43,13 +44,13 @@ </div> <div class="right"> <div style="margin-bottom: 10px"> <el-button type="primary" @click="modelDia = true">新增规格型号</el-button> <el-button type="primary" @click="openModelDia('add')">新增规格型号</el-button> <el-button type="danger" @click="handleDelete" style="margin-left: 10px" plain>删除</el-button> </div> <PIMTable :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" :handleSelectionChange="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination" :total="total"></PIMTable> </div> <el-dialog :visible.sync="productDia" title="产品" width="400px"> <el-dialog v-model="productDia" title="产品" width="400px"> <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row :gutter="30"> <el-col :span="24"> @@ -66,17 +67,52 @@ </div> </template> </el-dialog> <el-dialog v-model="modelDia" title="产品" width="400px"> <el-form :model="modelForm" label-width="140px" label-position="top" :rules="modelRules" ref="modelFormRef"> <el-row> <el-col :span="24"> <el-form-item label="规格型号:" prop="model"> <el-input v-model="modelForm.model" placeholder="请输入规格型号" clearable/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="单位:" prop="unit"> <el-input v-model="modelForm.unit" placeholder="请输入单位" clearable/> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitModelForm">确认</el-button> <el-button @click="closeProDia">取消</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import {ref} from "vue"; import {listCustomer} from "@/api/basicData/customerFile.js"; import {ElMessageBox} from "element-plus"; import {productTreeList} from "@/api/basicData/product.js"; import { addOrEditProduct, addOrEditProductModel, delProduct, delProductModel, modelList, productTreeList } from "@/api/basicData/product.js"; const { proxy } = getCurrentInstance() const productDia = ref(false) const modelDia = ref(false) const modelOperationType = ref('') const search = ref('') const currentId = ref('') const currentParentId = ref('') const operationType = ref('') const treeLoad = ref(false) const list = ref([]) const expandedKeys = ref([]) @@ -87,7 +123,7 @@ }, { label: '单位', prop: 'model', prop: 'unit', }, { dataType: "action", @@ -98,7 +134,7 @@ name: "编辑", type: "text", clickFun: (row) => { openForm('edit', row); openModelDia('edit', row); }, }, ], @@ -112,17 +148,24 @@ current: 1, size: 10, }) const productDia = ref(false) const modelDia = ref(false) const data = reactive({ form: { productName: '', }, rules: { productName: [{ required: true, message: "请输入", trigger: "blur" }], }, modelForm: { model: '', unit: '', }, modelRules: { model: [{ required: true, message: "请输入", trigger: "blur" }], unit: [{ required: true, message: "请输入", trigger: "blur" }], } }) const { form, rules } = toRefs(data) const { form, rules, modelForm, modelRules } = toRefs(data) // 查询产品树 const getProductTreeList = () => { treeLoad.value = true; productTreeList().then(res => { @@ -135,27 +178,122 @@ treeLoad.value = false; }) } // 过滤产品树 const searchFilter = () => { proxy.$refs.tree.filter(search.value); } // 打开产品弹框 const openProDia = (type, data) => { operationType.value = type; productDia.value = true console.log('openEditDia', data) form.value.productName = '' if (type === 'edit') { form.value.productName = data.productName } } // 打开规格型号弹框 const openModelDia = (type, data) => { modelOperationType.value = type; modelDia.value = true modelForm.value.model = '' modelForm.value.model = '' modelForm.value.id = '' if (type === 'edit') { modelForm.value = {...data} } } // 提交产品名称修改 const submitForm = () => { proxy.$refs.formRef.validate(valid => { if (valid) { if (operationType.value === 'add') { form.value.parentId = currentId.value form.value.id = '' } else { form.value.id = currentId.value form.value.parentId = '' } addOrEditProduct(form.value).then(res => { proxy.$modal.msgSuccess("提交成功") closeProDia() getProductTreeList() }) } }) } // 关闭产品弹框 const closeProDia = () => { proxy.$refs.formRef.resetFields(); productDia.value = false; } const remove = (value) => { // 删除产品 const remove = (node, data) => { let ids = [] ids.push(data.id) ElMessageBox.confirm( '选中的内容将被删除,是否确认删除?', '删除提示', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', } ).then(() => { tableLoading.value = true delProduct(ids).then(res => { proxy.$modal.msgSuccess("删除成功") getProductTreeList() }).finally(() => { tableLoading.value = false }) }).catch(() => { proxy.$modal.msg("已取消") }) } // 选择产品 const handleNodeClick = (val, node, el) => { currentId.value = val.id currentParentId.value = val.parentId getModelList() } // 提交规格型号修改 const submitModelForm = () => { proxy.$refs.modelFormRef.validate(valid => { if (valid) { modelForm.value.productId = currentId.value addOrEditProductModel(modelForm.value).then(res => { proxy.$modal.msgSuccess("提交成功") closeModelDia() getModelList() }) } }) } // 关闭产品弹框 const closeModelDia = () => { proxy.$refs.modelFormRef.resetFields(); modelDia.value = false; } // 表格选择数据 const handleSelectionChange = (selection) => { selectedRows.value = selection } // 删除 // 查询规格型号 const pagination = ({ current, limit }) => { page.current = current; page.size = limit; getModelList() } const getModelList = () => { tableLoading.value = true modelList({id: currentId.value}).then(res => { tableLoading.value = false tableData.value = res }) } // 删除规格型号 const handleDelete = () => { let ids = [] if (selectedRows.value.length > 0) { @@ -173,28 +311,14 @@ } ).then(() => { tableLoading.value = true delCustomer(ids).then(res => { delProductModel(ids).then(res => { proxy.$modal.msgSuccess("删除成功") getList() getModelList() }).finally(() => { tableLoading.value = false }) }).catch(() => { proxy.$modal.msg("已取消") }) } // 查询规格型号 const pagination = ({ current, limit }) => { page.current = current; page.size = limit; getList() } const getList = () => { tableLoading.value = true listCustomer({...searchForm.value, ...page}).then(res => { tableLoading.value = false tableData.value = res.rows total.value = res.total }) } // 调用tree过滤方法 中文英过滤 src/views/procurementManagement/invoiceEntry/index.vue
@@ -40,13 +40,13 @@ <el-table-column label="单位" prop="unit" /> <el-table-column label="数量" prop="quantity" /> <el-table-column label="税率(%)" prop="taxRate" /> <el-table-column label="含税单价(元)" prop="taxInclusiveUnitPrice" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" /> <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" /> <el-table-column label="本次来票金额(元)" prop="ticketsAmount" /> <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber"/> <el-table-column label="未来票数" prop="futureTickets" /> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" /> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber"/> </el-table> </template> </el-table-column> @@ -55,7 +55,7 @@ <el-table-column label="销售合同号" prop="salesContractNo" show-overflow-tooltip/> <el-table-column label="供应商名称" prop="supplierName" show-overflow-tooltip/> <el-table-column label="项目名称" prop="projectName" show-overflow-tooltip/> <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip/> <el-table-column label="合同金额(元)" prop="contractAmount" show-overflow-tooltip :formatter="formattedNumber"/> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button> @@ -97,42 +97,25 @@ <el-form-item label="产品信息:" prop="entryDate"> </el-form-item> </el-row> <el-table :data="productData" border @selection-change="productSelected"> <el-table :data="productData" border @selection-change="productSelected" 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" /> <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" /> <el-table-column label="不含税总价(元)" prop="taxExclusiveTotalPrice" /> <el-table-column label="本次来票数" prop="ticketsNum"> <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="170"> <template #default="scope"> <el-input :disabled="!scope.row.editFlag" v-model="scope.row.ticketsNum"></el-input> <el-input-number v-model="scope.row.ticketsNum" :precision="0" :step="1" clearable style="width: 100%"/> </template> </el-table-column> <el-table-column label="本次来票金额(元)" prop="ticketsAmount"> <template #default="scope"> <el-input :disabled="!scope.row.editFlag" v-model="scope.row.ticketsAmount"></el-input> </template> </el-table-column> <el-table-column label="未来票数" prop="futureTickets"> <template #default="scope"> <el-input :disabled="!scope.row.editFlag" v-model="scope.row.futureTickets"></el-input> </template> </el-table-column> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount"> <template #default="scope"> <el-input :disabled="!scope.row.editFlag" v-model="scope.row.futureTicketsAmount"></el-input> </template> </el-table-column> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button v-if="!scope.row.editFlag" link type="primary" size="small" @click="openProductEdit(scope.row);">编辑</el-button> <el-button v-else link type="primary" size="small" @click="openProductEdit(scope.row);">保存</el-button> </template> </el-table-column> <el-table-column label="本次来票金额(元)" prop="ticketsAmount" :formatter="formattedNumber"></el-table-column> <el-table-column label="未来票数" prop="futureTickets"></el-table-column> <el-table-column label="未来票金额(元)" prop="futureTicketsAmount" :formatter="formattedNumber"> </el-table-column> </el-table> </el-form> <template #footer> @@ -219,6 +202,9 @@ tableLoading.value = false }) } const formattedNumber = (row, column, cellValue) => { return parseFloat(cellValue).toFixed(2); }; // 表格选择数据 const handleSelectionChange = (selection) => { selectedRows.value = selection @@ -248,49 +234,17 @@ } // 主表合计方法 const summarizeMainTable = (param) => { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计'; return; } const prop = column.property; if (['contractAmount'].includes(prop)) { const values = data.map(item => Number(item[prop])); if (!values.every(value => isNaN(value))) { sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0); } else { sums[index] = ''; } } else { sums[index] = ''; } }) return sums; return proxy.summarizeTable(param, ['contractAmount'], { ticketsNum: { noDecimal: true }, // 不保留小数 futureTickets: { noDecimal: true }, // 不保留小数 }); }; // 子表合计方法 const summarizeChildrenTable = (param) => { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计'; return; } const prop = column.property; if (['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'].includes(prop)) { const values = data.map(item => Number(item[prop])); if (!values.every(value => isNaN(value))) { sums[index] = values.reduce((acc, val) => (!isNaN(val) ? acc + val : acc), 0); } else { sums[index] = ''; } } else { sums[index] = ''; } }); return sums; return proxy.summarizeTable(param, ['taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice', 'ticketsNum', 'ticketsAmount', 'futureTickets', 'futureTicketsAmount'],{ ticketsNum: { noDecimal: true }, // 不保留小数 futureTickets: { noDecimal: true }, // 不保留小数 }); } // 打开弹框 const openForm = (type, row) => { src/views/procurementManagement/procurementLedger/index.vue
@@ -184,9 +184,15 @@ <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="产品大类:" prop="productCategory"> <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-form-item> </el-col> </el-row> @@ -194,7 +200,7 @@ <el-col :span="24"> <el-form-item label="规格型号:" prop="specificationModel"> <el-select v-model="productForm.specificationModel" placeholder="请选择" clearable> <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id"/> </el-select> </el-form-item> </el-col> @@ -282,7 +288,9 @@ 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) @@ -293,6 +301,7 @@ const total = ref(0) const fileList = ref([]) import useUserStore from "@/store/modules/user" import {modelList, productTreeList} from "@/api/basicData/product.js"; const userStore = useUserStore() @@ -528,6 +537,31 @@ productForm.value = {...row} } productFormVisible.value = true getProductOptions() } const getProductOptions = () => { productTreeList().then(res => { productOptions.value = convertIdToValue(res) }) } const getModels =(value) => { modelList({id: value}).then(res => { modelOptions.value = res }) } 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 = () => {