| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request.js"; |
| | | |
| | | // å页æ¥è¯¢èæåºåè®°å½å表 |
| | | export const getConsumablesInListPage = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/pageConsumablesInventory", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å建èæåºåè®°å½ï¼æ°å¢åºåï¼ |
| | | export const createConsumablesIn = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/addConsumablesInventory", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // åå°èæåºåè®°å½ï¼æ£ååºåï¼ |
| | | export const subtractConsumablesIn = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/subtractConsumablesInventory", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // èæåºåæ¥è¡¨å页 |
| | | export const getConsumablesInReportList = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/ConsumablesInventoryPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // èæè¿åºåæ¥è¡¨ï¼ç»è®¡å个产åçå
¥åºååºåºè®°å½ï¼ |
| | | export const getConsumablesInInAndOutReportList = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/ConsumablesInAndOutRecord", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å»ç»èæåºåè®°å½ |
| | | export const frozenConsumablesIn = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/frozenConsumables", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // è§£å»èæåºåè®°å½ |
| | | export const thawConsumablesIn = (params) => { |
| | | return request({ |
| | | url: "/consumablesInventory/thawConsumables", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // èæå
¥åºç®¡ç-æ¥è¯¢å
¥åºè®°å½å表 |
| | | export const getConsumablesInRecordListPage = (params) => { |
| | | return request({ |
| | | url: "/consumablesInRecord/listPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | export const updateConsumablesInRecord = (id, data) => { |
| | | return request({ |
| | | url: "/consumablesInRecord/" + id, |
| | | method: "put", |
| | | data: data, |
| | | }); |
| | | }; |
| | | |
| | | export const batchDeleteConsumablesInRecords = (ids) => { |
| | | return request({ |
| | | url: "/consumablesInRecord", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | // èæåºåºå°è´¦-æ¥è¯¢åºåºå表 |
| | | export const getConsumablesOutRecordPage = (params) => { |
| | | return request({ |
| | | url: "/consumablesOutRecord/listPage", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å é¤èæåºåºä¿¡æ¯ |
| | | export const delConsumablesOutRecord = (ids) => { |
| | | return request({ |
| | | url: "/consumablesOutRecord", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request.js"; |
| | | |
| | | // å页æ¥è¯¢èæä¸åæ ¼åºåè®°å½å表 |
| | | export const getConsumablesUninventoryListPage = (params) => { |
| | | return request({ |
| | | url: "/consumablesUnInventory/pageConsumablesUnInventory", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | | |
| | | // å建èæä¸åæ ¼åºåè®°å½ |
| | | export const createConsumablesUnInventory = (params) => { |
| | | return request({ |
| | | url: "/consumablesUninventory/addstockUninventory", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // åå°èæä¸åæ ¼åºåè®°å½ |
| | | export const subtractConsumablesUnInventory = (params) => { |
| | | return request({ |
| | | url: "/consumablesUninventory/subtractstockUninventory", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // å»ç»èæä¸åæ ¼åºåè®°å½ |
| | | export const frozenConsumablesUninventory = (params) => { |
| | | return request({ |
| | | url: "/consumablesUninventory/frozenStock", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| | | |
| | | // è§£å»èæä¸åæ ¼åºåè®°å½ |
| | | export const thawConsumablesUninventory = (params) => { |
| | | return request({ |
| | | url: "/consumablesUninventory/thawStock", |
| | | method: "post", |
| | | data: params, |
| | | }); |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">åºåºæ¥æï¼</span> |
| | | <el-date-picker |
| | | v-model="searchForm.timeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©æ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | @change="handleQuery" |
| | | /> |
| | | <span class="search_title ml10">æ¥æºï¼</span> |
| | | <el-select v-model="searchForm.recordType" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option v-for="item in stockRecordTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value"/> |
| | | </el-select> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button type="primary" plain @click="handlePrint">æå°</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table |
| | | :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | style="width: 100%" |
| | | height="calc(100vh - 18.5em)" |
| | | > |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column |
| | | label="åºåºæ¹æ¬¡" |
| | | prop="outboundBatches" |
| | | min-width="100" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åºåºæ¥æ" |
| | | prop="createTime" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="产å大类" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="è§æ ¼åå·" |
| | | prop="model" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åä½" |
| | | prop="unit" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åºåºæ°é" |
| | | prop="stockOutNum" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åé(å¨)" |
| | | prop="netWeight" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åºåºäºº" |
| | | prop="createBy" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column label="æ¥æº" |
| | | prop="recordType" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="车ç" |
| | | prop="licensePlateNo" |
| | | show-overflow-tooltip |
| | | /> |
| | | </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 pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import { |
| | | getConsumablesOutRecordPage, |
| | | delConsumablesOutRecord, |
| | | } from "@/api/consumablesLogistics/consumablesOutRecord.js"; |
| | | import { |
| | | findAllQualifiedStockOutRecordTypeOptions, findAllUnQualifiedStockOutRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | // æ¥æºç±»åé项 |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: '0' |
| | | } |
| | | }) |
| | | |
| | | // æå°ç¸å
³ |
| | | const printPreviewVisible = ref(false); |
| | | const printData = ref([]); |
| | | |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | } |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getConsumablesOutRecordPage({ ...searchForm.value, ...page, type: props.type }) |
| | | .then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | tableData.value.map((item) => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.data.total; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const getRecordType = (recordType) => { |
| | | return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' |
| | | } |
| | | |
| | | // è·åæ¥æºç±»åé项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === '0') { |
| | | findAllQualifiedStockOutRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | return |
| | | } |
| | | findAllUnQualifiedStockOutRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | } |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | // è¿æ»¤æåæ°æ® |
| | | selectedRows.value = selection.filter((item) => item.id); |
| | | console.log("selection", selectedRows.value); |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/consumablesOutRecord/exportConsumablesOutRecord", {type: props.type}, props.type === '0' ? "èæåæ ¼åºåºå°è´¦.xlsx" : "èæä¸åæ ¼åºåºå°è´¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delConsumablesOutRecord(ids).then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æå°åè½ |
| | | const handlePrint = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©è¦æå°çæ°æ®"); |
| | | return; |
| | | } |
| | | printData.value = [...selectedRows.value]; |
| | | console.log('æå°æ°æ®:', printData.value); |
| | | printPreviewVisible.value = true; |
| | | }; |
| | | |
| | | // æ§è¡æå° |
| | | const executePrint = () => { |
| | | console.log('å¼å§æ§è¡æå°ï¼æ°æ®æ¡æ°:', printData.value.length); |
| | | console.log('æå°æ°æ®:', printData.value); |
| | | |
| | | // å建ä¸ä¸ªæ°çæå°çªå£ |
| | | const printWindow = window.open('', '_blank', 'width=800,height=600'); |
| | | |
| | | // æå»ºæå°å
容 |
| | | let printContent = ` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>æå°é¢è§</title> |
| | | <style> |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: "SimSun", serif; |
| | | background: white; |
| | | } |
| | | .print-page { |
| | | width: 200mm; |
| | | height: 75mm; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | background: white; |
| | | box-sizing: border-box; |
| | | page-break-after: always; |
| | | page-break-inside: avoid; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #000; |
| | | } |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .info-row { |
| | | line-height: 20px; |
| | | } |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 12px; |
| | | } |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .table-section { |
| | | margin-bottom: 40px; |
| | | // flex: 0.6; |
| | | } |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | } |
| | | .product-table th, .product-table td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | .product-table th { |
| | | font-weight: bold; |
| | | } |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | .footer-section { |
| | | margin-top: auto; |
| | | } |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 22px; |
| | | justify-content: space-between; |
| | | } |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | } |
| | | .footer-item .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .footer-item .value { |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .address-item .address-value { |
| | | min-width: 200px; |
| | | } |
| | | @media print { |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .print-page { |
| | | margin: 0; |
| | | padding: 10mm; |
| | | /* padding-left: 20mm; */ |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | `; |
| | | |
| | | // ä¸ºæ¯æ¡æ°æ®çææå°é¡µé¢ |
| | | printData.value.forEach((item, index) => { |
| | | printContent += ` |
| | | <div class="print-page"> |
| | | <div class="delivery-note"> |
| | | <div class="header"> |
| | | <div class="company-name">é¼è¯çå®ä¸æé责任å
¬å¸</div> |
| | | <div class="document-title">é¶å®åè´§å</div> |
| | | </div> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | | <span class="label">åè´§æ¥æï¼</span> |
| | | <span class="value">${formatDate(item.createTime)}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">客æ·åç§°ï¼</span> |
| | | <span class="value">${item.supplierName || 'å¼ ç±æ'}</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">åå·ï¼</span> |
| | | <span class="value">${item.code || ''}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼åå·</th> |
| | | <th>åä½</th> |
| | | <th>åä»·</th> |
| | | <th>é¶å®æ°é</th> |
| | | <th>é¶å®éé¢</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>${item.productName || 'ç ç°ç '}</td> |
| | | <td>${item.model || 'æ å'}</td> |
| | | <td>${item.unit || 'å'}</td> |
| | | <td>${item.taxInclusiveUnitPrice || '0'}</td> |
| | | <td>${item.inboundNum || '2000'}</td> |
| | | <td>${item.taxInclusiveTotalPrice || '0'}</td> |
| | | </tr> |
| | | </tbody> |
| | | <tfoot> |
| | | <tr> |
| | | <td class="label">å计</td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value">${item.inboundNum || '2000'}</td> |
| | | <td class="total-value">${item.taxInclusiveTotalPrice || '0'}</td> |
| | | </tr> |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§çµè¯ï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§äººï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item address-item"> |
| | | <span class="label">æ¶è´§å°åï¼</span> |
| | | <span class="value address-value"></span> |
| | | </div> |
| | | </div> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æä½åï¼</span> |
| | | <span class="value">${userStore.nickName || 'æå¼å'}</span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æå°æ¥æï¼</span> |
| | | <span class="value">${formatDateTime(new Date())}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | `; |
| | | }); |
| | | |
| | | printContent += ` |
| | | </body> |
| | | </html> |
| | | `; |
| | | |
| | | // åå
¥å
容尿°çªå£ |
| | | printWindow.document.write(printContent); |
| | | printWindow.document.close(); |
| | | |
| | | // çå¾
å
容å è½½å®æåæå° |
| | | printWindow.onload = () => { |
| | | setTimeout(() => { |
| | | printWindow.print(); |
| | | printWindow.close(); |
| | | printPreviewVisible.value = false; |
| | | }, 500); |
| | | }; |
| | | }; |
| | | |
| | | |
| | | |
| | | // æ ¼å¼åæ¥æ |
| | | const formatDate = (dateString) => { |
| | | if (!dateString) return getCurrentDate(); |
| | | const date = new Date(dateString); |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | return `${year}/${month}/${day}`; |
| | | }; |
| | | |
| | | // æ ¼å¼åæ¥ææ¶é´ |
| | | const formatDateTime = (date) => { |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, "0"); |
| | | const day = String(date.getDate()).padStart(2, "0"); |
| | | const hours = String(date.getHours()).padStart(2, "0"); |
| | | const minutes = String(date.getMinutes()).padStart(2, "0"); |
| | | const seconds = String(date.getSeconds()).padStart(2, "0"); |
| | | return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`; |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .print-preview-dialog { |
| | | .el-dialog__body { |
| | | padding: 0; |
| | | max-height: 80vh; |
| | | overflow-y: auto; |
| | | } |
| | | } |
| | | |
| | | .print-preview-container { |
| | | .print-preview-header { |
| | | padding: 15px; |
| | | border-bottom: 1px solid #e4e7ed; |
| | | text-align: center; |
| | | |
| | | .el-button { |
| | | margin: 0 10px; |
| | | } |
| | | } |
| | | |
| | | .print-preview-content { |
| | | padding: 20px; |
| | | background-color: #f5f5f5; |
| | | min-height: 400px; |
| | | } |
| | | } |
| | | |
| | | .print-page { |
| | | width: 220mm; |
| | | height: 90mm; |
| | | padding: 10mm; |
| | | margin: 0 auto; |
| | | background: white; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
| | | margin-bottom: 10px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-family: "SimSun", serif; |
| | | font-size: 10px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | |
| | | .info-row { |
| | | line-height: 20px; |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .table-section { |
| | | margin-bottom: 4px; |
| | | flex: 1; |
| | | |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | |
| | | th, td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 14px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | th { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-label { |
| | | text-align: right; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .footer-section { |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 20px; |
| | | justify-content: space-between; |
| | | |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | |
| | | .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .value { |
| | | min-width: 80px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | &.address-item { |
| | | .address-value { |
| | | min-width: 200px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | @media print { |
| | | .app-container { |
| | | display: none; |
| | | } |
| | | |
| | | .print-page { |
| | | box-shadow: none; |
| | | margin: 0; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane v-for="tab in tabs" |
| | | :label="tab.label" |
| | | :name="tab.name" |
| | | :key="tab.name"> |
| | | <record :type="tab.type" v-if="activeTab === tab.name" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from "vue"; |
| | | import Record from "@/views/consumablesLogistics/dispatchLog/Record.vue"; |
| | | const activeTab = ref('qualified') |
| | | const type = ref(0) |
| | | const tabs = computed(() => { |
| | | return [ |
| | | { |
| | | label: 'åæ ¼åºåº', |
| | | name: 'qualified', |
| | | type: '0' |
| | | }, |
| | | { |
| | | label: 'ä¸åæ ¼åºåº', |
| | | name: 'unqualified', |
| | | type: '1' |
| | | } |
| | | ] |
| | | }) |
| | | |
| | | const handleTabChange = (tabName) => { |
| | | activeTab.value = tabName; |
| | | type.value = tabName === 'qualified' ? 0 : 1 |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">å
¥åºæ¥æï¼</span> |
| | | <el-date-picker v-model="searchForm.timeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©æ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | @change="handleQuery"/> |
| | | <span class="search_title ml10">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable/> |
| | | <span class="search_title ml10">æ¥æºï¼</span> |
| | | <el-select v-model="searchForm.recordType" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option v-for="item in stockRecordTypeOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value"/> |
| | | </el-select> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢ |
| | | </el-button> |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="row => row.id" |
| | | style="width: 100%" |
| | | height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55"/> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60"/> |
| | | <el-table-column label="å
¥åºæ¹æ¬¡" |
| | | prop="inboundBatches" |
| | | width="280" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="å
¥åºæ¶é´" |
| | | prop="createTime" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="产å大类" |
| | | prop="productName" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="model" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="å
¥åºæ°é" |
| | | prop="stockInNum" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="车çå·" |
| | | prop="licensePlateNo" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="åé(å¨)" |
| | | prop="netWeight" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="å
¥åºäºº" |
| | | prop="createBy" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="æ¥æº" |
| | | prop="recordType" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è¿ç£
æ¥æ" |
| | | prop="weighingDate" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | <el-table-column label="è¿ç£
å" |
| | | prop="weighingOperator" |
| | | v-if="type === '0'" |
| | | show-overflow-tooltip/> |
| | | </el-table> |
| | | <pagination v-show="total > 0" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="pageProductChange"/> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | onMounted, |
| | | getCurrentInstance, |
| | | } from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import { |
| | | getConsumablesInRecordListPage, |
| | | batchDeleteConsumablesInRecords, |
| | | } from "@/api/consumablesLogistics/consumablesInRecord.js"; |
| | | import { |
| | | findAllQualifiedStockInRecordTypeOptions, findAllUnQualifiedStockInRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | |
| | | const {proxy} = getCurrentInstance(); |
| | | |
| | | const props = defineProps({ |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: '0' |
| | | } |
| | | }) |
| | | |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const tableLoading = ref(false); |
| | | const stockRecordTypeOptions = ref([]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: "", |
| | | timeStr: "", |
| | | recordType: "", |
| | | }, |
| | | }); |
| | | const {searchForm} = toRefs(data); |
| | | |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | const getRecordType = (recordType) => { |
| | | return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' |
| | | } |
| | | |
| | | const pageProductChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const params = {...page, type: props.type}; |
| | | params.timeStr = searchForm.value.timeStr; |
| | | params.productName = searchForm.value.productName; |
| | | params.recordType = searchForm.value.recordType; |
| | | getConsumablesInRecordListPage(params) |
| | | .then(res => { |
| | | tableData.value = res.data.records || []; |
| | | total.value = res.data.total ?? 0; |
| | | }).finally(() => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | |
| | | const fetchStockRecordTypeOptions = () => { |
| | | if (props.type === '0') { |
| | | findAllQualifiedStockInRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | return |
| | | } |
| | | findAllUnQualifiedStockInRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | } |
| | | |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | }; |
| | | |
| | | const expandedRowKeys = ref([]); |
| | | |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/consumablesInRecord/exportConsumablesInRecord", {type: props.type}, props.type === '0' ? "èæåæ ¼å
¥åº.xlsx" : "èæä¸åæ ¼å
¥åº.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (selectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | const ids = selectedRows.value.map(item => item.id); |
| | | |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | batchDeleteConsumablesInRecords(ids) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchStockRecordTypeOptions(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"></style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane v-for="tab in tabs" |
| | | :label="tab.label" |
| | | :name="tab.name" |
| | | :key="tab.name"> |
| | | <record :type="tab.type" v-if="activeTab === tab.name" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import Record from "@/views/consumablesLogistics/receiptManagement/Record.vue"; |
| | | |
| | | const activeTab = ref('qualified') |
| | | const type = ref(0) |
| | | const tabs = ref([ |
| | | { |
| | | label: 'åæ ¼å
¥åº', |
| | | name: 'qualified', |
| | | type: '0' |
| | | }, |
| | | { |
| | | label: 'ä¸åæ ¼å
¥åº', |
| | | name: 'unqualified', |
| | | type: '1' |
| | | } |
| | | ]) |
| | | |
| | | const handleTabChange = (tabName) => { |
| | | activeTab.value = tabName; |
| | | type.value = tabName === 'qualified' ? 0 : 1 |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | :title="operationType === 'frozen' ? 'å»ç»åºå' : 'è§£å»åºå'" |
| | | width="800" |
| | | @close="closeModal" |
| | | > |
| | | <el-form label-width="140px" :model="formState" ref="formRef"> |
| | | <el-form-item |
| | | :label="operationType === 'frozen' ? 'å»ç»æ°éï¼' : 'è§£å»æ°éï¼'" |
| | | prop="lockedQuantity" |
| | | > |
| | | <el-input-number v-model="formState.lockedQuantity" :step="1" :min="1" precision="0" style="width: 100%" :max="maxCount" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="handleSubmit">确认</el-button> |
| | | <el-button @click="closeModal">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, computed, getCurrentInstance} from "vue"; |
| | | import {frozenConsumablesIn, thawConsumablesIn} from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | import {frozenConsumablesUninventory, thawConsumablesUninventory} from "@/api/consumablesLogistics/consumablesUninventory.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | |
| | | operationType: { |
| | | type: String, |
| | | required: true, |
| | | default: 'frozen', |
| | | }, |
| | | |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: 'qualified', |
| | | }, |
| | | |
| | | record: { |
| | | type: Object, |
| | | default: () => {}, |
| | | } |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:visible', 'completed']); |
| | | |
| | | // ååºå¼æ°æ®ï¼æ¿ä»£é项å¼ç dataï¼ |
| | | const formState = ref({ |
| | | lockedQuantity: 0, |
| | | }); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit('update:visible', val); |
| | | }, |
| | | }); |
| | | |
| | | |
| | | let { proxy } = getCurrentInstance() |
| | | |
| | | const closeModal = () => { |
| | | // éç½®è¡¨åæ°æ® |
| | | formState.value = { |
| | | lockedQuantity: undefined |
| | | }; |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const maxCount = computed(() => { |
| | | // å»ç»åºåæå¤§æ°é为æªè§£å»æ°é |
| | | if (props.operationType === 'frozen') { |
| | | return props.record.unLockedQuantity |
| | | } |
| | | // è§£å»åºåæå¤§æ°é为已å»ç»æ°é |
| | | return props.record.lockedQuantity |
| | | }) |
| | | |
| | | const handleSubmit = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | const data = Object.assign({id: props.record.id}, formState.value); |
| | | if (props.type === 'qualified') { |
| | | // å»ç» |
| | | if (props.operationType === 'frozen') { |
| | | frozenConsumablesIn(data).then(res => { |
| | | if (res.code === 200) { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | } |
| | | }) |
| | | } else { |
| | | thawConsumablesIn(data).then(res => { |
| | | if (res.code === 200) { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | } |
| | | }) |
| | | } |
| | | } else { |
| | | if (props.operationType === 'frozen') { |
| | | frozenConsumablesUninventory(data).then(res => { |
| | | if (res.code === 200) { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | } |
| | | }) |
| | | } else { |
| | | thawConsumablesUninventory(data).then(res => { |
| | | if (res.code === 200) { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | } |
| | | }) |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | formState.value.lockedQuantity = maxCount.value; |
| | | }) |
| | | |
| | | defineExpose({ |
| | | closeModal, |
| | | handleSubmit, |
| | | isShow, |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog v-model="isShow" title="导å
¥åºå" @close="closeModal"> |
| | | <FileUpload |
| | | ref="fileUploadRef" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url" |
| | | :disabled="upload.isUploading" |
| | | :showTip="true" |
| | | @success="handleFileSuccess" |
| | | :downloadTemplate="downloadTemplate" |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="closeModal">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {computed, ref, getCurrentInstance, reactive} from "vue"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import { FileUpload } from "@/components/Upload"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | defineOptions({ |
| | | name: "导å
¥åºå", |
| | | }); |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: 'qualified', |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:visible', 'uploadSuccess']); |
| | | |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit('update:visible', val); |
| | | }, |
| | | }); |
| | | |
| | | const fileUploadRef = ref(); |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼åºå导å
¥ï¼ |
| | | open: false, |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/consumablesInventory/importConsumablesInventory", |
| | | }); |
| | | |
| | | const submitFileForm = () => { |
| | | fileUploadRef.value.uploadApi(); |
| | | }; |
| | | |
| | | const handleFileSuccess = (response) => { |
| | | const { code, msg } = response; |
| | | if (code == 200) { |
| | | ElMessage({ message: "导å
¥æå", type: "success" }); |
| | | emit('uploadSuccess'); |
| | | closeModal(); |
| | | } else { |
| | | ElMessage({ message: msg, type: "error" }); |
| | | } |
| | | }; |
| | | |
| | | const downloadTemplate = () => { |
| | | proxy.download("/consumablesInventory/downloadConsumablesInventory", {}, "èæåºå导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | const closeModal = () => { |
| | | isShow.value = false; |
| | | }; |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | title="æ°å¢åºå" |
| | | width="800" |
| | | @close="closeModal" |
| | | > |
| | | <el-form label-width="140px" :model="formState" label-position="top" ref="formRef"> |
| | | <el-form-item |
| | | label="产ååç§°" |
| | | prop="productModelId" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: 'è¯·éæ©äº§å', |
| | | trigger: 'change', |
| | | } |
| | | ]" |
| | | > |
| | | <el-button type="primary" @click="showProductSelectDialog = true"> |
| | | {{ formState.productName ? formState.productName : 'éæ©äº§å' }} |
| | | </el-button> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="è§æ ¼" |
| | | prop="productModelName" |
| | | > |
| | | <el-input v-model="formState.productModelName" disabled /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="åä½" |
| | | prop="unit" |
| | | > |
| | | <el-input v-model="formState.unit" disabled /> |
| | | </el-form-item> |
| | | |
| | | <!-- productType === 0ï¼åææ --> |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="车çå·" |
| | | prop="licensePlateNo" |
| | | > |
| | | <el-input v-model="formState.licensePlateNo" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.grossWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | @change="computeNetWeight" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.tareWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | @change="computeNetWeight" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="åé(å¨)" |
| | | prop="netWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.netWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="è¿ç£
æ¥æ" |
| | | prop="weighingDate" |
| | | > |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="formState.weighingDate" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©è¿ç£
æ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | v-if="type === 'qualified' && formState.productType === 0" |
| | | label="è¿ç£
å" |
| | | prop="weighingOperator" |
| | | > |
| | | <el-input v-model="formState.weighingOperator" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="formState.remark" type="textarea" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 产åéæ©å¼¹çª --> |
| | | <ProductSelectDialog |
| | | v-model="showProductSelectDialog" |
| | | @confirm="handleProductSelect" |
| | | single |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="handleSubmit">确认</el-button> |
| | | <el-button @click="closeModal">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, computed, getCurrentInstance} from "vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import {createConsumablesIn} from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | import {createConsumablesUnInventory} from "@/api/consumablesLogistics/consumablesUninventory.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: 'qualified', |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:visible', 'completed']); |
| | | |
| | | // ååºå¼æ°æ®ï¼æ¿ä»£é项å¼ç dataï¼ |
| | | const formState = ref({ |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | unit: "", |
| | | productType: undefined, |
| | | // è¿ç£
ç¸å
³å段ï¼ä»
åææåæ ¼å使ç¨ï¼ |
| | | licensePlateNo: "", |
| | | grossWeight: undefined, |
| | | tareWeight: undefined, |
| | | netWeight: undefined, |
| | | weighingDate: undefined, |
| | | weighingOperator: "", |
| | | remark: '', |
| | | }); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit('update:visible', val); |
| | | }, |
| | | }); |
| | | |
| | | const showProductSelectDialog = ref(false); |
| | | |
| | | let { proxy } = getCurrentInstance() |
| | | |
| | | const closeModal = () => { |
| | | // éç½®è¡¨åæ°æ® |
| | | formState.value = { |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | description: '', |
| | | }; |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | // 产åéæ©å¤ç |
| | | const handleProductSelect = async (products) => { |
| | | formState.value.weighingDate = undefined; |
| | | formState.value.grossWeight = undefined; |
| | | formState.value.tareWeight = undefined; |
| | | formState.value.netWeight = undefined; |
| | | if (products && products.length > 0) { |
| | | const product = products[0]; |
| | | formState.value.productId = product.productId; |
| | | formState.value.productName = product.productName; |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.unit = product.unit; |
| | | formState.value.productType = product.productType; |
| | | showProductSelectDialog.value = false; |
| | | // 触å表åéªè¯æ´æ° |
| | | proxy.$refs["formRef"]?.validateField('productModelId'); |
| | | } |
| | | }; |
| | | |
| | | // åé = æ¯é - ç®é |
| | | const computeNetWeight = () => { |
| | | const { grossWeight, tareWeight } = formState.value; |
| | | if (grossWeight != null && tareWeight != null) { |
| | | const net = Number(grossWeight) - Number(tareWeight); |
| | | // ä¿ç两ä½å°æ°ï¼ä¸ä¸ä¸ºè´ |
| | | const safeNet = Number(net.toFixed(2)); |
| | | formState.value.netWeight = safeNet > 0 ? safeNet : 0; |
| | | } else { |
| | | formState.value.netWeight = undefined; |
| | | } |
| | | }; |
| | | |
| | | const handleSubmit = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // éªè¯æ¯å¦éæ©äºäº§ååè§æ ¼ |
| | | if (!formState.value.productModelId) { |
| | | proxy.$modal.msgError("è¯·éæ©äº§å"); |
| | | return; |
| | | } |
| | | if (!formState.value.productModelId) { |
| | | proxy.$modal.msgError("è¯·éæ©è§æ ¼"); |
| | | return; |
| | | } |
| | | if (props.type === 'qualified') { |
| | | createConsumablesIn(formState.value).then(res => { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | }) |
| | | } else { |
| | | createConsumablesUnInventory(formState.value).then(res => { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | }) |
| | | } |
| | | |
| | | } |
| | | }) |
| | | }; |
| | | |
| | | |
| | | defineExpose({ |
| | | closeModal, |
| | | handleSubmit, |
| | | isShow, |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable/> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true">æ°å¢åºå</el-button> |
| | | <el-button type="info" plain icon="Upload" @click="isShowImportModal = true"> |
| | | 导å
¥åºå |
| | | </el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="row => row.id" style="width: 100%" |
| | | :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产åç±»å" prop="parentName" show-overflow-tooltip /> |
| | | <el-table-column label="产å大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="åºåæ°é" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="å»ç»æ°é" prop="lockedQuantity" show-overflow-tooltip /> |
| | | <!-- <el-table-column label="åºåé¢è¦æ°é" prop="warnNum" show-overflow-tooltip /> --> |
| | | <el-table-column label="åé(å¨)" prop="netWeight" show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="æè¿æ´æ°æ¶é´" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" min-width="60" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">åºåº</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">å»ç»</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.lockedQuantity > 0" @click="showThawModal(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> |
| | | <new-stock-inventory v-if="isShowNewModal" |
| | | v-model:visible="isShowNewModal" |
| | | type="qualified" |
| | | @completed="handleQuery" /> |
| | | |
| | | <subtract-stock-inventory v-if="isShowSubtractModal" |
| | | v-model:visible="isShowSubtractModal" |
| | | :record="record" |
| | | type="qualified" |
| | | @completed="handleQuery" /> |
| | | <!-- 导å
¥åºå--> |
| | | <import-stock-inventory v-if="isShowImportModal" |
| | | v-model:visible="isShowImportModal" |
| | | type="qualified" |
| | | @uploadSuccess="handleQuery" /> |
| | | <!-- å»ç»/è§£å»åºå--> |
| | | <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal" |
| | | v-model:visible="isShowFrozenAndThawModal" |
| | | :record="record" |
| | | :operation-type="operationType" |
| | | type="qualified" |
| | | @completed="handleQuery" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from '@/components/PIMTable/Pagination.vue' |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import { getConsumablesInListPage } from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | const NewStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/New.vue")); |
| | | const SubtractStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/Subtract.vue")); |
| | | const ImportStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/Import.vue")); |
| | | const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/FrozenAndThaw.vue")); |
| | | const { proxy } = getCurrentInstance() |
| | | const tableData = ref([]) |
| | | const selectedRows = ref([]) |
| | | const record = ref({}) |
| | | const tableLoading = ref(false) |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }) |
| | | const total = ref(0) |
| | | // æ¯å¦æ¾ç¤ºæ°å¢å¼¹æ¡ |
| | | const isShowNewModal = ref(false) |
| | | // æ¯å¦æ¾ç¤ºé¢ç¨å¼¹æ¡ |
| | | const isShowSubtractModal = ref(false) |
| | | // æ¯å¦æ¾ç¤ºå»ç»/è§£å»å¼¹æ¡ |
| | | const isShowFrozenAndThawModal = ref(false) |
| | | // æä½ç±»å |
| | | const operationType = ref('frozen') |
| | | // æ¯å¦æ¾ç¤ºå¯¼å
¥å¼¹æ¡ |
| | | const isShowImportModal = ref(false) |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: '', |
| | | } |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList() |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true |
| | | getConsumablesInListPage({ ...searchForm.value, ...page }).then(res => { |
| | | tableLoading.value = false |
| | | tableData.value = res.data.records |
| | | total.value = res.data.total |
| | | // æ°æ®å è½½å®æåæ£æ¥åºå |
| | | // checkStockAndCreatePurchase(); |
| | | }).catch(() => { |
| | | tableLoading.value = false |
| | | }) |
| | | } |
| | | |
| | | const handleFileSuccess = (response) => { |
| | | const { code, msg } = response; |
| | | if (code == 200) { |
| | | ElMessage({ message: "导å
¥æå", type: "success" }); |
| | | upload.open = false; |
| | | emits("uploadSuccess"); |
| | | } else { |
| | | ElMessage({ message: msg, type: "error" }); |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»é¢ç¨ |
| | | const showSubtractModal = (row) => { |
| | | record.value = row |
| | | isShowSubtractModal.value = true |
| | | } |
| | | |
| | | // ç¹å»å»ç» |
| | | const showFrozenModal = (row) => { |
| | | record.value = row |
| | | isShowFrozenAndThawModal.value = true |
| | | operationType.value = 'frozen' |
| | | } |
| | | |
| | | // ç¹å»è§£å» |
| | | const showThawModal = (row) => { |
| | | record.value = row |
| | | isShowFrozenAndThawModal.value = true |
| | | operationType.value = 'thaw' |
| | | } |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | // è¿æ»¤æåæ°æ® |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | console.log('selection', selectedRows.value) |
| | | } |
| | | const expandedRowKeys = ref([]) |
| | | |
| | | // è¡¨æ ¼è¡ç±»å |
| | | const tableRowClassName = ({ row }) => { |
| | | const stock = Number(row?.unLockedQuantity ?? 0); |
| | | const warn = Number(row?.warnNum ?? 0); |
| | | if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | | return ''; |
| | | } |
| | | return stock < warn ? 'row-low-stock' : ''; |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm( |
| | | 'æ¯å¦ç¡®è®¤å¯¼åºï¼', |
| | | '导åº', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning', |
| | | } |
| | | ).then(() => { |
| | | proxy.download("/consumablesInventory/exportConsumablesInventory", {}, 'èæåæ ¼åºåä¿¡æ¯.xlsx') |
| | | }).catch(() => { |
| | | proxy.$modal.msg("已忶") |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | | } |
| | | |
| | | :deep(.row-low-stock:hover > td) { |
| | | background-color: #fcd4d4; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="isShow" |
| | | title="é¢ç¨" |
| | | width="800" |
| | | @close="closeModal" |
| | | > |
| | | <el-form label-width="140px" :model="formState" label-position="top" ref="formRef"> |
| | | <el-form-item |
| | | label="产ååç§°" |
| | | prop="productModelId" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: 'è¯·éæ©äº§å', |
| | | trigger: 'change', |
| | | } |
| | | ]" |
| | | > |
| | | <el-button type="primary" @click="showProductSelectDialog = true" disabled> |
| | | {{ formState.productName ? formState.productName : 'éæ©äº§å' }} |
| | | </el-button> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="è§æ ¼" |
| | | prop="productModelName" |
| | | > |
| | | <el-input v-model="formState.model" disabled /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="åä½" |
| | | prop="unit" |
| | | > |
| | | <el-input v-model="formState.unit" disabled /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="车çå·" |
| | | prop="licensePlateNo" |
| | | > |
| | | <el-input v-model="formState.licensePlateNo" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.grossWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | @change="computeNetWeight" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.tareWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | @change="computeNetWeight" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="åé(å¨)" |
| | | prop="netWeight" |
| | | > |
| | | <el-input-number |
| | | v-model="formState.netWeight" |
| | | :step="0.01" |
| | | :min="0" |
| | | style="width: 100%" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="è¿ç£
æ¥æ" |
| | | prop="weighingDate" |
| | | > |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="formState.weighingDate" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm:ss" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©è¿ç£
æ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="è¿ç£
å" |
| | | prop="weighingOperator" |
| | | > |
| | | <el-input v-model="formState.weighingOperator" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="formState.remark" type="textarea" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- 产åéæ©å¼¹çª --> |
| | | <ProductSelectDialog |
| | | v-model="showProductSelectDialog" |
| | | @confirm="handleProductSelect" |
| | | single |
| | | /> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="handleSubmit">确认</el-button> |
| | | <el-button @click="closeModal">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, computed, getCurrentInstance, onMounted} from "vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import {subtractConsumablesIn} from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | import {subtractConsumablesUnInventory} from "@/api/consumablesLogistics/consumablesUninventory.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | | type: Boolean, |
| | | required: true, |
| | | }, |
| | | record: { |
| | | type: Object, |
| | | default: () => {}, |
| | | }, |
| | | type: { |
| | | type: String, |
| | | required: true, |
| | | default: 'qualified', |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(['update:visible', 'completed']); |
| | | |
| | | onMounted(() => { |
| | | initFormData() |
| | | }) |
| | | |
| | | const isRawMaterial = computed(() => { |
| | | return props.record.parentName === 'åææ'; |
| | | }) |
| | | |
| | | const initFormData = () => { |
| | | if (props.record) { |
| | | formState.value = { |
| | | ...props.record, |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ååºå¼æ°æ®ï¼æ¿ä»£é项å¼ç dataï¼ |
| | | const formState = ref({ |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | model: "", |
| | | unit: "", |
| | | // è¿ç£
ç¸å
³å段 |
| | | licensePlateNo: "", |
| | | grossWeight: undefined, |
| | | tareWeight: undefined, |
| | | netWeight: undefined, |
| | | weighingDate: undefined, |
| | | weighingOperator: "", |
| | | remark: '', |
| | | }); |
| | | |
| | | const isShow = computed({ |
| | | get() { |
| | | return props.visible; |
| | | }, |
| | | set(val) { |
| | | emit('update:visible', val); |
| | | }, |
| | | }); |
| | | |
| | | const showProductSelectDialog = ref(false); |
| | | |
| | | let { proxy } = getCurrentInstance() |
| | | |
| | | const closeModal = () => { |
| | | // éç½®è¡¨åæ°æ® |
| | | formState.value = { |
| | | productId: undefined, |
| | | productModelId: undefined, |
| | | productName: "", |
| | | model: "", |
| | | unit: "", |
| | | licensePlateNo: "", |
| | | grossWeight: undefined, |
| | | tareWeight: undefined, |
| | | netWeight: undefined, |
| | | weighingDate: undefined, |
| | | weighingOperator: "", |
| | | remark: '', |
| | | }; |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | // åé = æ¯é - ç®é |
| | | const computeNetWeight = () => { |
| | | const { grossWeight, tareWeight } = formState.value; |
| | | if (grossWeight != null && tareWeight != null) { |
| | | const net = Number(grossWeight) - Number(tareWeight); |
| | | const safeNet = Number(net.toFixed(2)); |
| | | formState.value.netWeight = safeNet > 0 ? safeNet : 0; |
| | | } else { |
| | | formState.value.netWeight = undefined; |
| | | } |
| | | }; |
| | | |
| | | // 产åéæ©å¤ç |
| | | const handleProductSelect = async (products) => { |
| | | if (products && products.length > 0) { |
| | | const product = products[0]; |
| | | console.log(product) |
| | | formState.value.productId = product.productId; |
| | | formState.value.productName = product.productName; |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | | formState.value.unit = product.unit; |
| | | showProductSelectDialog.value = false; |
| | | // 触å表åéªè¯æ´æ° |
| | | proxy.$refs["formRef"]?.validateField('productModelId'); |
| | | } |
| | | }; |
| | | |
| | | const handleSubmit = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | // éªè¯æ¯å¦éæ©äºäº§ååè§æ ¼ |
| | | if (!formState.value.productModelId) { |
| | | proxy.$modal.msgError("è¯·éæ©äº§å"); |
| | | return; |
| | | } |
| | | if (!formState.value.productModelId) { |
| | | proxy.$modal.msgError("è¯·éæ©è§æ ¼"); |
| | | return; |
| | | } |
| | | if (props.type === 'qualified') { |
| | | subtractConsumablesIn(formState.value).then(res => { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | }) |
| | | } else { |
| | | subtractConsumablesUnInventory(formState.value).then(res => { |
| | | // å
³éæ¨¡ææ¡ |
| | | isShow.value = false; |
| | | // åç¥ç¶ç»ä»¶å·²å®æ |
| | | emit('completed'); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | }) |
| | | } |
| | | } |
| | | }) |
| | | }; |
| | | |
| | | |
| | | defineExpose({ |
| | | closeModal, |
| | | handleSubmit, |
| | | isShow, |
| | | }); |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | clearable/> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true">æ°å¢åºå</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="row => row.id" style="width: 100%" |
| | | :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产å大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="è§æ ¼åå·" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="åä½" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="åºåæ°é" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="å»ç»æ°é" prop="lockedQuantity" show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="æè¿æ´æ°æ¶é´" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" min-width="60" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">é¢ç¨</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">å»ç»</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.lockedQuantity > 0" @click="showThawModal(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> |
| | | <new-stock-inventory v-if="isShowNewModal" |
| | | v-model:visible="isShowNewModal" |
| | | type="unqualified" |
| | | @completed="handleQuery" /> |
| | | |
| | | <subtract-stock-inventory v-if="isShowSubtractModal" |
| | | v-model:visible="isShowSubtractModal" |
| | | :record="record" |
| | | type="unqualified" |
| | | @completed="handleQuery" /> |
| | | <!-- å»ç»/è§£å»åºå--> |
| | | <frozen-and-thaw-stock-inventory v-if="isShowFrozenAndThawModal" |
| | | v-model:visible="isShowFrozenAndThawModal" |
| | | :record="record" |
| | | :operation-type="operationType" |
| | | type="unqualified" |
| | | @completed="handleQuery" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import pagination from '@/components/PIMTable/Pagination.vue' |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { getConsumablesUninventoryListPage } from "@/api/consumablesLogistics/consumablesUninventory.js"; |
| | | const NewStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/New.vue")); |
| | | const SubtractStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/Subtract.vue")); |
| | | const FrozenAndThawStockInventory = defineAsyncComponent(() => import("@/views/consumablesLogistics/stockManagement/FrozenAndThaw.vue")); |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const tableData = ref([]) |
| | | const selectedRows = ref([]) |
| | | const record = ref({}) |
| | | const tableLoading = ref(false) |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }) |
| | | const total = ref(0) |
| | | // æ¯å¦æ¾ç¤ºæ°å¢å¼¹æ¡ |
| | | const isShowNewModal = ref(false) |
| | | // æ¯å¦æ¾ç¤ºé¢ç¨å¼¹æ¡ |
| | | const isShowSubtractModal = ref(false) |
| | | // æ¯å¦æ¾ç¤ºå»ç»/è§£å»å¼¹æ¡ |
| | | const isShowFrozenAndThawModal = ref(false) |
| | | // æä½ç±»å |
| | | const operationType = ref('frozen') |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: '', |
| | | } |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | const paginationChange = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList() |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true |
| | | getConsumablesUninventoryListPage({ ...searchForm.value, ...page }).then(res => { |
| | | tableLoading.value = false |
| | | tableData.value = res.data.records |
| | | total.value = res.data.total |
| | | // æ°æ®å è½½å®æåæ£æ¥åºå |
| | | // checkStockAndCreatePurchase(); |
| | | }).catch(() => { |
| | | tableLoading.value = false |
| | | }) |
| | | } |
| | | |
| | | // ç¹å»é¢ç¨ |
| | | const showSubtractModal = (row) => { |
| | | record.value = row |
| | | isShowSubtractModal.value = true |
| | | } |
| | | |
| | | // ç¹å»å»ç» |
| | | const showFrozenModal = (row) => { |
| | | record.value = row |
| | | isShowFrozenAndThawModal.value = true |
| | | operationType.value = 'frozen' |
| | | } |
| | | |
| | | // ç¹å»è§£å» |
| | | const showThawModal = (row) => { |
| | | record.value = row |
| | | isShowFrozenAndThawModal.value = true |
| | | operationType.value = 'thaw' |
| | | } |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | // è¿æ»¤æåæ°æ® |
| | | selectedRows.value = selection.filter(item => item.id); |
| | | console.log('selection', selectedRows.value) |
| | | } |
| | | const expandedRowKeys = ref([]) |
| | | |
| | | // è¡¨æ ¼è¡ç±»å |
| | | const tableRowClassName = ({ row }) => { |
| | | // const stock = Number(row?.unLockedQuantity ?? 0); |
| | | // const warn = Number(row?.warnNum ?? 0); |
| | | // if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | | // return ''; |
| | | // } |
| | | // return stock < warn ? 'row-low-stock' : ''; |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm( |
| | | 'æ¯å¦ç¡®è®¤å¯¼åºï¼', |
| | | '导åº', { |
| | | confirmButtonText: '确认', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning', |
| | | } |
| | | ).then(() => { |
| | | proxy.download("/consumablesUninventory/exportStockUninventory", {}, 'èæä¸åæ ¼åºåä¿¡æ¯.xlsx') |
| | | }).catch(() => { |
| | | proxy.$modal.msg("已忶") |
| | | }) |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | | } |
| | | |
| | | :deep(.row-low-stock:hover > td) { |
| | | background-color: #fcd4d4; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-tabs v-model="activeTab" @tab-change="handleTabChange"> |
| | | <el-tab-pane v-for="tab in tabs" |
| | | :label="tab.label" |
| | | :name="tab.name" |
| | | :key="tab.name"> |
| | | <component :is="tab.name === 'qualified' ? QualifiedRecord : UnqualifiedRecord" /> |
| | | </el-tab-pane> |
| | | </el-tabs> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import QualifiedRecord from "@/views/consumablesLogistics/stockManagement/Qualified.vue"; |
| | | import UnqualifiedRecord from "@/views/consumablesLogistics/stockManagement/Unqualified.vue"; |
| | | |
| | | const activeTab = ref('qualified') |
| | | const tabs = ref([ |
| | | { |
| | | label: 'åæ ¼åºå', |
| | | name: 'qualified' |
| | | }, |
| | | { |
| | | label: 'ä¸åæ ¼åºå', |
| | | name: 'unqualified' |
| | | } |
| | | ]) |
| | | |
| | | const handleTabChange = (tabName) => { |
| | | activeTab.value = tabName; |
| | | } |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æç´¢è¡¨å --> |
| | | <div class="search_form"> |
| | | <div class="search_left"> |
| | | <span class="search_title">æ¥è¡¨ç±»åï¼</span> |
| | | <el-select |
| | | v-model="searchForm.reportType" |
| | | style="width: 150px;" |
| | | placeholder="è¯·éæ©" |
| | | @change="handleReportTypeChange" |
| | | > |
| | | <el-option label="æ¥æ¥" value="daily" /> |
| | | <el-option label="ææ¥" value="monthly" /> |
| | | <el-option label="è¿åºåæ¥è¡¨" value="inout" /> |
| | | </el-select> |
| | | |
| | | <span class="search_title ml10">æ¶é´èå´ï¼</span> |
| | | <el-date-picker |
| | | v-if="searchForm.reportType === 'daily'" |
| | | v-model="searchForm.singleDate" |
| | | type="date" |
| | | placeholder="è¯·éæ©æ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 200px;" |
| | | /> |
| | | <el-date-picker |
| | | v-else-if="searchForm.reportType === 'monthly'" |
| | | v-model="searchForm.monthRange" |
| | | type="monthrange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æä»½" |
| | | end-placeholder="ç»ææä»½" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px;" |
| | | /> |
| | | <el-date-picker |
| | | v-else |
| | | v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px;" |
| | | /> |
| | | |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px"> |
| | | æ¥è¯¢ |
| | | </el-button> |
| | | <el-button @click="handleReset">éç½®</el-button> |
| | | </div> |
| | | |
| | | <div class="search_right"> |
| | | <!-- <el-button type="success" @click="handleExport" icon="Download">--> |
| | | <!-- å¯¼åºæ¥è¡¨--> |
| | | <!-- </el-button>--> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- <!– ç»è®¡å¡ç –>--> |
| | | <!-- <div class="stats_cards" v-if="reportData.summary">--> |
| | | <!-- <el-row :gutter="20">--> |
| | | <!-- <el-col :span="6">--> |
| | | <!-- <el-card class="stats_card">--> |
| | | <!-- <div class="stats_content">--> |
| | | <!-- <div class="stats_icon in">--> |
| | | <!-- <el-icon><TrendCharts /></el-icon>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="stats_info">--> |
| | | <!-- <div class="stats_value">{{ reportData.summary.totalIn || 0 }}</div>--> |
| | | <!-- <div class="stats_label">æ»å
¥åºé</div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- <el-col :span="6">--> |
| | | <!-- <el-card class="stats_card">--> |
| | | <!-- <div class="stats_content">--> |
| | | <!-- <div class="stats_icon out">--> |
| | | <!-- <el-icon><TrendCharts /></el-icon>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="stats_info">--> |
| | | <!-- <div class="stats_value">{{ reportData.summary.totalOut || 0 }}</div>--> |
| | | <!-- <div class="stats_label">æ»åºåºé</div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- <el-col :span="6">--> |
| | | <!-- <el-card class="stats_card">--> |
| | | <!-- <div class="stats_content">--> |
| | | <!-- <div class="stats_icon stock">--> |
| | | <!-- <el-icon><Box /></el-icon>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="stats_info">--> |
| | | <!-- <div class="stats_value">{{ reportData.summary.currentStock || 0 }}</div>--> |
| | | <!-- <div class="stats_label">å½ååºå</div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- <el-col :span="6">--> |
| | | <!-- <el-card class="stats_card">--> |
| | | <!-- <div class="stats_content">--> |
| | | <!-- <div class="stats_icon turnover">--> |
| | | <!-- <el-icon><Refresh /></el-icon>--> |
| | | <!-- </div>--> |
| | | <!-- <div class="stats_info">--> |
| | | <!-- <div class="stats_value">{{ reportData.summary.turnoverRate || 0 }}%</div>--> |
| | | <!-- <div class="stats_label">å¨è½¬ç</div>--> |
| | | <!-- </div>--> |
| | | <!-- </div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- </el-row>--> |
| | | <!-- </div>--> |
| | | |
| | | <!-- <!– å¾è¡¨åºå –>--> |
| | | <!-- <div class="chart_section" v-if="reportData.chartData">--> |
| | | <!-- <el-row :gutter="20">--> |
| | | <!-- <el-col :span="12">--> |
| | | <!-- <el-card>--> |
| | | <!-- <template #header>--> |
| | | <!-- <span>åºåè¶å¿å¾</span>--> |
| | | <!-- </template>--> |
| | | <!-- <div ref="trendChart" style="height: 300px;"></div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- <el-col :span="12">--> |
| | | <!-- <el-card>--> |
| | | <!-- <template #header>--> |
| | | <!-- <span>è¿åºåºå¯¹æ¯</span>--> |
| | | <!-- </template>--> |
| | | <!-- <div ref="comparisonChart" style="height: 300px;"></div>--> |
| | | <!-- </el-card>--> |
| | | <!-- </el-col>--> |
| | | <!-- </el-row>--> |
| | | <!-- </div>--> |
| | | |
| | | <!-- è¯¦ç»æ°æ®è¡¨æ ¼ --> |
| | | <div class="table_section"> |
| | | <el-card> |
| | | <template #header> |
| | | <span>{{ getTableTitle() }}</span> |
| | | </template> |
| | | <el-table |
| | | v-loading="tableLoading" |
| | | :data="reportData.tableData" |
| | | border |
| | | height="400" |
| | | style="width: 100%" |
| | | :header-cell-style="{ background: '#F0F1F5', color: '#333333' }" |
| | | > |
| | | <el-table-column |
| | | align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" |
| | | /> |
| | | <el-table-column |
| | | label="å
¥åºæ¶é´" |
| | | prop="createTime" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="å
¥åºæ¹æ¬¡" |
| | | prop="inboundBatches" |
| | | width="240" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="产å大类" |
| | | prop="productName" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="è§æ ¼åå·" |
| | | prop="model" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åä½" |
| | | prop="unit" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="å
¥åºæ°é" |
| | | prop="totalStockIn" |
| | | align="center" |
| | | v-if="searchForm.reportType === 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="å
¥åºæ°é" |
| | | prop="stockInNum" |
| | | align="center" |
| | | v-else |
| | | /> |
| | | <el-table-column |
| | | label="åºåºæ°é" |
| | | prop="totalStockOut" |
| | | width="100" |
| | | align="center" |
| | | v-if="searchForm.reportType === 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="ç°å¨åºå" |
| | | prop="currentStock" |
| | | align="center" |
| | | /> |
| | | <el-table-column |
| | | label="ç°åé(å¨)" |
| | | prop="currentWeight" |
| | | align="center" |
| | | /> |
| | | <el-table-column label="æ¥æº" |
| | | prop="recordType" |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ getRecordType(scope.row.recordType) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="å
¥åºäºº" |
| | | prop="createBy" |
| | | width="80" |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | show-overflow-tooltip |
| | | /> |
| | | </el-table> |
| | | </el-card> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, nextTick, getCurrentInstance } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import * as echarts from 'echarts' |
| | | import { |
| | | getConsumablesInInAndOutReportList, |
| | | getConsumablesInReportList |
| | | } from "@/api/consumablesLogistics/consumablesIn.js"; |
| | | import { |
| | | findAllQualifiedStockInRecordTypeOptions, |
| | | } from "@/api/basicData/enum.js"; |
| | | |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | // ååºå¼æ°æ® |
| | | const tableLoading = ref(false) |
| | | const trendChart = ref(null) |
| | | const comparisonChart = ref(null) |
| | | |
| | | const searchForm = reactive({ |
| | | reportType: 'daily', |
| | | singleDate: '', |
| | | dateRange: [], |
| | | monthRange: [] |
| | | }) |
| | | |
| | | const reportData = ref({ |
| | | summary: null, |
| | | chartData: null, |
| | | tableData: [] |
| | | }) |
| | | |
| | | const stockRecordTypeOptions = ref([]) |
| | | |
| | | const getRecordType = (recordType) => { |
| | | return stockRecordTypeOptions.value.find(item => item.value === recordType)?.label || '' |
| | | } |
| | | |
| | | // è·åæ¥æºç±»åé项 |
| | | const fetchStockRecordTypeOptions = () => { |
| | | findAllQualifiedStockInRecordTypeOptions() |
| | | .then(res => { |
| | | stockRecordTypeOptions.value = res.data; |
| | | }) |
| | | } |
| | | |
| | | // è·åè¡¨æ ¼æ é¢ |
| | | const getTableTitle = () => { |
| | | const typeMap = { |
| | | daily: 'æ¥æ¥è¯¦ç»æ°æ®', |
| | | monthly: 'ææ¥è¯¦ç»æ°æ®', |
| | | inout: 'è¿åºåæ¥è¡¨è¯¦ç»æ°æ®' |
| | | } |
| | | return typeMap[searchForm.reportType] || 'æ¥è¡¨è¯¦ç»æ°æ®' |
| | | } |
| | | |
| | | // æ¥è¡¨ç±»åæ¹å |
| | | const handleReportTypeChange = () => { |
| | | reportData.value = { |
| | | summary: null, |
| | | chartData: null, |
| | | tableData: [] |
| | | } |
| | | } |
| | | |
| | | // æ¥è¯¢æ°æ® |
| | | const handleQuery = async () => { |
| | | if (!validateSearchForm()) { |
| | | return |
| | | } |
| | | |
| | | tableLoading.value = true |
| | | try { |
| | | const params = getQueryParams() |
| | | let response |
| | | |
| | | if (searchForm.reportType === 'inout') { |
| | | response = await getConsumablesInInAndOutReportList(params) |
| | | } else { |
| | | response = await getConsumablesInReportList(params) |
| | | } |
| | | if (response.code === 200) { |
| | | reportData.value.tableData = response.data.records |
| | | // reportData.value.summary = response.data.summary |
| | | // reportData.value.chartData = response.data.chartData |
| | | // nextTick(() => { |
| | | // initCharts() |
| | | // }) |
| | | |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error('æ¥è¯¢å¤±è´¥ï¼' + error.message) |
| | | } finally { |
| | | tableLoading.value = false |
| | | } |
| | | } |
| | | // // çæåæ°æ® |
| | | // const generateMockData = () => { |
| | | // // çæç»è®¡å¡çåæ°æ® |
| | | // const summary = { |
| | | // totalIn: 1000, |
| | | // totalOut: 600, |
| | | // currentStock: 400, |
| | | // turnoverRate: 30 |
| | | // } |
| | | |
| | | // // çæå¾è¡¨åæ°æ® |
| | | // const trendDates = ['2025-09-15', '2025-09-16', '2025-09-17', '2025-09-18', '2025-09-19'] |
| | | // const trendValues = [300, 350, 400, 380, 420] |
| | | // const comparisonDates = ['2025-09-15', '2025-09-16', '2025-09-17'] |
| | | // const inValues = [100, 150, 200] |
| | | // const outValues = [80, 120, 100] |
| | | |
| | | // const chartData = { |
| | | // trendDates, |
| | | // trendValues, |
| | | // comparisonDates, |
| | | // inValues, |
| | | // outValues |
| | | // } |
| | | |
| | | // reportData.value = { |
| | | // summary, |
| | | // chartData, |
| | | // tableData: [] |
| | | // } |
| | | // } |
| | | // éªè¯æç´¢è¡¨å |
| | | const validateSearchForm = () => { |
| | | if (searchForm.reportType === 'daily') { |
| | | if (!searchForm.singleDate) { |
| | | ElMessage.warning('è¯·éæ©æ¥æ') |
| | | return false |
| | | } |
| | | } else if (searchForm.reportType === 'inout') { |
| | | if (!searchForm.dateRange || searchForm.dateRange.length !== 2) { |
| | | ElMessage.warning('è¯·éæ©æ¥æèå´') |
| | | return false |
| | | } |
| | | } else if (searchForm.reportType === 'monthly') { |
| | | if (!searchForm.monthRange || searchForm.monthRange.length !== 2) { |
| | | ElMessage.warning('è¯·éæ©æä»½èå´') |
| | | return false |
| | | } |
| | | } |
| | | return true |
| | | } |
| | | |
| | | // è·åæ¥è¯¢åæ° |
| | | const getQueryParams = () => { |
| | | const params = { |
| | | reportType: searchForm.reportType, |
| | | reportDate: "", |
| | | startMonth: "", |
| | | endMonth: "", |
| | | startDate: "", |
| | | endDate: "" |
| | | } |
| | | |
| | | if (searchForm.reportType === 'daily') { |
| | | params.reportDate = searchForm.singleDate |
| | | } else if (searchForm.reportType === 'monthly') { |
| | | params.startMonth = searchForm.monthRange[0] |
| | | params.endMonth = searchForm.monthRange[1] |
| | | } else { |
| | | params.startDate = searchForm.dateRange[0] |
| | | params.endDate = searchForm.dateRange[1] |
| | | } |
| | | |
| | | return params |
| | | } |
| | | |
| | | // éç½®æç´¢ |
| | | const handleReset = () => { |
| | | searchForm.reportType = 'daily' |
| | | searchForm.singleDate = '' |
| | | searchForm.dateRange = [] |
| | | searchForm.monthRange = [] |
| | | reportData.value = { |
| | | summary: null, |
| | | chartData: null, |
| | | tableData: [] |
| | | } |
| | | } |
| | | |
| | | // å¯¼åºæ¥è¡¨ |
| | | const handleExport = async () => { |
| | | if (!validateSearchForm()) { |
| | | return |
| | | } |
| | | |
| | | try { |
| | | const params = getQueryParams() |
| | | // const response = await exportStockReport(params) |
| | | proxy.download("/consumablesInventory/exportConsumablesInventory", params, 'èæåºåæ¥è¡¨.xlsx') |
| | | // å建ä¸è½½é¾æ¥ |
| | | // const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) |
| | | // const url = window.URL.createObjectURL(blob) |
| | | // const link = document.createElement('a') |
| | | // link.href = url |
| | | // link.download = `${getTableTitle()}_${new Date().getTime()}.xlsx` |
| | | // document.body.appendChild(link) |
| | | // link.click() |
| | | // document.body.removeChild(link) |
| | | // window.URL.revokeObjectURL(url) |
| | | |
| | | // ElMessage.success('å¯¼åºæå') |
| | | } catch (error) { |
| | | ElMessage.error('导åºå¤±è´¥ï¼' + error.message) |
| | | } |
| | | } |
| | | |
| | | // åå§åå¾è¡¨ |
| | | const initCharts = () => { |
| | | if (!reportData.value.chartData) return |
| | | |
| | | initTrendChart() |
| | | initComparisonChart() |
| | | } |
| | | |
| | | // åå§åè¶å¿å¾ |
| | | const initTrendChart = () => { |
| | | if (!trendChart.value) return |
| | | |
| | | const chart = echarts.init(trendChart.value) |
| | | const option = { |
| | | title: { |
| | | text: 'åºåååè¶å¿', |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis' |
| | | }, |
| | | legend: { |
| | | data: ['åºåé'], |
| | | top: 30 |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: reportData.value.chartData.trendDates || [] |
| | | }, |
| | | yAxis: { |
| | | type: 'value' |
| | | }, |
| | | series: [{ |
| | | name: 'åºåé', |
| | | type: 'line', |
| | | data: reportData.value.chartData.trendValues || [], |
| | | smooth: true, |
| | | itemStyle: { |
| | | color: '#409EFF' |
| | | } |
| | | }] |
| | | } |
| | | chart.setOption(option) |
| | | } |
| | | |
| | | // åå§å对æ¯å¾ |
| | | const initComparisonChart = () => { |
| | | if (!comparisonChart.value) return |
| | | |
| | | const chart = echarts.init(comparisonChart.value) |
| | | const option = { |
| | | title: { |
| | | text: 'è¿åºåºå¯¹æ¯', |
| | | left: 'center' |
| | | }, |
| | | tooltip: { |
| | | trigger: 'axis' |
| | | }, |
| | | legend: { |
| | | data: ['å
¥åº', 'åºåº'], |
| | | top: 30 |
| | | }, |
| | | xAxis: { |
| | | type: 'category', |
| | | data: reportData.value.chartData.comparisonDates || [] |
| | | }, |
| | | yAxis: { |
| | | type: 'value' |
| | | }, |
| | | series: [ |
| | | { |
| | | name: 'å
¥åº', |
| | | type: 'bar', |
| | | data: reportData.value.chartData.inValues || [], |
| | | itemStyle: { |
| | | color: '#67C23A' |
| | | } |
| | | }, |
| | | { |
| | | name: 'åºåº', |
| | | type: 'bar', |
| | | data: reportData.value.chartData.outValues || [], |
| | | itemStyle: { |
| | | color: '#F56C6C' |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | chart.setOption(option) |
| | | } |
| | | |
| | | // ç»ä»¶æè½½æ¶è®¾ç½®é»è®¤æ¶é´ |
| | | onMounted(() => { |
| | | const today = new Date() |
| | | searchForm.singleDate = today.toISOString().split('T')[0] |
| | | |
| | | const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000) |
| | | searchForm.dateRange = [ |
| | | yesterday.toISOString().split('T')[0], |
| | | today.toISOString().split('T')[0] |
| | | ] |
| | | |
| | | fetchStockRecordTypeOptions() |
| | | }) |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .search_form { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | padding: 20px; |
| | | background: #fff; |
| | | border-radius: 4px; |
| | | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .search_left { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .search_title { |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .ml10 { |
| | | margin-left: 10px; |
| | | } |
| | | |
| | | .stats_cards { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .stats_card { |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .stats_content { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .stats_icon { |
| | | width: 50px; |
| | | height: 50px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | margin-right: 15px; |
| | | font-size: 24px; |
| | | color: #fff; |
| | | } |
| | | |
| | | .stats_icon.in { |
| | | background: linear-gradient(135deg, #67C23A, #85CE61); |
| | | } |
| | | |
| | | .stats_icon.out { |
| | | background: linear-gradient(135deg, #F56C6C, #F78989); |
| | | } |
| | | |
| | | .stats_icon.stock { |
| | | background: linear-gradient(135deg, #409EFF, #66B1FF); |
| | | } |
| | | |
| | | .stats_icon.turnover { |
| | | background: linear-gradient(135deg, #E6A23C, #EEBE77); |
| | | } |
| | | |
| | | .stats_info { |
| | | flex: 1; |
| | | } |
| | | |
| | | .stats_value { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | line-height: 1; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .stats_label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | } |
| | | |
| | | .chart_section { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .table_section { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | :deep(.el-card__header) { |
| | | background: #f8f9fa; |
| | | border-bottom: 1px solid #e9ecef; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | :deep(.el-table .el-table__header-wrapper th) { |
| | | background-color: #F0F1F5 !important; |
| | | color: #333333; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | :deep(.el-table .el-table__body-wrapper td) { |
| | | padding: 8px 0; |
| | | } |
| | | </style> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="ç°åºç
§ç"> |
| | | <div class="repair-upload-area"> |
| | | <el-upload |
| | | v-model:file-list="uploadFileList" |
| | | :action="uploadUrl" |
| | | :headers="uploadHeaders" |
| | | accept="image/*" |
| | | list-type="picture-card" |
| | | :limit="uploadLimit" |
| | | :on-success="handleUploadSuccess" |
| | | :on-remove="handleRemoveFile" |
| | | :before-upload="beforeUpload" |
| | | > |
| | | <el-icon><Plus /></el-icon> |
| | | </el-upload> |
| | | <div v-if="repairFileList.length === 0" class="upload-tip">请ä¸ä¼ ç°åºç
§çï¼æå¤ {{ uploadLimit }} å¼ </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { Plus } from "@element-plus/icons-vue"; |
| | | import dayjs from "dayjs"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®å¼¹çª", |
| | |
| | | const userStore = useUserStore(); |
| | | const deviceOptions = ref([]); |
| | | |
| | | // ç°åºç
§çä¸ä¼ ï¼ä¸ APP åæ®µä¸è´ï¼fileList / commonFileListï¼ |
| | | const uploadUrl = import.meta.env.VITE_APP_BASE_API + "/file/upload"; |
| | | const uploadLimit = 10; |
| | | const uploadFileList = ref([]); |
| | | const repairFileList = ref([]); |
| | | const uploadHeaders = { Authorization: "Bearer " + getToken() }; |
| | | const baseApi = import.meta.env.VITE_APP_BASE_API || ""; |
| | | |
| | | const formatFileUrl = (url) => { |
| | | if (!url) return ""; |
| | | if (url.startsWith("http://") || url.startsWith("https://")) return url; |
| | | const path = url.replace(/^\/+/, ""); |
| | | return path ? baseApi + "/" + path : baseApi; |
| | | }; |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | }; |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设å¤Id |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // æ¥ä¿®æ¥æï¼é»è®¤å½å¤© |
| | | repairName: userStore.nickName, // æ¥ä¿®äºº |
| | | remark: undefined, // æ
éç°è±¡ |
| | | status: 0, // æ¥ä¿®ç¶æ |
| | | deviceLedgerId: undefined, |
| | | deviceName: undefined, |
| | | deviceModel: undefined, |
| | | repairTime: dayjs().format("YYYY-MM-DD"), |
| | | repairName: userStore.nickName, |
| | | remark: undefined, |
| | | status: 0, |
| | | }); |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | | const option = deviceOptions.value.find((item) => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | }; |
| | | |
| | | const beforeUpload = (file) => { |
| | | const isImage = file.type.startsWith("image/"); |
| | | if (!isImage) { |
| | | ElMessage.warning("åªè½ä¸ä¼ å¾ç"); |
| | | return false; |
| | | } |
| | | if (repairFileList.value.length >= uploadLimit) { |
| | | ElMessage.warning(`æå¤ä¸ä¼ ${uploadLimit} å¼ å¾ç`); |
| | | return false; |
| | | } |
| | | return true; |
| | | }; |
| | | |
| | | const handleUploadSuccess = (res, file) => { |
| | | if (res?.code !== 200 && res?.code !== 0) { |
| | | ElMessage.error(res?.msg || "ä¸ä¼ 失败"); |
| | | const idx = uploadFileList.value.findIndex((f) => f.uid === file.uid); |
| | | if (idx > -1) uploadFileList.value.splice(idx, 1); |
| | | return; |
| | | } |
| | | const d = res?.data !== undefined ? res.data : res; |
| | | if (!d) return; |
| | | const item = { |
| | | uid: file.uid, |
| | | id: d.id, |
| | | url: d.url || d.downloadUrl || d.tempPath, |
| | | downloadUrl: d.downloadUrl || d.url, |
| | | bucketFilename: d.bucketFilename || d.originalFilename || file.name, |
| | | originalFilename: d.originalFilename || d.bucketFilename || file.name, |
| | | name: d.bucketFilename || d.originalFilename || file.name, |
| | | size: d.size ?? d.byteSize ?? file.size, |
| | | byteSize: d.byteSize ?? d.size ?? file.size, |
| | | uploadResponse: res, |
| | | }; |
| | | repairFileList.value.push(item); |
| | | }; |
| | | |
| | | const handleRemoveFile = (file) => { |
| | | const targetUrl = file.url || file.response?.data?.url || file.response?.data?.downloadUrl; |
| | | repairFileList.value = repairFileList.value.filter( |
| | | (f) => f.uid !== file.uid && (f.url || f.downloadUrl) !== targetUrl |
| | | ); |
| | | }; |
| | | |
| | | const setForm = (data) => { |
| | |
| | | form.repairName = data.repairName; |
| | | form.remark = data.remark; |
| | | form.status = data.status; |
| | | const list = data.fileList || data.commonFileList || []; |
| | | repairFileList.value = (Array.isArray(list) ? list : []).map((f, i) => ({ |
| | | uid: f.id || "existing-" + i, |
| | | id: f.id, |
| | | url: f.url || f.downloadUrl, |
| | | downloadUrl: f.downloadUrl || f.url, |
| | | bucketFilename: f.bucketFilename || f.originalFilename || f.name, |
| | | originalFilename: f.originalFilename || f.bucketFilename || f.name, |
| | | name: f.bucketFilename || f.originalFilename || f.name || "å¾ç", |
| | | size: f.size ?? f.byteSize, |
| | | byteSize: f.byteSize ?? f.size, |
| | | ...f, |
| | | })); |
| | | uploadFileList.value = repairFileList.value.map((f, i) => ({ |
| | | uid: f.uid || "existing-" + i, |
| | | name: f.name || f.bucketFilename || "å¾ç", |
| | | url: formatFileUrl(f.url || f.downloadUrl), |
| | | status: "success", |
| | | })); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | const fileList = repairFileList.value.map((f) => { |
| | | const d = f.uploadResponse?.data !== undefined ? f.uploadResponse.data : f.uploadResponse; |
| | | return d ? { ...d } : (f.id || f.url ? { ...f } : null); |
| | | }).filter(Boolean); |
| | | const submitData = { ...form }; |
| | | if (fileList.length) submitData.fileList = fileList; |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...form }) |
| | | : await addRepair(form); |
| | | ? await editRepair({ id: unref(id), ...submitData }) |
| | | : await addRepair(submitData); |
| | | if (code == 200) { |
| | | ElMessage.success(`${id.value ? "ç¼è¾" : "æ°å¢"}æ¥ä¿®æå`); |
| | | visible.value = false; |
| | |
| | | |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | repairFileList.value = []; |
| | | uploadFileList.value = []; |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | repairFileList.value = []; |
| | | uploadFileList.value = []; |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const openAdd = async () => { |
| | | id.value = undefined; |
| | | repairFileList.value = []; |
| | | uploadFileList.value = []; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | | <style lang="scss" scoped> |
| | | .repair-upload-area { |
| | | :deep(.el-upload-list--picture-card) { |
| | | --el-upload-list-picture-card-size: 100px; |
| | | } |
| | | } |
| | | .upload-tip { |
| | | font-size: 12px; |
| | | color: var(--el-text-color-secondary); |
| | | margin-top: 8px; |
| | | } |
| | | </style> |
| | |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button |
| | | type="info" |
| | | link |
| | | @click="viewAttachments(row)" |
| | | > |
| | | æ¥çéä»¶ |
| | | </el-button> |
| | | <el-button |
| | | type="success" |
| | | link |
| | | :disabled="row.status === 1" |
| | |
| | | </div> |
| | | <RepairModal ref="repairModalRef" @ok="getTableData"/> |
| | | <MaintainModal ref="maintainModalRef" @ok="getTableData"/> |
| | | <FileListDialog |
| | | ref="fileListDialogRef" |
| | | v-model="fileDialogVisible" |
| | | title="æ¥çéä»¶" |
| | | :show-upload-button="false" |
| | | :show-delete-button="false" |
| | | name-column-label="éä»¶åç§°" |
| | | /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, getCurrentInstance, computed } from "vue"; |
| | | import {usePaginationApi} from "@/hooks/usePaginationApi"; |
| | | import {getRepairPage, delRepair} from "@/api/equipmentManagement/repair"; |
| | | import {getRepairPage, delRepair, getRepairById} from "@/api/equipmentManagement/repair"; |
| | | import RepairModal from "./Modal/RepairModal.vue"; |
| | | import {ElMessageBox, ElMessage} from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import MaintainModal from "./Modal/MaintainModal.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®", |
| | |
| | | // æ¨¡ææ¡å®ä¾ |
| | | const repairModalRef = ref(); |
| | | const maintainModalRef = ref(); |
| | | const fileListDialogRef = ref(); |
| | | const fileDialogVisible = ref(false); |
| | | |
| | | const baseApi = import.meta.env.VITE_APP_BASE_API || ""; |
| | | const formatFileUrl = (url) => { |
| | | if (!url) return ""; |
| | | if (url.startsWith("http://") || url.startsWith("https://")) return url; |
| | | const path = String(url).replace(/^\/+/, ""); |
| | | return path ? baseApi + "/" + path : baseApi; |
| | | }; |
| | | |
| | | // æ¥çéä»¶ï¼ä¸ APP åæ®µä¸è´ï¼fileList / commonFileListï¼ |
| | | const viewAttachments = async (row) => { |
| | | try { |
| | | const { code, data } = await getRepairById(row.id); |
| | | if (code === 200 && data) { |
| | | const list = data.fileList || data.commonFileList || []; |
| | | const mapped = (Array.isArray(list) ? list : []).map((f) => ({ |
| | | id: f.id, |
| | | name: f.originalFilename || f.bucketFilename || f.name || "éä»¶", |
| | | url: formatFileUrl(f.url || f.downloadUrl), |
| | | raw: f, |
| | | })); |
| | | fileListDialogRef.value?.open(mapped); |
| | | } else { |
| | | ElMessage.warning("è·åé件失败"); |
| | | } |
| | | } catch (e) { |
| | | ElMessage.error("è·åé件失败"); |
| | | } |
| | | }; |
| | | |
| | | // è¡¨æ ¼å¤éæ¡éä¸é¡¹ |
| | | const multipleList = ref([]); |
| | |
| | | dataType: "slot", |
| | | slot: "operation", |
| | | align: "center", |
| | | width: "300px", |
| | | width: "360px", |
| | | }, |
| | | ] |
| | | ); |
| | |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="车çå·" |
| | | prop="licensePlateNo" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="æ¯é(å¨)" |
| | | prop="grossWeight" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="ç®é(å¨)" |
| | | prop="tareWeight" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="åé(å¨)" |
| | | prop="netWeight" |
| | | show-overflow-tooltip |
| | |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="车ç" |
| | | prop="licensePlateNo" |
| | | label="è¿ç£
æ¥æ" |
| | | prop="weighingDate" |
| | | show-overflow-tooltip |
| | | /> |
| | | <el-table-column |
| | | label="è¿ç£
å" |
| | | prop="weighingOperator" |
| | | show-overflow-tooltip |
| | | /> |
| | | </el-table> |
| | |
| | | <el-form-item label="å
æ§å¼" prop="internalControl"> |
| | | <el-input v-model="form.internalControl" placeholder="请è¾å
¥å
æ§å¼" clearable style="width: 280px" /> |
| | | </el-form-item> |
| | | <el-form-item label="åéªå¼" prop="testValue"> |
| | | <!-- <el-form-item label="åéªå¼" prop="testValue"> |
| | | <el-input v-model="form.testValue" placeholder="请è¾å
¥åéªå¼" clearable style="width: 280px" /> |
| | | </el-form-item> |
| | | </el-form-item> --> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | { label: "åä½", prop: "unit", width: 120 }, |
| | | { label: "æ åå¼", prop: "standardValue", width: 160 }, |
| | | { label: "å
æ§å¼", prop: "internalControl", width: 160 }, |
| | | { label: "åéªå¼", prop: "testValue", width: 160 }, |
| | | // { label: "åéªå¼", prop: "testValue", width: 160 }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |