| src/api/salesManagement/reverseAuditHistory.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/receiptManagement/Record.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/reverseAuditHistory/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/salesManagement/reverseAuditHistory.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,27 @@ import request from "@/utils/request"; // å页æ¥è¯¢å审åå² export function reverseAuditHistoryList(query) { return request({ url: "/sales/ledger/reverseAuditHistory/list", method: "get", params: query, }); } // ä¿ååå®¡å¿«ç § export function saveReverseAuditSnapshot(data) { return request({ url: "/sales/ledger/reverseAuditHistory/save", method: "post", data, }); } // è·åå¿«ç §è¯¦æ export function getReverseAuditSnapshotDetail(id) { return request({ url: `/sales/ledger/reverseAuditHistory/${id}`, method: "get", }); } src/views/inventoryManagement/receiptManagement/Record.vue
@@ -9,26 +9,26 @@ value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable @change="handleQuery"/> @change="handleQuery" /> <span class="search_title ml10">产å大类ï¼</span> <el-input v-model="searchForm.productName" style="width: 240px" placeholder="请è¾å ¥" clearable/> clearable /> <span class="search_title ml10">ååå·ï¼</span> <el-input v-model="searchForm.salesContractNo" style="width: 240px" placeholder="请è¾å ¥ååå·" clearable/> clearable /> <span class="search_title ml10">æ¥æºï¼</span> <el-select v-model="searchForm.recordType" style="width: 240px" placeholder="è¯·éæ©" clearable> style="width: 240px" placeholder="è¯·éæ©" clearable> <el-option v-for="item in stockRecordTypeOptions" :key="item.value" :label="item.label" :value="item.value"/> :value="item.value" /> </el-select> <el-button type="primary" @click="handleQuery" @@ -54,40 +54,40 @@ height="calc(100vh - 18.5em)"> <el-table-column align="center" type="selection" width="55"/> width="55" /> <el-table-column align="center" label="åºå·" type="index" width="60"/> width="60" /> <el-table-column label="å ¥åºæ¹æ¬¡" prop="inboundBatches" width="280" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="ååå·" prop="salesContractNo" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="å ¥åºæ¶é´" prop="createTime" :formatter="formatTableDateYmd" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="产å大类" prop="productName" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip/> <el-table-column label="å度(mm)" prop="thickness" show-overflow-tooltip /> show-overflow-tooltip /> <el-table-column label="å度(mm)" prop="thickness" show-overflow-tooltip /> <el-table-column label="åä½" prop="unit" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="å ¥åºæ°é" prop="stockInNum" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="å ¥åºäºº" prop="createBy" show-overflow-tooltip/> show-overflow-tooltip /> <el-table-column label="æ¥æº" prop="recordType" show-overflow-tooltip> @@ -101,170 +101,171 @@ layout="total, sizes, prev, pager, next, jumper" :page="page.current" :limit="page.size" @pagination="pageProductChange"/> @pagination="pageProductChange" /> </div> </div> </template> <script setup> import pagination from "@/components/PIMTable/Pagination.vue"; import { ref, reactive, toRefs, onMounted, getCurrentInstance, } from "vue"; import {ElMessageBox} from "element-plus"; import { getStockInRecordListPage, batchDeleteStockInRecords, } from "@/api/inventoryManagement/stockInRecord.js"; import { findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions, } from "@/api/basicData/enum.js"; import {parseTime} from "@/utils/ruoyi"; import pagination from "@/components/PIMTable/Pagination.vue"; import { ref, reactive, toRefs, onMounted, getCurrentInstance } from "vue"; import { ElMessageBox } from "element-plus"; import { getStockInRecordListPage, batchDeleteStockInRecords, } from "@/api/inventoryManagement/stockInRecord.js"; import { findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions, } from "@/api/basicData/enum.js"; import { parseTime } from "@/utils/ruoyi"; const {proxy} = getCurrentInstance(); const { proxy } = getCurrentInstance(); const formatTableDateYmd = (row, column, cellValue) => { if (cellValue == null || cellValue === "") { return ""; } return parseTime(cellValue, "{y}-{m}-{d}") || ""; }; const formatTableDateYmd = (row, column, cellValue) => { if (cellValue == null || cellValue === "") { return ""; } return parseTime(cellValue, "{y}-{m}-{d}") || ""; }; const props = defineProps({ type: { type: String, required: true, default: '0' } }) const props = defineProps({ type: { type: String, required: true, default: "0", }, }); const tableData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); // æ¥æºç±»åé项 const stockRecordTypeOptions = ref([]); const page = reactive({ current: 1, size: 10, }); const total = ref(0); const tableData = ref([]); const selectedRows = ref([]); const tableLoading = ref(false); // æ¥æºç±»åé项 const stockRecordTypeOptions = ref([]); const page = reactive({ current: 1, size: 10, }); const total = ref(0); const data = reactive({ searchForm: { productName: "", salesContractNo: "", timeStr: "", recordType: "", }, }); const {searchForm} = toRefs(data); // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); }; const data = reactive({ searchForm: { productName: "", salesContractNo: "", timeStr: "", recordType: "", }, }); const { searchForm } = toRefs(data); // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); }; const getRecordType = (recordType) => { return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' } const getRecordType = recordType => { return ( stockRecordTypeOptions.value.find(item => item.value === recordType) ?.label || "" ); }; const pageProductChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const pageProductChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; const params = {...page, type: props.type}; params.timeStr = searchForm.value.timeStr; params.productName = searchForm.value.productName; params.salesContractNo = searchForm.value.salesContractNo; params.recordType = searchForm.value.recordType; getStockInRecordListPage(params) const getList = () => { tableLoading.value = true; const params = { ...page, type: props.type }; params.timeStr = searchForm.value.timeStr; params.productName = searchForm.value.productName; params.salesContractNo = searchForm.value.salesContractNo; params.recordType = searchForm.value.recordType; getStockInRecordListPage(params) .then(res => { tableData.value = res.data.records; total.value = res.data.total || 0; }).finally(() => { tableLoading.value = false; }) }; // è·åæ¥æºç±»åé项 const fetchStockRecordTypeOptions = () => { if (props.type === '0') { findAllQualifiedStockInRecordTypeOptions() .then(res => { stockRecordTypeOptions.value = res.data; }) return } findAllUnQualifiedStockInRecordTypeOptions() .then(res => { stockRecordTypeOptions.value = res.data; }) } .finally(() => { tableLoading.value = false; }); }; // è¡¨æ ¼éæ©æ°æ® const handleSelectionChange = selection => { selectedRows.value = selection.filter(item => item.id); }; // è·åæ¥æºç±»åé项 const fetchStockRecordTypeOptions = () => { if (props.type === "0") { findAllQualifiedStockInRecordTypeOptions().then(res => { stockRecordTypeOptions.value = res.data; }); return; } findAllUnQualifiedStockInRecordTypeOptions().then(res => { stockRecordTypeOptions.value = res.data; }); }; const expandedRowKeys = ref([]); // è¡¨æ ¼éæ©æ°æ® const handleSelectionChange = selection => { selectedRows.value = selection.filter(item => item.id); }; // å¯¼åº const handleOut = () => { ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) const expandedRowKeys = ref([]); // å¯¼åº const handleOut = () => { ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) .then(() => { // æ ¹æ®ä¸åç tab ç±»åè°ç¨ä¸åçå¯¼åºæ¥å£ proxy.download("/stockInRecord/exportStockInRecord", {type: props.type}, props.type === '0' ? "åæ ¼å ¥åº.xlsx" : "ä¸åæ ¼å ¥åº.xlsx"); proxy.download( "/stockInRecord/exportStockInRecord", { type: props.type }, props.type === "0" ? "åæ ¼å ¥åº.xlsx" : "ä¸åæ ¼å ¥åº.xlsx" ); }) .catch(() => { proxy.$modal.msg("已忶"); }); }; }; // å é¤ const handleDelete = () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); return; } const ids = selectedRows.value.map(item => item.id); // å é¤ const handleDelete = () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); return; } const ids = selectedRows.value.map(item => item.id); ElMessageBox.confirm("éä¸çå 容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) ElMessageBox.confirm("éä¸çå 容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) .then(() => { batchDeleteStockInRecords(ids) .then(() => { proxy.$modal.msgSuccess("å 餿å"); getList(); }) .catch(() => { proxy.$modal.msgError("å é¤å¤±è´¥"); }); .then(() => { proxy.$modal.msgSuccess("å 餿å"); getList(); }) .catch(() => { proxy.$modal.msgError("å é¤å¤±è´¥"); }); }) .catch(() => { proxy.$modal.msg("已忶"); }); }; }; onMounted(() => { getList(); fetchStockRecordTypeOptions(); }); onMounted(() => { getList(); fetchStockRecordTypeOptions(); }); </script> <style scoped lang="scss"></style> src/views/salesManagement/reverseAuditHistory/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,472 @@ <template> <div class="app-container"> <div class="search_form"> <el-form :model="searchForm" :inline="true"> <el-form-item label="客æ·åç§°ï¼"> <el-select v-model="searchForm.customerId" filterable placeholder="è¯·éæ©å®¢æ·åç§°" clearable style="width: 220px" @change="handleQuery"> <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.id"> {{ item.customerName + "ââ" + item.taxpayerIdentificationNumber }} </el-option> </el-select> </el-form-item> <el-form-item label="éå®ååå·ï¼"> <el-input v-model="searchForm.salesContractNo" placeholder="请è¾å ¥" clearable @change="handleQuery" /> </el-form-item> <el-form-item label="项ç®åç§°ï¼"> <el-input v-model="searchForm.projectName" placeholder="请è¾å ¥" clearable @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="handleQuery" /> </el-form-item> <el-form-item> <el-button type="primary" @click="handleQuery">æç´¢</el-button> <el-button @click="resetQuery">éç½®</el-button> </el-form-item> </el-form> </div> <div class="table_list"> <el-table :data="tableData" border v-loading="loading"> <el-table-column label="åºå·" type="index" width="60" align="center" /> <el-table-column label="å审æ¶é´" prop="counterReviewTime" align="center"> <template #default="scope"> {{ formatTime(scope.row.counterReviewTime) }} </template> </el-table-column> <el-table-column label="å审人" prop="counterReviewPerson" align="center" /> <el-table-column label="éå®ååå·" prop="salesContractNo" /> <el-table-column label="客æ·åç§°" prop="customerName" show-overflow-tooltip /> <el-table-column label="项ç®åç§°" prop="projectName" show-overflow-tooltip /> <el-table-column label="ååéé¢(å )" prop="contractAmount" align="right"> <template #default="scope"> {{ formattedNumber(null, null, scope.row.contractAmount) }} </template> </el-table-column> <el-table-column label="æä½" width="100" align="center" fixed="right"> <template #default="scope"> <el-button link type="primary" @click="handleView(scope.row)">æ¥çå¿«ç §</el-button> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" :page="page.current" :limit="page.size" @pagination="paginationChange" /> </div> <!-- å¿«ç §è¯¦æ å¯¹è¯æ¡ --> <el-dialog v-model="dialogVisible" title="åå®¡æ°æ®å¿«ç §è¯¦æ " width="85%"> <div class="snapshot-detail"> <el-divider content-position="left">åºæ¬ä¿¡æ¯</el-divider> <el-descriptions border :column="3"> <el-descriptions-item label="éå®ååå·">{{ currentSnapshot.salesContractNo }}</el-descriptions-item> <el-descriptions-item label="ä¸å¡å">{{ currentSnapshot.salesman }}</el-descriptions-item> <el-descriptions-item label="客æ·åç§°">{{ currentSnapshot.customerName }}</el-descriptions-item> <el-descriptions-item label="项ç®åç§°">{{ currentSnapshot.projectName }}</el-descriptions-item> <el-descriptions-item label="ç¾è®¢æ¥æ">{{ currentSnapshot.executionDate }}</el-descriptions-item> <el-descriptions-item label="äº¤è´§æ¥æ">{{ currentSnapshot.deliveryDate }}</el-descriptions-item> <el-descriptions-item label="å½å ¥äºº">{{ currentSnapshot.entryPersonName || currentSnapshot.entryPerson }}</el-descriptions-item> <el-descriptions-item label="å½å ¥æ¥æ">{{ currentSnapshot.entryDate }}</el-descriptions-item> <el-descriptions-item label="ååéé¢(å )">{{ formattedNumber(null, null, currentSnapshot.contractAmount) }}</el-descriptions-item> <el-descriptions-item label="å审æ¶é´">{{ formatTime(currentSnapshot.counterReviewTime) }}</el-descriptions-item> <el-descriptions-item label="å审人">{{ currentSnapshot.counterReviewPerson }}</el-descriptions-item> </el-descriptions> <el-divider content-position="left" style="margin-top: 30px;">产åä¿¡æ¯</el-divider> <el-table :data="currentSnapshot.productData" border stripe show-summary :summary-method="summarizeMainTable"> <el-table-column align="center" label="åºå·" type="index" width="60" /> <el-table-column label="产å大类" prop="productCategory" min-width="120" show-overflow-tooltip /> <el-table-column label="è§æ ¼åå·" prop="specificationModel" min-width="150" show-overflow-tooltip /> <el-table-column label="å度(mm)" prop="thickness" width="90" align="center" /> <el-table-column label="楼å±ç¼å·" prop="floorCode" min-width="120" show-overflow-tooltip /> <el-table-column label="å«ç¨åä»·(å )" prop="taxInclusiveUnitPrice" width="110" align="right"> <template #default="scope"> {{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }} </template> </el-table-column> <el-table-column label="宽(mm)" prop="width" width="80" align="center" /> <el-table-column label="é«(mm)" prop="height" width="80" align="center" /> <el-table-column label="æ°é" prop="quantity" width="80" align="center" /> <el-table-column label="ç»ç®åçé¢ç§¯(ã¡)" prop="settlePieceArea" width="130" align="center"> <template #default="scope"> {{ scope.row.settlePieceArea ? Number(scope.row.settlePieceArea).toFixed(4) : "" }} </template> </el-table-column> <el-table-column label="é¢ç§¯(m²)" prop="actualTotalArea" width="110" align="center"> <template #default="scope"> {{ scope.row.actualTotalArea ? Number(scope.row.actualTotalArea).toFixed(4) : "" }} </template> </el-table-column> <el-table-column label="ç¨ç(%)" prop="taxRate" width="80" align="center" /> <el-table-column label="å«ç¨æ»ä»·(å )" prop="taxInclusiveTotalPrice" width="110" align="right"> <template #default="scope"> {{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }} </template> </el-table-column> <el-table-column label="ä¸å«ç¨æ»ä»·(å )" prop="taxExclusiveTotalPrice" width="110" align="right"> <template #default="scope"> {{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }} </template> </el-table-column> <el-table-column label="å å·¥è¦æ±" prop="processRequirement" min-width="150" show-overflow-tooltip /> <el-table-column label="å票类å" prop="invoiceType" width="100" align="center" /> <el-table-column label="é¢å¤å å·¥" min-width="180"> <template #default="scope"> <div v-if="scope.row.salesProductProcessList && scope.row.salesProductProcessList.length > 0"> <el-tag v-for="(item, idx) in scope.row.salesProductProcessList" :key="idx" size="small" type="info" style="margin: 2px;"> {{ item.processName }} ({{ item.quantity }}) </el-tag> </div> </template> </el-table-column> <el-table-column label="夿³¨" prop="remark" min-width="120" show-overflow-tooltip /> <el-table-column label="éç®±" prop="heavyBox" width="100" show-overflow-tooltip /> </el-table> <el-row :gutter="30" style="margin-top: 20px;"> <el-col :span="12"> <div class="remark-section"> <div class="label">夿³¨ï¼</div> <div class="content">{{ currentSnapshot.remarks || "æ " }}</div> </div> </el-col> <el-col :span="12"> <div class="remark-section"> <div class="label">客æ·å¤æ³¨ï¼</div> <div class="content">{{ currentSnapshot.customerRemarks || "æ " }}</div> </div> </el-col> </el-row> </div> <template #footer> <el-button @click="dialogVisible = false">å ³é</el-button> </template> </el-dialog> </div> </template> <script setup> import { ref, reactive, onMounted, getCurrentInstance } from "vue"; import { customerList, ledgerListPage, getSalesLedgerWithProducts, } from "@/api/salesManagement/salesLedger.js"; import pagination from "@/components/PIMTable/Pagination.vue"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance(); const loading = ref(false); const tableData = ref([]); const total = ref(0); const dialogVisible = ref(false); const currentSnapshot = ref({}); const customerOption = ref([]); const searchForm = reactive({ customerId: undefined, salesContractNo: "", projectName: "", width: undefined, height: undefined, entryDate: [], deliveryStatus: undefined, stockStatus: undefined, reverseAuditDate: [], }); const page = reactive({ current: 1, size: 10, }); const getList = () => { loading.value = true; const params = { ...page, salesContractNo: searchForm.salesContractNo, projectName: searchForm.projectName, width: searchForm.width, height: searchForm.height, deliveryStatus: searchForm.deliveryStatus, stockStatus: searchForm.stockStatus, reviewStatus: 2, // åºå®ä¼ 2 beginTime: searchForm.reverseAuditDate?.[0], endTime: searchForm.reverseAuditDate?.[1], entryDateStart: searchForm.entryDate?.[0], entryDateEnd: searchForm.entryDate?.[1], }; // æ¥è¯¢å®¢æ·åç§°ä¸å°è´¦ä¿æä¸è´ï¼å é customerIdï¼åæ å°ä¸º customerName æ¥è¯¢ const selectedCustomer = (customerOption.value || []).find( item => String(item?.id ?? "") === String(searchForm.customerId ?? "") ); if (selectedCustomer?.customerName) { params.customerName = String(selectedCustomer.customerName).trim(); } ledgerListPage(params) .then(res => { tableData.value = res.records || []; total.value = res.total || 0; }) .catch(err => { console.error("è·åå审åå²å¤±è´¥:", err); tableData.value = []; total.value = 0; }) .finally(() => { loading.value = false; }); }; const handleQuery = () => { page.current = 1; getList(); }; const paginationChange = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const resetQuery = () => { searchForm.customerId = undefined; searchForm.salesContractNo = ""; searchForm.projectName = ""; searchForm.width = undefined; searchForm.height = undefined; searchForm.entryDate = []; searchForm.deliveryStatus = undefined; searchForm.stockStatus = undefined; searchForm.reverseAuditDate = []; page.current = 1; handleQuery(); }; const getCustomerOption = () => { customerList().then(res => { customerOption.value = res || []; }); }; const handleView = row => { getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => { currentSnapshot.value = { ...res }; // åæ®µåå ¼å®¹å¤çï¼ä¸éå®å°è´¦ä¿æä¸è´ currentSnapshot.value.customerRemarks = res?.customerRemarks ?? res?.customer_remarks ?? ""; dialogVisible.value = true; }); }; const formattedNumber = (row, column, cellValue) => { if (cellValue == null || cellValue === "") return "0.00"; return Number(cellValue).toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2, }); }; const formatTime = time => { if (!time) return ""; return dayjs(time).format("YYYY-MM-DD HH:mm:ss"); }; const summarizeMainTable = param => { const { columns, data } = param; const sums = []; columns.forEach((column, index) => { if (index === 0) { sums[index] = "å计"; return; } const prop = column.property; if ( [ "quantity", "actualTotalArea", "taxInclusiveTotalPrice", "taxExclusiveTotalPrice", ].includes(prop) ) { const values = data.map(item => Number(item[prop])); if (!values.every(value => isNaN(value))) { const sum = values.reduce((prev, curr) => { const value = Number(curr); if (!isNaN(value)) { return prev + curr; } else { return prev; } }, 0); if (prop === "quantity") { sums[index] = sum; } else if (prop === "actualTotalArea") { sums[index] = sum.toFixed(4); } else { sums[index] = sum.toLocaleString("zh-CN", { minimumFractionDigits: 2, maximumFractionDigits: 2, }); } } else { sums[index] = ""; } } else { sums[index] = ""; } }); return sums; }; onMounted(() => { getCustomerOption(); getList(); }); </script> <style scoped lang="scss"> .app-container { padding: 20px; } .search_form { margin-bottom: 20px; } .table_list { background: #fff; padding: 20px; border-radius: 4px; } .snapshot-detail { max-height: 70vh; overflow-y: auto; padding-right: 10px; .remark-section { margin-bottom: 15px; .label { font-weight: bold; color: #606266; margin-bottom: 8px; } .content { padding: 10px; background-color: #f5f7fa; border-radius: 4px; min-height: 40px; white-space: pre-wrap; } } } </style> src/views/salesManagement/salesLedger/index.vue
@@ -105,6 +105,10 @@ @confirm="handleProcessFlowSelectConfirm" /> <el-space wrap> <el-button type="primary" @click="handleAudit">å®¡æ ¸</el-button> <el-button type="primary" @click="handleReverseAudit">å审</el-button> <el-button type="primary" @click="handleSalesStock">å ¥åº</el-button> <el-button type="primary" @click="openForm('add')">æ°å¢å°è´¦</el-button> @@ -255,7 +259,7 @@ align="center"> <template #default="scope"> <el-tag v-if="scope.row.productStockStatus == 1" type="warning">é¨åå ¥åº</el-tag> type="warning">é¨åå ¥åº</el-tag> <el-tag v-else-if="scope.row.productStockStatus == 2" type="success">å·²å ¥åº</el-tag> <el-tag v-else-if="scope.row.productStockStatus == 0" @@ -381,6 +385,18 @@ type="info">-</el-tag> </template> </el-table-column> <el-table-column label="å®¡æ ¸ç¶æ" width="120" align="center"> <template #default="scope"> <el-tag v-if="Number(scope.row.reviewStatus) === 0" type="warning">å¾ å®¡æ ¸</el-tag> <el-tag v-else-if="Number(scope.row.reviewStatus) === 1" type="success">å·²å®¡æ ¸</el-tag> <el-tag v-else type="info">å¾ å®¡æ ¸</el-tag> </template> </el-table-column> <el-table-column label="å ¥åºç¶æ" width="120" align="center"> @@ -433,7 +449,7 @@ <el-button link type="primary" @click="openProcessFlowSelect(scope.row)" :disabled="!scope.row.isEdit">å·¥èºè·¯çº¿</el-button> :disabled="!scope.row.isEdit || Number(scope.row.reviewStatus) === 1">å·¥èºè·¯çº¿</el-button> <el-button link type="primary" @click="downLoadFile(scope.row)">éä»¶</el-button> @@ -491,7 +507,7 @@ <el-select v-model="form.salesman" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'"> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1"> <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" @@ -508,7 +524,7 @@ filterable placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'"> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1"> <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" @@ -524,7 +540,7 @@ <el-input v-model="form.projectName" placeholder="请è¾å ¥" clearable :disabled="operationType === 'view'" /> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> </el-row> @@ -539,7 +555,7 @@ type="date" placeholder="è¯·éæ©" clearable :disabled="operationType === 'view'" /> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> <el-col :span="12"> @@ -551,7 +567,8 @@ format="YYYY-MM-DD" type="date" placeholder="è¯·éæ©" clearable /> clearable :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> </el-row> @@ -565,7 +582,8 @@ :reserve-keyword="false" placeholder="è¯·éæ©" clearable @change="changs"> @change="changs" :disabled="operationType === 'view' || Number(form.reviewStatus) === 1"> <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" @@ -582,7 +600,8 @@ format="YYYY-MM-DD" type="date" placeholder="è¯·éæ©" clearable /> clearable :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> </el-row> @@ -591,13 +610,14 @@ prop="entryDate"> <el-button v-if="operationType !== 'view'" type="primary" :disabled="hasEditingProductRow()" :disabled="hasEditingProductRow() || Number(form.reviewStatus) === 1" @click="addProductInline"> æ·»å </el-button> <el-button v-if="operationType !== 'view'" plain type="danger" :disabled="Number(form.reviewStatus) === 1" @click="deleteProduct">å é¤</el-button> </el-form-item> </el-row> @@ -629,7 +649,8 @@ :render-after-expand="false" style="width: 100%" :filter-node-method="filterProductCategoryNode" @change="(val) => handleInlineProductCategoryChange(scope.row, val)" /> @change="(val) => handleInlineProductCategoryChange(scope.row, val)" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.productCategory ?? "" }}</span> </template> </el-table-column> @@ -643,7 +664,8 @@ clearable filterable style="width: 100%" @change="(val) => handleInlineProductModelChange(scope.row, val)"> @change="(val) => handleInlineProductModelChange(scope.row, val)" :disabled="Number(form.reviewStatus) === 1"> <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" @@ -664,7 +686,8 @@ :precision="2" style="width: 100%" placeholder="请è¾å ¥" clearable /> clearable :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.thickness ?? "" }}</span> </template> </el-table-column> @@ -677,7 +700,8 @@ v-model="scope.row.floorCode" placeholder="请è¾å ¥" clearable style="width: 100%" /> style="width: 100%" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.floorCode ?? "" }}</span> </template> </el-table-column> @@ -712,7 +736,8 @@ placeholder="请è¾å ¥" clearable @change="() => handleInlineSizeChange(scope.row)" @input="() => handleInlineSizeChange(scope.row)" /> @input="() => handleInlineSizeChange(scope.row)" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.width ?? "" }}</span> </template> </el-table-column> @@ -730,7 +755,8 @@ placeholder="请è¾å ¥" clearable @change="() => handleInlineSizeChange(scope.row)" @input="() => handleInlineSizeChange(scope.row)" /> @input="() => handleInlineSizeChange(scope.row)" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.height ?? "" }}</span> </template> </el-table-column> @@ -748,7 +774,8 @@ placeholder="请è¾å ¥" clearable @change="() => handleInlineQuantityChange(scope.row)" @input="() => handleInlineQuantityChange(scope.row)" /> @input="() => handleInlineQuantityChange(scope.row)" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.quantity ?? "" }}</span> </template> </el-table-column> @@ -765,7 +792,8 @@ style="width: 100%" placeholder="请è¾å ¥" clearable @change="() => handleInlineSettleAreaChange(scope.row)" /> @change="() => handleInlineSettleAreaChange(scope.row)" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.settlePieceArea ? Number(scope.row.settlePieceArea).toFixed(4) : "" }}</span> </template> </el-table-column> @@ -780,7 +808,8 @@ :step="1" :precision="4" style="width: 100%" placeholder="èªå¨è®¡ç®" /> placeholder="èªå¨è®¡ç®" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.actualTotalArea ? Number(scope.row.actualTotalArea).toFixed(4) : "" }}</span> </template> </el-table-column> @@ -793,7 +822,8 @@ placeholder="è¯·éæ©" clearable style="width: 100%" @change="() => handleInlineTaxRateChange(scope.row)"> @change="() => handleInlineTaxRateChange(scope.row)" :disabled="Number(form.reviewStatus) === 1"> <el-option label="1" value="1" /> <el-option label="3" @@ -825,10 +855,11 @@ v-model="scope.row.processRequirement" placeholder="请è¾å ¥" clearable style="width: 100%" /> style="width: 100%" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.processRequirement ?? "" }}</span> </template> </el-table-column> </el-table-column> <el-table-column label="å票类å" prop="invoiceType" min-width="120"> @@ -837,7 +868,8 @@ v-model="scope.row.invoiceType" placeholder="è¯·éæ©" clearable style="width: 100%"> style="width: 100%" :disabled="Number(form.reviewStatus) === 1"> <el-option label="墿®ç¥¨" value="墿®ç¥¨" /> <el-option label="å¢ä¸ç¥¨" @@ -855,7 +887,8 @@ v-model="scope.row.remark" placeholder="请è¾å ¥" clearable style="width: 100%" /> style="width: 100%" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.remark ?? "" }}</span> </template> </el-table-column> @@ -867,7 +900,8 @@ v-model="scope.row.heavyBox" placeholder="请è¾å ¥" clearable style="width: 100%" /> style="width: 100%" :disabled="Number(form.reviewStatus) === 1" /> <span v-else>{{ scope.row.heavyBox ?? "" }}</span> </template> </el-table-column> @@ -978,7 +1012,7 @@ <el-button link type="primary" size="small" :disabled="isProductShipped(scope.row) || hasEditingProductRow()" :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1" @click="copyProductInline(scope.row, scope.$index)"> å¤å¶æ°å»º </el-button> @@ -1003,7 +1037,7 @@ <el-button type="primary" plain size="small" :disabled="isProductShipped(scope.row)" :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1" @click="startAddOtherAmountForRow(scope.row)"> æ°å¢ </el-button> @@ -1016,7 +1050,7 @@ clearable placeholder="è¯·éæ©é¢å¤å 工项ç®" style="width: 100%;" :disabled="isProductShipped(scope.row)"> :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1"> <el-option v-for="item in otherAmountSelectOptions" :key="item.id" :label="item.processName" @@ -1024,13 +1058,13 @@ </el-select> <div style="display:flex; justify-content:flex-end; gap: 8px;"> <el-button size="small" :disabled="isProductShipped(scope.row)" :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1" @click="scope.row.__inlineOtherAmountAdding = false; scope.row.__inlineOtherAmountAddId = null"> åæ¶ </el-button> <el-button type="primary" size="small" :disabled="isProductShipped(scope.row) || scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''" :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1 || scope.row.__inlineOtherAmountAddId === null || scope.row.__inlineOtherAmountAddId === undefined || scope.row.__inlineOtherAmountAddId === ''" @click="confirmAddOtherAmountForRow(scope.row)"> 确认添å </el-button> @@ -1051,12 +1085,12 @@ :precision="0" style="width: 120px;" placeholder="æ°é" :disabled="operationType === 'view' || isProductShipped(scope.row)" :disabled="operationType === 'view' || isProductShipped(scope.row) || Number(form.reviewStatus) === 1" @change="handleOtherAmountQuantityChange(scope.row)" /> <el-button type="danger" link size="small" :disabled="isProductShipped(scope.row)" :disabled="isProductShipped(scope.row) || Number(form.reviewStatus) === 1" @click="removeOtherAmountAtForRow(scope.row, idx)"> å é¤ </el-button> @@ -1080,7 +1114,7 @@ clearable type="textarea" :rows="2" :disabled="operationType === 'view'" /> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> </el-row> @@ -1093,7 +1127,7 @@ clearable type="textarea" :rows="2" :disabled="operationType === 'view'" /> :disabled="operationType === 'view' || Number(form.reviewStatus) === 1" /> </el-form-item> </el-col> </el-row> @@ -1941,9 +1975,14 @@ const ctx = canvas.getContext("2d"); canvas.width = Math.max(QR_SIZE + horizontalPad * 2, 280); ctx.font = `${fontSize}px "Microsoft YaHei", "PingFang SC", sans-serif`; const lines = wrapLedgerQrTextLines(ctx, label, canvas.width - horizontalPad * 2); const lines = wrapLedgerQrTextLines( ctx, label, canvas.width - horizontalPad * 2 ); const textBlockHeight = lines.length * lineHeight; canvas.height = padTop + QR_SIZE + gapAfterQr + textBlockHeight + bottomPad; canvas.height = padTop + QR_SIZE + gapAfterQr + textBlockHeight + bottomPad; ctx.fillStyle = "#ffffff"; ctx.fillRect(0, 0, canvas.width, canvas.height); @@ -2011,6 +2050,7 @@ entryDateEnd: undefined, deliveryStatus: undefined, // åè´§ç¶æï¼1æªåè´§ 2审æ¹ä¸ 3审æ¹ä¸éè¿ 4审æ¹éè¿ 5å·²åè´§ 6é¨ååè´§ stockStatus: undefined, // å ¥åºç¶æï¼0æªå ¥åº 1é¨åå ¥åº 2å·²å ¥åº reviewStatus: undefined, // å®¡æ ¸ç¶æï¼0å¾ å®¡æ ¸ 1å·²å®¡æ ¸ 2å·²å审 }, form: { salesContractNo: "", @@ -2022,6 +2062,8 @@ maintenanceTime: "", productData: [], executionDate: "", reviewStatus: undefined, stockStatus: undefined, }, rules: { salesman: [{ required: true, message: "è¯·éæ©", trigger: "change" }], @@ -2219,7 +2261,9 @@ copied.productModelId = row.productModelId ?? null; copied.specificationModel = row.specificationModel ?? ""; copied.thickness = row.thickness !== null && row.thickness !== undefined && row.thickness !== "" row.thickness !== null && row.thickness !== undefined && row.thickness !== "" ? Number(row.thickness) : null; copied.floorCode = row?.floorCode ?? row?.floor_code ?? ""; @@ -2354,10 +2398,6 @@ } if (row.actualTotalArea <= 0) { proxy.$modal.msgWarning("é¢ç§¯å¿ 须大äº0"); return false; } if (row.taxInclusiveUnitPrice <= 0) { proxy.$modal.msgWarning("å«ç¨åä»·å¿ é¡»å¤§äº0"); return false; } if (!row.productModelId) { @@ -2956,6 +2996,67 @@ expandedRowKeys.value = []; getList(); }; /** å®¡æ ¸æé®æä½ */ const handleAudit = async () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("è¯·éæ©è¦å®¡æ ¸çæ°æ®"); return; } const canNotAudit = selectedRows.value.filter( row => Number(row.reviewStatus) !== 0 ); if (canNotAudit.length > 0) { proxy.$modal.msgWarning("éä¸çæ°æ®ä¸å å«éå¾ å®¡æ ¸é¡¹ï¼è¯·éæ°éæ©"); return; } try { await ElMessageBox.confirm("æ¯å¦ç¡®è®¤å®¡æ ¸éä¸çéå®å°è´¦ï¼", "æç¤º", { confirmButtonText: "ç¡®å®", cancelButtonText: "åæ¶", type: "warning", }); for (const row of selectedRows.value) { await addOrUpdateSalesLedger({ ...row, reviewStatus: 1 }); } proxy.$modal.msgSuccess("å®¡æ ¸æå"); getList(); } catch (error) { console.log(error); } }; /** å审æé®æä½ */ const handleReverseAudit = async () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("è¯·éæ©è¦åå®¡çæ°æ®"); return; } const canNotReverse = selectedRows.value.filter( row => Number(row.reviewStatus) !== 1 ); if (canNotReverse.length > 0) { proxy.$modal.msgWarning("éä¸çæ°æ®ä¸å å«éå·²å®¡æ ¸é¡¹ï¼è¯·éæ°éæ©"); return; } try { await ElMessageBox.confirm("æ¯å¦ç¡®è®¤å审éä¸çéå®å°è´¦ï¼", "æç¤º", { confirmButtonText: "ç¡®å®", cancelButtonText: "åæ¶", type: "warning", }); for (const row of selectedRows.value) { await addOrUpdateSalesLedger({ ...row, reviewStatus: 2 }); } proxy.$modal.msgSuccess("å审æå"); getList(); } catch (error) { console.log(error); } }; const paginationChange = obj => { page.current = obj.page; page.size = obj.limit; @@ -2965,7 +3066,7 @@ tableLoading.value = true; const { entryDate, ...rest } = searchForm; // å°èå´æ¥æåæ®µä¼ éç»å端 const params = { ...rest, ...page }; const params = { ...rest, ...page, reviewStatusList: [0, 1] }; // ç§»é¤å½å ¥æ¥æçé»è®¤å¼è®¾ç½®ï¼åªä¿çèå´æ¥æå段 delete params.entryDate; // æ¥è¯¢å®¢æ·åç§°ä¸æ°å¢ä¿æä¸è´ï¼å é customerIdï¼åæ å°ä¸º customerName æ¥è¯¢ @@ -2983,15 +3084,13 @@ delete params.customerName; } } const widthValue = params.width != null ? String(params.width).trim() : ""; const widthValue = params.width != null ? String(params.width).trim() : ""; if (widthValue) { params.width = widthValue; } else { delete params.width; } const heightValue = params.height != null ? String(params.height).trim() : ""; const heightValue = params.height != null ? String(params.height).trim() : ""; if (heightValue) { params.height = heightValue; } else { @@ -3065,7 +3164,9 @@ const res = await productList({ salesLedgerId: id, type: 1 }); stockProductList.value = []; stockProductList.value = res.data.filter(item => item.productStockStatus == 0 || item.productStockStatus == 1) || []; res.data.filter( item => item.productStockStatus == 0 || item.productStockStatus == 1 ) || []; } catch (e) { proxy?.$modal?.msgError?.("è·å产åæå®¡æ¹äººå¤±è´¥"); } finally { @@ -3096,9 +3197,16 @@ proxy?.$modal?.loading?.("æ£å¨å ¥åºï¼è¯·ç¨å..."); try { const approveUserIds = stockApproverNodes.value.map(node => node.userId).join(","); const approveUserIds = stockApproverNodes.value .map(node => node.userId) .join(","); const approveUserName = stockApproverNodes.value .map(node => stockApproverOptions.value.find(item => String(item.userId) === String(node.userId))?.userName) .map( node => stockApproverOptions.value.find( item => String(item.userId) === String(node.userId) )?.userName ) .filter(Boolean) .join(","); await salesStock({ @@ -3656,6 +3764,8 @@ } form.value.tempFileIds = tempFileIds; form.value.type = 1; form.value.reviewStatus = 0; // é»è®¤å®¡æ ¸ç¶æä¸ºå¾ å®¡æ ¸ form.value.stockStatus = 0; // é»è®¤å ¥åºç¶æä¸ºæªå ¥åº const submitPayload = { ...form.value }; delete submitPayload.paymentMethod; addOrUpdateSalesLedger(submitPayload).then(res => { @@ -3919,7 +4029,11 @@ const templateUrl = HISTORY_IMPORT_TEMPLATE_URL_MAP[command]; const fileName = HISTORY_IMPORT_TEMPLATE_FILE_NAME_MAP[command]; if (templateUrl) { proxy.download(templateUrl, {}, fileName || "éå®åè´§å岿°æ®å¯¼å ¥æ¨¡æ¿.xlsx"); proxy.download( templateUrl, {}, fileName || "éå®åè´§å岿°æ®å¯¼å ¥æ¨¡æ¿.xlsx" ); return; } } @@ -3981,6 +4095,15 @@ return; } const ids = selectedRows.value.map(item => item.id); // æ£æ¥æ¯å¦æå·²å®¡æ ¸çå°è´¦ const audited = selectedRows.value.filter( row => Number(row.reviewStatus) === 1 ); if (audited.length > 0) { proxy.$modal.msgWarning("éä¸çæ°æ®ä¸å å«å·²å®¡æ ¸é¡¹ï¼ä¸è½å é¤"); return; } // æ£æ¥æ¯å¦æå·²è¿è¡åè´§æåè´§å®æçéå®è®¢åï¼è¥æåä¸å 许å é¤ const cannotDeleteNames = []; @@ -4099,7 +4222,8 @@ const processCardData = res?.data ?? {}; // è¡¥é½äºç»´ç æéçå°è´¦æ è¯ï¼åç«¯æ°æ®ææ¶ä¸å¸¦ idï¼ if (processCardData && typeof processCardData === "object") { processCardData.salesLedgerId = processCardData.salesLedgerId ?? selectedId; processCardData.salesLedgerId = processCardData.salesLedgerId ?? selectedId; processCardData.salesContractNo = (processCardData.salesContractNo ?? "").trim() || String(selectedRow?.salesContractNo ?? "").trim(); @@ -4583,8 +4707,7 @@ // å 许ï¼1æªåè´§ã3审æ¹ä¸éè¿ã4审æ¹éè¿ã6é¨ååè´§ï¼ä¸å 许ï¼2审æ¹ä¸ã5å·²åè´§ const statusItem = selectedRows.value[0].deliveryStatus; const ledgerAllowsDelivery = s => [1, 3, 4, 6].includes(Number(s)); const ledgerAllowsDelivery = s => [1, 3, 4, 6].includes(Number(s)); let isTrue = true; selectedRows.value.forEach(row => { if (!ledgerAllowsDelivery(row.deliveryStatus)) { @@ -4811,7 +4934,7 @@ const run = async () => { for (const salesLedgerId of uniqueLedgerIds) { await addShippingInfo({ scanOutbound: false, scanOutbound: false, salesLedgerId, type: deliveryForm.value.type, approveUserIds,