新疆马铃薯
1.首页问题:挪新系统ui,需要确认一下页面数据完整。
2.协同办公:挪新系统
3.营销管理:客户往来取消回款金额字段,改为点击左侧客户时显示与该客户的所有订单信息,以及发货情况。销售可以选好对应的采购订单方便质量追溯。
4.采购管理:供应商往来同上逻辑,显示是否收货,也加上采购退货和采购报表功能。
5.采购加上设备备件选项,设备备件入库到备件库存。设备,仓储不足时做采购提醒。
6.仓储物流:得区分成品库和原料库(不存在半成品,成品只有一个产品,很好确认),原材料需要有批号,采集原料库需要做好仓库字段,让他们可以区分哪个仓库,然后把数采设备信息做一个实时的显示。总库存显示好当前存在的批次信息。
7.质量:只有不通过才需要填写对应的数据信息。在外侧做好选择通过不通过。过程,出厂检验无法对应到生产订单,那就对应到销售订单。
8.决策分析:基础数据分析和进销存分析,质量数据分析需要重新设计
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // éè´-æ¥ç¥¨ç»è®°æ¥å£ |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢éè´ååå· |
| | | export function getProduct(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getProduct", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢idéè´ååå· |
| | | export function getPurchaseNoById(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getPurchaseNoById", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // æ ¹æ®éè´ååå·æ¥è¯¢è¯¦ç»ä¿¡æ¯ |
| | | export function getInfo(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/getInfo", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // 主å表æ¥è¯¢ |
| | | export function gePurchaseList(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // 主å表æ¥è¯¢ |
| | | export function getRegistrationById(query) { |
| | | return request({ |
| | | url: "/purchase/registration/getRegistrationById", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // æ°å¢ç¼è¾æ¥ç¥¨ç»è®° |
| | | export function addOrUpdateRegistration(query) { |
| | | return request({ |
| | | url: "/purchase/registration/addOrUpdateRegistration", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å 餿¥ç¥¨ç»è®° |
| | | export function delRegistration(query) { |
| | | return request({ |
| | | url: "/purchase/registration/delRegistration", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | // 主å表æ¥è¯¢ |
| | | export function gePurchaseListPage(query) { |
| | | return request({ |
| | | url: "/purchase/ledger/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // éè´ä»æ¬¾ç»è®°é¡µé¢æ¥å£ |
| | | import request from "@/utils/request"; |
| | | |
| | | // å页æ¥è¯¢ |
| | | export function registrationList(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // æ¥è¯¢è¯¦æ
|
| | | export function registrationInfo(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/" + query, |
| | | method: "get", |
| | | }); |
| | | } |
| | | // æ ¹æ®éè´ååå·æ¥è¯¢è¯¦æ
|
| | | export function byPurchaseId(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/byPurchaseId/" + query, |
| | | method: "get", |
| | | }); |
| | | } |
| | | // æ¥è¯¢éè´ååå· |
| | | export function getPurchaseNo() { |
| | | return request({ |
| | | url: "/purchase/ledger/getPurchaseNo", |
| | | method: "get", |
| | | }); |
| | | } |
| | | // æ°å¢ |
| | | export function paymentRegistrationAdd(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | // ä¿®æ¹ |
| | | export function paymentRegistrationEdit(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration", |
| | | method: "put", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å é¤ |
| | | export function paymentRegistrationDel(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/delete", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | | // è·åå票å·åå票éé¢ |
| | | export function getTicketNo(query) { |
| | | return request({ |
| | | url: "/purchase/registration/getTicketNo", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // å页æ¥è¯¢ |
| | | export function paymentHistoryList(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/paymentHistoryList", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // å页æ¥è¯¢ |
| | | export function paymentHistoryListPage(query) { |
| | | return request({ |
| | | url: "/purchase/paymentRegistration/paymentHistoryListPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // éè´-æ¥ç¥¨å°è´¦æ¥å£ |
| | | import request from "@/utils/request"; |
| | | |
| | | // æ¥è¯¢å表 |
| | | export function invoiceList(query) { |
| | | return request({ |
| | | url: "/purchase/registration/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // æ¥è¯¢è¯¦æ
|
| | | // export function getInvoiceById(query) { |
| | | // return request({ |
| | | // url: "/purchase/registration/getRegistrationById", |
| | | // method: "get", |
| | | // params: query, |
| | | // }); |
| | | // } |
| | | // æ°å¢ãç¼è¾ |
| | | export function addOrUpdateInvoice(query) { |
| | | return request({ |
| | | url: "/purchase/invoice/addOrUpdateInvoice", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å é¤ |
| | | export function delInvoice(query) { |
| | | return request({ |
| | | url: "/purchase/invoice/delInvoice", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å 餿¥ç¥¨å°è´¦ |
| | | export function delRegistration(query) { |
| | | return request({ |
| | | url: "/purchase/registration/delRegistration", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å é¤éä»¶ |
| | | export function delCommonFile(query) { |
| | | return request({ |
| | | url: "/commonFile/delCommonFile", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | | // åè¡¨æ ¼æ¥è¯¢ |
| | | export function productRecordList(query) { |
| | | return request({ |
| | | url: "/purchase/registration/productRecordList", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢å表 |
| | | export function invoiceListPage(query) { |
| | | return request({ |
| | | url: "/sales/product/listPagePurchaseLedger", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | export function productRecordPage(query) { |
| | | return request({ |
| | | url: "/purchase/registration/productRecordPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | export function productUploadFile(data) { |
| | | return request({ |
| | | url: "/file/uploadFile", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // export function getProductRecordById(params) { |
| | | // return request({ |
| | | // url: "/purchase/registration/getProductRecordById", |
| | | // method: "get", |
| | | // params: params, |
| | | // }); |
| | | // } |
| | | export function getProductRecordById(data) { |
| | | return request({ |
| | | url: "/purchase/registration/getProductRecordById", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function updateRegistration(data) { |
| | | return request({ |
| | | url: "/purchase/registration/updateRegistration", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢ä»æ¬¾ç»è®°åå表 |
| | | export function registrationListPageGetById(query) { |
| | | return request({ |
| | | url: "/purchase/registration/getById", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // ä¿®æ¹ä»æ¬¾æµæ°´ |
| | | export function updatePaymentRegistration(query) { |
| | | return request({ |
| | | url: "/purchase/registration/updatePaymentRegistration", |
| | | method: "put", |
| | | data: query, |
| | | }); |
| | | } |
| | | // å é¤ä»æ¬¾æµæ°´ |
| | | export function delPaymentRegistration(query) { |
| | | return request({ |
| | | url: "/purchase/registration/delPaymentRegistration", |
| | | method: "delete", |
| | | data: query, |
| | | }); |
| | | } |
| | |
| | | }) |
| | | } |
| | | |
| | | // æ¹éå¿«éæ£éª |
| | | export function batchQuickInspect(data) { |
| | | return request({ |
| | | url: '/quality/qualityInspect/batchQuickInspect', |
| | | method: 'post', |
| | | data: data, |
| | | }) |
| | | } |
| | | |
| | |
| | | <el-form-item label="æè¿°" prop="description"> |
| | | <el-input v-model="form.description"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="åºåé¢è¦æ°é" prop="warnNum"> |
| | | <el-input-number |
| | | v-model="form.warnNum" |
| | | placeholder="请è¾å
¥åºåé¢è¦æ°é" |
| | | :min="0" |
| | | :step="0.1" |
| | | :precision="2" |
| | | style="width: 100%" |
| | | ></el-input-number> |
| | | </el-form-item> |
| | | <el-form-item label="é¢è¦éç¥äºº" prop="notifyPersonId"> |
| | | <el-select |
| | | v-model="form.notifyPersonId" |
| | | placeholder="è¯·éæ©é¢è¦éç¥äºº" |
| | | filterable |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option |
| | | v-for="user in userOptions" |
| | | :key="user.userId" |
| | | :label="user.nickName || user.userName" |
| | | :value="user.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="ä»·æ ¼" prop="price"> |
| | | <el-input-number |
| | | v-model="form.price" |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="dialogVisible = false" :disabled="formLoading">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm" :loading="formLoading">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false" :disabled="formLoading">åæ¶</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { getSparePartsList, addSparePart, editSparePart, delSparePart } from "@/api/equipmentManagement/spareParts"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { getSparePartsUsagePage } from "@/api/equipmentManagement/sparePartsUsage"; |
| | | |
| | |
| | | const operationType = ref('add') |
| | | // 设å¤é项 |
| | | const deviceOptions = ref([]); |
| | | const userOptions = ref([]); |
| | | // 表åå¼ç¨ |
| | | const formRef = ref(null); |
| | | // æ¥è¯¢åæ° |
| | |
| | | prop: "quantity", |
| | | }, |
| | | { |
| | | label: "åºåé¢è¦æ°é", |
| | | prop: "warnNum", |
| | | }, |
| | | { |
| | | label: "é¢è¦éç¥äºº", |
| | | prop: "notifyPersonName", |
| | | }, |
| | | { |
| | | label: "æè¿°", |
| | | prop: "description", |
| | | }, |
| | |
| | | status: '', |
| | | description: '', |
| | | deviceLedgerIds: [], |
| | | price: null |
| | | price: null, |
| | | warnNum: null, |
| | | notifyPersonId: null |
| | | }); |
| | | |
| | | // 表åéªè¯è§å |
| | |
| | | } |
| | | }; |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | const loadUserOptions = async () => { |
| | | try { |
| | | const res = await userListNoPage(); |
| | | userOptions.value = res.data || []; |
| | | } catch (error) { |
| | | ElMessage.error('è·åç¨æ·å表失败'); |
| | | } |
| | | }; |
| | | |
| | | // æ°å¢åç±» |
| | | const addCategory = async () => { |
| | | await loadDeviceName(); |
| | | await loadUserOptions(); |
| | | form.id = ''; |
| | | form.name = ''; |
| | | form.sparePartsNo = ''; |
| | |
| | | form.deviceLedgerIds = []; |
| | | form.quantity = undefined; |
| | | form.price = null; |
| | | form.warnNum = null; |
| | | form.notifyPersonId = null; |
| | | operationType.value = 'add' |
| | | dialogVisible.value = true; |
| | | }; |
| | |
| | | // ç¼è¾åç±» |
| | | const editCategory = async (row) => { |
| | | await loadDeviceName(); |
| | | await loadUserOptions(); |
| | | Object.assign(form, row); |
| | | // 妿å端è¿åçæ¯ deviceIds å符串ï¼éè¦è½¬æ¢ä¸ºæ°ç» |
| | | if (row.deviceIds && typeof row.deviceIds === 'string') { |
| | |
| | | :max="formState.qualitity" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="å
¥åºæ¶é´" |
| | | prop="createTime"> |
| | | <el-date-picker v-model="formState.createTime" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©å
¥åºæ¶é´" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" |
| | | prop="remark"> |
| | | <el-input v-model="formState.remark" |
| | |
| | | qualitity: 0, |
| | | batchNo: null, |
| | | warnNum: 0, |
| | | createTime: "", |
| | | remark: "", |
| | | }); |
| | | |
| | |
| | | qualitity: 0, |
| | | batchNo: null, |
| | | warnNum: 0, |
| | | createTime: "", |
| | | remark: "", |
| | | }; |
| | | isShow.value = false; |
| | |
| | | <div></div> |
| | | </div> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="14"> |
| | | <el-col :span="8"> |
| | | <div class="table_list"> |
| | | <el-table ref="multipleTable" |
| | | border |
| | |
| | | prop="contractAmounts" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="仿¬¾éé¢(å
)" |
| | | prop="paymentAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="åºä»éé¢(å
)" |
| | | prop="payableAmount" |
| | | show-overflow-tooltip> |
| | |
| | | :limit="page.size" /> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="10"> |
| | | <el-col :span="16"> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumnSon" |
| | | :tableData="originalTableDataSon" |
| | | :isSelection="false" |
| | | :isShowPagination="true" |
| | | :page="sonPage" |
| | | :tableLoading="tableLoadingSon" |
| | | :isShowSummary="isShowSummarySon" |
| | | :summaryMethod="summarizeMainTable1" |
| | | height="calc(100vh - 18.5em)" |
| | | @pagination="sonPaginationSearch"> |
| | | <template #payableAmountSlot="{ row }"> |
| | | <el-text type="danger"> |
| | | {{ parseFloat(row.payableAmount).toFixed(2) }} |
| | | </el-text> |
| | | </template> |
| | | </PIMTable> |
| | | <div class="table-header" v-if="selectedSupplierName"> |
| | | <span class="supplier-title">ä¾åºåï¼{{ selectedSupplierName }}</span> |
| | | </div> |
| | | <el-table border |
| | | v-loading="tableLoadingSon" |
| | | :data="originalTableDataSon" |
| | | :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" |
| | | height="calc(100vh - 20em)" |
| | | style="width: 100%" |
| | | tooltip-effect="dark" |
| | | :show-summary="isShowSummarySon" |
| | | :summary-method="summarizeMainTable1"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="ååç¾è®¢æ¥æ" |
| | | prop="executionDate" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="éè´ååå·" |
| | | prop="purchaseContractNumber" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="项ç®åç§°" |
| | | prop="projectName" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="æ¶è´§ç¶æ" |
| | | prop="status" |
| | | show-overflow-tooltip |
| | | width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getReceiptStatusType(row.status)" size="small"> |
| | | {{ receiptStatusText[row.status] || 'æªç¥ç¶æ' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="sonPage.total > 0" |
| | | @pagination="sonPaginationSearch" |
| | | :total="sonPage.total" |
| | | :layout="sonPage.layout" |
| | | :page="sonPage.current" |
| | | :limit="sonPage.size" /> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs } from "vue"; |
| | | import { ref, toRefs, reactive, getCurrentInstance } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { |
| | | paymentLedgerList, |
| | | paymentRecordList, |
| | | } from "@/api/procurementManagement/paymentLedger.js"; |
| | | import { gePurchaseListPage } from "@/api/procurementManagement/invoiceEntry.js"; |
| | | import Pagination from "../../../components/PIMTable/Pagination.vue"; |
| | | |
| | | const tableData = ref([]); |
| | |
| | | const isShowSummary = ref(true); |
| | | const { searchForm } = toRefs(data); |
| | | const currentSupplierId = ref(""); |
| | | const selectedSupplierName = ref(""); |
| | | const rowClick = row => { |
| | | currentSupplierId.value = row.supplierId; |
| | | selectedSupplierName.value = row.supplierName; |
| | | sonPage.current = 1; |
| | | getPaymenRecordtList(row.supplierId); |
| | | getPurchaseList(row.supplierName); |
| | | }; |
| | | // 忍¡å |
| | | const tableColumnSon = ref([ |
| | | { |
| | | label: "ååç¾è®¢æ¥æ", |
| | | prop: "executionDate", |
| | | width: 110, |
| | | }, |
| | | { |
| | | label: "éè´ååå·", |
| | | prop: "purchaseContractNumber", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ååéé¢(å
)", |
| | | prop: "contractAmount", |
| | | width: 200, |
| | | formatData: params => { |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "仿¬¾éé¢(å
)", |
| | | prop: "paymentAmount", |
| | | width: 200, |
| | | formatData: params => { |
| | | return params ? parseFloat(params).toFixed(2) : 0; |
| | | }, |
| | | }, |
| | | { |
| | | label: "åºä»éé¢(å
)", |
| | | dataType: "slot", |
| | | width: 200, |
| | | prop: "payableAmount", |
| | | slot: "payableAmountSlot", |
| | | }, |
| | | ]); |
| | | const tableDataSon = ref([]); |
| | | const originalTableDataSon = ref([]); |
| | | const tableLoadingSon = ref(false); |
| | | const isShowSummarySon = ref(true); |
| | |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["contractAmounts", "paymentAmount", "payableAmount"], |
| | | ["contractAmounts", "payableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | ticketsNum: { noDecimal: true }, |
| | | futureTickets: { noDecimal: true }, |
| | | } |
| | | ); |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeMainTable1 = param => { |
| | | let summarizeTable = proxy.summarizeTable( |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["contractAmount", "invoiceAmount", "paymentAmount"], |
| | | ["contractAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | ticketsNum: { noDecimal: true }, |
| | | futureTickets: { noDecimal: true }, |
| | | } |
| | | ); |
| | | if (originalTableDataSon.value.length > 0) { |
| | | summarizeTable[summarizeTable.length - 1] = |
| | | originalTableDataSon.value[ |
| | | originalTableDataSon.value.length - 1 |
| | | ].payableAmount.toFixed(2); |
| | | } else { |
| | | summarizeTable[summarizeTable.length - 1] = 0.0; |
| | | } |
| | | return summarizeTable; |
| | | }; |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | |
| | | total.value = result.total || 0; |
| | | if (tableData.value.length > 0) { |
| | | currentSupplierId.value = tableData.value[0].supplierId; |
| | | selectedSupplierName.value = tableData.value[0].supplierName; |
| | | sonPage.current = 1; |
| | | getPaymenRecordtList(tableData.value[0].supplierId); |
| | | getPurchaseList(tableData.value[0].supplierName); |
| | | } else { |
| | | originalTableDataSon.value = []; |
| | | selectedSupplierName.value = ""; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const getPaymenRecordtList = supplierId => { |
| | | const getPurchaseList = supplierName => { |
| | | tableLoadingSon.value = true; |
| | | paymentRecordList({ |
| | | supplierId: supplierId, |
| | | gePurchaseListPage({ |
| | | supplierName: supplierName, |
| | | current: sonPage.current, |
| | | size: sonPage.size, |
| | | }) |
| | |
| | | tableLoadingSon.value = false; |
| | | let result = res.data; |
| | | if (Array.isArray(result)) { |
| | | tableDataSon.value = result; |
| | | originalTableDataSon.value = result; |
| | | sonPage.total = result.length; |
| | | handlePagination({ page: sonPage.current, limit: sonPage.size }); |
| | | } else { |
| | | originalTableDataSon.value = result.records || []; |
| | | sonPage.total = result.total || 0; |
| | |
| | | tableLoadingSon.value = false; |
| | | }); |
| | | }; |
| | | const handlePagination = ({ page, limit }) => { |
| | | console.log(page, limit); |
| | | sonPage.current = page; |
| | | sonPage.size = limit; |
| | | |
| | | const start = (page - 1) * limit; |
| | | const end = start + limit; |
| | | |
| | | originalTableDataSon.value = tableDataSon.value.slice(start, end); |
| | | }; |
| | | |
| | | const sonPaginationSearch = pagination => { |
| | | // æ¥æ¶å页å¨åæ° { page, limit } |
| | | sonPage.current = pagination.page; |
| | | sonPage.size = pagination.limit; |
| | | getPaymenRecordtList(currentSupplierId.value); |
| | | getPurchaseList(selectedSupplierName.value); |
| | | }; |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (column.property !== "supplierName") { |
| | | if (cellValue !== undefined && cellValue !== null && !isNaN(cellValue)) { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | } else { |
| | | return cellValue; |
| | | } |
| | | return "0.00"; |
| | | }; |
| | | |
| | | // æ¶è´§ç¶æææ¬æ å° |
| | | const receiptStatusText = { |
| | | 1: 'å¾
æ¶è´§', |
| | | 2: 'æ¶è´§ä¸', |
| | | 3: 'å·²æ¶è´§' |
| | | }; |
| | | |
| | | // æ¶è´§ç¶ææ ç¾ç±»å |
| | | const getReceiptStatusType = (status) => { |
| | | const typeMap = { |
| | | 1: 'info', |
| | | 2: 'warning', |
| | | 3: 'success' |
| | | }; |
| | | return typeMap[status] || 'info'; |
| | | }; |
| | | |
| | | getList(); |
| | | </script> |
| | | |
| | |
| | | .pagination-container { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | .table-header { |
| | | margin-bottom: 10px; |
| | | padding: 10px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | |
| | | .supplier-title { |
| | | font-weight: bold; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> |
| | | <el-button type="success" |
| | | plain |
| | | @click="handleBatchGenerate">æ¹éçææ°æ®</el-button> |
| | | <!-- <el-button type="success"--> |
| | | <!-- plain--> |
| | | <!-- @click="handleBatchGenerate">æ¹éçææ°æ®</el-button>--> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å°è´¦</el-button> |
| | | <el-button type="primary" |
| | |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="ç±»å" |
| | | prop="productType" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.productType === 2 ? 'warning' : 'success'" size="small"> |
| | | {{ scope.row.productType === 2 ? '设å¤å¤ä»¶' : '产å' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" /> |
| | | prop="specificationModel" |
| | | width="120"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">/</span> |
| | | <span v-else>{{ scope.row.specificationModel || '--' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åä½" |
| | | prop="unit" /> |
| | | prop="unit" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.unit || '--' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¥åºå®¡æ ¸ç¶æ" |
| | | prop="stockInApprovalStatus" |
| | | width="120"> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" /> |
| | | prop="quantity" |
| | | width="100" /> |
| | | <el-table-column label="å¯ç¨æ°é" |
| | | prop="availableQuality" /> |
| | | prop="availableQuality" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.availableQuality }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="éè´§æ°é" |
| | | prop="returnQuality" /> |
| | | prop="returnQuality" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.returnQuality }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" /> |
| | | prop="taxRate" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.taxRate }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | width="130"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | width="130"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | :formatter="formattedNumber" |
| | | width="140"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="ç±»å" |
| | | prop="productType" |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.productType === 2 ? 'warning' : 'success'" size="small"> |
| | | {{ scope.row.productType === 2 ? '设å¤å¤ä»¶' : '产å' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" /> |
| | | prop="specificationModel" |
| | | width="120"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">/</span> |
| | | <span v-else>{{ scope.row.specificationModel || '--' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | width="70" /> |
| | | width="70"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.unit || '--' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" |
| | | width="70" /> |
| | | <el-table-column label="åºåé¢è¦æ°é" |
| | | prop="warnNum" |
| | | width="120" |
| | | show-overflow-tooltip /> |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.warnNum }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" |
| | | width="80" /> |
| | | width="80"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ scope.row.taxRate }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="130"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveUnitPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="130"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxInclusiveTotalPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | width="140"> |
| | | <template #default="scope"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <span v-else>{{ formattedNumber(null, null, scope.row.taxExclusiveTotalPrice) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¯å¦è´¨æ£" |
| | | prop="isChecked" |
| | | width="150"> |
| | | width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isChecked ? 'success' : 'info'"> |
| | | <span v-if="scope.row.productType === 2">--</span> |
| | | <el-tag v-else :type="scope.row.isChecked ? 'success' : 'info'"> |
| | | {{ scope.row.isChecked ? 'æ¯' : 'å¦' }} |
| | | </el-tag> |
| | | </template> |
| | |
| | | ref="productFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç±»åï¼" |
| | | prop="productType"> |
| | | <el-radio-group v-model="productForm.productType" @change="handleProductTypeChange"> |
| | | <el-radio :label="1">产å</el-radio> |
| | | <el-radio :label="2">设å¤å¤ä»¶</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="产å大类ï¼" |
| | | prop="productId"> |
| | | <el-tree-select v-model="productForm.productId" |
| | | <el-tree-select v-if="productForm.productType !== 2" |
| | | v-model="productForm.productId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | |
| | | :data="productOptions" |
| | | :render-after-expand="false" |
| | | style="width: 100%" /> |
| | | <el-select v-else |
| | | v-model="productForm.productId" |
| | | placeholder="è¯·éæ©è®¾å¤å¤ä»¶" |
| | | filterable |
| | | clearable |
| | | @change="handleSparePartsChange" |
| | | style="width: 100%"> |
| | | <el-option v-for="item in sparePartsOptions" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row :gutter="30" v-if="productForm.productType !== 2"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" |
| | | prop="productModelId"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row :gutter="30" v-if="productForm.productType !== 2"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" |
| | | prop="unit"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row :gutter="30" v-if="productForm.productType !== 2"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨åä»·(å
)ï¼" |
| | | prop="taxInclusiveUnitPrice"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row :gutter="30" v-if="productForm.productType === 2"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æ°éï¼" |
| | | prop="quantity"> |
| | | <el-input-number :step="0.1" |
| | | clearable |
| | | :precision="2" |
| | | :min="0" |
| | | style="width: 100%" |
| | | v-model="productForm.quantity" |
| | | placeholder="请è¾å
¥" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30" v-if="productForm.productType !== 2"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨æ»ä»·(å
)ï¼" |
| | | prop="taxInclusiveTotalPrice"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-col :span="12" v-if="productForm.productType !== 2"> |
| | | <el-form-item label="åºåé¢è¦æ°éï¼" |
| | | prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row :gutter="30" v-if="productForm.productType !== 2"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦è´¨æ£ï¼" |
| | | prop="isChecked"> |
| | |
| | | const modelOptions = ref([]); |
| | | const userList = ref([]); |
| | | const productOptions = ref([]); |
| | | const sparePartsOptions = ref([]); |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | | const tableLoading = ref(false); |
| | |
| | | const fileList = ref([]); |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import { getSparePartsList } from "@/api/equipmentManagement/spareParts.js"; |
| | | import dayjs from "dayjs"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | |
| | |
| | | const currentId = ref(""); |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productType: 1, |
| | | productId: "", |
| | | productCategory: "", |
| | | productModelId: "", |
| | |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | invoiceType: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | isChecked: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | // isChecked é»è®¤ä¼ å¦ï¼ä¸éè¦éªè¯ |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | | const { productForm } = toRefs(productFormData); |
| | | |
| | | // å¨æè®¡ç®éªè¯è§å |
| | | const productRules = computed(() => { |
| | | const isSpareParts = productForm.value.productType === 2; |
| | | return { |
| | | productId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | productModelId: isSpareParts ? [] : [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | unit: isSpareParts ? [] : [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxInclusiveUnitPrice: isSpareParts ? [] : [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxRate: isSpareParts ? [] : [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | warnNum: isSpareParts ? [] : [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | taxInclusiveTotalPrice: isSpareParts ? [] : [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxExclusiveTotalPrice: isSpareParts ? [] : [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | invoiceType: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }; |
| | | }); |
| | | const upload = reactive({ |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | |
| | | await nextTick(); |
| | | |
| | | if (type === "add") { |
| | | productForm.value.isChecked = false; |
| | | productForm.value.isChecked = false; // æ¯å¦è´¨æ£é»è®¤ä¼ å¦ |
| | | productForm.value.productType = "product"; |
| | | } |
| | | |
| | | if (type === "edit") { |
| | | // å¤å¶è¡æ°æ® |
| | | productForm.value = { ...row }; |
| | | |
| | | // å¦ææ²¡æ productTypeï¼é»è®¤ä¸º product (1) |
| | | if (!productForm.value.productType) { |
| | | productForm.value.productType = 1; |
| | | } |
| | | |
| | | // 妿æ¯è®¾å¤å¤ä»¶ç±»åï¼å 载设å¤å¤ä»¶å表 |
| | | if (productForm.value.productType === 2) { |
| | | await getSparePartsOptions(); |
| | | } |
| | | |
| | | // 妿æ¯ä»æ¨¡æ¿å è½½çæ°æ®ï¼å¯è½æ²¡æ productId å productModelId |
| | | // éè¦æ ¹æ® productCategory å specificationModel æ¥æ¥æ¾å¯¹åºç ID |
| | | if (!productForm.value.productId && productForm.value.productCategory) { |
| | | if (!productForm.value.productId && productForm.value.productCategory && productForm.value.productType !== 2) { |
| | | // æ ¹æ® productCategory æ¥æ¾ productId |
| | | const findProductIdByCategory = (nodes, categoryName) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | |
| | | return res; |
| | | }); |
| | | }; |
| | | |
| | | // è·å设å¤å¤ä»¶å表 |
| | | const getSparePartsOptions = () => { |
| | | return getSparePartsList({ current: -1, size: -1 }).then(res => { |
| | | if (res.data && Array.isArray(res.data.rows)) { |
| | | sparePartsOptions.value = res.data.rows; |
| | | } else if (res.data && Array.isArray(res.data.records)) { |
| | | sparePartsOptions.value = res.data.records; |
| | | } else { |
| | | sparePartsOptions.value = []; |
| | | } |
| | | return res; |
| | | }); |
| | | }; |
| | | |
| | | // å¤çç±»ååå |
| | | const handleProductTypeChange = (type) => { |
| | | productForm.value.productId = ""; |
| | | productForm.value.productCategory = ""; |
| | | productForm.value.productModelId = ""; |
| | | productForm.value.specificationModel = ""; |
| | | modelOptions.value = []; |
| | | |
| | | if (type === 2) { |
| | | getSparePartsOptions(); |
| | | } |
| | | }; |
| | | |
| | | // å¤ç设å¤å¤ä»¶éæ© |
| | | const handleSparePartsChange = (value) => { |
| | | const selectedSparePart = sparePartsOptions.value.find(item => item.id === value); |
| | | if (selectedSparePart) { |
| | | productForm.value.productCategory = selectedSparePart.name; |
| | | productForm.value.specificationModel = "/"; |
| | | } else { |
| | | productForm.value.productCategory = ""; |
| | | productForm.value.specificationModel = ""; |
| | | } |
| | | }; |
| | | const getModels = value => { |
| | | if (value) { |
| | | productForm.value.productCategory = |
| | |
| | | |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | | // 妿æ¯è®¾å¤å¤ä»¶ï¼å
设置é»è®¤å¼ï¼åéªè¯ |
| | | if (productForm.value.productType === 2) { |
| | | productForm.value.specificationModel = "/"; |
| | | productForm.value.productModelId = null; |
| | | productForm.value.unit = ""; |
| | | productForm.value.taxRate = ""; |
| | | productForm.value.taxInclusiveUnitPrice = 0; |
| | | productForm.value.taxInclusiveTotalPrice = 0; |
| | | productForm.value.taxExclusiveTotalPrice = 0; |
| | | productForm.value.warnNum = 0; |
| | | productForm.value.isChecked = false; // æ¯å¦è´¨æ£é»è®¤ä¼ å¦ |
| | | } |
| | | |
| | | proxy.$refs["productFormRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="ä¾åºååç§°ï¼"> |
| | | <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="请è¾å
¥" |
| | | 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-form-item> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <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-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery">æç´¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | |
| | | <div class="table_list"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | show-summary |
| | | :summary-method="summarizeMainTable" |
| | | @expand-change="expandChange" |
| | | height="calc(100vh - 21.5em)" |
| | | > |
| | | <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="availableQuality" /> |
| | | <el-table-column label="éè´§æ°é" prop="returnQuality" /> |
| | | <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="160" show-overflow-tooltip /> |
| | | <el-table-column label="éå®ååå·" prop="salesContractNo" width="160" show-overflow-tooltip /> |
| | | <el-table-column label="ä¾åºååç§°" prop="supplierName" width="160" show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" prop="projectName" width="320" show-overflow-tooltip /> |
| | | <el-table-column label="æ¶è´§ç¶æ" prop="status" width="100" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getReceiptStatusType(scope.row.status)" size="small"> |
| | | {{ receiptStatusText[scope.row.status] || 'æªç¥ç¶æ' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="审æ¹ç¶æ" prop="approvalStatus" width="100" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" 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="仿¬¾æ¹å¼" prop="paymentMethod" width="100" 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 label="夿³¨" prop="remarks" width="200" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="120" align="center"> |
| | | <template #default="scope"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | :disabled="isConfirmed(scope.row)" |
| | | @click="confirmReceipt(scope.row)" |
| | | > |
| | | {{ isConfirmed(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" |
| | | /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, reactive, ref } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import dayjs from 'dayjs' |
| | | import Pagination from '@/components/PIMTable/Pagination.vue' |
| | | import { productList, purchaseListPage, updateApprovalStatus } from '@/api/procurementManagement/procurementLedger.js' |
| | | |
| | | const tableData = ref([]) |
| | | const tableLoading = ref(false) |
| | | const total = ref(0) |
| | | const expandedRowKeys = ref([]) |
| | | const receiptResultMap = ref({}) |
| | | |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100 |
| | | }) |
| | | |
| | | const searchForm = reactive({ |
| | | supplierName: '', |
| | | purchaseContractNumber: '', |
| | | salesContractNo: '', |
| | | projectName: '', |
| | | entryDate: [], |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined |
| | | }) |
| | | |
| | | const approvalStatusText = { |
| | | 1: 'å¾
å®¡æ ¸', |
| | | 2: '审æ¹ä¸', |
| | | 3: '审æ¹éè¿', |
| | | 4: '审æ¹å¤±è´¥' |
| | | } |
| | | |
| | | const receiptStatusText = { |
| | | 1: 'å¾
æ¶è´§', |
| | | 2: 'æ¶è´§ä¸', |
| | | 3: 'å·²æ¶è´§' |
| | | } |
| | | |
| | | const getApprovalStatusType = (status) => { |
| | | const typeMap = { |
| | | 1: 'info', |
| | | 2: 'warning', |
| | | 3: 'success', |
| | | 4: 'danger' |
| | | } |
| | | return typeMap[status] |
| | | } |
| | | |
| | | const getReceiptStatusType = (status) => { |
| | | const typeMap = { |
| | | 1: 'info', |
| | | 2: 'warning', |
| | | 3: 'success' |
| | | } |
| | | return typeMap[status] |
| | | } |
| | | |
| | | const formattedNumber = (_row, _column, cellValue) => { |
| | | const value = Number(cellValue) |
| | | return Number.isFinite(value) ? value.toFixed(2) : '0.00' |
| | | } |
| | | |
| | | const createSummary = (columns, data, sumFields) => { |
| | | const sums = [] |
| | | columns.forEach((column, index) => { |
| | | if (index === 0) { |
| | | sums[index] = 'å计' |
| | | return |
| | | } |
| | | if (!sumFields.includes(column.property)) { |
| | | sums[index] = '' |
| | | return |
| | | } |
| | | const totalValue = data.reduce((sum, item) => sum + Number(item?.[column.property] || 0), 0) |
| | | sums[index] = Number.isFinite(totalValue) ? totalValue.toFixed(2) : '0.00' |
| | | }) |
| | | return sums |
| | | } |
| | | |
| | | const summarizeMainTable = ({ columns, data }) => createSummary(columns, data, ['contractAmount']) |
| | | |
| | | const summarizeChildrenTable = ({ columns, data }) => |
| | | createSummary(columns, data, ['quantity', 'availableQuality', 'returnQuality', 'taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice']) |
| | | |
| | | const isConfirmed = (row) => Number(row?.status) === 3 || Boolean(receiptResultMap.value[row?.id]) |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | 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 paginationChange = (obj) => { |
| | | page.current = obj.page |
| | | page.size = obj.limit |
| | | getList() |
| | | } |
| | | |
| | | 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) { |
| | | ElMessage.error('å 载产åå表失败') |
| | | const index = expandedRows.findIndex((item) => item.id === row.id) |
| | | if (index > -1) { |
| | | expandedRows.splice(index, 1) |
| | | } |
| | | } |
| | | } else { |
| | | expandedRowKeys.value = [] |
| | | } |
| | | } |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true |
| | | const { entryDate, ...rest } = searchForm |
| | | purchaseListPage({ ...rest, ...page, approvalStatus: 3 }) |
| | | .then((res) => { |
| | | tableData.value = (res.data?.records || []).map((record) => ({ |
| | | ...record, |
| | | children: [] |
| | | })) |
| | | total.value = res.data?.total || 0 |
| | | expandedRowKeys.value = [] |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false |
| | | }) |
| | | } |
| | | |
| | | const confirmReceipt = async (row) => { |
| | | try { |
| | | await ElMessageBox.confirm('æ¯å¦ç¡®è®¤æ¶è´§ï¼', '确认æ¶è´§', { |
| | | type: 'warning', |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: 'åæ¶' |
| | | }) |
| | | |
| | | await updateApprovalStatus({ |
| | | id: row.id, |
| | | status: 3 |
| | | }) |
| | | |
| | | receiptResultMap.value[row.id] = true |
| | | ElMessage.success('确认æ¶è´§æå') |
| | | getList() |
| | | } catch (error) { |
| | | if (error !== 'cancel' && error !== 'close') { |
| | | ElMessage.error('确认æ¶è´§å¤±è´¥') |
| | | } |
| | | } |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | title="确认æ¶è´§" |
| | | width="70%" |
| | | operation-type="edit" |
| | | @close="handleClose" |
| | | @cancel="handleClose" |
| | | @confirm="handleConfirm" |
| | | > |
| | | <el-form ref="formRef" :model="detailData" label-width="140px" label-position="top"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´ååå·ï¼"> |
| | | <el-input :model-value="detailData.purchaseContractNumber || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <el-input :model-value="detailData.salesContractNo || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºååç§°ï¼"> |
| | | <el-input :model-value="detailData.supplierName || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <el-input :model-value="detailData.projectName || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="仿¬¾æ¹å¼ï¼"> |
| | | <el-input :model-value="detailData.paymentMethod || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¾è®¢æ¥æï¼"> |
| | | <el-input :model-value="detailData.executionDate || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äººï¼"> |
| | | <el-input :model-value="detailData.recorderName || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥æ¥æï¼"> |
| | | <el-input :model-value="detailData.entryDate || ''" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="审æ¹äººéæ©ï¼"> |
| | | <div class="approver-nodes-container"> |
| | | <div v-for="(name, index) in approverNames" :key="`${name}-${index}`" class="approver-node-item"> |
| | | <div class="approver-node-header"> |
| | | <span class="approver-node-label">审æ¹èç¹ {{ index + 1 }}</span> |
| | | </div> |
| | | <el-input :model-value="name" disabled /> |
| | | </div> |
| | | <el-empty v-if="!approverNames.length" description="ææ å®¡æ¹äººä¿¡æ¯" /> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-form-item label="产åä¿¡æ¯ï¼"> |
| | | <el-table :data="detailData.productData" border show-summary :summary-method="summarizeProductTable"> |
| | | <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="90" /> |
| | | <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" width="150" :formatter="formattedNumber" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" prop="taxInclusiveTotalPrice" width="150" :formatter="formattedNumber" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" prop="taxExclusiveTotalPrice" width="150" :formatter="formattedNumber" /> |
| | | <el-table-column label="æ¯å¦è´¨æ£" prop="isChecked" width="100"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isChecked ? 'success' : 'info'"> |
| | | {{ scope.row.isChecked ? 'æ¯' : 'å¦' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ¯å¦åæ ¼" min-width="180"> |
| | | <template #default="scope"> |
| | | <el-form-item |
| | | :prop="`productData.${scope.$index}.isQualified`" |
| | | :rules="[{ required: true, message: 'è¯·éæ©æ¯å¦åæ ¼', trigger: 'change' }]" |
| | | class="inline-form-item" |
| | | > |
| | | <el-radio-group v-model="scope.row.isQualified"> |
| | | <el-radio :label="1">åæ ¼</el-radio> |
| | | <el-radio :label="2">ä¸åæ ¼</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ä¸åæ ¼åå " min-width="220"> |
| | | <template #default="scope"> |
| | | <el-form-item |
| | | :prop="`productData.${scope.$index}.reason`" |
| | | :rules="[{ |
| | | validator: (_rule, value, callback) => validateReason(scope.row, value, callback), |
| | | trigger: 'blur' |
| | | }]" |
| | | class="inline-form-item" |
| | | > |
| | | <el-input |
| | | v-model="scope.row.reason" |
| | | :disabled="scope.row.isQualified !== 2" |
| | | placeholder="ä¸åæ ¼æ¶è¯·å¡«ååå " |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-form-item> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼"> |
| | | <el-input :model-value="detailData.remarks || ''" type="textarea" :rows="2" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ææï¼"> |
| | | <div class="file-list"> |
| | | <el-tag v-for="file in detailData.salesLedgerFiles" :key="file.id || file.fileName" class="file-tag"> |
| | | {{ file.fileName || file.name }} |
| | | </el-tag> |
| | | <el-empty v-if="!detailData.salesLedgerFiles?.length" description="ææ éä»¶" /> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, reactive, ref, watch } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue' |
| | | |
| | | const props = defineProps({ |
| | | modelValue: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | record: { |
| | | type: Object, |
| | | default: () => ({}) |
| | | } |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:modelValue', 'submit']) |
| | | |
| | | const formRef = ref() |
| | | |
| | | const dialogVisible = computed({ |
| | | get: () => props.modelValue, |
| | | set: (value) => emit('update:modelValue', value) |
| | | }) |
| | | |
| | | const createDefaultDetail = () => ({ |
| | | id: '', |
| | | purchaseContractNumber: '', |
| | | salesContractNo: '', |
| | | supplierName: '', |
| | | projectName: '', |
| | | paymentMethod: '', |
| | | executionDate: '', |
| | | recorderName: '', |
| | | entryDate: '', |
| | | remarks: '', |
| | | approveUserIds: '', |
| | | approverNames: [], |
| | | salesLedgerFiles: [], |
| | | productData: [] |
| | | }) |
| | | |
| | | const detailData = reactive(createDefaultDetail()) |
| | | |
| | | const approverNames = computed(() => detailData.approverNames || []) |
| | | |
| | | const formattedNumber = (_row, _column, cellValue) => { |
| | | const value = Number(cellValue) |
| | | return Number.isFinite(value) ? value.toFixed(2) : '0.00' |
| | | } |
| | | |
| | | const summarizeProductTable = ({ columns, data }) => { |
| | | const sumFields = ['quantity', 'taxInclusiveUnitPrice', 'taxInclusiveTotalPrice', 'taxExclusiveTotalPrice'] |
| | | const sums = [] |
| | | columns.forEach((column, index) => { |
| | | if (index === 0) { |
| | | sums[index] = 'å计' |
| | | return |
| | | } |
| | | if (!sumFields.includes(column.property)) { |
| | | sums[index] = '' |
| | | return |
| | | } |
| | | const total = data.reduce((sum, item) => sum + Number(item?.[column.property] || 0), 0) |
| | | sums[index] = Number.isFinite(total) ? total.toFixed(2) : '0.00' |
| | | }) |
| | | return sums |
| | | } |
| | | |
| | | const validateReason = (row, value, callback) => { |
| | | if (row.isQualified === 2 && (!value || !value.trim())) { |
| | | callback(new Error('ä¸åæ ¼æ¶å¿
须填ååå ')) |
| | | return |
| | | } |
| | | callback() |
| | | } |
| | | |
| | | watch( |
| | | () => props.record, |
| | | (value) => { |
| | | const nextData = createDefaultDetail() |
| | | Object.assign(nextData, value || {}) |
| | | nextData.productData = (value?.productData || []).map((item) => ({ |
| | | ...item, |
| | | isQualified: item.isQualified ?? undefined, |
| | | reason: item.reason || '' |
| | | })) |
| | | nextData.salesLedgerFiles = value?.salesLedgerFiles || [] |
| | | nextData.approverNames = value?.approverNames || [] |
| | | Object.assign(detailData, nextData) |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ) |
| | | |
| | | const handleClose = () => { |
| | | dialogVisible.value = false |
| | | } |
| | | |
| | | const handleConfirm = async () => { |
| | | if (!formRef.value) { |
| | | return |
| | | } |
| | | try { |
| | | await formRef.value.validate() |
| | | const unqualifiedRows = detailData.productData.filter((item) => item.isQualified === 2) |
| | | emit('submit', { |
| | | id: detailData.id, |
| | | purchaseContractNumber: detailData.purchaseContractNumber, |
| | | supplierName: detailData.supplierName, |
| | | projectName: detailData.projectName, |
| | | productData: detailData.productData.map((item) => ({ |
| | | id: item.id, |
| | | specificationModel: item.specificationModel, |
| | | quantity: item.quantity, |
| | | isQualified: item.isQualified, |
| | | reason: item.reason || '' |
| | | })), |
| | | unqualifiedQuantity: unqualifiedRows.reduce((sum, item) => sum + Number(item.quantity || 0), 0) |
| | | }) |
| | | dialogVisible.value = false |
| | | } catch (_error) { |
| | | ElMessage.warning('请å
å®ææ¯æ¡äº§åçæ¶è´§å¤æ') |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approver-nodes-container { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .approver-node-item { |
| | | flex: 0 0 calc(33.333% - 12px); |
| | | min-width: 220px; |
| | | padding: 12px; |
| | | background-color: #fff; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | } |
| | | |
| | | .approver-node-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .approver-node-label { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #606266; |
| | | } |
| | | |
| | | .inline-form-item { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .file-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | width: 100%; |
| | | } |
| | | |
| | | .file-tag { |
| | | margin-right: 0; |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .approver-node-item { |
| | | flex: 0 0 calc(50% - 8px); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .approver-node-item { |
| | | flex: 0 0 100%; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <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="salesLedgerId"> |
| | | <el-select |
| | | v-model="form.salesLedgerId" |
| | | placeholder="è¯·éæ©éå®è®¢å" |
| | | clearable |
| | | filterable |
| | | :disabled="isViewMode" |
| | | style="width: 100%" |
| | | @change="handleSalesLedgerChange" |
| | | > |
| | | <el-option |
| | | v-for="item in salesLedgerOptions" |
| | | :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="productId"> |
| | | <el-tree-select |
| | | v-model="form.productId" |
| | |
| | | import {userListNoPage} from "@/api/system/user.js"; |
| | | import {qualityInspectDetailByProductId, getQualityTestStandardParamByTestStandardId} from "@/api/qualityManagement/metricMaintenance.js"; |
| | | import {qualityInspectParamInfo} from "@/api/qualityManagement/qualityInspectParam.js"; |
| | | import {ledgerListNoPage} from "@/api/salesManagement/salesLedger.js"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | |
| | |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | salesLedgerId: "", |
| | | salesContractNo: "", |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | const currentProductId = ref(0); |
| | | const testStandardOptions = ref([]); // ææ éæ©ä¸ææ¡æ°æ® |
| | | const modelOptions = ref([]); |
| | | const salesLedgerOptions = ref([]); // éå®è®¢åä¸ææ¡æ°æ® |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = async (type, row) => { |
| | |
| | | proxy.$refs.formRef?.clearValidate(); |
| | | |
| | | // å¹¶è¡å è½½åºç¡æ°æ® |
| | | const [userListsRes] = await Promise.all([ |
| | | const [userListsRes, salesLedgerRes] = await Promise.all([ |
| | | userListNoPage(), |
| | | getProductOptions(), |
| | | getOptions().then((res) => { |
| | | supplierList.value = res.data; |
| | | }), |
| | | ledgerListNoPage({ current: -1, size: -1 }).then((res) => { |
| | | salesLedgerOptions.value = res.data || []; |
| | | }) |
| | | ]); |
| | | userList.value = userListsRes.data; |
| | |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | } |
| | | |
| | | // éå®è®¢åéæ©ååå¤ç |
| | | const handleSalesLedgerChange = (value) => { |
| | | const selectedItem = salesLedgerOptions.value.find(item => item.id == value); |
| | | if (selectedItem) { |
| | | form.value.salesContractNo = selectedItem.salesContractNo || ''; |
| | | } else { |
| | | form.value.salesContractNo = ''; |
| | | } |
| | | } |
| | | |
| | | const handleQualifiedQuantityChange = (value) => { |
| | | if (value === null || value === undefined) { |
| | | form.value.qualifiedQuantity = 0; |
| | |
| | | :model="searchForm" |
| | | class="demo-form-inline"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="产ååç§°" |
| | | prop="productName"> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥äº§ååç§°æç´¢" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="6"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="æ£æµæ¥æ" |
| | | prop="entryDate"> |
| | | <el-date-picker v-model="searchForm.entryDate" |
| | |
| | | @change="changeDaterange" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-col :span="6"> |
| | | <el-form-item label="éå®åå·" |
| | | prop="salesContractNo"> |
| | | <el-input v-model="searchForm.salesContractNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥éå®åå·æç´¢" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="ç产工åå·" |
| | | prop="workOrderNo"> |
| | | <el-input v-model="searchForm.workOrderNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥ç产工åå·æç´¢" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div class="actions"> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="margin-bottom: 20px; text-align: right;"> |
| | | <el-button type="primary" @click="openQuickCheck">å¿«éæ£éª</el-button> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | qualityInspectListPage, |
| | | qualityInspectUpdate, |
| | | submitQualityInspect, |
| | | batchQuickInspect, |
| | | } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import FilesDia from "@/views/qualityManagement/finalInspection/components/filesDia.vue"; |
| | | import dayjs from "dayjs"; |
| | |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "æ£æµæ¥æ", |
| | |
| | | { |
| | | label: "éå®åå·", |
| | | prop: "salesContractNo", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "ç产工åå·", |
| | | prop: "workOrderNo", |
| | | width: 120, |
| | | }, |
| | | { |
| | |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å¿«éæ£éªç¡®è®¤æ¡ |
| | | const openQuickCheck = () => { |
| | | // æ£æ¥æ¯å¦éæ©äºæ°æ® |
| | | if (!selectedRows.value || selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请å
éæ©è¦æ£éªçæ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | // è¿æ»¤åºæªæäº¤çæ°æ® |
| | | const unSubmittedRows = selectedRows.value.filter(item => item.inspectState !== 1); |
| | | if (unSubmittedRows.length === 0) { |
| | | proxy.$modal.msgWarning("éä¸çæ°æ®å·²å
¨é¨æäº¤ï¼æ éé夿£éª"); |
| | | return; |
| | | } |
| | | |
| | | const totalCount = selectedRows.value.length; |
| | | const submittedCount = totalCount - unSubmittedRows.length; |
| | | |
| | | let confirmMessage = `已鿩 ${totalCount} æ¡æ£éªå`; |
| | | if (submittedCount > 0) { |
| | | confirmMessage += `ï¼å
¶ä¸ ${submittedCount} æ¡å·²æäº¤ï¼å°èªå¨è·³è¿ï¼`; |
| | | } |
| | | confirmMessage += `\n\n确认åå°èªå¨ï¼\n· æ£éªç»æè®¾ä¸º"åæ ¼"\n· åæ ¼æ°éè®¾ä¸ºæ»æ°\n· ä¸åæ ¼æ°é设为 0\n· æäº¤å¹¶å
¥åº`; |
| | | |
| | | ElMessageBox.confirm(confirmMessage, "å¿«éæ£éª", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | dangerouslyUseHTMLString: false, |
| | | }) |
| | | .then(() => { |
| | | // è°ç¨æ¹éå¿«éæ£éªæ¥å£ |
| | | const ids = unSubmittedRows.map(item => item.id); |
| | | batchQuickInspect(ids).then(res => { |
| | | proxy.$modal.msgSuccess(res.msg || "å¿«éæ£éªå®æ"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼æ°å¢æ£éªå¼¹æ¡ |
| | | const openInspectionForm = (type, row) => { |
| | | nextTick(() => { |
| | |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="margin-bottom: 20px; text-align: right;"> |
| | | <el-button type="primary" @click="openQuickCheck">å¿«éæ£éª</el-button> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | qualityInspectListPage, |
| | | qualityInspectUpdate, |
| | | submitQualityInspect, |
| | | batchQuickInspect, |
| | | } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import FilesDia from "@/views/qualityManagement/processInspection/components/filesDia.vue"; |
| | | import dayjs from "dayjs"; |
| | |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "æ£æµæ¥æ", |
| | | prop: "checkTime", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "ç产工åå·", |
| | | prop: "workOrderNo", |
| | | width: 120, |
| | | }, |
| | | { |
| | |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å¿«éæ£éªç¡®è®¤æ¡ |
| | | const openQuickCheck = () => { |
| | | // æ£æ¥æ¯å¦éæ©äºæ°æ® |
| | | if (!selectedRows.value || selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请å
éæ©è¦æ£éªçæ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | // è¿æ»¤åºæªæäº¤çæ°æ® |
| | | const unSubmittedRows = selectedRows.value.filter(item => item.inspectState !== 1); |
| | | if (unSubmittedRows.length === 0) { |
| | | proxy.$modal.msgWarning("éä¸çæ°æ®å·²å
¨é¨æäº¤ï¼æ éé夿£éª"); |
| | | return; |
| | | } |
| | | |
| | | const totalCount = selectedRows.value.length; |
| | | const submittedCount = totalCount - unSubmittedRows.length; |
| | | |
| | | let confirmMessage = `已鿩 ${totalCount} æ¡æ£éªå`; |
| | | if (submittedCount > 0) { |
| | | confirmMessage += `ï¼å
¶ä¸ ${submittedCount} æ¡å·²æäº¤ï¼å°èªå¨è·³è¿ï¼`; |
| | | } |
| | | confirmMessage += `\n\n确认åå°èªå¨ï¼\n· æ£éªç»æè®¾ä¸º"åæ ¼"\n· åæ ¼æ°éè®¾ä¸ºæ»æ°\n· ä¸åæ ¼æ°é设为 0\n· æäº¤å¹¶å
¥åº`; |
| | | |
| | | ElMessageBox.confirm(confirmMessage, "å¿«éæ£éª", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | dangerouslyUseHTMLString: false, |
| | | }) |
| | | .then(() => { |
| | | // è°ç¨æ¹éå¿«éæ£éªæ¥å£ |
| | | const ids = unSubmittedRows.map(item => item.id); |
| | | batchQuickInspect(ids).then(res => { |
| | | proxy.$modal.msgSuccess(res.msg || "å¿«éæ£éªå®æ"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼æ°å¢æ£éªå¼¹æ¡ |
| | | const openInspectionForm = (type, row) => { |
| | | nextTick(() => { |
| | |
| | | style="margin-left: 10px">æç´¢ |
| | | </el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="margin-bottom: 20px; text-align: right;"> |
| | | <el-button type="primary" @click="openQuickCheck">å¿«éæ£éª</el-button> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | qualityInspectListPage, |
| | | qualityInspectUpdate, |
| | | submitQualityInspect, |
| | | batchQuickInspect, |
| | | } from "@/api/qualityManagement/rawMaterialInspection.js"; |
| | | import FilesDia from "@/views/qualityManagement/rawMaterialInspection/components/filesDia.vue"; |
| | | import dayjs from "dayjs"; |
| | |
| | | }, |
| | | }); |
| | | const { searchForm, rules } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "æ£æµæ¥æ", |
| | |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å¿«éæ£éªç¡®è®¤æ¡ |
| | | const openQuickCheck = () => { |
| | | // æ£æ¥æ¯å¦éæ©äºæ°æ® |
| | | if (!selectedRows.value || selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("请å
éæ©è¦æ£éªçæ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | // è¿æ»¤åºæªæäº¤çæ°æ® |
| | | const unSubmittedRows = selectedRows.value.filter(item => item.inspectState !== 1); |
| | | if (unSubmittedRows.length === 0) { |
| | | proxy.$modal.msgWarning("éä¸çæ°æ®å·²å
¨é¨æäº¤ï¼æ éé夿£éª"); |
| | | return; |
| | | } |
| | | |
| | | const totalCount = selectedRows.value.length; |
| | | const unSubmittedCount = unSubmittedRows.length; |
| | | const submittedCount = totalCount - unSubmittedCount; |
| | | |
| | | let confirmMessage = `已鿩 ${totalCount} æ¡æ£éªå`; |
| | | if (submittedCount > 0) { |
| | | confirmMessage += `ï¼å
¶ä¸ ${submittedCount} æ¡å·²æäº¤ï¼å°èªå¨è·³è¿ï¼`; |
| | | } |
| | | confirmMessage += `\n\n确认åå°èªå¨ï¼\n· æ£éªç»æè®¾ä¸º"åæ ¼"\n· åæ ¼æ°éè®¾ä¸ºæ»æ°\n· ä¸åæ ¼æ°é设为 0\n· æäº¤å¹¶å
¥åº`; |
| | | |
| | | ElMessageBox.confirm(confirmMessage, "å¿«éæ£éª", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | dangerouslyUseHTMLString: false, |
| | | }) |
| | | .then(() => { |
| | | // è°ç¨æ¹éå¿«éæ£éªæ¥å£ |
| | | const ids = unSubmittedRows.map(item => item.id); |
| | | batchQuickInspect(ids).then(res => { |
| | | proxy.$modal.msgSuccess(res.msg || "å¿«éæ£éªå®æ"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = (type, row) => { |
| | | nextTick(() => { |
| | |
| | | <div class="stat-card"> |
| | | <img src="@/assets/BI/icon@2x.png" alt="徿 " class="card-icon" /> |
| | | <div class="card-content"> |
| | | <span class="card-label">åå·¥æ»æ°</span> |
| | | <span class="card-value">{{ totalStaff }}</span> |
| | | <div class="card-compare" :class="compareClass(staffYoY)"> |
| | | <span>忝</span> |
| | | <span class="compare-value">{{ formatPercent(staffYoY) }}</span> |
| | | <span class="compare-icon">{{ staffYoY >= 0 ? 'â' : 'â' }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="stat-card"> |
| | | <img src="@/assets/BI/icon@2x.png" alt="徿 " class="card-icon" /> |
| | | <div class="card-content"> |
| | | <span class="card-label">å®¢æ·æ»æ°</span> |
| | | <span class="card-value">{{ totalCustomers }}</span> |
| | | <div class="card-compare" :class="compareClass(customersYoY)"> |
| | |
| | | import { measuringInstrumentListPage } from '@/api/equipmentManagement/measurementEquipment.js' |
| | | |
| | | // ç»è®¡æ°æ® |
| | | const totalStaff = ref(0) |
| | | const totalCustomers = ref(0) |
| | | const totalSuppliers = ref(0) |
| | | // 忝 |
| | | const staffYoY = ref(0) |
| | | const customersYoY = ref(0) |
| | | const suppliersYoY = ref(0) |
| | | const equipmentNum = ref(0) |
| | |
| | | |
| | | const compareClass = (val) => (val >= 0 ? 'compare-up' : 'compare-down') |
| | | |
| | | // è·ååå·¥ã客æ·ãä¾åºåæ°é |
| | | // è·å客æ·ãä¾åºåæ°é |
| | | const getNum = () => { |
| | | summaryStatistics().then((res) => { |
| | | totalStaff.value = res.data.totalStaff |
| | | staffYoY.value = res.data.staffGrowthRate |
| | | totalCustomers.value = res.data.totalCustomer |
| | | customersYoY.value = res.data.customerGrowthRate |
| | | totalSuppliers.value = res.data.totalSupplier |
| | |
| | | padding: 18px; |
| | | height: 240px; |
| | | padding-top: 0px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .equipment-header { |
| | |
| | | background-repeat: no-repeat; |
| | | padding: 20px; |
| | | padding-top: 10px; |
| | | height: 186px; |
| | | height: 480px; |
| | | flex: 1; |
| | | } |
| | | |
| | | .event-header { |
| | |
| | | list-style: none; |
| | | padding: 0; |
| | | margin: 0; |
| | | height: 120px; /* æç¨æ·è¦æ±è°æ´é«åº¦ */ |
| | | height: 210px; |
| | | overflow: hidden; |
| | | font-size: 15px; |
| | | } |
| | |
| | | <!-- ä¸é´åºå --> |
| | | <div class="center-panel"> |
| | | <CenterTop /> |
| | | |
| | | <CenterBottom /> |
| | | </div> |
| | | |
| | | <!-- å³ä¾§åºå --> |
| | |
| | | import LeftTop from './components/basic/left-top.vue' |
| | | import LeftBottom from './components/basic/left-bottom.vue' |
| | | import CenterTop from './components/basic/center-top.vue' |
| | | import CenterBottom from './components/basic/center-bottom.vue' |
| | | import RightTop from './components/basic/right-top.vue' |
| | | import RightBottom from './components/basic/right-bottom.vue' |
| | | import useUserStore from '@/store/modules/user' |
| | |
| | | </div> |
| | | </div> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <!-- 左侧客æ·å表 --> |
| | | <el-col :span="8"> |
| | | <div class="table_list" |
| | | style="width: 100%"> |
| | | <el-table :data="tableData" |
| | |
| | | prop="contractAmounts" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="忬¾éé¢(å
)" |
| | | prop="receiptPaymentAmount" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="åºæ¶éé¢(å
)" |
| | | prop="receiptableAmount" |
| | | show-overflow-tooltip |
| | | width="200"> |
| | | <template #default="{ row, column }"> |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.receiptableAmount) }} |
| | | </el-text> |
| | | </template> |
| | | </el-table-column> |
| | | width="150" /> |
| | | <!-- <el-table-column label="åºæ¶éé¢(å
)"--> |
| | | <!-- prop="receiptableAmount"--> |
| | | <!-- show-overflow-tooltip--> |
| | | <!-- width="150">--> |
| | | <!-- <template #default="{ row, column }">--> |
| | | <!-- <el-text type="danger">--> |
| | | <!-- {{ formattedNumber(row, column, row.receiptableAmount) }}--> |
| | | <!-- </el-text>--> |
| | | <!-- </template>--> |
| | | <!-- </el-table-column>--> |
| | | </el-table> |
| | | <pagination v-show="total > 0" |
| | | :total="total" |
| | |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <!-- å³ä¾§è®¢åä¿¡æ¯ --> |
| | | <el-col :span="16"> |
| | | <div class="table_list" |
| | | style="width: 100%"> |
| | | <el-table :data="receiptRecord" |
| | | |
| | | <el-table :data="orderRecord" |
| | | border |
| | | :row-key="(row) => row.id" |
| | | show-summary |
| | | :summary-method="summarizeMainTable1" |
| | | height="calc(100vh - 18.5em)"> |
| | | v-loading="orderLoading" |
| | | height="calc(100vh - 20em)"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="ååç¾è®¢æ¥æ" |
| | | prop="executionDate" |
| | | show-overflow-tooltip |
| | | width="110" /> |
| | | <el-table-column label="éå®ååå·" |
| | | <el-table-column label="éå®è®¢å" |
| | | prop="salesContractNo" |
| | | show-overflow-tooltip |
| | | width="200" /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | width="150" /> |
| | | <!-- <el-table-column label="å货订åå·" |
| | | prop="shippingNo" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="忬¾éé¢(å
)" |
| | | prop="receiptPaymentAmount" |
| | | width="150" /> --> |
| | | <el-table-column label="客æ·åç§°" |
| | | prop="customerName" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="åºæ¶éé¢(å
)" |
| | | prop="receiptableAmount" |
| | | width="150" /> |
| | | <el-table-column label="产ååç§°" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | width="200"> |
| | | <template #default="{ row, column }"> |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.receiptableAmount) }} |
| | | </el-text> |
| | | width="150" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" |
| | | show-overflow-tooltip |
| | | width="120" /> |
| | | <el-table-column label="åè´§æ¶é´" |
| | | prop="shippingDate" |
| | | show-overflow-tooltip |
| | | width="110" /> |
| | | <el-table-column label="åè´§æ°é" |
| | | prop="totalQuantity" |
| | | show-overflow-tooltip |
| | | width="100" /> |
| | | <!-- <el-table-column label="å货车çå·" |
| | | prop="shippingCarNumber" |
| | | show-overflow-tooltip |
| | | width="120" /> |
| | | <el-table-column label="å¿«éå
¬å¸" |
| | | prop="expressCompany" |
| | | show-overflow-tooltip |
| | | width="120" /> |
| | | <el-table-column label="å¿«éåå·" |
| | | prop="expressNumber" |
| | | show-overflow-tooltip |
| | | width="150" /> --> |
| | | <el-table-column label="åè´§ç¶æ" |
| | | prop="status" |
| | | align="center" |
| | | width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getApprovalStatusType(row.status)"> |
| | | {{ getApprovalStatusText(row.status) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="åºåºåå·" |
| | | prop="outboundBatches" |
| | | show-overflow-tooltip |
| | | width="130" /> |
| | | </el-table> |
| | | <pagination v-show="recordTotal > 0" |
| | | :total="recordTotal" |
| | | <pagination v-show="orderTotal > 0" |
| | | :total="orderTotal" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="recordPage.current" |
| | | :limit="recordPage.size" |
| | | @pagination="recordPaginationChange" /> |
| | | :page="orderPage.current" |
| | | :limit="orderPage.size" |
| | | @pagination="orderPaginationChange" /> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { onMounted, ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { |
| | | customewTransactions, |
| | | customewTransactionsDetails, |
| | | } from "@/api/salesManagement/indicatorStats.js"; |
| | | import { deliveryLedgerListPage } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import Pagination from "../../../components/PIMTable/Pagination.vue"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const receiptRecord = ref([]); |
| | | const orderRecord = ref([]); |
| | | const tableLoading = ref(false); |
| | | const orderLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const recordPage = reactive({ |
| | | const orderPage = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | const recordTotal = ref(0); |
| | | const orderTotal = ref(0); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | searchText: "", |
| | |
| | | }); |
| | | const customerId = ref(""); |
| | | const { searchForm } = toRefs(data); |
| | | const originReceiptRecord = ref([]); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | |
| | | tableData.value = res.data.records; |
| | | total.value = res.data.total; |
| | | if (tableData.value.length > 0) { |
| | | recordPage.current = 1; |
| | | orderPage.current = 1; |
| | | customerId.value = tableData.value[0].customerId; |
| | | receiptPaymentList(customerId.value); |
| | | getOrderList(customerId.value); |
| | | } else { |
| | | orderRecord.value = []; |
| | | customerId.value = ""; |
| | | } |
| | | }); |
| | | }; |
| | |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | ["invoiceTotal", "receiptPaymentAmount", "unReceiptPaymentAmount"], |
| | | ["contractAmounts", "receiptableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | ticketsNum: { noDecimal: true }, |
| | | futureTickets: { noDecimal: true }, |
| | | } |
| | | ); |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeMainTable1 = param => { |
| | | var summarizeTable = proxy.summarizeTable( |
| | | param, |
| | | ["contractAmount", "receiptPaymentAmount", "receiptableAmount"], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | |
| | | // è·å订ååè¡¨ï¼æ ¹æ®å®¢æ·IDæ¥è¯¢åè´§å°è´¦ï¼ |
| | | const getOrderList = async (id) => { |
| | | orderLoading.value = true; |
| | | try { |
| | | // ä½¿ç¨ deliveryLedgerListPage æ¥å£æ ¹æ® customerId æ¥è¯¢ |
| | | const res = await deliveryLedgerListPage({ |
| | | customerId: id, |
| | | current: 1, |
| | | size: 1000, |
| | | }); |
| | | let orders = []; |
| | | if (res.data) { |
| | | if (Array.isArray(res.data)) { |
| | | orders = res.data; |
| | | } else if (res.data.records && Array.isArray(res.data.records)) { |
| | | orders = res.data.records; |
| | | } |
| | | } |
| | | ); |
| | | return summarizeTable; |
| | | |
| | | orderTotal.value = orders.length; |
| | | handleOrderPagination({ page: orderPage.current, limit: orderPage.size }, orders); |
| | | } catch (error) { |
| | | console.error('è·å订åå表失败:', error); |
| | | orderRecord.value = []; |
| | | } finally { |
| | | orderLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const receiptPaymentList = id => { |
| | | const param = { |
| | | customerId: id, |
| | | current: recordPage.current, |
| | | size: recordPage.size, |
| | | }; |
| | | customewTransactionsDetails(param).then(res => { |
| | | if (Array.isArray(res.data)) { |
| | | originReceiptRecord.value = res.data; |
| | | recordTotal.value = res.data.length; |
| | | handlePagination({ page: 1, limit: recordPage.size }); |
| | | } else { |
| | | receiptRecord.value = res.data.records; |
| | | recordTotal.value = res.data.total; |
| | | } |
| | | }); |
| | | // 订åå表å页 |
| | | const orderPaginationChange = pagination => { |
| | | orderPage.current = pagination.page; |
| | | orderPage.size = pagination.limit; |
| | | getOrderList(customerId.value); |
| | | }; |
| | | |
| | | // æ±æ¬¾è®°å½å表å页 |
| | | const recordPaginationChange = pagination => { |
| | | recordPage.current = pagination.page; |
| | | recordPage.size = pagination.limit; |
| | | receiptPaymentList(customerId.value); |
| | | const handleOrderPagination = ({ page, limit }, allOrders) => { |
| | | const start = (page - 1) * limit; |
| | | const end = start + limit; |
| | | orderRecord.value = allOrders.slice(start, end); |
| | | }; |
| | | |
| | | const rowClickMethod = row => { |
| | | customerId.value = row.customerId; |
| | | receiptPaymentList(customerId.value); |
| | | orderPage.current = 1; |
| | | getOrderList(customerId.value); |
| | | }; |
| | | |
| | | const handlePagination = ({ page, limit }) => { |
| | | recordPage.current = page; |
| | | recordPage.size = limit; |
| | | // å®¡æ ¸ç¶ææ ç¾ç±»å |
| | | const getApprovalStatusType = (status) => { |
| | | const statusMap = { |
| | | 'å·²åè´§': 'success', |
| | | 'å®¡æ ¸éè¿': 'success', |
| | | 'å®¡æ ¸ä¸': 'warning', |
| | | 'å®¡æ ¸ä¸éè¿': 'danger', |
| | | }; |
| | | return statusMap[status] || 'info'; |
| | | }; |
| | | |
| | | const start = (page - 1) * limit; |
| | | const end = start + limit; |
| | | |
| | | receiptRecord.value = originReceiptRecord.value.slice(start, end); |
| | | // å®¡æ ¸ç¶æææ¬ |
| | | const getApprovalStatusText = (status) => { |
| | | const statusMap = { |
| | | 'å·²åè´§': 'å·²åè´§', |
| | | 'å®¡æ ¸éè¿': 'å®¡æ ¸éè¿', |
| | | 'å®¡æ ¸ä¸': 'å®¡æ ¸ä¸', |
| | | 'å®¡æ ¸ä¸éè¿': 'å®¡æ ¸ä¸éè¿', |
| | | }; |
| | | return statusMap[status] || status || '--'; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | |
| | | <style scoped lang="scss"> |
| | | .table_list { |
| | | width: 50%; |
| | | width: 100%; |
| | | } |
| | | |
| | | </style> |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´ååå·ï¼" prop="purchaseContractNumber"> |
| | | <el-select |
| | | v-model="form.purchaseContractNumber" |
| | | placeholder="è¯·éæ©éè´ååå·" |
| | | clearable |
| | | filterable |
| | | style="width: 100%" |
| | | :disabled="operationType === 'view'" |
| | | > |
| | | <el-option |
| | | v-for="item in purchaseContractOptions" |
| | | :key="item.purchaseContractNumber" |
| | | :label="item.purchaseContractNumber + ' - ' + item.supplierName" |
| | | :value="item.purchaseContractNumber" |
| | | /> |
| | | </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.deliveryDate" |
| | | 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" |
| | |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.entryDate" |
| | | 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="entryDate"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.deliveryDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | /> |
| | | <el-table-column label="æ¯å¦ç产" prop="isProduction" width="150"> |
| | | <!-- æ¯å¦ç产åå·²éèï¼é»è®¤å¼ä¸º false --> |
| | | <!-- <el-table-column label="æ¯å¦ç产" prop="isProduction" width="150"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isProduction ? 'success' : 'info'"> |
| | | {{ scope.row.isProduction ? "æ¯" : "å¦" }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table-column> --> |
| | | <el-table-column |
| | | fixed="right" |
| | | label="æä½" |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <!-- æ¯å¦çäº§åæ®µå·²éèï¼é»è®¤å¼ä¸º false --> |
| | | <!-- <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç产ï¼" prop="isProduction"> |
| | | <el-radio-group v-model="productForm.isProduction"> |
| | | <el-radio label="æ¯" :value="true" /> |
| | | <el-radio label="å¦" :value="false" /> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-col> --> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { getStockInventoryByModelId } from "@/api/inventoryManagement/stockInventory.js"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import { purchaseList } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import dayjs from "dayjs"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | |
| | | const customerOption = ref([]); |
| | | const productOptions = ref([]); |
| | | const modelOptions = ref([]); |
| | | const purchaseContractOptions = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | |
| | | executionDate: "", |
| | | hasProductionRecord: false, |
| | | createTime: "", |
| | | purchaseContractNumber: "", |
| | | }, |
| | | rules: { |
| | | salesman: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | isProduction: false, |
| | | isProduction: false, // é»è®¤å¼ä¸º falseï¼å¦ï¼ |
| | | }, |
| | | productRules: { |
| | | productCategory: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | |
| | | const getDeliveryBatchNoList = async (productModelId) => { |
| | | if (!productModelId) return []; |
| | | const res = await getStockInventoryByModelId(productModelId); |
| | | const rawList = Array.isArray(res?.data) |
| | | ? res.data |
| | | : res?.data?.records || res?.data?.rows || []; |
| | | const rawList = res.data || []; |
| | | const seenIds = new Set(); |
| | | return rawList |
| | | .filter((item) => { |
| | | if (!item?.id || !item?.batchNo || seenIds.has(item.id)) { |
| | | return false; |
| | | } |
| | | seenIds.add(item.id); |
| | | return true; |
| | | }) |
| | | .map((item) => ({ |
| | | ...item, |
| | | deliveryQuantity: 0, |
| | | })); |
| | | }; |
| | | const validateDeliveryShippingCarNumber = (_rule, value, callback) => { |
| | | if (deliveryForm.value.type === "货车" && !value) { |
| | |
| | | listCustomer({ current: -1, size: -1, type: 0 }).then((res) => { |
| | | customerOption.value = res.data.records; |
| | | }); |
| | | // è·åéè´ååå表 |
| | | await getPurchaseContractList(); |
| | | form.value.entryPerson = userStore.id; |
| | | if (type === "add") { |
| | | // æ°å¢æ¶è®¾ç½®å½å
¥æ¥æä¸ºå½å¤© |
| | |
| | | taxInclusiveTotalPrice: taxInclusiveTotalPrice, |
| | | taxExclusiveTotalPrice: taxExclusiveTotalPrice, |
| | | invoiceType: "墿®ç¥¨", |
| | | isProduction: true, |
| | | isProduction: false, // é»è®¤å¼ä¸º falseï¼å¦ï¼ |
| | | productId: p.productId, |
| | | productModelId: p.productModelId, |
| | | }; |
| | |
| | | productOperationType.value = type; |
| | | productForm.value = {}; |
| | | if (type === "add") { |
| | | productForm.value.isProduction = true; |
| | | productForm.value.isProduction = false; // é»è®¤å¼ä¸º falseï¼å¦ï¼ |
| | | } |
| | | proxy.resetForm("productFormRef"); |
| | | if (type === "edit") { |
| | |
| | | } |
| | | productFormVisible.value = true; |
| | | }; |
| | | |
| | | // è·åéè´ååå表 |
| | | const getPurchaseContractList = async () => { |
| | | try { |
| | | const res = await purchaseList({ current: -1, size: -1 }); |
| | | purchaseContractOptions.value = res.rows; |
| | | } catch (error) { |
| | | console.error("è·åéè´ååå表失败", error); |
| | | purchaseContractOptions.value = []; |
| | | } |
| | | }; |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | | proxy.$refs["productFormRef"].validate((valid) => { |