From 1ed11ff9b539891e92f73940772b680497bda98f Mon Sep 17 00:00:00 2001 From: chenrui <1187576398@qq.com> Date: 星期二, 20 五月 2025 15:36:23 +0800 Subject: [PATCH] Merge remote-tracking branch 'origin/dev' into dev --- src/views/procurementManagement/procurementLedger/index.vue | 42 +++++ src/api/basicData/product.js | 40 +++++ src/views/basicData/product/index.vue | 184 ++++++++++++++++++++++---- src/views/procurementManagement/invoiceEntry/index.vue | 100 +++---------- src/utils/summarizeTable.js | 18 +- 5 files changed, 270 insertions(+), 114 deletions(-) diff --git a/src/api/basicData/product.js b/src/api/basicData/product.js index b9260e6..1cf7625 100644 --- a/src/api/basicData/product.js +++ b/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 + }) } \ No newline at end of file diff --git a/src/utils/summarizeTable.js b/src/utils/summarizeTable.js index 6013def..3b3a178 100644 --- a/src/utils/summarizeTable.js +++ b/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 }; \ No newline at end of file diff --git a/src/views/basicData/product/index.vue b/src/views/basicData/product/index.vue index 0275185..dba78e3 100644 --- a/src/views/basicData/product/index.vue +++ b/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杩囨护鏂规硶 涓枃鑻辫繃婊� diff --git a/src/views/procurementManagement/invoiceEntry/index.vue b/src/views/procurementManagement/invoiceEntry/index.vue index bebd18d..c1254af 100644 --- a/src/views/procurementManagement/invoiceEntry/index.vue +++ b/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) => { diff --git a/src/views/procurementManagement/procurementLedger/index.vue b/src/views/procurementManagement/procurementLedger/index.vue index 887f786..1352682 100644 --- a/src/views/procurementManagement/procurementLedger/index.vue +++ b/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 = () => { -- Gitblit v1.9.3