| | |
| | | <template> |
| | | <vol-box v-model="show" title="空æå
¥åº" :width="800" :height="1200"> |
| | | <template #content> |
| | | <el-form ref="form" :model="form" label-width="90px"> |
| | | <el-form-item label="å
¥åºåºå:"> |
| | | <el-form ref="form" :model="form" :rules="rules" label-width="90px"> |
| | | <el-form-item label="å
¥åºåºå:" prop="locationType"> |
| | | <el-select v-model="form.locationType" placeholder="è¯·éæ©å
¥åºåºå"> |
| | | <el-option v-for="item in locationTypes" :key="item.locationType" :label="item.locationTypeDesc" |
| | | :value="item.locationType" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="æçæ¡ç :"> |
| | | <el-input v-model="form.palletCode" placeholder="è¯·æ«æ/è¾å
¥æçæ¡ç " @keyup.enter="submit" @keyup.13="submit" |
| | | clearable maxlength="50" @paste="handlePaste" @input="handleInput" ref="boxCodeInput" /> |
| | | <el-form-item label="æçæ¡ç :" prop="palletCode"> |
| | | <el-input v-model="form.palletCode" placeholder="è¯·æ«æ/è¾å
¥æçæ¡ç ï¼Aå¼å¤´ï¼åè·æ°åï¼" @keyup.enter="submit" clearable |
| | | @paste="handlePaste" @input="handleInput" ref="boxCodeInput" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | |
| | | value: { type: Boolean, default: false } |
| | | }, |
| | | data() { |
| | | // èªå®ä¹æ¡ç éªè¯è§å |
| | | const validatePalletCode = (rule, value, callback) => { |
| | | if (!value) { |
| | | return callback(new Error('请è¾å
¥æçæ¡ç ')); |
| | | } |
| | | |
| | | // éªè¯æ¡ç æ ¼å¼ï¼Aå¼å¤´ï¼åé¢è³å°1使°åï¼ä¸éå¶å
·ä½é¿åº¦ï¼ |
| | | const codePattern = /^A\d+$/; |
| | | if (!codePattern.test(value)) { |
| | | return callback(new Error('æ¡ç æ ¼å¼ä¸æ£ç¡®ï¼æ£ç¡®æ ¼å¼ï¼Aå¼å¤´ï¼åè·æ°åï¼å¦ï¼A000008080')); |
| | | } |
| | | |
| | | callback(); |
| | | }; |
| | | |
| | | return { |
| | | show: false, |
| | | form: { |
| | | palletCode: '', |
| | | locationType: '' |
| | | }, |
| | | locationTypes: [] |
| | | locationTypes: [], |
| | | // 表åéªè¯è§å |
| | | rules: { |
| | | locationType: [ |
| | | { required: true, message: 'è¯·éæ©å
¥åºåºå', trigger: 'change' } |
| | | ], |
| | | palletCode: [ |
| | | { validator: validatePalletCode, trigger: ['blur', 'change'] } |
| | | ] |
| | | } |
| | | } |
| | | }, |
| | | methods: { |
| | |
| | | }, |
| | | |
| | | async submit() { |
| | | if (!this.form.palletCode) { |
| | | this.$message.warning('请è¾å
¥æçæ¡ç ') |
| | | this.focusInput() |
| | | return |
| | | } |
| | | |
| | | if (!this.form.locationType) { |
| | | this.$message.warning('è¯·éæ©å
¥åºåºå') |
| | | return |
| | | // 表åéªè¯ |
| | | try { |
| | | await this.$refs.form.validate(); |
| | | } catch (error) { |
| | | // éªè¯å¤±è´¥ï¼èç¦è¾å
¥æ¡ |
| | | this.focusAndSelectInput(); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | |
| | | this.$message.success("ç»çæå"); |
| | | // æ¸
空è¾å
¥æ¡æ°æ® |
| | | this.form.palletCode = ''; |
| | | // éç½®éªè¯ç¶æ |
| | | this.$refs.form.clearValidate('palletCode'); |
| | | // èç¦å¹¶éä¸è¾å
¥æ¡ |
| | | this.focusAndSelectInput(); |
| | | } else { |
| | |
| | | |
| | | // æ«ææªä¼åå¤ç |
| | | handleInput(value) { |
| | | // è¿æ»¤éæ°ååæ¡ç 常ç¨å符 |
| | | this.form.palletCode = value.replace(/[^a-zA-Z0-9\-]/g, '') |
| | | // è¿æ»¤éæ°ååæ¡ç 常ç¨å符ï¼å
许Aå¼å¤´ |
| | | this.form.palletCode = value.replace(/[^a-zA-Z0-9]/g, '') |
| | | |
| | | // èªå¨è½¬æ¢ä¸ºå¤§åï¼æ¡ç é常为大åï¼ |
| | | this.form.palletCode = this.form.palletCode.toUpperCase(); |
| | | |
| | | // èªå¨è§¦åéªè¯ |
| | | this.$nextTick(() => { |
| | | this.$refs.form.validateField('palletCode'); |
| | | }); |
| | | }, |
| | | |
| | | handlePaste(e) { |
| | | // ç²è´´æ¶èªå¨æäº¤ |
| | | setTimeout(this.submit, 100) |
| | | // è·åç²è´´çå
容 |
| | | const clipboardData = e.clipboardData || window.clipboardData; |
| | | const pastedText = clipboardData.getData('text'); |
| | | |
| | | // å¤çç²è´´å
容 |
| | | const cleanedText = pastedText.replace(/[^a-zA-Z0-9]/g, '').toUpperCase(); |
| | | |
| | | // 妿ç²è´´å
å®¹ç¬¦åæ¡ç æ ¼å¼ï¼èªå¨å¡«å
å¹¶æäº¤ |
| | | if (cleanedText.startsWith('A')) { |
| | | this.form.palletCode = cleanedText; |
| | | // å»¶è¿æäº¤ï¼ç¡®ä¿è¡¨åå·²æ´æ° |
| | | setTimeout(() => { |
| | | this.submit(); |
| | | }, 50); |
| | | } |
| | | |
| | | // 黿¢é»è®¤ç²è´´è¡ä¸ºï¼ä½¿ç¨æä»¬å¤çåçå¼ |
| | | e.preventDefault(); |
| | | }, |
| | | |
| | | |
| | | // èç¦å¹¶éä¸è¾å
¥æ¡ |
| | | focusAndSelectInput() { |
| | | this.$nextTick(() => { |
| | |
| | | }, 100); |
| | | }); |
| | | }, |
| | | |
| | | |
| | | // åªèç¦è¾å
¥æ¡ï¼ä¸æ¸
ç©ºæ°æ®ï¼ |
| | | focusInput() { |
| | | this.$nextTick(() => { |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | |
| | | // æ¸
ç©ºè¡¨åæ°æ® |
| | | clearForm() { |
| | | this.form.palletCode = ''; |
| | | // éç½®éªè¯ç¶æ |
| | | if (this.$refs.form) { |
| | | this.$refs.form.clearValidate(); |
| | | } |
| | | // 䏿¸
空 locationTypeï¼ä¿æåºåéæ© |
| | | } |
| | | }, |
| | |
| | | <el-divider direction="vertical"></el-divider> |
| | | <span class="less-style">ç©æç¼å·ï¼ {{ row.materielCode }} </span> |
| | | <el-divider direction="vertical"></el-divider> |
| | | <span class="less-style">éæ±æ°éï¼ {{ row.qty }} </span> |
| | | <span class="less-style" |
| | | >éæ±æ°éï¼ {{ row.orderQuantity }} |
| | | </span> |
| | | <el-divider direction="vertical"></el-divider> |
| | | <span :class="selectionClass">已鿰éï¼ {{ selectionSum }} </span> |
| | | <span :class="selectionClass" |
| | | >已鿰éï¼ {{ selectionSum }} |
| | | </span> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <!-- <el-link |
| | | type="primary" |
| | | size="small" |
| | | style="float: right; height: 20px" |
| | | @click="getData(false)" |
| | | >{{ kcname }}</el-link |
| | | > --> |
| | | <el-link |
| | | type="primary" |
| | | size="small" |
| | |
| | | @click="getData" |
| | | >å·æ°</el-link |
| | | > |
| | | <el-link |
| | | <!-- <el-link |
| | | type="primary" |
| | | size="small" |
| | | style="float: right; height: 20px; margin-right: 10px" |
| | | @click="openOutboundDialog" |
| | | >ç´æ¥åºåº</el-link |
| | | > |
| | | @click="revokeAssign" |
| | | >æ¤éåé
</el-link |
| | | > --> |
| | | </el-col> |
| | | </el-row> |
| | | </el-alert> |
| | | </div> |
| | | |
| | | <!-- æ°å¢çéåºå --> |
| | | <div class="filter-area" style="margin: 10px 0; padding: 10px; background: #f8f9fa; border-radius: 4px;"> |
| | | <el-form :model="filterForm" inline @submit.prevent> |
| | | <el-form-item label="ç©æç¼å·ï¼"> |
| | | <el-input |
| | | v-model="filterForm.materielCode" |
| | | placeholder="模ç³çéç©æç¼å·" |
| | | clearable |
| | | style="width: 180px" |
| | | @input="filterTable" |
| | | ></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ç©ææ¡ç ï¼"> |
| | | <el-input |
| | | v-model="filterForm.barcode" |
| | | placeholder="模ç³çéç©ææ¡ç " |
| | | clearable |
| | | style="width: 180px" |
| | | @input="filterTable" |
| | | ></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æçç¼å·ï¼"> |
| | | <el-input |
| | | v-model="filterForm.palletCode" |
| | | placeholder="模ç³çéæçç¼å·" |
| | | clearable |
| | | style="width: 180px" |
| | | @input="filterTable" |
| | | ></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="è´§ä½ç¼å·ï¼"> |
| | | <el-input |
| | | v-model="filterForm.locationCode" |
| | | placeholder="模ç³çéè´§ä½ç¼å·" |
| | | clearable |
| | | style="width: 180px" |
| | | @input="filterTable" |
| | | ></el-input> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="filterTable">æç´¢</el-button> |
| | | <el-button @click="resetFilter">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | |
| | | <div class="box-table" style="margin-top: 1%"> |
| | | <el-table |
| | | ref="singleTable" |
| | |
| | | height="500px" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | > |
| | | <el-table-column type="selection" width="55"> </el-table-column> |
| | | <el-table-column |
| | | label="åºå·" |
| | |
| | | </el-table> |
| | | </div> |
| | | <template #footer> |
| | | <!-- 廿éå®åºåæé®ï¼åªä¿çå
³éæé® --> |
| | | <!-- <el-button type="primary" size="small" @click="outbound" |
| | | >ç´æ¥åºåº</el-button |
| | | > |
| | | <el-button type="primary" size="small" @click="lockStock" |
| | | >éå®åºå</el-button |
| | | > --> |
| | | <el-button type="danger" size="small" @click="showDetialBox = false" |
| | | >å
³é</el-button |
| | | > |
| | | </template> |
| | | </vol-box> |
| | | |
| | | <!-- åºåºç«å°éæ©å¼¹çªï¼éææ¨¡æ¿å®ç°ï¼ --> |
| | | <el-dialog |
| | | v-model="showOutboundDialog" |
| | | title="åºåºæä½ - éæ©åºåºç«å°" |
| | | width="500px" |
| | | :append-to-body="true" |
| | | > |
| | | <el-form |
| | | :model="outboundForm" |
| | | :rules="outboundRules" |
| | | ref="outboundFormRef" |
| | | label-width="100px" |
| | | style="padding: 0 20px" |
| | | > |
| | | <el-form-item label="åºåºç«å°" prop="selectedPlatform" style="margin-bottom: 24px"> |
| | | <el-select |
| | | v-model="outboundForm.selectedPlatform" |
| | | placeholder="è¯·éæ©åºåºç«å°ï¼3-12ï¼" |
| | | style="width: 100%; height: 40px" |
| | | > |
| | | <el-option |
| | | v-for="platform in platformOptions" |
| | | :key="platform.value" |
| | | :label="platform.label" |
| | | :value="platform.value" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="showOutboundDialog = false" style="margin-right: 8px">åæ¶</el-button> |
| | | <el-button type="primary" @click="confirmOutbound">ç¡®å®åºåº</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import VolBox from "@/components/basic/VolBox.vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | |
| | | import { fa } from "element-plus/es/locales.mjs"; |
| | | export default { |
| | | components: { VolBox }, |
| | | data() { |
| | | return { |
| | | row: null, // æ¥æ¶ç¶ç»ä»¶ä¼ éç宿´æ°æ®ï¼å
嫿ç»IDéåï¼ |
| | | row: null, |
| | | kcname: "", |
| | | pkcx: false, |
| | | showDetialBox: false, |
| | | tableData: [], |
| | | originalTableData: [], // åå¨åå§æ°æ®ï¼ç¨äºçé |
| | | tableColumns: [ |
| | | { prop: "materielCode", title: "ç©æç¼å·", type: "string", width: 150 }, |
| | | { prop: "barcode", title: "ç©ææ¡ç ", type: "string", width: 150 }, |
| | | { prop: "palletCode", title: "æçç¼å·", type: "string", width: 150 }, |
| | | { prop: "locationCode", title: "è´§ä½ç¼å·", type: "string", width: 180 }, |
| | | { prop: "useableQuantity", title: "å¯ç¨æ°é", type: "string" }, |
| | | { |
| | | prop: "materielCode", |
| | | title: "ç©æç¼å·", |
| | | type: "string", |
| | | width: 150, |
| | | }, |
| | | { |
| | | prop: "materielName", |
| | | title: "ç©æåç§°", |
| | | type: "string", |
| | | width: 150, |
| | | }, |
| | | { |
| | | prop: "palletCode", |
| | | title: "æçç¼å·", |
| | | type: "string", |
| | | width: 150, |
| | | }, |
| | | { |
| | | prop: "locationCode", |
| | | title: "è´§ä½ç¼å·", |
| | | type: "string", |
| | | width: 180, |
| | | }, |
| | | { |
| | | prop: "useableQuantity", |
| | | title: "å¯ç¨æ°é", |
| | | type: "string", |
| | | }, |
| | | ], |
| | | selection: [], // éä¸çåºåæ°æ® |
| | | selectionSum: 0, // 已鿰鿻å |
| | | selection: [], |
| | | selectionSum: 0, |
| | | selectionClass: "less-style", |
| | | originalQuantity: 0, |
| | | |
| | | // çéè¡¨åæ°æ® |
| | | filterForm: { |
| | | materielCode: "", |
| | | barcode: "", |
| | | palletCode: "", |
| | | locationCode: "" |
| | | }, |
| | | |
| | | // åºåºå¼¹çªç¸å
³æ°æ® |
| | | showOutboundDialog: false, |
| | | outboundForm: { selectedPlatform: "" }, // 表åç»å®æ°æ® |
| | | outboundRules: { |
| | | selectedPlatform: [ |
| | | { required: true, message: "è¯·éæ©åºåºç«å°", trigger: "change" }, |
| | | ], |
| | | }, |
| | | platformOptions: [ |
| | | { label: "ç«å°2", value: "2-1" }, |
| | | { label: "ç«å°3", value: "3-1" }, |
| | | ], |
| | | pkcx: false, // æ°å¢ï¼é»è®¤falseï¼å¦æéè¦å¯ä»ç¶ç»ä»¶ä¼ éï¼ |
| | | }; |
| | | }, |
| | | methods: { |
| | | // æ¥æ¶ç¶ç»ä»¶ä¼ éçæ°æ®ï¼å
嫿ç»IDéååç©æä¿¡æ¯ï¼ |
| | | open(data) { |
| | | this.row = data; // dataç»æï¼{materielCode, materielName, qty, orderNo, detailIds, mainOrderId, groupRow} |
| | | open(row) { |
| | | console.log(row); |
| | | this.row = row; |
| | | this.showDetialBox = true; |
| | | this.getData(); // å è½½åºåæ°æ® |
| | | this.updateSelectionClass(); // åå§åå·²éæ°éæ ·å¼ |
| | | console.log("æ¥æ¶çåç»æç»IDéåï¼", this.row.detailIds); |
| | | console.log("æ¥è¯¢åºåçç©æç¼ç ï¼", this.row.materielCode); |
| | | }, |
| | | |
| | | // æå¼åºåºå¼¹çª |
| | | openOutboundDialog() { |
| | | if (this.selection.length === 0) { |
| | | return ElMessage.error("è¯·éæ©åºåæ°æ®"); |
| | | } |
| | | // æ ¡éªæç»IDéå |
| | | if (!this.row?.detailIds || this.row.detailIds.length === 0) { |
| | | return ElMessage.error("没æè·åå°åæ®æç»IDï¼æ æ³åºåº"); |
| | | } |
| | | // é置表åé¿å
æ®çå¼ |
| | | this.outboundForm.selectedPlatform = ""; |
| | | this.showOutboundDialog = true; |
| | | }, |
| | | |
| | | // æ ¸å¿ä¿®æ¹ï¼URLæ¼æ¥ä¼ éint[] orderDetailIdï¼éå¤åæ°åï¼åstationï¼è¯·æ±ä½ä¼ åºåæ°æ® |
| | | confirmOutbound() { |
| | | this.$refs.outboundFormRef.validate((valid) => { |
| | | if (!valid) return; |
| | | |
| | | // æ ¡éªéä¸åºååæç»ID |
| | | if (this.selection.length <= 0) { |
| | | return this.$message.error("请å¾éåºåæ°æ®"); |
| | | } |
| | | if (!this.row?.detailIds || this.row.detailIds.length === 0) { |
| | | return this.$message.error("没æè·åå°åæ®æç»IDï¼æ æ³åºåº"); |
| | | } |
| | | |
| | | try { |
| | | // 1. 转æ¢IDä¸ºæ´æ°æ°ç»ï¼ç¡®ä¿å端è½è¯å«ä¸ºint[]ï¼ |
| | | const orderDetailId = this.row.detailIds.map(id => { |
| | | const num = Number(id); |
| | | if (isNaN(num) || !Number.isInteger(num)) { |
| | | throw new Error(`ID ${id} 䏿¯ææçæ´æ°`); |
| | | } |
| | | return num; |
| | | }); |
| | | |
| | | // 2. æ¼æ¥URLï¼int[] ç¨éå¤åæ°åæ ¼å¼ï¼?orderDetailId=1&orderDetailId=2&...ï¼ |
| | | let url = "api/Task/GenerateOutboundTask"; |
| | | // æ¼æ¥IDæ°ç»åæ° |
| | | const idParams = orderDetailId.map(id => `orderDetailId=${id}`).join("&"); |
| | | // æ¼æ¥ç«å°åæ° |
| | | const stationParam = `station=${encodeURIComponent(this.outboundForm.selectedPlatform)}`; |
| | | // 宿´URLï¼å¤çåæ°æ¼æ¥é»è¾ï¼ |
| | | const fullUrl = idParams |
| | | ? `${url}?${idParams}&${stationParam}` |
| | | : `${url}?${stationParam}`; |
| | | |
| | | console.log("åºåºè¯·æ±URLï¼", fullUrl); |
| | | |
| | | // 3. åé请æ±ï¼URLæ¼æ¥IDåç«å°ï¼è¯·æ±ä½ä¼ åºåæ°æ®ï¼éé
FromBodyï¼ |
| | | this.http |
| | | .post(fullUrl, this.selection, "æ°æ®å¤çä¸") |
| | | .then((x) => { |
| | | if (!x.status) return this.$message.error(x.message); |
| | | this.$message.success("æä½æå"); |
| | | this.showDetialBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.getData(); // å·æ°ç¶ç»ä»¶æ°æ® |
| | | }); |
| | | }) |
| | | .catch((err) => { |
| | | console.error("åºåºå¤±è´¥ï¼", err); |
| | | this.$message.error(`åºåºå¤±è´¥ï¼${err.message || '请ç¨åéè¯'}`); |
| | | }); |
| | | } catch (err) { |
| | | this.$message.error(err.message); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // æç¬¬ä¸ä¸ªç©æç¼ç æ¥è¯¢åºåæ°æ® |
| | | getData() { |
| | | const url = "api/StockInfo/GetSelectViewDTOs?materielCode="; |
| | | // 使ç¨ç¶ç»ä»¶ä¼ éçç©æç¼ç ï¼ç¬¬ä¸ä¸ªæç»çç¼ç ï¼ |
| | | this.http |
| | | .post( |
| | | url + this.row.materielCode + "&orderNo=" + (this.row.upperOrderNo || this.row.orderNo), |
| | | null, |
| | | "æ¥è¯¢ä¸" |
| | | ) |
| | | .then((x) => { |
| | | this.tableData = x || []; |
| | | this.originalTableData = [...this.tableData]; // ä¿ååå§æ°æ® |
| | | // å·æ°åæ¸
空ä¹åçéæ©åè®¡æ° |
| | | this.clearSelection(); |
| | | this.selectionSum = 0; |
| | | this.originalQuantity = 0; |
| | | this.updateSelectionClass(); |
| | | // å·æ°åéç½®ç鿡件 |
| | | this.resetFilter(); |
| | | }) |
| | | .catch((err) => { |
| | | console.error("åºåæ¥è¯¢å¤±è´¥ï¼", err); |
| | | ElMessage.error("åºåæ¥è¯¢å¤±è´¥ï¼è¯·ç¨åéè¯"); |
| | | this.tableData = []; |
| | | this.originalTableData = []; |
| | | }); |
| | | }, |
| | | |
| | | // æ¤éæå®åºåï¼å¦æéè¦ï¼ |
| | | revokeAssign() { |
| | | if (!this.row?.detailIds || this.row.detailIds.length === 0) { |
| | | return ElMessage.error("没æè·åå°åæ®æç»IDï¼æ æ³æ¤é"); |
| | | } |
| | | |
| | | try { |
| | | // IDè½¬ä¸ºæ´æ°æ°ç»ï¼æ¼æ¥URL |
| | | const detailIds = this.row.detailIds.map(id => Number(id)); |
| | | const idParams = detailIds.map(id => `detailIds=${id}`).join("&"); |
| | | const url = `api/OutboundOrderDetail/RevokeLockOutboundStock?id=${this.row.mainOrderId}&${idParams}`; |
| | | |
| | | this.http |
| | | .post(url, null, "æ°æ®å¤çä¸") |
| | | .then((x) => { |
| | | if (!x.status) return ElMessage.error(x.message); |
| | | ElMessage.success("æ¤éæå"); |
| | | this.showDetialBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.getData(); |
| | | }); |
| | | }); |
| | | } catch (err) { |
| | | this.$message.error(`æ¤é失败ï¼${err.message}`); |
| | | } |
| | | }, |
| | | |
| | | // å¤çè¡¨æ ¼éæ©ååï¼è®¡ç®å·²éæ°éï¼ |
| | | handleSelectionChange(val) { |
| | | this.selection = val; |
| | | // 计ç®å·²éæ°éï¼è½¬æ°åé¿å
åç¬¦ä¸²æ¼æ¥ï¼ |
| | | this.selectionSum = val.reduce( |
| | | (acc, curr) => acc + Number(curr.useableQuantity || 0), |
| | | 0 |
| | | ) + this.originalQuantity; |
| | | this.updateSelectionClass(); |
| | | }, |
| | | |
| | | // æ´æ°å·²éæ°éæ ·å¼ï¼å¯¹æ¯åç»æ»éæ±æ°éï¼ |
| | | updateSelectionClass() { |
| | | if (!this.row) return; |
| | | if (this.selectionSum === this.row.qty) { |
| | | this.originalQuantity = this.row.lockQuantity; |
| | | this.selectionSum = this.row.lockQuantity; |
| | | this.getData(); |
| | | if (this.selectionSum == this.row.orderQuantity) { |
| | | this.selectionClass = "equle-style"; |
| | | } else if (this.selectionSum < this.row.qty) { |
| | | } else if (this.selectionSum < this.row.orderQuantity) { |
| | | this.selectionClass = "less-style"; |
| | | } else { |
| | | this.selectionClass = "more-style"; |
| | | } |
| | | }, |
| | | |
| | | // åæ¢è¡¨æ ¼éæ© |
| | | toggleSelection(rows) { |
| | | rows |
| | | ? rows.forEach((row) => this.$refs.singleTable.toggleRowSelection(row)) |
| | | : this.clearSelection(); |
| | | lockStock() { |
| | | this.http |
| | | .post( |
| | | "api/OutboundOrderDetail/LockOutboundStock?id=" + this.row.id, |
| | | this.selection, |
| | | "æ°æ®å¤çä¸" |
| | | ) |
| | | .then((x) => { |
| | | if (!x.status) return this.$message.error(x.message); |
| | | this.$message.success("æä½æå"); |
| | | this.showDetialBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.getData(); |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // æ¸
ç©ºéæ© |
| | | clearSelection() { |
| | | if (this.$refs.singleTable) { |
| | | outbound() { |
| | | if (this.selection.length <= 0) { |
| | | return this.$message.error("请å¾é"); |
| | | } |
| | | let url = this.pkcx |
| | | ? "api/Task/GenerateOutboundTask?orderDetailId=" |
| | | : "api/Task/GenerateOutboundTask?orderDetailId="; |
| | | this.http |
| | | .post(url + this.row.id, this.selection, "æ°æ®å¤çä¸") |
| | | .then((x) => { |
| | | if (!x.status) return this.$message.error(x.message); |
| | | this.$message.success("æä½æå"); |
| | | this.showDetialBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.getData(); |
| | | }); |
| | | }); |
| | | }, |
| | | getData(a) { |
| | | if (!a) this.pkcx = !this.pkcx; |
| | | let url = this.pkcx |
| | | ? "api/StockInfo/GetStockSelectViews?materielCode=" |
| | | : "api/StockInfo/GetStockSelectViews?materielCode="; |
| | | this.kcname = this.pkcx ? "ç«åºåºå" : "å¹³åºåºå"; |
| | | this.http |
| | | .post( |
| | | url + this.row.materielCode + "&orderId=" + this.row.orderId, |
| | | null, |
| | | "æ¥è¯¢ä¸" |
| | | ) |
| | | .then((x) => { |
| | | this.tableData = x; |
| | | }); |
| | | }, |
| | | revokeAssign() { |
| | | console.log(this.row); |
| | | this.http |
| | | .post( |
| | | "api/OutboundOrderDetail/RevokeLockOutboundStock?id=" + this.row.id, |
| | | null, |
| | | "æ°æ®å¤çä¸" |
| | | ) |
| | | .then((x) => { |
| | | if (!x.status) return this.$message.error(x.message); |
| | | this.$message.success("æä½æå"); |
| | | this.showDetialBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.getData(); |
| | | }); |
| | | }); |
| | | }, |
| | | handleSelectionChange(val) { |
| | | this.selection = val; |
| | | this.selectionSum = |
| | | val.reduce( |
| | | (accumulator, currentValue) => |
| | | accumulator + currentValue["useableQuantity"], |
| | | 0 |
| | | ) + this.originalQuantity; |
| | | if (this.selectionSum == this.row.orderQuantity) { |
| | | this.selectionClass = "equle-style"; |
| | | } else if (this.selectionSum < this.row.orderQuantity) { |
| | | this.selectionClass = "less-style"; |
| | | } else { |
| | | this.selectionClass = "more-style"; |
| | | } |
| | | }, |
| | | toggleSelection(rows) { |
| | | if (rows) { |
| | | rows.forEach((row) => { |
| | | this.$refs.singleTable.toggleRowSelection(row); |
| | | }); |
| | | } else { |
| | | this.$refs.singleTable.clearSelection(); |
| | | } |
| | | }, |
| | | |
| | | // è¡ç¹å»äºä»¶ |
| | | clearSelection() { |
| | | this.$refs.singleTable.clearSelection(); |
| | | }, |
| | | handleRowClick(row) { |
| | | this.$refs.singleTable.toggleRowSelection(row); |
| | | }, |
| | | |
| | | // 徿 æé®ç¹å»å 使¹æ³ï¼å¯æ ¹æ®éæ±æ©å±ï¼ |
| | | tableButtonClick(row, item) { |
| | | console.log("徿 æé®ç¹å»ï¼", item.title, row); |
| | | }, |
| | | |
| | | // çéè¡¨æ ¼æ°æ® |
| | | filterTable() { |
| | | if (!this.originalTableData.length) return; |
| | | |
| | | // è§£æçéæ¡ä»¶å¹¶è½¬ä¸ºå°åï¼å¿½ç¥å¤§å°åï¼ |
| | | const { materielCode, barcode, palletCode, locationCode } = this.filterForm; |
| | | const mc = materielCode.toLowerCase().trim(); |
| | | const bc = barcode.toLowerCase().trim(); |
| | | const pc = palletCode.toLowerCase().trim(); |
| | | const lc = locationCode.toLowerCase().trim(); |
| | | |
| | | // 模ç³çéé»è¾ |
| | | this.tableData = this.originalTableData.filter(item => { |
| | | // æ¯ä¸ªå段é½å空å¼å¤çåå°å转æ¢ï¼æ¯ææ¨¡ç³å¹é
|
| | | const itemMc = (item.materielCode || "").toLowerCase(); |
| | | const itemBc = (item.barcode || "").toLowerCase(); |
| | | const itemPc = (item.palletCode || "").toLowerCase(); |
| | | const itemLc = (item.locationCode || "").toLowerCase(); |
| | | |
| | | return ( |
| | | itemMc.includes(mc) && |
| | | itemBc.includes(bc) && |
| | | itemPc.includes(pc) && |
| | | itemLc.includes(lc) |
| | | ); |
| | | }); |
| | | |
| | | // çé忏
ç©ºéæ©ç¶æ |
| | | this.clearSelection(); |
| | | this.selectionSum = 0; |
| | | this.updateSelectionClass(); |
| | | }, |
| | | |
| | | // éç½®ç鿡件 |
| | | resetFilter() { |
| | | this.filterForm = { |
| | | materielCode: "", |
| | | barcode: "", |
| | | palletCode: "", |
| | | locationCode: "" |
| | | }; |
| | | // æ¢å¤åå§æ°æ® |
| | | this.tableData = [...this.originalTableData]; |
| | | // éç½®éæ©ç¶æ |
| | | this.clearSelection(); |
| | | this.selectionSum = 0; |
| | | this.updateSelectionClass(); |
| | | } |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .less-style { |
| | | color: black; |
| | |
| | | |
| | | .more-style { |
| | | color: red; |
| | | } |
| | | |
| | | /* çéåºåæ ·å¼ä¼å */ |
| | | .filter-area :deep(.el-form-item) { |
| | | margin-bottom: 0; |
| | | margin-right: 10px; |
| | | } |
| | | </style> |
| | | |
| | |
| | | |
| | | .box-table .el-table tbody tr:hover > td { |
| | | background-color: #d8e0d4 !important; |
| | | /* color: #ffffff; */ |
| | | } |
| | | |
| | | .box-table .el-table tbody tr.current-row > td { |
| | | background-color: #f0f9eb !important; |
| | | /* color: #ffffff; */ |
| | | } |
| | | |
| | | .el-table .success-row { |
| | |
| | | <div class="box-table" style="margin-top: 1%"> |
| | | <el-table |
| | | ref="singleTable" |
| | | :data="groupedTableData" |
| | | :data="tableData" |
| | | style="width: 100%; height: 100%" |
| | | highlight-current-row |
| | | @current-change="handleCurrentChange" |
| | |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="materielCode" |
| | | label="ç©æç¼å·" |
| | | width="120" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="materielName" |
| | | label="ç©æåç§°" |
| | | width="150" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="batchNo" |
| | | label="æ¹æ¬¡å·" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="supplyCode" |
| | | label="ä¾åºåç¼å·" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="orderQuantity" |
| | | label="åæ®æ°é" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="lockQuantity" |
| | | label="é宿°é" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="overOutQuantity" |
| | | label="å·²åºæ°é" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="moveQty" |
| | | label="æªææ°é" |
| | | width="90" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="unit" |
| | | label="åä½" |
| | | width="80" |
| | | align="center" |
| | | ></el-table-column> |
| | | <el-table-column |
| | | prop="orderDetailStatus" |
| | | label="订åæç»ç¶æ" |
| | | width="90" |
| | | v-for="(item, index) in tableColumns.filter((x) => !x.hidden)" |
| | | :key="index" |
| | | :prop="item.prop" |
| | | :label="item.title" |
| | | :width="item.width" |
| | | align="center" |
| | | > |
| | | <template #default="scoped"> |
| | | <el-tag size="small"> |
| | | {{ getDictionaryForGroup(scoped.row) }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | prop="assignStock" |
| | | label="æå®åºå" |
| | | width="90" |
| | | align="center" |
| | | :hidden="mainBusinessType !== '22'" |
| | | > |
| | | <template #default="scoped"> |
| | | <el-tooltip |
| | | class="item" |
| | | effect="dark" |
| | | content="æå®åºå" |
| | | placement="bottom" |
| | | > |
| | | <el-link |
| | | type="primary" |
| | | :disabled="getButtonEnable('assignStock', scoped.row)" |
| | | @click="handleAssignStock(scoped.row)" |
| | | <div v-if="item.type == 'icon'"> |
| | | <el-tooltip |
| | | class="item" |
| | | effect="dark" |
| | | :content="item.title" |
| | | placement="bottom" |
| | | > |
| | | <i class="el-icon-s-grid" style="font-size: 22px"></i> |
| | | </el-link> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | prop="viewDetail" |
| | | label="åºåºè¯¦ç»" |
| | | width="90" |
| | | align="center" |
| | | > |
| | | <template #default="scoped"> |
| | | <el-tooltip |
| | | class="item" |
| | | effect="dark" |
| | | content="æ¥çåºåºè¯¦ç»" |
| | | placement="bottom" |
| | | > |
| | | <el-link |
| | | type="primary" |
| | | @click="handleViewDetail(scoped.row)" |
| | | > |
| | | <i class="el-icon-s-operation" style="font-size: 22px"></i> |
| | | </el-link> |
| | | </el-tooltip> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | prop="detailCount" |
| | | label="æç»æ°é" |
| | | width="80" |
| | | align="center" |
| | | > |
| | | <template #default="scoped"> |
| | | <el-tag type="info" size="small"> |
| | | {{ scoped.row.detailCount }} |
| | | </el-tag> |
| | | <el-link |
| | | type="primary" |
| | | :disabled="getButtonEnable(item.prop, scoped.row)" |
| | | @click="tableButtonClick(scoped.row, item)" |
| | | > |
| | | <i :class="item.icon" style="font-size: 22px"></i> |
| | | </el-link> |
| | | </el-tooltip> |
| | | </div> |
| | | <div v-else-if="item.type == 'tag'"> |
| | | <el-tag size="small"> |
| | | {{ getDictionary(scoped.row, item) }} |
| | | </el-tag> |
| | | </div> |
| | | <div v-else> |
| | | {{ scoped.row[item.prop] }} |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | import StockSelect from "./StockSelect.vue"; |
| | | import SelectedStock from "./SelectedStock.vue"; |
| | | import NoStockOut from "./NoStockOut.vue"; |
| | | import { stationManager, STATION_STORAGE_KEY } from "@/../src/uitils/stationManager"; |
| | | import { h, createVNode, render, reactive } from "vue"; |
| | | import { |
| | | ElDialog, |
| | |
| | | flag: false, |
| | | currentRow: null, |
| | | selection: [], |
| | | tableData: [], // åå§æ°æ® |
| | | groupedTableData: [], // åç»åçæ°æ® |
| | | mainBusinessType: null, // åå¨ä¸»åæ®çbusinessType |
| | | tableData: [], |
| | | mainBusinessType: null, // æ°å¢ï¼åå¨ä¸»åæ®çbusinessType |
| | | tableColumns: [ |
| | | { |
| | | prop: "id", |
| | | title: "Id", |
| | | type: "int", |
| | | width: 90, |
| | | hidden: true, |
| | | }, |
| | | { |
| | | prop: "orderId", |
| | | title: "åºåºå主é®", |
| | | type: "string", |
| | | width: 90, |
| | | hidden: true, |
| | | }, |
| | | { |
| | | prop: "materielCode", |
| | | title: "ç©æç¼å·", |
| | | type: "string", |
| | | width: 120, |
| | | }, |
| | | { |
| | | prop: "materielName", |
| | | title: "ç©æåç§°", |
| | | type: "string", |
| | | width: 150, |
| | | }, |
| | | { |
| | | prop: "batchNo", |
| | | title: "æ¹æ¬¡å·", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "supplyCode", |
| | | title: "ä¾åºåç¼å·", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "orderQuantity", |
| | | title: "åæ®æ°é", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "lockQuantity", |
| | | title: "é宿°é", |
| | | type: "int", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "overOutQuantity", |
| | | title: "å·²åºæ°é", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "moveQty", |
| | | title: "æªææ°é", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "unit", |
| | | title: "åä½", |
| | | type: "string", |
| | | width: 80, |
| | | }, |
| | | { |
| | | prop: "orderDetailStatus", |
| | | title: "订åæç»ç¶æ", |
| | | type: "tag", |
| | | width: 90, |
| | | bindKey: "orderDetailStatusEnum", |
| | | }, |
| | | { |
| | | prop: "assignStock", |
| | | title: "æå®åºå", |
| | | type: "icon", |
| | | width: 90, |
| | | hidden: true, // é»è®¤éè |
| | | icon: "el-icon-s-grid", |
| | | }, |
| | | { |
| | | prop: "viewDetail", |
| | | title: "åºåºè¯¦ç»", |
| | | type: "icon", |
| | | width: 90, |
| | | icon: "el-icon-s-operation", |
| | | }, |
| | | { |
| | | prop: "creater", |
| | | title: "å建人", |
| | | type: "string", |
| | | width: 90, |
| | | }, |
| | | { |
| | | prop: "createDate", |
| | | title: "å建æ¶é´", |
| | | type: "datetime", |
| | | width: 160, |
| | | }, |
| | | { |
| | | prop: "modifier", |
| | | title: "ä¿®æ¹äºº", |
| | | type: "string", |
| | | width: 100, |
| | | }, |
| | | { |
| | | prop: "modifyDate", |
| | | title: "ä¿®æ¹æ¶é´", |
| | | type: "datetime", |
| | | width: 160, |
| | | }, |
| | | { |
| | | prop: "remark", |
| | | title: "夿³¨", |
| | | type: "string", |
| | | }, |
| | | ], |
| | | paginations: { |
| | | sort: "id", |
| | | order: "desc", |
| | |
| | | dictionaryList: null, |
| | | }; |
| | | }, |
| | | onMounted() { |
| | | // 仿¬å°åå¨å è½½ä¿åçç«å°å¼ |
| | | const savedStation = stationManager.getStation(); |
| | | console.log(savedStation); |
| | | if (savedStation) { |
| | | outboundForm.selectedPlatform = savedStation; |
| | | } else if (stationOptions.length > 0) { |
| | | // å¦ææ²¡æä¿åçå¼ï¼ä½¿ç¨ç¬¬ä¸ä¸ªé项 |
| | | //stationValue.value = stationOptions[0].value; |
| | | methods: { |
| | | toggleAssignStockColumn() { |
| | | const assignStockColumn = this.tableColumns.find( |
| | | (item) => item.prop === "assignStock" |
| | | ); |
| | | if (assignStockColumn) { |
| | | // businessType为22æ¶æ¾ç¤ºï¼å¦åéè |
| | | assignStockColumn.hidden = this.mainBusinessType !=='22'; |
| | | } |
| | | }, |
| | | methods: { |
| | | // æ ¹æ®ç©æç¼å·ãæ¹æ¬¡ãä¾åºååç»æ°æ® |
| | | groupDataByMaterial() { |
| | | const groups = {}; |
| | | |
| | | this.tableData.forEach(item => { |
| | | // æå»ºåç»é®ï¼æ¹æ¬¡åä¾åºåå¯ä»¥ä¸ºç©º |
| | | const groupKey = `${item.materielCode}_${item.batchNo || ''}_${item.supplyCode || ''}`; |
| | | |
| | | if (!groups[groupKey]) { |
| | | // å建æ°åç» |
| | | groups[groupKey] = { |
| | | materielCode: item.materielCode, |
| | | materielName: item.materielName, |
| | | batchNo: item.batchNo || '-', |
| | | supplyCode: item.supplyCode || '-', |
| | | orderQuantity: 0, |
| | | lockQuantity: 0, |
| | | overOutQuantity: 0, |
| | | moveQty: 0, |
| | | unit: item.unit, |
| | | orderDetailStatus: item.orderDetailStatus, |
| | | detailCount: 0, |
| | | originalDetails: [] // ä¿ååå§æç»æ°æ® |
| | | }; |
| | | } |
| | | |
| | | // ç´¯å æ°é |
| | | groups[groupKey].orderQuantity += item.orderQuantity || 0; |
| | | groups[groupKey].lockQuantity += item.lockQuantity || 0; |
| | | groups[groupKey].overOutQuantity += item.overOutQuantity || 0; |
| | | groups[groupKey].moveQty += item.moveQty || 0; |
| | | groups[groupKey].detailCount += 1; |
| | | groups[groupKey].originalDetails.push(item); |
| | | |
| | | // å¦æç¶æä¸åï¼å¯ä»¥ç¨ç¬¬ä¸ä¸ªç¶ææç¹æ®å¤ç |
| | | // è¿é使ç¨ç¬¬ä¸ä¸ªæç»çç¶æ |
| | | }); |
| | | |
| | | // 转æ¢ä¸ºæ°ç» |
| | | this.groupedTableData = Object.values(groups); |
| | | |
| | | console.log('åç»åçæ°æ®:', this.groupedTableData); |
| | | }, |
| | | |
| | | open(row) { |
| | | this.row = row; |
| | | this.showDetialBox = true; |
| | |
| | | this.mainBusinessType = row.businessType; |
| | | this.getDictionaryData(); |
| | | this.getData(); |
| | | this.toggleAssignStockColumn(); |
| | | }, |
| | | |
| | | getData() { |
| | | var wheres = [{ name: "orderId", value: this.row.id }]; |
| | | var param = { |
| | |
| | | .post("api/OutboundOrderDetail/GetPageData", param, "æ¥è¯¢ä¸") |
| | | .then((x) => { |
| | | this.tableData = x.rows; |
| | | // åç»æ°æ® |
| | | this.groupDataByMaterial(); |
| | | this.toggleAssignStockColumn(); // æ°æ®å è½½åéæ°ç¡®è®¤åæ¾é |
| | | }); |
| | | }, |
| | | |
| | | // éç¹ä¿®æ¹ï¼å¤çæå®åºåç¹å»äºä»¶ - ä¼ é宿´çåç»æç»ä¿¡æ¯ |
| | | handleAssignStock(row) { |
| | | // ä¼ é宿´çåç»æç»æ°æ®ï¼å
嫿æåå§æç»IDåç©æä¿¡æ¯ï¼ |
| | | if (row.originalDetails && row.originalDetails.length > 0) { |
| | | this.$refs.child.open({ |
| | | // ç©æåºæ¬ä¿¡æ¯ï¼å第ä¸ä¸ªæç»çä¿¡æ¯ï¼ |
| | | materielCode: row.originalDetails[0].materielCode, |
| | | materielName: row.originalDetails[0].materielName, |
| | | // åç»åçæ»éæ±æ°é |
| | | qty: row.orderQuantity, |
| | | // 䏻忮ç¼å· |
| | | upperOrderNo: this.row.upperOrderNo, |
| | | // å
³é®ï¼å½ååç»çæææç»IDéå |
| | | detailIds: row.originalDetails.map(detail => detail.id), |
| | | // 䏻忮ID |
| | | mainOrderId: this.row.id, |
| | | // 宿´åç»è¡ä¿¡æ¯ï¼å¤ç¨ï¼ |
| | | groupRow: row |
| | | }); |
| | | tableButtonClick(row, column) { |
| | | if (column.prop == "assignStock") { |
| | | this.$refs.child.open(row); |
| | | } else if (column.prop == "NoStockOut") { |
| | | this.$refs.NoStockOut.open(row); |
| | | } else { |
| | | ElMessage.warning("该åç»æ²¡ææç»æ°æ®ï¼æ æ³æå®åºå"); |
| | | this.$refs.selectedStock.open(row); |
| | | } |
| | | }, |
| | | |
| | | handleViewDetail(row) { |
| | | // æ¥çåç»æç»ç详ç»ä¿¡æ¯ |
| | | if (row.originalDetails && row.originalDetails.length > 0) { |
| | | // è¿éå¯ä»¥æå¼ä¸ä¸ªæ°çå¼¹çªæ¾ç¤ºæææç»ï¼æè
使ç¨ç¬¬ä¸ä¸ªæç» |
| | | this.$refs.selectedStock.open(row.originalDetails[0]); |
| | | } |
| | | }, |
| | | |
| | | lockstocks() { |
| | | if (this.selection.length === 0) { |
| | | return this.$message.error("è¯·éæ©åæ®æç»"); |
| | | } |
| | | |
| | | // è·åææéä¸åç»çåå§æç»ID |
| | | const detailIds = []; |
| | | this.selection.forEach(group => { |
| | | if (group.originalDetails && group.originalDetails.length > 0) { |
| | | group.originalDetails.forEach(detail => { |
| | | if (detail.id) { |
| | | detailIds.push(detail.id); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | if (detailIds.length === 0) { |
| | | return this.$message.error("æ²¡ææ¾å°å¯éå®çæç»"); |
| | | } |
| | | |
| | | var keys = this.selection.map((item) => item.id); |
| | | this.http |
| | | .post("api/OutboundOrderDetail/LockOutboundStocks", detailIds, "æ°æ®å¤çä¸") |
| | | .post("api/OutboundOrderDetail/LockOutboundStocks", keys, "æ°æ®å¤çä¸") |
| | | .then((x) => { |
| | | if (!x.status) return this.$message.error(x.message); |
| | | this.$message.success("æä½æå"); |
| | |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | handleOpenPicking() { |
| | | this.$router.push({ |
| | | path: "/outbound/picking", |
| | | query: { orderId: this.row.id, orderNo: this.row.orderNo }, |
| | | }); |
| | | }, |
| | | |
| | | handleOpenBatchPicking() { |
| | | this.$router.push({ |
| | | path: "/outbound/batchpicking", |
| | | query: { orderId: this.row.id, orderNo: this.row.orderNo }, |
| | | }); |
| | | }, |
| | | |
| | | outbound() { |
| | | const savedStation = stationManager.getStation(); |
| | | console.log(savedStation); |
| | | if (this.selection.length === 0) { |
| | | return this.$message.error("è¯·éæ©åæ®æç»"); |
| | | } |
| | | |
| | | // è·åææéä¸åç»çåå§æç»ID |
| | | const detailIds = []; |
| | | this.selection.forEach(group => { |
| | | if (group.originalDetails && group.originalDetails.length > 0) { |
| | | group.originalDetails.forEach(detail => { |
| | | if (detail.id) { |
| | | detailIds.push(detail.id); |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | |
| | | if (detailIds.length === 0) { |
| | | return this.$message.error("æ²¡ææ¾å°å¯åºåºçæç»"); |
| | | } |
| | | |
| | | const platformOptions = [ |
| | | { label: "ç«å°2", value: "2-1" }, |
| | | { label: "ç«å°3", value: "3-1" }, |
| | |
| | | selectedPlatform: platformOptions[0].value, |
| | | }); |
| | | |
| | | if (savedStation) { |
| | | formData.selectedPlatform = savedStation; |
| | | } |
| | | const vnode = createVNode( |
| | | ElDialog, |
| | | { |
| | |
| | | }, |
| | | }, [ |
| | | h(ElSelect, { |
| | | placeholder: "è¯·éæ©åºåºç«å°", |
| | | placeholder: "è¯·éæ©åºåºç«å°ï¼3-12ï¼", |
| | | modelValue: formData.selectedPlatform, |
| | | "onUpdate:modelValue": (val) => { |
| | | formData.selectedPlatform = val; |
| | |
| | | return; |
| | | } |
| | | |
| | | const keys = this.selection.map((item) => item.id); |
| | | const requestParams = { |
| | | taskIds: detailIds, |
| | | taskIds: keys, |
| | | outboundPlatform: formData.selectedPlatform, |
| | | }; |
| | | |
| | |
| | | vnode.appContext = this.$.appContext; |
| | | render(vnode, mountNode); |
| | | }, |
| | | |
| | | outboundbatch() { |
| | | const savedStation = stationManager.getStation(); |
| | | console.log(savedStation); |
| | | if (this.selection.length === 0) { |
| | | return this.$message.error("è¯·éæ©åæ®æç»"); |
| | | } |
| | | if (this.selection.length > 1) { |
| | | return this.$message.error("åªè½éæ©ä¸æ¡åæ®æç»è¿è¡åæ¹åºåº"); |
| | | } |
| | | |
| | | const selectedGroup = this.selection[0]; |
| | | if (!selectedGroup.originalDetails || selectedGroup.originalDetails.length === 0) { |
| | | return this.$message.error("æ²¡ææ¾å°æç»æ°æ®"); |
| | | } |
| | | |
| | | // åæ¹åºåºé常é对å个æç» |
| | | // è¿é使ç¨ç¬¬ä¸ä¸ªæç» |
| | | const selectedDetail = selectedGroup.originalDetails[0]; |
| | | |
| | | const platformOptions = [ |
| | | { label: "ç«å°2", value: "2-1" }, |
| | | { label: "ç«å°3", value: "3-1" }, |
| | |
| | | selectedPlatform: platformOptions[0].value, |
| | | outboundDecimal: "", |
| | | }); |
| | | if (savedStation) { |
| | | formData.selectedPlatform = savedStation; |
| | | } |
| | | |
| | | const vnode = createVNode( |
| | | ElDialog, |
| | | { |
| | |
| | | }, |
| | | }, [ |
| | | h(ElSelect, { |
| | | placeholder: "è¯·éæ©åºåºç«å°", |
| | | placeholder: "è¯·éæ©åºåºç«å°ï¼3-12ï¼", |
| | | modelValue: formData.selectedPlatform, |
| | | "onUpdate:modelValue": (val) => { |
| | | formData.selectedPlatform = val; |
| | |
| | | step: "0.01", |
| | | precision: 2, |
| | | min: 0.01, |
| | | max: selectedDetail.orderQuantity - selectedDetail.overOutQuantity - selectedDetail.lockQuantity - selectedDetail.moveQty, |
| | | }), |
| | | ]), |
| | | h("div", { |
| | |
| | | return; |
| | | } |
| | | |
| | | const keys = this.selection.map((item) => item.id); |
| | | const requestParams = { |
| | | orderDetailId: selectedDetail.id, |
| | | orderDetailId: keys[0], |
| | | outboundPlatform: formData.selectedPlatform, |
| | | batchQuantity: formData.outboundDecimal, |
| | | }; |
| | |
| | | } |
| | | ); |
| | | |
| | | vnode.appContext = this.$appContext; |
| | | vnode.appContext = this.$.appContext; |
| | | render(vnode, mountNode); |
| | | }, |
| | | |
| | | setCurrent(row) { |
| | | this.$refs.singleTable.setCurrentRow(row); |
| | | }, |
| | | |
| | | handleCurrentChange(val) { |
| | | this.currentRow = val; |
| | | }, |
| | | |
| | | getButtonEnable(propName, row) { |
| | | if (propName == "assignStock") { |
| | | if ( |
| | | row.orderDetailStatus !== 0 && |
| | | row.orderDetailStatus !== 70 |
| | | row.orderDetailStatus !== 60 && |
| | | row.orderDetailStatus !== 70 && |
| | | row.orderDetailStatus !== 80 |
| | | ) { |
| | | return false; |
| | | } else { |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | return false; |
| | | }, |
| | | |
| | | parentCall(fun) { |
| | | if (typeof fun != "function") { |
| | | return console.log("æ©å±ç»ä»¶éè¦ä¼ å
¥ä¸ä¸ªåè°æ¹æ³æè½è·åç¶çº§Vue对象"); |
| | | } |
| | | fun(this); |
| | | }, |
| | | |
| | | handleRowClick(row) { |
| | | this.$refs.singleTable.toggleRowSelection(row); |
| | | }, |
| | | |
| | | handleSelectionChange(val) { |
| | | this.selection = val; |
| | | }, |
| | | |
| | | getDictionaryData() { |
| | | if (this.dictionaryList) { |
| | | return; |
| | | } |
| | | var param = ["orderDetailStatusEnum"]; |
| | | var param = []; |
| | | this.tableColumns.forEach((x) => { |
| | | if (x.type == "tag" && x.bindKey != "") { |
| | | param.push(x.bindKey); |
| | | } |
| | | }); |
| | | this.http |
| | | .post("api/Sys_Dictionary/GetVueDictionary", param, "æ¥è¯¢ä¸") |
| | | .then((x) => { |
| | |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | getDictionaryForGroup(row) { |
| | | getDictionary(row, column) { |
| | | if (this.dictionaryList) { |
| | | var item = this.dictionaryList.find((x) => x.dicNo == "orderDetailStatusEnum"); |
| | | var item = this.dictionaryList.find((x) => x.dicNo == column.bindKey); |
| | | if (item) { |
| | | var dicItem = item.data.find((x) => x.key == row.orderDetailStatus); |
| | | var dicItem = item.data.find((x) => x.key == row[column.prop]); |
| | | if (dicItem) { |
| | | return dicItem.value; |
| | | } else { |
| | | return row.orderDetailStatus; |
| | | return row[column.prop]; |
| | | } |
| | | } else { |
| | | return row.orderDetailStatus; |
| | | return row[column.prop]; |
| | | } |
| | | } |
| | | return row.orderDetailStatus; |
| | | return row[column.prop]; |
| | | }, |
| | | }, |
| | | }; |
| | |
| | | path:'/printForm', |
| | | name: 'printForm', |
| | | component: () => import('@/views/outbound/printForm.vue') |
| | | }, |
| | | },{ |
| | | path: '/Log', |
| | | name: 'Log', |
| | | component: () => import('@/views/system/Log.vue'), |
| | | meta: { |
| | | } |
| | | } |
| | | ] |
| | | |
| | | export default viewgird |
| | |
| | | [ |
| | | { title: "è´§ä½ç¼å·", field: "locationCode", type: "like" }, |
| | | { title: "å··éç¼å·", field: "roadwayNo",type:"like" }, |
| | | { title: "è´§ä½ç±»å", field: "locationType",type: "select",dataKey: "locationTypeEnum",data: [], }, |
| | | { title: "è´§ä½åºå", field: "locationType",type: "select",dataKey: "locationTypeEnum",data: [], }, |
| | | { title: "ç¦ç¨ç¶æ", field: "enableStatus" ,type: "select",dataKey: "enableStatusEnum",data: [],}, |
| | | ], |
| | | [ |
| | |
| | | }, |
| | | { |
| | | field: "locationType", |
| | | title: "è´§ä½ç±»å", |
| | | title: "è´§ä½åºå", |
| | | type: "string", |
| | | width: 120, |
| | | align: "left", |
| | |
| | | }); |
| | | const searchFormOptions = ref([ |
| | | [ |
| | | { title: "æ«æåæ®ç¼å·ææ¡ç ", field: "inboundOrderNo", type: "like" }, |
| | | { title: "æ«æåæ®ææ¡ç ", field: "inboundOrderNo", type: "like" }, |
| | | { title: "䏿¸¸åæ®ç¼å·", field: "upperOrderNo", type: "like" }, |
| | | { |
| | | title: "ä¸å¡ç±»å", |
| | |
| | | }, |
| | | { |
| | | field: "locationType", |
| | | title: "è´§ä½ç±»å", |
| | | title: "è´§ä½åºå", |
| | | type: "string", |
| | | width: 140, |
| | | align: "left", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="tree-container"> |
| | | <el-input placeholder="è¾å
¥å
³é®åè¿è¡è¿æ»¤" v-model="filterText" class="filter-input"> |
| | | </el-input> |
| | | <div class="custom-tree-wrapper"> |
| | | <el-tree ref="tree" class="filter-tree" :filter-node-method="filterNode" :data="data" node-key="id" accordion> |
| | | <template #default="{ node, data }"> |
| | | <div class="custom-tree-node"> |
| | | <span class="node-label">{{ node.label }}</span> |
| | | <span v-if="data.hidden" class="node-actions"> |
| | | <el-button type="text" size="mini" @click="() => view(data)" class="action-btn"> |
| | | æ¥ç |
| | | </el-button> |
| | | <el-button type="text" size="mini" @click="() => dowmload(node, data)" class="action-btn"> |
| | | ä¸è½½ |
| | | </el-button> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </el-tree> |
| | | </div> |
| | | </div> |
| | | <div class="log-container"> |
| | | <el-card shadow="always" v-if="logName" class="log-card"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <el-tag type="info" size="small">æ¥å¿æä»¶</el-tag> |
| | | <span class="log-title">{{ logName }}</span> |
| | | </div> |
| | | </template> |
| | | <div class="log-content"> |
| | | <div v-for="(item, index) in log" :key="index" class="log-line"> |
| | | <span class="line-number">{{ index + 1 }}</span> |
| | | <span class="line-content">{{ item }}</span> |
| | | </div> |
| | | </div> |
| | | </el-card> |
| | | <div v-else class="empty-log"> |
| | | <el-empty description="è¯·éæ©æ¥å¿æä»¶è¿è¡æ¥ç" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | data() { |
| | | return { |
| | | data: [], |
| | | defaultProps: { |
| | | children: "children", |
| | | label: "label", |
| | | }, |
| | | filterText: "", |
| | | logName: "", |
| | | log: [], |
| | | }; |
| | | }, |
| | | watch: { |
| | | filterText(val) { |
| | | this.$refs.tree.filter(val); |
| | | }, |
| | | }, |
| | | created() { |
| | | this.getLogName(); |
| | | }, |
| | | |
| | | methods: { |
| | | filterNode(value, data) { |
| | | if (!value) return true; |
| | | return data.label.indexOf(value) !== -1; |
| | | }, |
| | | getLogName() { |
| | | this.http |
| | | .post("/api/Sys_Log/GetLogName", null, "æ£å¨æ§è¡ä¸...") |
| | | .then((x) => { |
| | | if (x.status) { |
| | | this.data = x.data; |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | view(data) { |
| | | // var params = { |
| | | // MainData: { fileName: data.label }, |
| | | // }; |
| | | this.http |
| | | .post("/api/Sys_Log/GetLog?fileName=" + data.label, "æ£å¨æ¥è¯¢ä¸...") |
| | | .then((x) => { |
| | | if (x.status) { |
| | | this.logName = data.label; |
| | | this.log = x.data; |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | dowmload(node, data) { |
| | | let ipAddress = this.http.ipAddress; |
| | | let url = |
| | | "api/Sys_Log/DownLoadLog?fileName=" + |
| | | data.fatherNode + |
| | | "\\" + |
| | | data.label; |
| | | let fileName = data.label; |
| | | let xmlResquest = new XMLHttpRequest(); |
| | | xmlResquest.open("GET", ipAddress + url, true); |
| | | xmlResquest.setRequestHeader("Content-type", "application/json"); |
| | | xmlResquest.setRequestHeader( |
| | | "Authorization", |
| | | this.$store.getters.getToken() |
| | | ); |
| | | let elink = this.$refs.template; |
| | | xmlResquest.responseType = "blob"; |
| | | let $_vue = this; |
| | | this.loadingStatus = true; |
| | | xmlResquest.onload = function (e) { |
| | | // è¯·æ±æå |
| | | if (this.status == 200) { |
| | | let blob = this.response; |
| | | let a = document.createElement("a"); |
| | | //window.URL.createObjectURL() éææ¹æ³ä¼å建ä¸ä¸ª DOMStringï¼å
¶ä¸å
å«ä¸ä¸ªè¡¨ç¤ºåæ°ä¸ç»åºç对象çURLãè¿ä¸ª URL ççå½å¨æåå建å®ççªå£ä¸ç document ç»å®ãè¿ä¸ªæ°çURL 对象表示æå®ç File 对象æ Blob 对象ã |
| | | let url = window.URL.createObjectURL(blob); |
| | | a.href = url; |
| | | a.download = fileName; |
| | | a.click(); |
| | | //URL.revokeObjectURL() éææ¹æ³ç¨æ¥éæ¾ä¸ä¸ªä¹åå·²ç»åå¨çãéè¿è°ç¨ URL.createObjectURL() å建ç URL 对象ãå½ä½ ç»æä½¿ç¨æä¸ª URL 对象ä¹åï¼åºè¯¥éè¿è°ç¨è¿ä¸ªæ¹æ³æ¥è®©æµè§å¨ç¥éä¸ç¨å¨å
åä¸ç»§ç»ä¿ç对è¿ä¸ªæä»¶çå¼ç¨äºã |
| | | window.URL.revokeObjectURL(url); |
| | | |
| | | } else { |
| | | //ä¸è½½å¤±è´¥å¤ç |
| | | |
| | | } |
| | | }; |
| | | xmlResquest.send(); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .tree-container { |
| | | width: 30%; |
| | | float: left; |
| | | padding: 16px; |
| | | background: #f8f9fa; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .filter-input { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .filter-input :deep(.el-input__inner) { |
| | | border-radius: 20px; |
| | | border-color: #dcdfe6; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .filter-input :deep(.el-input__inner):focus { |
| | | border-color: #409eff; |
| | | box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.1); |
| | | } |
| | | |
| | | .custom-tree-wrapper { |
| | | height: 760px; |
| | | overflow-y: auto; |
| | | padding: 8px; |
| | | background: white; |
| | | border-radius: 6px; |
| | | border: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .filter-tree :deep(.el-tree-node__content) { |
| | | height: 40px; |
| | | margin: 2px 0; |
| | | border-radius: 4px; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .filter-tree :deep(.el-tree-node__content:hover) { |
| | | background-color: #f0f9ff; |
| | | } |
| | | |
| | | .filter-tree :deep(.el-tree-node.is-current > .el-tree-node__content) { |
| | | background-color: #ecf5ff; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .custom-tree-node { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | width: 100%; |
| | | padding: 0 8px; |
| | | } |
| | | |
| | | .node-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .node-actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | margin-left: 12px; |
| | | } |
| | | |
| | | .action-btn { |
| | | padding: 4px 8px; |
| | | font-size: 12px; |
| | | color: #409eff; |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | .action-btn:hover { |
| | | background-color: rgba(64, 158, 255, 0.1); |
| | | } |
| | | |
| | | .log-container { |
| | | width: 68%; |
| | | float: right; |
| | | padding: 16px; |
| | | } |
| | | |
| | | .log-card { |
| | | height: 800px; |
| | | border-radius: 8px; |
| | | border: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .log-card :deep(.el-card__header) { |
| | | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | | border-bottom: 1px solid #ebeef5; |
| | | padding: 16px 20px; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .log-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: white; |
| | | flex: 1; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .log-content { |
| | | height: 700px; |
| | | overflow-y: auto; |
| | | font-family: 'Consolas', 'Monaco', 'Courier New', monospace; |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .log-line { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | margin-bottom: 4px; |
| | | line-height: 1.5; |
| | | background: white; |
| | | padding: 8px 12px; |
| | | border-radius: 4px; |
| | | border-left: 3px solid #409eff; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .log-line:hover { |
| | | background: #f0f9ff; |
| | | transform: translateX(2px); |
| | | } |
| | | |
| | | .line-number { |
| | | display: inline-block; |
| | | min-width: 40px; |
| | | padding-right: 12px; |
| | | text-align: right; |
| | | color: #909399; |
| | | font-size: 12px; |
| | | user-select: none; |
| | | } |
| | | |
| | | .line-content { |
| | | flex: 1; |
| | | color: #303133; |
| | | font-size: 13px; |
| | | word-break: break-all; |
| | | white-space: pre-wrap; |
| | | } |
| | | |
| | | .empty-log { |
| | | height: 800px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background: white; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .empty-log :deep(.el-empty__description) { |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | /* æ»å¨æ¡æ ·å¼ */ |
| | | .custom-tree-wrapper::-webkit-scrollbar, |
| | | .log-content::-webkit-scrollbar { |
| | | width: 6px; |
| | | height: 6px; |
| | | } |
| | | |
| | | .custom-tree-wrapper::-webkit-scrollbar-track, |
| | | .log-content::-webkit-scrollbar-track { |
| | | background: #f1f1f1; |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | .custom-tree-wrapper::-webkit-scrollbar-thumb, |
| | | .log-content::-webkit-scrollbar-thumb { |
| | | background: #c1c1c1; |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | .custom-tree-wrapper::-webkit-scrollbar-thumb:hover, |
| | | .log-content::-webkit-scrollbar-thumb:hover { |
| | | background: #a8a8a8; |
| | | } |
| | | |
| | | /* æ¸
餿µ®å¨ */ |
| | | .tree-container::after, |
| | | .log-container::after { |
| | | content: ""; |
| | | display: table; |
| | | clear: both; |
| | | } |
| | | </style> |
| | |
| | | _logger.LogInformation($"InPickTaskCompleted AddLocationStatusChangeRecord : {ex.Message} "); |
| | | } |
| | | |
| | | _logger.LogInformation($"æçååºå®æå¤çæå - ä»»å¡å·: {task.TaskNum}, æç: {task.PalletCode}, 订å: {task.OrderNo}"); |
| | | _logger.LogInformation($"æçååºå®æå¤çæå - ä»»å¡å·: {task.TaskNum}, æç: {task.PalletCode}, 订å: {task.OrderNo} è´§ä½ç¶æï¼{locationInfo.LocationStatus}"); |
| | | _ = Task.Run(async () => |
| | | { |
| | | try |
| | |
| | | |
| | | allocatefeedmodel.Details.Add(detailModel); |
| | | } |
| | | var groupedResult = allocatefeedmodel.Details.GroupBy(item => new |
| | | { |
| | | item.WarehouseCode, |
| | | item.MaterialCode, |
| | | item.Unit, |
| | | item.LineNo |
| | | }).Select(group => new AllocateDtoDetail |
| | | { |
| | | WarehouseCode = group.Key.WarehouseCode, |
| | | MaterialCode = group.Key.MaterialCode, |
| | | LineNo = group.Key.LineNo, |
| | | Qty = group.Sum(x => x.Qty), |
| | | Unit = group.Key.Unit, |
| | | Barcodes = group.SelectMany(x => x.Barcodes) |
| | | .GroupBy(b => b.Barcode) |
| | | .Select(b => new BarcodeInfo |
| | | { |
| | | Barcode = b.Key, |
| | | BatchNo = b.First().BatchNo, |
| | | SupplyCode = b.First().SupplyCode, |
| | | Qty = b.Max(x => x.Qty), |
| | | Unit = b.First().Unit |
| | | }) .ToList() |
| | | }) .ToList(); |
| | | var groupedResult = allocatefeedmodel.Details |
| | | .GroupBy(item => new { item.WarehouseCode, item.MaterialCode, item.Unit, item.LineNo }) |
| | | .Select(group => |
| | | { |
| | | |
| | | var deduplicatedBarcodes = group.SelectMany(x => x.Barcodes) |
| | | .GroupBy(b => b.Barcode) |
| | | .Select(b => new BarcodeInfo |
| | | { |
| | | Barcode = b.Key, |
| | | BatchNo = b.First().BatchNo, |
| | | SupplyCode = b.First().SupplyCode, |
| | | Qty = b.Max(x => x.Qty), |
| | | Unit = b.First().Unit |
| | | }).ToList(); |
| | | return new AllocateDtoDetail |
| | | { |
| | | WarehouseCode = group.Key.WarehouseCode, |
| | | MaterialCode = group.Key.MaterialCode, |
| | | LineNo = group.Key.LineNo, |
| | | Qty = deduplicatedBarcodes.Sum(b => b.Qty), |
| | | Unit = group.Key.Unit, |
| | | Barcodes = deduplicatedBarcodes |
| | | }; |
| | | }).ToList(); |
| | | |
| | | allocatefeedmodel.Details = groupedResult; |
| | | |
| | | var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel); |
| | | |
| | | var result = await _invokeMESService.FeedbackAllocate(allocatefeedmodel); |
| | | if (result != null && result.code == 200) |
| | | { |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | |
| | | ReturnToMESStatus = 1, |
| | | }).Where(x => x.OrderNo == orderNo).ExecuteCommandAsync(); |
| | | } |
| | | else |
| | | { |
| | | await _outboundOrderDetailService.Db.Updateable<Dt_OutboundOrderDetail>() |
| | | .SetColumns(x => x.ReturnToMESStatus == 2) |
| | | .Where(x => x.OrderId == outboundOrder.Id) |
| | | .ExecuteCommandAsync(); |
| | | |
| | | await _outboundOrderService.Db.Updateable<Dt_OutboundOrder>() |
| | | .SetColumns(it => new Dt_OutboundOrder { ReturnToMESStatus = 2, Remark = result.message }) |
| | | .Where(x => x.OrderNo == orderNo) |
| | | .ExecuteCommandAsync(); |
| | | } |
| | | |
| | | } |
| | | } |
| | | else if (outboundOrder.OrderType == OutOrderTypeEnum.ReCheck.ObjToInt()) |
| | |
| | | } |
| | | feedmodel.details.Add(detailModel); |
| | | } |
| | | var groupedResult = feedmodel.details.GroupBy(item => new |
| | | { |
| | | item.warehouseCode, |
| | | item.materialCode, |
| | | item.unit, |
| | | item.lineNo |
| | | }).Select(group => new FeedbackOutboundDetailsModel |
| | | { |
| | | warehouseCode = group.Key.warehouseCode, |
| | | materialCode = group.Key.materialCode, |
| | | lineNo = group.Key.lineNo, |
| | | qty = group.Sum(x => x.qty), |
| | | unit = group.Key.unit, |
| | | barcodes = group.SelectMany(x => x.barcodes) |
| | | .GroupBy(b => b.barcode) |
| | | .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel |
| | | { |
| | | barcode = b.Key, |
| | | batchNo = b.First().batchNo, |
| | | supplyCode = b.First().supplyCode, |
| | | qty = b.Max(x => x.qty), |
| | | unit = b.First().unit |
| | | }).ToList() |
| | | }).ToList(); |
| | | |
| | | var groupedResult = feedmodel.details |
| | | .GroupBy(item => new { item.warehouseCode, item.materialCode, item.unit, item.lineNo }) |
| | | .Select(group => |
| | | { |
| | | var deduplicatedBarcodes = group.SelectMany(x => x.barcodes) |
| | | .GroupBy(b => b.barcode) |
| | | .Select(b => new WIDESEA_DTO.Outbound.BarcodesModel |
| | | { |
| | | barcode = b.Key, |
| | | batchNo = b.First().batchNo, |
| | | supplyCode = b.First().supplyCode, |
| | | qty = b.Max(x => x.qty), |
| | | unit = b.First().unit |
| | | }).ToList(); |
| | | return new FeedbackOutboundDetailsModel |
| | | { |
| | | warehouseCode = group.Key.warehouseCode, |
| | | materialCode = group.Key.materialCode, |
| | | lineNo = group.Key.lineNo, |
| | | qty = deduplicatedBarcodes.Sum(b => b.qty), |
| | | unit = group.Key.unit, |
| | | barcodes = deduplicatedBarcodes |
| | | }; |
| | | }).ToList(); |
| | | |
| | | feedmodel.details = groupedResult; |
| | | |
| | | var result = await _invokeMESService.FeedbackOutbound(feedmodel); |
| | |
| | | using Microsoft.AspNetCore.Http; |
| | | using Microsoft.AspNetCore.Authorization; |
| | | using Microsoft.AspNetCore.Http; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using System.Text; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseController; |
| | | using WIDESEA_ISystemService; |
| | | using WIDESEA_Model.Models; |
| | |
| | | [ApiController] |
| | | public class Sys_LogController : ApiBaseController<ISys_LogService, Sys_Log> |
| | | { |
| | | // é
置常é |
| | | private const int MAX_FILE_SIZE_MB = 50; |
| | | private const int MAX_RETRY_COUNT = 3; |
| | | private const int RETRY_DELAY_MS = 100; |
| | | private static readonly string[] ALLOWED_FILE_TYPES = { ".txt", ".log", ".csv", ".json", ".xml" }; |
| | | |
| | | public Sys_LogController(ISys_LogService service) : base(service) |
| | | { |
| | | } |
| | | |
| | | [HttpPost, Route("GetLogName"), AllowAnonymous] |
| | | public WebResponseContent GetLogName() |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | List<object> data = new List<object>(); |
| | | DirectoryInfo folder = new DirectoryInfo(AppContext.BaseDirectory + "\\logs\\"); |
| | | DirectoryInfo[] firstDirectoryInfos = folder.GetDirectories().OrderByDescending(x => x.CreationTime).ToArray(); |
| | | int k = 2020; |
| | | for (int i = 0; i < firstDirectoryInfos.Length; i++) |
| | | { |
| | | if (firstDirectoryInfos[i].Name != "Info") |
| | | { |
| | | FileInfo[] nextFileInfos = firstDirectoryInfos[i].GetFiles(); |
| | | List<object> values = new List<object>(); |
| | | for (int j = 0; j < nextFileInfos.Length; j++) |
| | | { |
| | | values.Add(new { label = nextFileInfos[j].Name, id = k, hidden = true, fatherNode = firstDirectoryInfos[i].Name }); |
| | | k++; |
| | | } |
| | | data.Add(new { label = firstDirectoryInfos[i].Name, children = values, id = i, hidden = false }); |
| | | } |
| | | } |
| | | |
| | | FileInfo[] nextFileInfo = folder.GetFiles(); |
| | | List<object> value = new List<object>(); |
| | | for (int j = 0; j < nextFileInfo.Length; j++) |
| | | { |
| | | value.Add(new { label = nextFileInfo[j].Name, id = k, hidden = true, fatherNode = folder.Name }); |
| | | k++; |
| | | } |
| | | data.Add(new { label = folder.Name, children = value, id = 1, hidden = false }); |
| | | |
| | | return WebResponseContent.Instance.OK(data: data); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | |
| | | [HttpPost, Route("GetLog"), AllowAnonymous] |
| | | public WebResponseContent GetLog(string fileName) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | List<FileInfo> files = new List<FileInfo>(); |
| | | DirectoryInfo folder = new DirectoryInfo(AppContext.BaseDirectory + "\\logs\\"); |
| | | DirectoryInfo[] firstDirectoryInfos = folder.GetDirectories(); |
| | | for (int i = 0; i < firstDirectoryInfos.Length; i++) |
| | | { |
| | | FileInfo[] nextFileInfos = firstDirectoryInfos[i].GetFiles(); |
| | | files.AddRange(nextFileInfos); |
| | | } |
| | | |
| | | FileInfo[] nextFileInfo = folder.GetFiles(); |
| | | files.AddRange(nextFileInfo); |
| | | if (files.Count > 0) |
| | | { |
| | | FileInfo file = files.Where(x => x.Name == fileName).FirstOrDefault(); |
| | | if (file == null) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°æ¥å¿æä»¶: {fileName}"); |
| | | } |
| | | |
| | | // 使ç¨å
±äº«è¯»åæ¨¡å¼ |
| | | using (FileStream stream = new FileStream( |
| | | file.FullName, |
| | | FileMode.Open, |
| | | FileAccess.Read, |
| | | FileShare.ReadWrite)) |
| | | using (StreamReader reader = new StreamReader(stream, Encoding.UTF8)) |
| | | { |
| | | StringBuilder text = new StringBuilder(); |
| | | List<string> lines = new List<string>(); |
| | | while (!reader.EndOfStream) |
| | | { |
| | | var line = reader.ReadLine(); |
| | | lines.Add(line); |
| | | } |
| | | |
| | | content = WebResponseContent.Instance.OK(data: lines); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | content = WebResponseContent.Instance.Error($"æªæ¾å°æ¥å¿æä»¶,ã{fileName}ã"); |
| | | } |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | if (IsFileLockedException(ex)) |
| | | { |
| | | content = WebResponseContent.Instance.Error($"æ¥å¿æä»¶æ£å¨è¢«ç³»ç»åå
¥ï¼è¯·ç¨ååè¯"); |
| | | } |
| | | else |
| | | { |
| | | content = WebResponseContent.Instance.Error($"æå¼æ¥å¿æä»¶é误,{ex.Message}"); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | content = WebResponseContent.Instance.Error($"æå¼æ¥å¿æä»¶é误,{ex.Message}"); |
| | | } |
| | | return content; |
| | | } |
| | | |
| | | [HttpPost, HttpGet, Route("DownLoadLog"), AllowAnonymous] |
| | | public virtual async Task<ActionResult> DownLoadLog(string fileName) |
| | | { |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(fileName)) |
| | | { |
| | | return BadRequest("æä»¶åä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // å®å
¨æ§æ£æ¥ï¼é²æ¢è·¯å¾éåæ»å» |
| | | if (fileName.Contains("..") || Path.IsPathRooted(fileName)) |
| | | { |
| | | return BadRequest("æ æçæä»¶å"); |
| | | } |
| | | |
| | | //string logDirectory = Path.Combine(AppContext.BaseDirectory, "logs"); |
| | | string logDirectory = Path.Combine(AppContext.BaseDirectory); |
| | | |
| | | if (!Directory.Exists(logDirectory)) |
| | | { |
| | | Directory.CreateDirectory(logDirectory); |
| | | } |
| | | |
| | | string filePath = Path.Combine(logDirectory, fileName); |
| | | |
| | | if (Directory.Exists(filePath)) |
| | | { |
| | | return NotFound($"æä»¶ {fileName} ä¸åå¨"); |
| | | } |
| | | |
| | | string extension = Path.GetExtension(fileName).ToLowerInvariant(); |
| | | if (!IsAllowedFileType(extension)) |
| | | { |
| | | return BadRequest($"䏿¯æçæä»¶ç±»å: {extension}"); |
| | | } |
| | | |
| | | FileInfo fileInfo = new FileInfo(filePath); |
| | | |
| | | if (fileInfo.Length > MAX_FILE_SIZE_MB * 1024 * 1024) |
| | | { |
| | | return BadRequest($"æä»¶è¿å¤§ï¼è¶
è¿{MAX_FILE_SIZE_MB}MBéå¶"); |
| | | } |
| | | |
| | | // æ¹æ¡1ï¼ä½¿ç¨éè¯æºå¶ + å
±äº«è¯»åï¼æ¨èï¼ |
| | | byte[] fileBytes = await ReadFileWithRetryAsync(filePath); |
| | | |
| | | if (fileBytes == null) |
| | | { |
| | | return StatusCode(500, "æä»¶è¢«å ç¨ï¼æ æ³ä¸è½½ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | |
| | | string contentType = GetContentType(extension); |
| | | |
| | | // 设置ä¸è½½å¤´ |
| | | Response.Headers.Add("Content-Disposition", $"attachment; filename=\"{System.Web.HttpUtility.UrlEncode(fileName, Encoding.UTF8)}\""); |
| | | Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate"); |
| | | Response.Headers.Add("Pragma", "no-cache"); |
| | | Response.Headers.Add("Expires", "0"); |
| | | |
| | | return File(fileBytes, contentType, fileName); |
| | | } |
| | | catch (UnauthorizedAccessException) |
| | | { |
| | | return StatusCode(403, "没æè®¿é®è¯¥æä»¶çæé"); |
| | | } |
| | | catch (PathTooLongException) |
| | | { |
| | | return BadRequest("æä»¶è·¯å¾è¿é¿"); |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | if (IsFileLockedException(ex)) |
| | | { |
| | | return StatusCode(500, "æä»¶è¢«éå®ï¼å¯è½æ£å¨è¢«ç³»ç»åå
¥ï¼è¯·ç¨ååè¯"); |
| | | } |
| | | return StatusCode(500, $"æä»¶è¯»å失败: {ex.Message}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è®°å½å¼å¸¸æ¥å¿ï¼è¿éç®å为è¿åï¼å®é
项ç®ä¸åºè¯¥è®°å½å°æ¥å¿ç³»ç»ï¼ |
| | | return StatusCode(500, $"æå¡å¨å
é¨é误: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 带éè¯æºå¶çæä»¶è¯»åæ¹æ³ |
| | | /// </summary> |
| | | private async Task<byte[]> ReadFileWithRetryAsync(string filePath) |
| | | { |
| | | for (int attempt = 0; attempt < MAX_RETRY_COUNT; attempt++) |
| | | { |
| | | try |
| | | { |
| | | // ä½¿ç¨ FileShare.ReadWrite å
许å
¶ä»è¿ç¨åæ¶è¯»åååå
¥ |
| | | // 使ç¨å¼æ¥è¯»åæé«æ§è½ |
| | | using (var fileStream = new FileStream( |
| | | filePath, |
| | | FileMode.Open, |
| | | FileAccess.Read, |
| | | FileShare.ReadWrite | FileShare.Delete, // å
许å é¤æä½ |
| | | bufferSize: 4096, |
| | | useAsync: true)) |
| | | { |
| | | using (var memoryStream = new MemoryStream()) |
| | | { |
| | | await fileStream.CopyToAsync(memoryStream); |
| | | return memoryStream.ToArray(); |
| | | } |
| | | } |
| | | } |
| | | catch (IOException) when (attempt < MAX_RETRY_COUNT - 1) |
| | | { |
| | | // 妿䏿¯æå䏿¬¡éè¯ï¼çå¾
䏿®µæ¶é´ |
| | | await Task.Delay(RETRY_DELAY_MS * (attempt + 1)); |
| | | } |
| | | catch (IOException ex) |
| | | { |
| | | // æå䏿¬¡å°è¯ä¹å¤±è´¥äº |
| | | throw; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 夿æ¯å¦ä¸ºæä»¶è¢«éå®çå¼å¸¸ |
| | | /// </summary> |
| | | private bool IsFileLockedException(IOException ex) |
| | | { |
| | | int errorCode = ex.HResult & 0xFFFF; |
| | | return errorCode == 32 || errorCode == 33; // ERROR_SHARING_VIOLATION or ERROR_LOCK_VIOLATION |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ£æ¥æä»¶ç±»åæ¯å¦å
许 |
| | | /// </summary> |
| | | private bool IsAllowedFileType(string extension) |
| | | { |
| | | return ALLOWED_FILE_TYPES.Contains(extension); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åContent-Type |
| | | /// </summary> |
| | | private string GetContentType(string extension) |
| | | { |
| | | return extension.ToLowerInvariant() switch |
| | | { |
| | | ".txt" => "text/plain; charset=utf-8", |
| | | ".log" => "text/plain; charset=utf-8", |
| | | ".csv" => "text/csv; charset=utf-8", |
| | | ".json" => "application/json; charset=utf-8", |
| | | ".xml" => "application/xml; charset=utf-8", |
| | | _ => "application/octet-stream" |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å¤éæ¹æ¡ï¼å建临æ¶å¯æ¬ä¸è½½ï¼æå®å
¨ï¼ä½æ§è½ç¨å·®ï¼ |
| | | /// </summary> |
| | | [HttpPost, HttpGet, Route("DownLoadLogCopy"), AllowAnonymous] |
| | | public virtual async Task<ActionResult> DownLoadLogCopy(string fileName) |
| | | { |
| | | try |
| | | { |
| | | // åæ°éªè¯ï¼åä¸ï¼ |
| | | if (string.IsNullOrWhiteSpace(fileName)) |
| | | { |
| | | return BadRequest("æä»¶åä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | string logDirectory = Path.Combine(AppContext.BaseDirectory, "logs"); |
| | | string filePath = Path.Combine(logDirectory, fileName); |
| | | |
| | | if (Directory.Exists(filePath)) |
| | | { |
| | | return NotFound($"æä»¶ {fileName} ä¸åå¨"); |
| | | } |
| | | |
| | | // çæä¸´æ¶æä»¶å |
| | | string tempFileName = $"{Path.GetFileNameWithoutExtension(fileName)}_{Guid.NewGuid():N}{Path.GetExtension(fileName)}"; |
| | | string tempFilePath = Path.Combine(Path.GetTempPath(), tempFileName); |
| | | |
| | | try |
| | | { |
| | | // å°è¯å¤å¶æä»¶å°ä¸´æ¶ä½ç½®ï¼ä½¿ç¨éè¯æºå¶ï¼ |
| | | bool copySuccess = false; |
| | | for (int attempt = 0; attempt < MAX_RETRY_COUNT; attempt++) |
| | | { |
| | | try |
| | | { |
| | | //Directory.GetFiles.Copy(filePath, tempFilePath, false); |
| | | copySuccess = true; |
| | | break; |
| | | } |
| | | catch (IOException) when (attempt < MAX_RETRY_COUNT - 1) |
| | | { |
| | | await Task.Delay(RETRY_DELAY_MS * (attempt + 1)); |
| | | } |
| | | } |
| | | |
| | | if (!copySuccess) |
| | | { |
| | | return StatusCode(500, "æ æ³å¤å¶æä»¶ï¼å¯è½è¢«å
¶ä»è¿ç¨å ç¨"); |
| | | } |
| | | |
| | | // ä»ä¸´æ¶æä»¶è¯»å |
| | | byte[] fileBytes; |
| | | using (FileStream tempStream = new FileStream(tempFilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) |
| | | { |
| | | using (MemoryStream memoryStream = new MemoryStream()) |
| | | { |
| | | await tempStream.CopyToAsync(memoryStream); |
| | | fileBytes = memoryStream.ToArray(); |
| | | } |
| | | } |
| | | |
| | | string extension = Path.GetExtension(fileName).ToLowerInvariant(); |
| | | string contentType = GetContentType(extension); |
| | | |
| | | // è¿åæä»¶åæ¸
çä¸´æ¶æä»¶ |
| | | var result = File(fileBytes, contentType, fileName); |
| | | |
| | | // 弿¥æ¸
çä¸´æ¶æä»¶ |
| | | _ = Task.Run(() => |
| | | { |
| | | try |
| | | { |
| | | Directory.Delete(tempFilePath); |
| | | } |
| | | catch |
| | | { |
| | | // 忽ç¥å é¤å¤±è´¥ |
| | | } |
| | | }); |
| | | |
| | | return result; |
| | | } |
| | | finally |
| | | { |
| | | // ç¡®ä¿ä¸´æ¶æä»¶è¢«æ¸
ç |
| | | if (Directory.Exists(tempFilePath)) |
| | | { |
| | | try |
| | | { |
| | | Directory.Delete(tempFilePath); |
| | | } |
| | | catch |
| | | { |
| | | // 忽ç¥å é¤å¤±è´¥ |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return StatusCode(500, $"æå¡å¨å
é¨é误: {ex.Message}"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |