1.新增多选盘点和EXCEL导入盘点
2.EWM接口优化 3.出库由自动改为手动下发 4.出库校验逻辑修改 5.库存合并功能 6.第二种入库模式 7.WMS新增图标统计
This commit is contained in:
parent
a52149750f
commit
32a853eecb
59
dev_wms_client/package-lock.json
generated
59
dev_wms_client/package-lock.json
generated
|
|
@ -11,6 +11,7 @@
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"axios": "^1.3.3",
|
"axios": "^1.3.3",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
|
"echarts": "^5.4.3",
|
||||||
"element-plus": "^2.9.8",
|
"element-plus": "^2.9.8",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
|
@ -5558,6 +5559,20 @@
|
||||||
"node": ">=6.0.0"
|
"node": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/echarts": {
|
||||||
|
"version": "5.4.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz",
|
||||||
|
"integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "2.3.0",
|
||||||
|
"zrender": "5.4.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/echarts/node_modules/tslib": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
|
@ -12223,6 +12238,19 @@
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zrender": {
|
||||||
|
"version": "5.4.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz",
|
||||||
|
"integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "2.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/zrender/node_modules/tslib": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
@ -16416,6 +16444,22 @@
|
||||||
"integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==",
|
"integrity": "sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"echarts": {
|
||||||
|
"version": "5.4.3",
|
||||||
|
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.3.tgz",
|
||||||
|
"integrity": "sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "2.3.0",
|
||||||
|
"zrender": "5.4.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"ee-first": {
|
"ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
|
@ -21683,6 +21727,21 @@
|
||||||
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz",
|
||||||
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
"integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"zrender": {
|
||||||
|
"version": "5.4.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.4.tgz",
|
||||||
|
"integrity": "sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "2.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
|
||||||
|
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
"axios": "^1.3.3",
|
"axios": "^1.3.3",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
|
"echarts": "^5.4.3",
|
||||||
"element-plus": "^2.9.8",
|
"element-plus": "^2.9.8",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"moment": "^2.29.4",
|
"moment": "^2.29.4",
|
||||||
|
|
|
||||||
|
|
@ -173,3 +173,12 @@ export const exportLocationDetailExcel = (data) => {
|
||||||
timeout: 600000
|
timeout: 600000
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 导入盘点任务
|
||||||
|
export const importInventoryExcel = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/excel/importGoods', // 根据你提供的地址修改
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
timeout: 600000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,13 @@
|
||||||
import request from "@/http/request";
|
import request from "@/http/request";
|
||||||
|
|
||||||
|
export function batchIssueTasks(params) {
|
||||||
|
return request({
|
||||||
|
url: '/taskQuery/updateOutsTaskStatus',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查找物料
|
* 分页查找物料
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,14 @@ export const queryStocksByPage = (params) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const querySpecialEmptyStocksForMix = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/stock/querySpecialEmptyStocksForMix',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const queryStocks = (params) => {
|
export const queryStocks = (params) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/stock/queryStocks',
|
url: '/stock/queryStocks',
|
||||||
|
|
@ -16,6 +24,22 @@ export const queryStocks = (params) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const queryStocksBySpecial = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/stock/queryStocksBySpecial',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const querySpecialEmptyStocksForPDA = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/stock/querySpecialEmptyStocksForPDA',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const queryStockUpdateByPage = (params) => {
|
export const queryStockUpdateByPage = (params) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/stock/queryStockUpdateByPage',
|
url: '/stock/queryStockUpdateByPage',
|
||||||
|
|
@ -23,3 +47,4 @@ export const queryStockUpdateByPage = (params) => {
|
||||||
data: params
|
data: params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,14 @@ export const confirmCurrentTask = (params, config = {}) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const mergeStocks = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/task/createInventoryFromMixStock',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const confirmCurrentTaskByPDA = (params) => {
|
export const confirmCurrentTaskByPDA = (params) => {
|
||||||
return request({
|
return request({
|
||||||
|
|
@ -115,6 +123,39 @@ export const confirmInventory = (params) => {
|
||||||
data: params
|
data: params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
export const confirmMixStock = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/task/confirmMixStock',
|
||||||
|
method: 'post',
|
||||||
|
data: params,
|
||||||
|
timeout: 30000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pdaOutTask = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/task/pdaOutTask',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const queryInOutBoundStatistics = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/board/queryInOutBoundStatistics',
|
||||||
|
method: 'post',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const queryStockAgeDistribution = (params) => {
|
||||||
|
return request({
|
||||||
|
url: '/board/queryStockAgeDistribution',
|
||||||
|
method: 'get',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获取缺料数量
|
// 获取缺料数量
|
||||||
export const getGoodsLackQty = (params) => {
|
export const getGoodsLackQty = (params) => {
|
||||||
return request({
|
return request({
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import axios from 'axios'
|
||||||
|
|
||||||
const request = axios.create({
|
const request = axios.create({
|
||||||
baseURL: 'http://172.18.222.253:12315/wms',
|
baseURL: 'http://172.18.222.253:12315/wms',
|
||||||
|
//baseURL: 'http://172.18.222.253:12306/wms',
|
||||||
//baseURL: 'http://localhost:12315/wms',
|
//baseURL: 'http://localhost:12315/wms',
|
||||||
timeout: 5000
|
timeout: 5000
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -274,6 +274,7 @@ const handleSelectionChange = (row) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理全选变化
|
||||||
// 处理全选变化
|
// 处理全选变化
|
||||||
const handleSelectAllChange = (val) => {
|
const handleSelectAllChange = (val) => {
|
||||||
displayStocks.value.forEach(row => {
|
displayStocks.value.forEach(row => {
|
||||||
|
|
@ -281,12 +282,15 @@ const handleSelectAllChange = (val) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (val) {
|
if (val) {
|
||||||
// 全选
|
// 全选 - 添加到选中数组
|
||||||
selectedRows.value = [...displayStocks.value]
|
selectedRows.value = [...displayStocks.value]
|
||||||
} else {
|
} else {
|
||||||
// 取消全选
|
// 取消全选 - 清空选中数组
|
||||||
selectedRows.value = []
|
selectedRows.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 强制更新视图
|
||||||
|
displayStocks.value = [...displayStocks.value]
|
||||||
}
|
}
|
||||||
// 处理批量盘点按钮点击
|
// 处理批量盘点按钮点击
|
||||||
const handleBatchInventory = () => {
|
const handleBatchInventory = () => {
|
||||||
|
|
@ -320,14 +324,13 @@ const confirmBatchInventory = () => {
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
ElMessage.success('批量盘点成功');
|
ElMessage.success('批量盘点成功');
|
||||||
showBatchInventoryDialog.value = false;
|
showBatchInventoryDialog.value = false;
|
||||||
search(); // 刷新表格数据
|
|
||||||
|
|
||||||
// 清空选择
|
// 先清空选择状态
|
||||||
selectedRows.value.forEach(row => {
|
selectedRows.value = []
|
||||||
row.checked = false;
|
isSelectAll.value = false
|
||||||
});
|
|
||||||
selectedRows.value = [];
|
// 然后刷新数据
|
||||||
isSelectAll.value = false;
|
search(); // 刷新表格数据
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.data.message);
|
ElMessage.error(res.data.message);
|
||||||
}
|
}
|
||||||
|
|
@ -336,6 +339,18 @@ const confirmBatchInventory = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 重置选择状态
|
||||||
|
const resetSelection = () => {
|
||||||
|
selectedRows.value = []
|
||||||
|
isSelectAll.value = false
|
||||||
|
if (displayStocks.value && displayStocks.value.length > 0) {
|
||||||
|
displayStocks.value.forEach(row => {
|
||||||
|
row.checked = false
|
||||||
|
})
|
||||||
|
// 强制更新视图
|
||||||
|
displayStocks.value = [...displayStocks.value]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 查询
|
// 查询
|
||||||
const search = () => {
|
const search = () => {
|
||||||
|
|
@ -356,11 +371,21 @@ const search = () => {
|
||||||
const data = response.data
|
const data = response.data
|
||||||
console.log(data)
|
console.log(data)
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
displayStocks.value = data.lists
|
// 重置每行的checked状态
|
||||||
|
displayStocks.value = data.lists.map(item => ({
|
||||||
|
...item,
|
||||||
|
checked: false
|
||||||
|
}))
|
||||||
baseTableQuery.total = data.total
|
baseTableQuery.total = data.total
|
||||||
|
|
||||||
|
// 重置选择状态
|
||||||
|
selectedRows.value = []
|
||||||
|
isSelectAll.value = false
|
||||||
} else {
|
} else {
|
||||||
displayStocks.value = []
|
displayStocks.value = []
|
||||||
baseTableQuery.total = 0
|
baseTableQuery.total = 0
|
||||||
|
selectedRows.value = []
|
||||||
|
isSelectAll.value = false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(response.message)
|
ElMessage.error(response.message)
|
||||||
|
|
@ -381,6 +406,7 @@ const clearQuery = () => {
|
||||||
stockQuery.fromDate = null,
|
stockQuery.fromDate = null,
|
||||||
stockQuery.toDate = null,
|
stockQuery.toDate = null,
|
||||||
stockQuery.noUseDays = null
|
stockQuery.noUseDays = null
|
||||||
|
resetSelection()
|
||||||
}
|
}
|
||||||
const loadAllGoodsInfo = () => {
|
const loadAllGoodsInfo = () => {
|
||||||
const request = {
|
const request = {
|
||||||
|
|
|
||||||
426
dev_wms_client/src/layout/excelInventory.vue
Normal file
426
dev_wms_client/src/layout/excelInventory.vue
Normal file
|
|
@ -0,0 +1,426 @@
|
||||||
|
<template>
|
||||||
|
<el-config-provider :locale="zhCn">
|
||||||
|
<el-container class="content">
|
||||||
|
<div class="work-area">
|
||||||
|
<fieldset class="search-area">
|
||||||
|
<el-form ref="searchQueryFormRef" :model="searchQueryFormEntity" :label-position="labelPosition"
|
||||||
|
label-width="158px" style="max-width: 100%" status-icon>
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<el-row>
|
||||||
|
<el-form-item label="箱号">
|
||||||
|
<el-input v-model="searchQueryFormEntity.vehicleId" @keyup.enter="search()" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="料号">
|
||||||
|
<el-input v-model="searchQueryFormEntity.goodsId" @keyup.enter="search()" clearable/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-row>
|
||||||
|
<div style="align-content: center;">
|
||||||
|
<el-row>
|
||||||
|
<el-button type="primary" class="btn-search" @click="search()">查询</el-button>
|
||||||
|
<el-button type="warning" class="btn-search" @click="clearQuery()">清除输入</el-button>
|
||||||
|
<el-button type="success" class="btn-search" @click="importExcel">导入盘点任务</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</fieldset>
|
||||||
|
<div class="table-area">
|
||||||
|
<el-table :data="tableData" stripe border v-loading="tableLoading" class="table-class"
|
||||||
|
:max-height="maxHeight" highlight-current-row @row-click="getCurrentRow"
|
||||||
|
:header-cell-style="{ 'text-align': 'center' }" :cell-style="{ 'text-align': 'center' }"
|
||||||
|
@sort-change="handleSortChange">
|
||||||
|
<el-table-column width="65px" fixed="left">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-radio :label="scope.row.inventoryId" v-model="inventoryId"> </el-radio>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="inventoryId" label="任务号" fixed="left" min-width="120px" sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="goodsId" label="料号" min-width="120px"
|
||||||
|
sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="vehicleId" label="箱号" min-width="120px" sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="stockNum" label="库存数量" min-width="120px" sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="confirmNum" label="确认数量"
|
||||||
|
min-width="120px" sortable="custom" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invStand" label="盘点站台" min-width="120px" sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invUser" label="盘点人" min-width="120px"
|
||||||
|
sortable="custom" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invStatus" label="任务状态" :formatter="invStatusFormat" min-width="120px"
|
||||||
|
sortable="custom" show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invResult" label="盘点结果" :formatter="invResultFormat" min-width="120px" sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invCreateTime" label="创建时间" :formatter="timeFormat" min-width="120px"
|
||||||
|
sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invConfirmTime" label="确认时间" :formatter="timeFormat" min-width="120px"
|
||||||
|
sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="invOrderId" label="任务组" min-width="120px"
|
||||||
|
sortable="custom"
|
||||||
|
show-overflow-tooltip/>
|
||||||
|
</el-table>
|
||||||
|
<br/>
|
||||||
|
<el-pagination v-model:current-page="baseTableQuery.currentPage"
|
||||||
|
v-model:page-size="baseTableQuery.pageSize" :page-sizes="[10, 25, 50]" :small="false"
|
||||||
|
:disabled="false" :background="false" :default-page-size="10" @size-change="search"
|
||||||
|
@current-change="search" layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="baseTableQuery.total"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-container>
|
||||||
|
<!-- Excel导入对话框 -->
|
||||||
|
<el-dialog v-model="excelDialogVisible" title="导入盘点任务" width="500px" :before-close="closeExcelDialog">
|
||||||
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
:auto-upload="false"
|
||||||
|
:limit="1"
|
||||||
|
accept=".xlsx, .xls"
|
||||||
|
:on-change="handleFileChange"
|
||||||
|
:file-list="fileList"
|
||||||
|
:show-file-list="true"
|
||||||
|
>
|
||||||
|
<template #trigger>
|
||||||
|
<el-button type="primary">选择Excel文件</el-button>
|
||||||
|
</template>
|
||||||
|
<el-button class="ml-3" type="success" @click="submitUpload" :disabled="!fileList.length">
|
||||||
|
上传文件
|
||||||
|
</el-button>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">
|
||||||
|
请上传Excel文件(.xlsx或.xls),文件格式请参考模板
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="closeExcelDialog">取消</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</el-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import store from '@/store'
|
||||||
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
|
import {queryInventoryRecordByPage} from '@/api/taskQuery.js'
|
||||||
|
import {timeFormatter} from '@/utils/formatter.js'
|
||||||
|
import {ref, reactive, onMounted, nextTick, onBeforeUnmount} from 'vue'
|
||||||
|
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||||
|
import {genTableRequest} from '@/utils/generator.js'
|
||||||
|
import {labelPosition} from '@/constant/form.js'
|
||||||
|
import {invResultOptions} from '@/constant/options.js'
|
||||||
|
import {addAllOptionOfOptions} from '@/utils/generator.js'
|
||||||
|
import {importInventoryExcel} from '@/api/excel.js' // 添加导入
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常量定义
|
||||||
|
*/
|
||||||
|
const STAND_ID = store.getters.getStandId
|
||||||
|
const USER_NAME = store.getters.getUserName
|
||||||
|
const DEFAULT_TOTAL_OPTIONS = 99
|
||||||
|
/**
|
||||||
|
* 变量定义
|
||||||
|
*/
|
||||||
|
let maxHeight = ref(window.innerHeight * 0.55)
|
||||||
|
let tableLoading = ref(false)
|
||||||
|
let tableData = ref([])
|
||||||
|
let baseTableQuery = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
sortBy: new Map([['invCreateTime', true]]),// 按照创建时间顺序排序
|
||||||
|
standId: STAND_ID,
|
||||||
|
userName: USER_NAME,
|
||||||
|
queryType: 1 // 只显示未关闭的盘点任务
|
||||||
|
})
|
||||||
|
let searchQueryFormEntity = reactive({
|
||||||
|
vehicleId: '',
|
||||||
|
goodsId: '',
|
||||||
|
invResult: DEFAULT_TOTAL_OPTIONS
|
||||||
|
})
|
||||||
|
let searchQueryFormRef = ref()
|
||||||
|
let inventoryId = ''
|
||||||
|
const queryTypeOptions = [
|
||||||
|
{
|
||||||
|
label: '未关闭',
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
// Excel导入相关
|
||||||
|
let excelDialogVisible = ref(false)
|
||||||
|
let fileList = ref([])
|
||||||
|
let uploadRef = ref()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统方法
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
window.addEventListener('resize', resizeHeight)
|
||||||
|
search()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
window.removeEventListener('resize', resizeHeight)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
const resizeHeight = () => {
|
||||||
|
maxHeight.value = window.innerHeight * 0.55
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 自定义方法
|
||||||
|
*/
|
||||||
|
// 查询
|
||||||
|
const search = () => {
|
||||||
|
tableLoading.value = true
|
||||||
|
let request = genTableRequest(baseTableQuery)
|
||||||
|
// 设定查询参数
|
||||||
|
request.vehicleId = searchQueryFormEntity.vehicleId.trim()
|
||||||
|
request.goodsId = searchQueryFormEntity.goodsId.trim()
|
||||||
|
request.invResult = searchQueryFormEntity.invResult === DEFAULT_TOTAL_OPTIONS ? null : searchQueryFormEntity.invResult
|
||||||
|
request.queryType = 1 // 固定为未关闭任务
|
||||||
|
queryInventoryRecordByPage(request).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
const data = response.data
|
||||||
|
if (data != null) {
|
||||||
|
tableData.value = data.lists
|
||||||
|
baseTableQuery.total = data.total
|
||||||
|
} else {
|
||||||
|
tableData.value = []
|
||||||
|
baseTableQuery.total = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
ElMessage.error('查询数据异常。')
|
||||||
|
}).finally(() => {
|
||||||
|
tableLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const clearQuery = () => {
|
||||||
|
searchQueryFormEntity.vehicleId = ''
|
||||||
|
searchQueryFormEntity.goodsId = ''
|
||||||
|
searchQueryFormEntity.invResult = DEFAULT_TOTAL_OPTIONS
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
const handleSortChange = (data) => {
|
||||||
|
if (baseTableQuery.sortBy.has(data.prop)) {
|
||||||
|
baseTableQuery.sortBy.delete(data.prop)
|
||||||
|
}
|
||||||
|
baseTableQuery.sortBy.set(data.prop, data.order.toLowerCase() === 'ascending')
|
||||||
|
search()
|
||||||
|
}
|
||||||
|
const getCurrentRow = (row) => {
|
||||||
|
inventoryId = row.inventoryId
|
||||||
|
}
|
||||||
|
const timeFormat = (row, column, cellValue, index) => {
|
||||||
|
return timeFormatter(cellValue)
|
||||||
|
}
|
||||||
|
// 盘点任务状态format
|
||||||
|
const invStatusFormat = (row, column, cellValue, index) => {
|
||||||
|
switch (cellValue) {
|
||||||
|
case 0:
|
||||||
|
return '初始化'
|
||||||
|
case 1:
|
||||||
|
return '已解析'
|
||||||
|
case 2:
|
||||||
|
return '已确认'
|
||||||
|
default:
|
||||||
|
return '未知状态'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 盘点类型format
|
||||||
|
const invTypeFormat = (row, column, cellValue, index) => {
|
||||||
|
if (cellValue === 1) {
|
||||||
|
return '明盘'
|
||||||
|
} else if (cellValue === 2) {
|
||||||
|
return '盲盘'
|
||||||
|
} else {
|
||||||
|
return '未知类型'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 盘点结果format
|
||||||
|
const invResultFormat = (row, column, cellValue, index) => {
|
||||||
|
switch (cellValue) {
|
||||||
|
case -99:
|
||||||
|
return '未盘'
|
||||||
|
case -1:
|
||||||
|
return '盘亏'
|
||||||
|
case 0:
|
||||||
|
return '正常'
|
||||||
|
case 1:
|
||||||
|
return '盘盈'
|
||||||
|
default:
|
||||||
|
return '未知结果'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Excel导入功能
|
||||||
|
const importExcel = () => {
|
||||||
|
excelDialogVisible.value = true
|
||||||
|
fileList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleFileChange = (file, files) => {
|
||||||
|
fileList.value = [file]
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitUpload = () => {
|
||||||
|
if (!fileList.value.length) {
|
||||||
|
ElMessage.warning('请选择要上传的文件')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', fileList.value[0].raw) // 添加 file 参数
|
||||||
|
|
||||||
|
// 创建 FileVo 对象
|
||||||
|
const fileVo = {
|
||||||
|
userName: USER_NAME, // 使用从 store 获取的用户名
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 FileVo 对象作为 JSON 字符串添加到 FormData
|
||||||
|
formData.append('fileVo', new Blob([JSON.stringify(fileVo)], { type: 'application/json' }))
|
||||||
|
|
||||||
|
importInventoryExcel(formData).then(res => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
ElMessage.success('导入成功')
|
||||||
|
search() // 重新查询数据
|
||||||
|
closeExcelDialog()
|
||||||
|
} else {
|
||||||
|
// 处理错误信息中的换行符,将其转换为HTML的<br>标签
|
||||||
|
let errorMessage = response.message || '导入失败'
|
||||||
|
// 将换行符替换为HTML换行标签
|
||||||
|
errorMessage = errorMessage.replace(/\n/g, '<br/>')
|
||||||
|
|
||||||
|
// 使用 ElMessageBox 显示多行错误信息
|
||||||
|
ElMessageBox.alert(errorMessage, '错误', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
type: 'error',
|
||||||
|
dangerouslyUseHTMLString: true, // 允许HTML格式
|
||||||
|
customClass: 'error-message-box' // 自定义样式类
|
||||||
|
}).catch(() => {
|
||||||
|
// 忽略取消操作
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
ElMessage.error('导入数据异常')
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const closeExcelDialog = () => {
|
||||||
|
excelDialogVisible.value = false
|
||||||
|
fileList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
const downloadTemplate = () => {
|
||||||
|
// 这里应该调用下载模板的API
|
||||||
|
// 模拟下载链接,实际需要后端提供接口
|
||||||
|
window.open('/api/inventory/template', '_blank')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style scoped>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-area {
|
||||||
|
width: 100%;
|
||||||
|
/* padding: 5px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-area {
|
||||||
|
margin: auto;
|
||||||
|
min-height: fit-content;
|
||||||
|
max-height: 40%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-width: inherit;
|
||||||
|
border: solid 1px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 15px 10px -15px #000;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-area {
|
||||||
|
margin: auto;
|
||||||
|
min-height: fit-content;
|
||||||
|
max-height: 60%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-width: inherit;
|
||||||
|
border: solid 1px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 15px 10px -15px #000;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin: 5px 5px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item .el-input {
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item .el-input-number {
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-class {
|
||||||
|
margin: 5px 5px 5px 5px;
|
||||||
|
width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-pagination {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li {
|
||||||
|
width: 196px;
|
||||||
|
line-height: normal;
|
||||||
|
padding: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li .name {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li .addr {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #b4b4b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li .highlighted .addr {
|
||||||
|
color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li .goods_id {
|
||||||
|
color: brown;
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-autocomplete li .goods_name {
|
||||||
|
color: cornflowerblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-search {
|
||||||
|
height: 30px;
|
||||||
|
width: 80px;
|
||||||
|
margin: auto 5px 5px auto;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -15,24 +15,30 @@
|
||||||
<el-input v-model="searchQueryFormEntity.workOrder" @keyup.enter="search()"
|
<el-input v-model="searchQueryFormEntity.workOrder" @keyup.enter="search()"
|
||||||
clearable/>
|
clearable/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<!-- <el-form-item label="工单号">-->
|
<!-- <el-form-item label="工单号">-->
|
||||||
<!-- <el-input v-model="searchQueryFormEntity.goodsDesc" @keyup.enter="search()"-->
|
<!-- <el-input v-model="searchQueryFormEntity.goodsDesc" @keyup.enter="search()"-->
|
||||||
<!-- clearable/>-->
|
<!-- clearable/>-->
|
||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
</el-row>
|
</el-row>
|
||||||
<div style="align-content: center;">
|
<div style="align-content: center;">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-button type="primary" class="btn-search" @click="search()">查询</el-button>
|
<el-button type="primary" class="btn-search" @click="search()">查询</el-button>
|
||||||
<el-button type="warning" class="btn-search" @click="clearQuery()">清除输入</el-button>
|
<el-button type="warning" class="btn-search" @click="clearQuery()">清除输入</el-button>
|
||||||
|
<!-- 添加下发按钮 -->
|
||||||
|
<el-button type="success" class="btn-search"
|
||||||
|
@click="handleBatchIssue"
|
||||||
|
:disabled="selectedRows.length === 0">
|
||||||
|
批量下发({{ selectedRows.length }})
|
||||||
|
</el-button>
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- <el-row>-->
|
<!-- <el-row>-->
|
||||||
<!-- <el-button style="background-color: #00CED1;" class="btn-search"-->
|
<!-- <el-button style="background-color: #00CED1;" class="btn-search"-->
|
||||||
<!-- @click="openUploadDialog()">导入数据-->
|
<!-- @click="openUploadDialog()">导入数据-->
|
||||||
<!-- </el-button>-->
|
<!-- </el-button>-->
|
||||||
<!-- <el-button type="success" class="btn-search"-->
|
<!-- <el-button type="success" class="btn-search"-->
|
||||||
<!-- @click="exportExcel()">导出excel-->
|
<!-- @click="exportExcel()">导出excel-->
|
||||||
<!-- </el-button>-->
|
<!-- </el-button>-->
|
||||||
<!-- </el-row>-->
|
<!-- </el-row>-->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
@ -46,6 +52,7 @@
|
||||||
<template #header>
|
<template #header>
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
v-model="isSelectAll"
|
v-model="isSelectAll"
|
||||||
|
:indeterminate="isSelectIndeterminate"
|
||||||
@change="handleSelectAllChange">
|
@change="handleSelectAllChange">
|
||||||
|
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
|
|
@ -64,6 +71,7 @@
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
<el-table-column prop="goodsId" label="料号" fixed="left" min-width="120px" sortable="custom"
|
<el-table-column prop="goodsId" label="料号" fixed="left" min-width="120px" sortable="custom"
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
|
|
||||||
<el-table-column prop="needNum" label="需求数量" min-width="120px" sortable="custom"
|
<el-table-column prop="needNum" label="需求数量" min-width="120px" sortable="custom"
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
<el-table-column prop="distributeNum" label="已分配数量" min-width="120px" sortable="custom"
|
<el-table-column prop="distributeNum" label="已分配数量" min-width="120px" sortable="custom"
|
||||||
|
|
@ -92,7 +100,18 @@
|
||||||
sortable="custom"
|
sortable="custom"
|
||||||
:formatter="(row, column, cellValue) => formatDateToDay(cellValue)"
|
:formatter="(row, column, cellValue) => formatDateToDay(cellValue)"
|
||||||
show-overflow-tooltip/>
|
show-overflow-tooltip/>
|
||||||
|
<el-table-column prop="taskStatus"
|
||||||
|
label="任务状态"
|
||||||
|
fixed="right"
|
||||||
|
min-width="120px"
|
||||||
|
sortable="custom"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<span :class="getStatusClass(scope.row.taskStatus)">
|
||||||
|
{{ getStatusText(scope.row.taskStatus) }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column label="操作" fixed="right" min-width="180px">
|
<el-table-column label="操作" fixed="right" min-width="180px">
|
||||||
<template v-slot="scope">
|
<template v-slot="scope">
|
||||||
<div style="display: flex; gap: 5px; justify-content: center;">
|
<div style="display: flex; gap: 5px; justify-content: center;">
|
||||||
|
|
@ -107,8 +126,7 @@
|
||||||
size="small"
|
size="small"
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="handleBatchEdit"
|
@click="handleBatchEdit"
|
||||||
:disabled="selectedRows.length === 0"
|
:disabled="selectedRows.length === 0" style="margin-top: 5px;">
|
||||||
style="margin-top: 5px;">
|
|
||||||
批量修改时间({{ selectedRows.length }})
|
批量修改时间({{ selectedRows.length }})
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -118,9 +136,15 @@
|
||||||
</el-table>
|
</el-table>
|
||||||
<br/>
|
<br/>
|
||||||
<el-pagination v-model:current-page="baseTableQuery.currentPage"
|
<el-pagination v-model:current-page="baseTableQuery.currentPage"
|
||||||
v-model:page-size="baseTableQuery.pageSize" :page-sizes="[10, 25, 50]" :small="false"
|
v-model:page-size="baseTableQuery.pageSize"
|
||||||
:disabled="false" :background="false" :default-page-size="10" @size-change="search"
|
:page-sizes="[20, 50, 100]"
|
||||||
@current-change="search" layout="total, sizes, prev, pager, next, jumper"
|
:small="false"
|
||||||
|
:disabled="false"
|
||||||
|
:background="false"
|
||||||
|
:default-page-size="20"
|
||||||
|
@size-change="search"
|
||||||
|
@current-change="search"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
:total="baseTableQuery.total"/>
|
:total="baseTableQuery.total"/>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog v-model="showEditDialog" title="编辑执行日期" width="30%" draggable>
|
<el-dialog v-model="showEditDialog" title="编辑执行日期" width="30%" draggable>
|
||||||
|
|
@ -170,9 +194,9 @@
|
||||||
<script setup>
|
<script setup>
|
||||||
import store from '@/store'
|
import store from '@/store'
|
||||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
import {batchEditDate, editDate, getGoodsInfoByPage, upOutsType} from '@/api/goods.js'
|
import {batchEditDate, editDate, getGoodsInfoByPage, upOutsType, batchIssueTasks} from '@/api/goods.js'
|
||||||
import {ref, reactive, onMounted, nextTick, onBeforeUnmount} from 'vue'
|
import {ref, reactive, onMounted, nextTick, onBeforeUnmount} from 'vue'
|
||||||
import {ElMessage} from 'element-plus'
|
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||||
import {genTableRequest} from '@/utils/generator.js'
|
import {genTableRequest} from '@/utils/generator.js'
|
||||||
import {labelPosition} from '@/constant/form.js'
|
import {labelPosition} from '@/constant/form.js'
|
||||||
import UploadExcelBaseGoods from '@/excel/UploadExcelBaseGoods.vue'
|
import UploadExcelBaseGoods from '@/excel/UploadExcelBaseGoods.vue'
|
||||||
|
|
@ -180,12 +204,36 @@ import UploadExcelKanban from '@/excel/UploadExcelKanban.vue'
|
||||||
import {exportGoodsExcel} from "@/api/excel";
|
import {exportGoodsExcel} from "@/api/excel";
|
||||||
import {dateFormatter} from "@/utils/formatter";
|
import {dateFormatter} from "@/utils/formatter";
|
||||||
import { getUserPermission } from '@/api/user.js'
|
import { getUserPermission } from '@/api/user.js'
|
||||||
|
import {computed} from 'vue' // 确保导入computed
|
||||||
/**
|
/**
|
||||||
* 常量定义
|
* 常量定义
|
||||||
*/
|
*/
|
||||||
const STAND_ID = store.getters.getStandId
|
const STAND_ID = store.getters.getStandId
|
||||||
const USER_NAME = store.getters.getUserName
|
const USER_NAME = store.getters.getUserName
|
||||||
|
|
||||||
|
// 添加状态文本映射函数
|
||||||
|
const getStatusText = (status) => {
|
||||||
|
if (status === -1) {
|
||||||
|
return '待下发'
|
||||||
|
} else if (status === 0) {
|
||||||
|
return '已下发'
|
||||||
|
} else {
|
||||||
|
// 如果有其他状态值,可以根据实际情况添加处理
|
||||||
|
return status // 返回原始值作为默认情况
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加状态样式类映射函数
|
||||||
|
const getStatusClass = (status) => {
|
||||||
|
if (status === -1) {
|
||||||
|
return 'status-pending'
|
||||||
|
} else if (status === 0) {
|
||||||
|
return 'status-completed'
|
||||||
|
} else {
|
||||||
|
return 'status-default'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 变量定义
|
* 变量定义
|
||||||
*/
|
*/
|
||||||
|
|
@ -194,9 +242,9 @@ let tableLoading = ref(false)
|
||||||
let tableData = ref([])
|
let tableData = ref([])
|
||||||
let baseTableQuery = reactive({
|
let baseTableQuery = reactive({
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 20, // 从10调整为20
|
||||||
total: 0,
|
total: 0,
|
||||||
sortBy: new Map([['goodsId', true]]),// 按照料号顺序排序
|
sortBy: new Map([['goodsId', true]]),
|
||||||
standId: STAND_ID,
|
standId: STAND_ID,
|
||||||
userName: USER_NAME
|
userName: USER_NAME
|
||||||
})
|
})
|
||||||
|
|
@ -234,18 +282,45 @@ const resizeHeight = () => {
|
||||||
maxHeight.value = window.innerHeight * 0.55
|
maxHeight.value = window.innerHeight * 0.55
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理选择变化
|
|
||||||
const handleSelectionChange = (row) => {
|
const handleSelectionChange = (row) => {
|
||||||
if (row.checked) {
|
if (row.checked) {
|
||||||
// 如果选中且不在列表中,则添加
|
// 如果选中且不在列表中,则添加
|
||||||
if (!selectedRows.value.some(item => item.goodsId === row.goodsId)) {
|
if (!selectedRows.value.some(item => item.taskId === row.taskId)) {
|
||||||
selectedRows.value.push(row)
|
selectedRows.value.push(row)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 如果取消选中,则从列表中移除
|
// 如果取消选中,则从列表中移除
|
||||||
selectedRows.value = selectedRows.value.filter(item => item.goodsId !== row.goodsId)
|
selectedRows.value = selectedRows.value.filter(item => item.taskId !== row.taskId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新全选状态
|
||||||
|
nextTick(() => {
|
||||||
|
// 这里计算属性会自动更新,不需要手动设置
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置选择状态
|
||||||
|
const resetSelection = () => {
|
||||||
|
selectedRows.value = []
|
||||||
|
if (tableData.value) {
|
||||||
|
tableData.value.forEach(row => {
|
||||||
|
row.checked = false
|
||||||
|
})
|
||||||
|
tableData.value = [...tableData.value]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 计算全选框的状态
|
||||||
|
const isSelectAll = computed(() => {
|
||||||
|
if (tableData.value.length === 0) return false
|
||||||
|
return tableData.value.length === selectedRows.value.length && tableData.value.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 计算是否部分选中
|
||||||
|
const isSelectIndeterminate = computed(() => {
|
||||||
|
return selectedRows.value.length > 0 && selectedRows.value.length < tableData.value.length
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
// 修改批量编辑处理函数
|
// 修改批量编辑处理函数
|
||||||
const handleBatchEdit = () => {
|
const handleBatchEdit = () => {
|
||||||
const permissionParams = {
|
const permissionParams = {
|
||||||
|
|
@ -280,21 +355,109 @@ const handleBatchEdit = () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSelectAllChange = (val) => {
|
|
||||||
tableData.value.forEach(row => {
|
|
||||||
row.checked = val
|
|
||||||
})
|
|
||||||
|
|
||||||
if (val) {
|
// 添加批量下发处理函数
|
||||||
// 全选
|
const handleBatchIssue = () => {
|
||||||
selectedRows.value = [...tableData.value]
|
const permissionParams = {
|
||||||
} else {
|
loginAccountUpdate: store.getters.getUser.loginAccount,
|
||||||
// 取消全选
|
roleIdOp: store.getters.getUser.roleId,
|
||||||
selectedRows.value = []
|
userName: USER_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getUserPermission(permissionParams).then(res => {
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
// 解析权限字符串,检查是否包含相应权限
|
||||||
|
const permissionStr = res.data.message || ''
|
||||||
|
if (!permissionStr.includes('B')) {
|
||||||
|
ElMessage.error('您没有批量下发的权限')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 有权限,继续执行原有逻辑
|
||||||
|
if (selectedRows.value.length === 0) {
|
||||||
|
ElMessage.warning('请至少选择一条记录')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认下发操作
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
`确定要批量下发这 ${selectedRows.value.length} 条任务吗?`,
|
||||||
|
'确认下发',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 获取选中行的taskIds
|
||||||
|
const taskIds = selectedRows.value.map(row => row.taskId)
|
||||||
|
const request = {
|
||||||
|
taskIds: taskIds,
|
||||||
|
}
|
||||||
|
// 调用批量下发接口
|
||||||
|
batchIssueTasks(request).then((res) => {
|
||||||
|
if (res.data.code === 0) {
|
||||||
|
ElMessage.success(res.data.message)
|
||||||
|
|
||||||
|
// 重置选择并刷新数据
|
||||||
|
resetSelection()
|
||||||
|
search()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.data.message || '批量下发失败')
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error('批量下发请求失败:', err)
|
||||||
|
ElMessage.error('批量下发请求失败')
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消操作
|
||||||
|
console.log('用户取消批量下发操作')
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.data.message || '权限检查失败')
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('权限检查失败:', err)
|
||||||
|
ElMessage.error('权限检查失败')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 清除选择状态
|
||||||
|
const clearSelection = () => {
|
||||||
|
// 清空选择数组
|
||||||
|
selectedRows.value = []
|
||||||
|
// 将表格中每行的checked状态设置为false
|
||||||
|
tableData.value.forEach(row => {
|
||||||
|
row.checked = false
|
||||||
|
})
|
||||||
|
// 触发强制更新
|
||||||
|
tableData.value = [...tableData.value] // 或者使用 nextTick 来确保更新
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleSelectAllChange = (val) => {
|
||||||
|
tableData.value.forEach(row => {
|
||||||
|
row.checked = val
|
||||||
|
// 确保同步更新selectedRows
|
||||||
|
if (val && !selectedRows.value.some(item => item.taskId === row.taskId)) {
|
||||||
|
selectedRows.value.push(row)
|
||||||
|
} else if (!val) {
|
||||||
|
selectedRows.value = selectedRows.value.filter(item => item.taskId !== row.taskId)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 强制更新视图
|
||||||
|
tableData.value = [...tableData.value]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 保存批量编辑
|
||||||
// 保存批量编辑
|
// 保存批量编辑
|
||||||
const saveBatchEdit = (form) => {
|
const saveBatchEdit = (form) => {
|
||||||
if (!form.pickingDate) {
|
if (!form.pickingDate) {
|
||||||
|
|
@ -308,16 +471,13 @@ const saveBatchEdit = (form) => {
|
||||||
pickingDate: form.pickingDate
|
pickingDate: form.pickingDate
|
||||||
}
|
}
|
||||||
|
|
||||||
// 需要在API中实现批量更新接口
|
|
||||||
batchEditDate(request).then((res) => {
|
batchEditDate(request).then((res) => {
|
||||||
if (res.data.code === 0) {
|
if (res.data.code === 0) {
|
||||||
ElMessage.success('批量修改成功')
|
ElMessage.success('批量修改成功')
|
||||||
showBatchEditDialog.value = false
|
showBatchEditDialog.value = false
|
||||||
|
resetSelection()
|
||||||
search()
|
search()
|
||||||
// 清空选择
|
// 清空选择状态
|
||||||
selectedRows.value.forEach(row => {
|
|
||||||
row.checked = false
|
|
||||||
})
|
|
||||||
selectedRows.value = []
|
selectedRows.value = []
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(res.data.message)
|
ElMessage.error(res.data.message)
|
||||||
|
|
@ -327,6 +487,7 @@ const saveBatchEdit = (form) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 保存编辑
|
// 保存编辑
|
||||||
const saveEdit = (editForm) => {
|
const saveEdit = (editForm) => {
|
||||||
let request = {
|
let request = {
|
||||||
|
|
@ -340,6 +501,7 @@ const saveEdit = (editForm) => {
|
||||||
type: 'success',
|
type: 'success',
|
||||||
});
|
});
|
||||||
search()
|
search()
|
||||||
|
clearSelection()
|
||||||
} else {
|
} else {
|
||||||
ElMessage({
|
ElMessage({
|
||||||
message: res.data.message,
|
message: res.data.message,
|
||||||
|
|
@ -422,7 +584,7 @@ const handleEdit = (row) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
editForm.taskId = row.taskId
|
editForm.taskId = row.taskId
|
||||||
// 使用 formatDateToDay 处理日期,避免时区问题
|
// 使用 formatDateToDay 处理日期,避免时区转换
|
||||||
editForm.pickingDate = row.pickingDate ? formatDateToDay(row.pickingDate) : ''
|
editForm.pickingDate = row.pickingDate ? formatDateToDay(row.pickingDate) : ''
|
||||||
showEditDialog.value = true
|
showEditDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
@ -457,8 +619,16 @@ const search = () => {
|
||||||
if (response.code === 0) {
|
if (response.code === 0) {
|
||||||
const data = response.data
|
const data = response.data
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
tableData.value = data.lists
|
// 重置每行的checked状态
|
||||||
|
const lists = data.lists.map(item => ({
|
||||||
|
...item,
|
||||||
|
checked: false
|
||||||
|
}))
|
||||||
|
tableData.value = lists
|
||||||
baseTableQuery.total = data.total
|
baseTableQuery.total = data.total
|
||||||
|
|
||||||
|
// 重置选择数组
|
||||||
|
selectedRows.value = []
|
||||||
} else {
|
} else {
|
||||||
tableData.value = []
|
tableData.value = []
|
||||||
baseTableQuery.total = 0
|
baseTableQuery.total = 0
|
||||||
|
|
@ -615,4 +785,37 @@ const exportExcel = () => {
|
||||||
margin: auto 5px 5px auto;
|
margin: auto 5px 5px auto;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
/* 任务状态样式 */
|
||||||
|
.status-pending {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #fa8c16;
|
||||||
|
border: 1px solid #ffd591;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-completed {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f6ffed;
|
||||||
|
color: #52c41a;
|
||||||
|
border: 1px solid #b7eb8f;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-default {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
color: #8c8c8c;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -82,9 +82,9 @@
|
||||||
|
|
||||||
<!-- 添加全局加载指示器 -->
|
<!-- 添加全局加载指示器 -->
|
||||||
<div v-if="showLoading" class="loading-overlay">
|
<div v-if="showLoading" class="loading-overlay">
|
||||||
<div class="loading-spinner">
|
<div class="loading-spinner-modern">
|
||||||
<i class="el-icon-loading"></i>
|
<div class="spinner"></div>
|
||||||
<p>处理中...</p>
|
<div class="text">数据请求中...</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-container>
|
</el-container>
|
||||||
|
|
@ -228,7 +228,7 @@ export default {
|
||||||
// 显示全局加载动画
|
// 显示全局加载动画
|
||||||
this.showLoading = true;
|
this.showLoading = true;
|
||||||
|
|
||||||
confirmCurrentTask(request, { timeout: 15000 }).then(res => {
|
confirmCurrentTask(request, { timeout: 60000 }).then(res => {
|
||||||
const responseData = res.data;
|
const responseData = res.data;
|
||||||
if (responseData.code === 0) {
|
if (responseData.code === 0) {
|
||||||
if (responseData.message === "继续拣选"){
|
if (responseData.message === "继续拣选"){
|
||||||
|
|
@ -489,6 +489,34 @@ export default {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 新增:更现代的加载动画 */
|
||||||
|
.loading-spinner-modern {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner-modern .spinner {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border: 5px solid rgba(255, 255, 255, 0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top-color: white;
|
||||||
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner-modern .text {
|
||||||
|
margin-top: 15px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
.highlight-pick-qty {
|
.highlight-pick-qty {
|
||||||
background-color: #dbeeff !important; /* 淡蓝色背景 */
|
background-color: #dbeeff !important; /* 淡蓝色背景 */
|
||||||
font-weight: bold !important; /* 加粗 */
|
font-weight: bold !important; /* 加粗 */
|
||||||
|
|
|
||||||
566
dev_wms_client/src/layout/pdaSecondIn.vue
Normal file
566
dev_wms_client/src/layout/pdaSecondIn.vue
Normal file
|
|
@ -0,0 +1,566 @@
|
||||||
|
<template>
|
||||||
|
<div class="pda-second-in">
|
||||||
|
<div class="header">
|
||||||
|
<h2>PDA扫码出库</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="scan-section">
|
||||||
|
<div class="input-group">
|
||||||
|
<label for="material-input">扫描物料条码:</label>
|
||||||
|
<input
|
||||||
|
id="material-input"
|
||||||
|
v-model="materialCode"
|
||||||
|
type="text"
|
||||||
|
placeholder="请扫描物料条码"
|
||||||
|
@keyup.enter="searchMaterial"
|
||||||
|
class="material-input"
|
||||||
|
/>
|
||||||
|
<button @click="searchMaterial" class="search-btn">搜索</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="loading" class="loading">查询中...</div>
|
||||||
|
<div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="materialInfo" class="material-info">
|
||||||
|
<h3>物料信息</h3>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="label">物料编号:</span>
|
||||||
|
<span class="value">{{ materialInfo.materialCode }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="label">物料名称:</span>
|
||||||
|
<span class="value">{{ materialInfo.materialName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="storageBoxes.length > 0" class="boxes-list">
|
||||||
|
<h3>可用库存箱</h3>
|
||||||
|
<div
|
||||||
|
v-for="(box, index) in storageBoxes"
|
||||||
|
:key="box.id"
|
||||||
|
class="box-item"
|
||||||
|
@click="selectBox(box)"
|
||||||
|
>
|
||||||
|
<div class="box-header">
|
||||||
|
<span class="box-id">箱号: {{ box.boxId }}</span>
|
||||||
|
<span class="box-location">库位: {{ box.location }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="box-details">
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">数量:</span>
|
||||||
|
<span class="value">{{ box.quantity }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">库存状态:</span>
|
||||||
|
<span class="value">{{ getStockStatusText(box.stockStatus) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="detail-row">
|
||||||
|
<span class="label">入库时间:</span>
|
||||||
|
<span class="value">{{ formatDate(box.inboundTime) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
:class="['outbound-btn',
|
||||||
|
selectedBox && selectedBox.id === box.id ? 'selected' : '',
|
||||||
|
box.stockStatus !== 0 ? 'disabled' : '']"
|
||||||
|
@click.stop="confirmOutbound(box)"
|
||||||
|
:disabled="box.stockStatus !== 0"
|
||||||
|
>
|
||||||
|
{{ box.stockStatus !== 0 ? '不可出库' : (selectedBox && selectedBox.id === box.id ? '已选择' : '出库') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else-if="materialInfo" class="no-data">
|
||||||
|
该物料暂无可用库存
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { ElMessageBox, ElMessage } from 'element-plus';
|
||||||
|
// 导入库存API
|
||||||
|
import {queryStocksBySpecial} from '@/api/stock';
|
||||||
|
// 导入任务API
|
||||||
|
import {pdaOutTask} from '@/api/task';
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const materialCode = ref('');
|
||||||
|
const materialInfo = ref(null);
|
||||||
|
const storageBoxes = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const errorMessage = ref('');
|
||||||
|
const selectedBox = ref(null);
|
||||||
|
|
||||||
|
// 调用后端API查询物料信息
|
||||||
|
const searchMaterial = async () => {
|
||||||
|
if (!materialCode.value.trim()) {
|
||||||
|
ElMessage.warning('请输入物料条码');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true;
|
||||||
|
errorMessage.value = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 调用后端API - 使用正确的参数名
|
||||||
|
const response = await queryStocksBySpecial({
|
||||||
|
goodsId: materialCode.value
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
// 成功获取数据
|
||||||
|
const result = response.data.data;
|
||||||
|
|
||||||
|
// 检查是否有分页数据结构
|
||||||
|
if (result && result.lists && Array.isArray(result.lists)) {
|
||||||
|
// 提取 lists 中的数据
|
||||||
|
const stockItems = result.lists;
|
||||||
|
|
||||||
|
// 如果有数据,设置物料信息
|
||||||
|
if (stockItems.length > 0) {
|
||||||
|
const firstItem = stockItems[0];
|
||||||
|
|
||||||
|
materialInfo.value = {
|
||||||
|
materialCode: materialCode.value,
|
||||||
|
materialName: firstItem.goodsDesc || '未知物料',
|
||||||
|
specification: firstItem.goodsId || '无规格',
|
||||||
|
unit: '个' // 假设单位为个,可根据实际情况调整
|
||||||
|
};
|
||||||
|
|
||||||
|
// 将库存数据转换为页面所需的箱子列表格式
|
||||||
|
storageBoxes.value = stockItems.map((item, index) => ({
|
||||||
|
id: item.stockId || `${materialCode.value}_${index}`,
|
||||||
|
boxId: item.vehicleId || `箱${index+1}`, // vehicleId是箱子ID
|
||||||
|
location: item.locationId || '未知库位',
|
||||||
|
quantity: item.remainNum || 0, // 使用 remainNum 作为数量
|
||||||
|
stockStatus: item.stockStatus, // 新增:库存状态
|
||||||
|
inboundTime: item.firstInTime || '' // 入库时间
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// 没有库存数据
|
||||||
|
materialInfo.value = {
|
||||||
|
materialCode: materialCode.value,
|
||||||
|
materialName: '未找到物料',
|
||||||
|
specification: '',
|
||||||
|
unit: ''
|
||||||
|
};
|
||||||
|
storageBoxes.value = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果没有分页结构,直接处理数组
|
||||||
|
if (result && Array.isArray(result)) {
|
||||||
|
materialInfo.value = {
|
||||||
|
materialCode: materialCode.value,
|
||||||
|
materialName: result[0]?.goodsDesc || '未知物料',
|
||||||
|
specification: result[0]?.goodsId || '无规格',
|
||||||
|
unit: '个'
|
||||||
|
};
|
||||||
|
|
||||||
|
storageBoxes.value = result.map((item, index) => ({
|
||||||
|
id: item.stockId || `${materialCode.value}_${index}`,
|
||||||
|
boxId: item.vehicleId || `箱${index+1}`,
|
||||||
|
location: item.locationId || '未知库位',
|
||||||
|
quantity: item.remainNum || 0,
|
||||||
|
stockStatus: item.stockStatus, // 新增:库存状态
|
||||||
|
inboundTime: item.firstInTime || ''
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// 没有数据
|
||||||
|
materialInfo.value = {
|
||||||
|
materialCode: materialCode.value,
|
||||||
|
materialName: '未找到物料',
|
||||||
|
specification: '',
|
||||||
|
unit: ''
|
||||||
|
};
|
||||||
|
storageBoxes.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// API返回错误
|
||||||
|
errorMessage.value = response.data.message || '查询失败';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false;
|
||||||
|
errorMessage.value = '查询失败: ' + error.message;
|
||||||
|
console.error('Error searching material:', error);
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 选择箱子
|
||||||
|
const selectBox = (box) => {
|
||||||
|
selectedBox.value = box;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认出库操作
|
||||||
|
const confirmOutbound = async (box) => {
|
||||||
|
// 检查库存状态,只允许出库状态为0的箱子
|
||||||
|
if (box.stockStatus !== 0) {
|
||||||
|
ElMessage.warning('该箱子有任务,无法执行操作');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await ElMessageBox.confirm(
|
||||||
|
`确认出库以下箱子?\n箱号: ${box.boxId}\n数量: ${box.quantity}`,
|
||||||
|
'确认出库',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result === 'confirm') {
|
||||||
|
// 调用实际的出库API - 传递vehicleId和origin参数
|
||||||
|
const response = await pdaOutTask({
|
||||||
|
vehicleId: box.boxId, // 载具号
|
||||||
|
origin: box.location // 库位
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
ElMessage.success('出库成功');
|
||||||
|
// 更新本地状态
|
||||||
|
storageBoxes.value = storageBoxes.value.filter(item => item.id !== box.id);
|
||||||
|
if (storageBoxes.value.length === 0) {
|
||||||
|
materialInfo.value = null;
|
||||||
|
}
|
||||||
|
selectedBox.value = null;
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.data.message || '出库失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
console.error('Outbound error:', error);
|
||||||
|
ElMessage.error('出库失败: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取库存状态文本
|
||||||
|
const getStockStatusText = (status) => {
|
||||||
|
return status === 0 ? '在库中' : status === 1 ? '出库中' : '未知状态';
|
||||||
|
};
|
||||||
|
|
||||||
|
// 格式化日期
|
||||||
|
const formatDate = (dateString) => {
|
||||||
|
if (!dateString) return '';
|
||||||
|
const date = new Date(dateString);
|
||||||
|
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.pda-second-in {
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding: 15px 0;
|
||||||
|
background: linear-gradient(to right, #409eff, #3a8ee6);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h2 {
|
||||||
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
font-size: 1.6em;
|
||||||
|
font-weight: 600;
|
||||||
|
text-shadow: 0 1px 2px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-section {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #e0e6ed;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center; /* 让子元素拉伸以填满容器 */
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.input-group label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-input {
|
||||||
|
padding: 14px;
|
||||||
|
font-size: 16px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 6px;
|
||||||
|
width: 300px; /* 修改:设置固定宽度 */
|
||||||
|
max-width: 100%; /* 防止在小屏幕上溢出 */
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.material-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #409eff;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn {
|
||||||
|
padding: 16px 0; /* 水平方向无内边距,垂直方向增加 */
|
||||||
|
font-size: 16px;
|
||||||
|
background: linear-gradient(to bottom, #409eff, #3a8ee6);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
display: block; /* 确保按钮为块级元素 */
|
||||||
|
width: 100%; /* 横向充满容器 */
|
||||||
|
text-align: center; /* 文字居中 */
|
||||||
|
box-sizing: border-box; /* 包含边框和内边距在内的总宽度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-btn:hover {
|
||||||
|
background: linear-gradient(to bottom, #3a8ee6, #337ecc);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
color: #606266;
|
||||||
|
font-style: italic;
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message {
|
||||||
|
color: #f56c6c;
|
||||||
|
padding: 12px;
|
||||||
|
background-color: #fef0f0;
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-top: 12px;
|
||||||
|
border-left: 4px solid #f56c6c;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-info {
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding: 20px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-info h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
color: #303133;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #409eff;
|
||||||
|
border-bottom: 2px solid #ebeef5;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px dashed #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #606266;
|
||||||
|
min-width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: #303133;
|
||||||
|
flex-grow: 1;
|
||||||
|
word-break: break-word;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boxes-list h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #303133;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.3em;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #409eff;
|
||||||
|
border-bottom: 2px solid #ebeef5;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 18px;
|
||||||
|
background-color: white;
|
||||||
|
position: relative;
|
||||||
|
transition: box-shadow 0.3s;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-item:hover {
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||||
|
border-color: #d2d9e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-id {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-location {
|
||||||
|
color: #606266;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-details {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row .label {
|
||||||
|
min-width: 80px;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-row .value {
|
||||||
|
flex-grow: 1;
|
||||||
|
color: #303133;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn {
|
||||||
|
position: absolute;
|
||||||
|
right: 18px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
background: linear-gradient(to bottom, #67c23a, #5daf34);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
font-weight: 500;
|
||||||
|
box-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn:hover:not(:disabled) {
|
||||||
|
background: linear-gradient(to bottom, #5daf34, #4a9e2a);
|
||||||
|
transform: translateY(calc(-50% - 1px));
|
||||||
|
box-shadow: 0 4px 8px rgba(103, 194, 58, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn.selected {
|
||||||
|
background: linear-gradient(to bottom, #409eff, #3a8ee6);
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn.selected:hover {
|
||||||
|
background: linear-gradient(to bottom, #3a8ee6, #337ecc);
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn.disabled {
|
||||||
|
background: linear-gradient(to bottom, #c0c4cc, #a8abb2);
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.7;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
padding: 40px 20px;
|
||||||
|
color: #909399;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.1em;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px dashed #ebeef5;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 适配移动端触摸操作 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.pda-second-in {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-input, .search-btn {
|
||||||
|
font-size: 17px;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-item {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outbound-btn {
|
||||||
|
padding: 12px 22px;
|
||||||
|
font-size: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header h2 {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-info, .scan-section {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-details {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
616
dev_wms_client/src/layout/stockMix.vue
Normal file
616
dev_wms_client/src/layout/stockMix.vue
Normal file
|
|
@ -0,0 +1,616 @@
|
||||||
|
<template>
|
||||||
|
<el-config-provider :locale="zhCn">
|
||||||
|
<el-container class="content">
|
||||||
|
<div class="work-area">
|
||||||
|
<fieldset class="search-area">
|
||||||
|
<el-form :model="summaryQuery" :label-position="labelPosition"
|
||||||
|
label-width="auto" style="max-width: 100%" status-icon>
|
||||||
|
<div style="display: flex;justify-content: space-between;">
|
||||||
|
<el-row>
|
||||||
|
<el-form-item label="料号">
|
||||||
|
<el-input v-model="summaryQuery.goodsId"
|
||||||
|
@keyup.enter="searchSummary()"
|
||||||
|
clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-row>
|
||||||
|
<div style="align-content: center;">
|
||||||
|
<el-row>
|
||||||
|
<el-button type="primary"
|
||||||
|
style="height: 30px; width: 80px; margin: auto 5px 5px auto; color: black;"
|
||||||
|
@click="searchSummary()">
|
||||||
|
查询汇总
|
||||||
|
</el-button>
|
||||||
|
<el-button type="warning"
|
||||||
|
style="height: 30px; width: 80px; margin: auto 5px 5px auto; color: black;"
|
||||||
|
@click="clearSummaryQuery()">
|
||||||
|
清除输入
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="table-area">
|
||||||
|
<el-table :data="summaryList"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
v-loading="tableLoading"
|
||||||
|
class="table-class"
|
||||||
|
:max-height="maxHeight"
|
||||||
|
:header-cell-style="{ 'text-align': 'center' }"
|
||||||
|
:cell-style="{ 'text-align': 'center' }">
|
||||||
|
<el-table-column prop="goodsId"
|
||||||
|
label="物料号"
|
||||||
|
min-width="150px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="goodsDesc"
|
||||||
|
label="物料描述"
|
||||||
|
min-width="200px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="remainNum"
|
||||||
|
label="总数量"
|
||||||
|
min-width="120px" />
|
||||||
|
<el-table-column prop="realNum"
|
||||||
|
label="条数"
|
||||||
|
min-width="100px" />
|
||||||
|
<el-table-column fixed="right"
|
||||||
|
label="操作"
|
||||||
|
width="120px">
|
||||||
|
<template v-slot="scope">
|
||||||
|
<el-button plain type="primary"
|
||||||
|
@click="showMergeDetails(scope.row)">
|
||||||
|
合并
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<el-pagination v-model:current-page="summaryTableQuery.currentPage"
|
||||||
|
v-model:page-size="summaryTableQuery.pageSize"
|
||||||
|
:page-sizes="[10, 25, 50]"
|
||||||
|
:small="false"
|
||||||
|
:disabled="false"
|
||||||
|
:background="false"
|
||||||
|
:default-page-size="10"
|
||||||
|
@size-change="searchSummary"
|
||||||
|
@current-change="searchSummary"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="summaryTableQuery.total" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 合并明细弹窗 -->
|
||||||
|
<el-dialog v-model="showMergeDialog"
|
||||||
|
title="合并明细"
|
||||||
|
width="80%"
|
||||||
|
:before-close="closeMergeDialog">
|
||||||
|
<el-descriptions :column="2" border>
|
||||||
|
<el-descriptions-item label="物料号">
|
||||||
|
{{ currentGoods.goodsId }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="物料描述">
|
||||||
|
{{ currentGoods.goodsDesc }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="总数量">
|
||||||
|
{{ currentGoods.remainNum }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="条数">
|
||||||
|
{{ currentGoods.realNum }}
|
||||||
|
</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
|
||||||
|
<el-table :data="detailList"
|
||||||
|
stripe
|
||||||
|
border
|
||||||
|
v-loading="detailLoading"
|
||||||
|
:max-height="maxHeight * 0.6"
|
||||||
|
:header-cell-style="{ 'text-align': 'center' }"
|
||||||
|
:cell-style="{ 'text-align': 'center' }"
|
||||||
|
style="margin-top: 20px;"
|
||||||
|
@selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection"
|
||||||
|
width="55" />
|
||||||
|
<el-table-column prop="vehicleId"
|
||||||
|
label="箱号"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="goodsId"
|
||||||
|
label="物料号"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="goodsDesc"
|
||||||
|
label="物料名称"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="locationId"
|
||||||
|
label="库位"
|
||||||
|
:formatter="locationFormat"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="totalNum"
|
||||||
|
label="入库数量"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="remainNum"
|
||||||
|
label="剩余可用数量"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="realNum"
|
||||||
|
label="实际剩余数量"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="goodsStatus"
|
||||||
|
label="物料状态"
|
||||||
|
:formatter="goodsStatusFormat"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
<el-table-column prop="stockStatus"
|
||||||
|
label="库存状态"
|
||||||
|
:formatter="stockStatusFormat"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip>
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="getStockStatusType(scope.row.stockStatus)">
|
||||||
|
{{ stockStatusFormat(scope.row) }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column prop="firstInTime"
|
||||||
|
label="上架时间"
|
||||||
|
:formatter="timeFormat"
|
||||||
|
min-width="120px"
|
||||||
|
show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button type="success"
|
||||||
|
style="height: 40px; width: 100px; color: black;"
|
||||||
|
@click="confirmMerge">
|
||||||
|
确认合并
|
||||||
|
</el-button>
|
||||||
|
<el-button type="warning"
|
||||||
|
style="height: 40px; width: 100px; color: black;"
|
||||||
|
@click="closeMergeDialog">
|
||||||
|
关闭
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 目标载具选择弹窗 -->
|
||||||
|
<el-dialog v-model="showTargetSelectDialog"
|
||||||
|
title="选择合并目标载具"
|
||||||
|
width="60%"
|
||||||
|
:before-close="closeTargetSelectDialog">
|
||||||
|
<p>请选择合并的目标载具(将其他选中载具的数据合并到此载具):</p>
|
||||||
|
|
||||||
|
<el-radio-group v-model="targetVehicle" style="width: 100%; margin-top: 20px;">
|
||||||
|
<el-row :gutter="10">
|
||||||
|
<el-col
|
||||||
|
v-for="item in multipleSelection"
|
||||||
|
:key="item.vehicleId"
|
||||||
|
:span="8"
|
||||||
|
style="margin-bottom: 10px;"
|
||||||
|
>
|
||||||
|
<el-card
|
||||||
|
:class="['vehicle-card', { 'selected-card': targetVehicle === item.vehicleId }]"
|
||||||
|
@click="selectTargetVehicle(item.vehicleId)"
|
||||||
|
shadow="hover"
|
||||||
|
>
|
||||||
|
<div class="vehicle-info">
|
||||||
|
<p><strong>载具:</strong> {{ item.vehicleId }}</p>
|
||||||
|
<p><strong>库位:</strong> {{ locationFormat(item, null, item.locationId) }}</p>
|
||||||
|
<p><strong>数量:</strong> {{ item.remainNum }}</p>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-radio-group>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="executeMerge" :disabled="!targetVehicle">
|
||||||
|
确认合并
|
||||||
|
</el-button>
|
||||||
|
<el-button @click="closeTargetSelectDialog">
|
||||||
|
取消
|
||||||
|
</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</el-container>
|
||||||
|
</el-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import store from '@/store'
|
||||||
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
|
import {querySpecialEmptyStocksForMix, queryStocksBySpecial} from '@/api/stock.js'
|
||||||
|
import {mergeStocks} from '@/api/task'
|
||||||
|
import { dateFormatter, locationFormatter, timeFormatter, yesOrNoFormatter } from '@/utils/formatter.js'
|
||||||
|
import { ref, reactive, onMounted, nextTick, onBeforeUnmount } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { genTableRequest, addAllOptionOfOptions } from '@/utils/generator.js'
|
||||||
|
import { labelPosition, shortcuts } from '@/constant/form'
|
||||||
|
import { stockStatusOptions, goodsStatusOptions } from '@/constant/options'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变量定义
|
||||||
|
*/
|
||||||
|
let maxHeight = ref(window.innerHeight * 0.55)
|
||||||
|
let tableLoading = ref(false)
|
||||||
|
let detailLoading = ref(false)
|
||||||
|
let showMergeDialog = ref(false)
|
||||||
|
let showTargetSelectDialog = ref(false)
|
||||||
|
let targetVehicle = ref('')
|
||||||
|
|
||||||
|
// 汇总页面数据
|
||||||
|
let summaryList = ref([])
|
||||||
|
let summaryTableQuery = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
sortBy: new Map([['goodsId', true]]),
|
||||||
|
standId: store.getters.getStandId,
|
||||||
|
userName: store.getters.getUserName
|
||||||
|
})
|
||||||
|
let summaryQuery = reactive({
|
||||||
|
goodsId: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 明细页面数据
|
||||||
|
let currentGoods = ref({}) // 当前查看的物料信息
|
||||||
|
let detailList = ref([]) // 明细列表
|
||||||
|
let multipleSelection = ref([]) // 多选的行数据
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统方法
|
||||||
|
*/
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
window.addEventListener('resize', resizeHeight)
|
||||||
|
searchSummary()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
window.removeEventListener('resize', resizeHeight)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const resizeHeight = () => {
|
||||||
|
maxHeight.value = window.innerHeight * 0.55
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自定义方法
|
||||||
|
*/
|
||||||
|
// 处理多选变化
|
||||||
|
const handleSelectionChange = (val) => {
|
||||||
|
multipleSelection.value = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// 汇总查询
|
||||||
|
const searchSummary = () => {
|
||||||
|
tableLoading.value = true
|
||||||
|
let request = genTableRequest(summaryTableQuery)
|
||||||
|
request.goodsId = summaryQuery.goodsId.trim()
|
||||||
|
|
||||||
|
querySpecialEmptyStocksForMix(request).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
const data = response.data
|
||||||
|
if (data != null) {
|
||||||
|
summaryList.value = data.lists
|
||||||
|
summaryTableQuery.total = data.total
|
||||||
|
} else {
|
||||||
|
summaryList.value = []
|
||||||
|
summaryTableQuery.total = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
ElMessage.error('查询物料汇总信息异常。')
|
||||||
|
}).finally(() => {
|
||||||
|
tableLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示合并明细弹窗
|
||||||
|
const showMergeDetails = (row) => {
|
||||||
|
currentGoods.value = { ...row }
|
||||||
|
loadDetails(row.goodsId)
|
||||||
|
showMergeDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载明细数据
|
||||||
|
const loadDetails = (goodsId) => {
|
||||||
|
detailLoading.value = true
|
||||||
|
const request = {
|
||||||
|
goodsId: goodsId,
|
||||||
|
standId: store.getters.getStandId,
|
||||||
|
pageSize: 9999
|
||||||
|
}
|
||||||
|
|
||||||
|
queryStocksBySpecial(request).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
detailList.value = response.data?.lists || []
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message)
|
||||||
|
detailList.value = []
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
ElMessage.error('查询明细信息异常。')
|
||||||
|
detailList.value = []
|
||||||
|
}).finally(() => {
|
||||||
|
detailLoading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认合并
|
||||||
|
const confirmMerge = () => {
|
||||||
|
if (multipleSelection.value.length === 0) {
|
||||||
|
ElMessage.warning('请至少选择一条记录进行合并')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (multipleSelection.value.length === 1) {
|
||||||
|
ElMessage.warning('请选择至少两条记录进行合并')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开目标载具选择弹窗
|
||||||
|
showTargetSelectDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择目标载具
|
||||||
|
const selectTargetVehicle = (vehicleId) => {
|
||||||
|
targetVehicle.value = vehicleId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行合并
|
||||||
|
const executeMerge = () => {
|
||||||
|
if (!targetVehicle.value) {
|
||||||
|
ElMessage.warning('请选择目标载具')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessageBox.confirm(
|
||||||
|
`确认将选中的 ${multipleSelection.value.length} 条记录合并到载具 ${targetVehicle.value} 吗?`,
|
||||||
|
'确认合并',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
).then(() => {
|
||||||
|
// 构建符合后端 MixStockRequest 结构的参数
|
||||||
|
const stockItems = multipleSelection.value.map(item => ({
|
||||||
|
vehicleNo: item.vehicleId, // 对应后端 vehicleNo 字段
|
||||||
|
materialNo: item.goodsId // 对应后端 materialNo 字段
|
||||||
|
}));
|
||||||
|
|
||||||
|
const mergeParams = {
|
||||||
|
stockItems: stockItems, // 对应后端 stockItems 字段
|
||||||
|
bindBoxNo: targetVehicle.value, // 对应后端 bindBoxNo 字段
|
||||||
|
standId: store.getters.getStandId // 保留必要的其他参数
|
||||||
|
};
|
||||||
|
|
||||||
|
mergeStocks(mergeParams).then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
ElMessage.success('合并操作成功')
|
||||||
|
closeTargetSelectDialog()
|
||||||
|
closeMergeDialog()
|
||||||
|
// 刷新汇总列表
|
||||||
|
searchSummary()
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
ElMessage.error('合并操作失败')
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
// 用户取消操作
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭合并弹窗
|
||||||
|
const closeMergeDialog = () => {
|
||||||
|
showMergeDialog.value = false
|
||||||
|
detailList.value = []
|
||||||
|
currentGoods.value = {}
|
||||||
|
multipleSelection.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 关闭目标载具选择弹窗
|
||||||
|
const closeTargetSelectDialog = () => {
|
||||||
|
showTargetSelectDialog.value = false
|
||||||
|
targetVehicle.value = ''
|
||||||
|
// 重置多选状态
|
||||||
|
multipleSelection.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除汇总查询条件
|
||||||
|
const clearSummaryQuery = () => {
|
||||||
|
summaryQuery.goodsId = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化函数
|
||||||
|
const locationFormat = (row, column, cellValue, index) => {
|
||||||
|
return locationFormatter(cellValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeFormat = (row, column, cellValue, index) => {
|
||||||
|
return timeFormatter(cellValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
const goodsStatusFormat = (row, column, cellValue, index) => {
|
||||||
|
if (cellValue === 0) {
|
||||||
|
return '正常'
|
||||||
|
} else if (cellValue === 1) {
|
||||||
|
return '不合格'
|
||||||
|
} else if (cellValue === 2) {
|
||||||
|
return '延期'
|
||||||
|
} else if (cellValue === 3) {
|
||||||
|
return '过期'
|
||||||
|
} else if (cellValue === 5) {
|
||||||
|
return '长时间未使用'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取库存状态标签类型
|
||||||
|
const getStockStatusType = (status) => {
|
||||||
|
switch (status) {
|
||||||
|
case 0: // 在库中
|
||||||
|
return 'success'
|
||||||
|
case 1: // 出库中
|
||||||
|
return 'warning'
|
||||||
|
case 2: // 已出库
|
||||||
|
return 'info'
|
||||||
|
case 3: // 回库中
|
||||||
|
return 'primary'
|
||||||
|
case 4: // 盘点中
|
||||||
|
return 'warning'
|
||||||
|
case 9: // 库存锁定
|
||||||
|
return 'danger'
|
||||||
|
default:
|
||||||
|
return 'info'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const stockStatusFormat = (row, column, cellValue, index) => {
|
||||||
|
// 如果是作为 el-table 的 formatter 使用,cellValue 是实际的状态值
|
||||||
|
// 如果是作为模板中的函数调用,row 是整个行对象
|
||||||
|
let statusValue;
|
||||||
|
|
||||||
|
// 判断调用方式,如果是表格列的 formatter,则使用 cellValue
|
||||||
|
if (arguments.length >= 3) {
|
||||||
|
statusValue = cellValue;
|
||||||
|
} else {
|
||||||
|
// 如果是模板中的直接调用,则从 row 对象获取 stockStatus
|
||||||
|
statusValue = row.stockStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (statusValue) {
|
||||||
|
case 0:
|
||||||
|
return '在库中';
|
||||||
|
case 1:
|
||||||
|
return '出库中';
|
||||||
|
case 2:
|
||||||
|
return '已出库';
|
||||||
|
case 3:
|
||||||
|
return '回库中';
|
||||||
|
case 4:
|
||||||
|
return '盘点中';
|
||||||
|
case 9:
|
||||||
|
return '库存锁定';
|
||||||
|
default:
|
||||||
|
return '异常';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-area {
|
||||||
|
width: 100%;
|
||||||
|
/* padding: 5px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-area {
|
||||||
|
margin: auto;
|
||||||
|
min-height: fit-content;
|
||||||
|
max-height: 40%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-width: inherit;
|
||||||
|
border: solid 1px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 15px 10px -15px #000;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-area {
|
||||||
|
margin: auto;
|
||||||
|
min-height: fit-content;
|
||||||
|
max-height: 60%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-width: inherit;
|
||||||
|
border: solid 1px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 15px 10px -15px #000;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin: 5px 5px 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item .el-input {
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-class {
|
||||||
|
margin: 5px 5px 5px 5px;
|
||||||
|
width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-pagination {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: right;
|
||||||
|
padding: 20px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer .el-button {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 新增样式 */
|
||||||
|
.vehicle-card {
|
||||||
|
cursor: pointer;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
height: 100px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vehicle-card:hover {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-card {
|
||||||
|
border-color: #409eff;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vehicle-info p {
|
||||||
|
margin: 5px 0;
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
402
dev_wms_client/src/layout/stockMixConfirm.vue
Normal file
402
dev_wms_client/src/layout/stockMixConfirm.vue
Normal file
|
|
@ -0,0 +1,402 @@
|
||||||
|
<template>
|
||||||
|
<el-config-provider :locale="zhCn">
|
||||||
|
<el-container class="content">
|
||||||
|
<div class="work-area">
|
||||||
|
<div style="display: flex; margin-top: 10px;">
|
||||||
|
<div v-for="(entity, index) in confirmEntities" :key="index" style="width: 32%; margin: 0 10px;">
|
||||||
|
<fieldset class="confirm-area">
|
||||||
|
<div style="text-align: center; font-size: 18px; font-weight: bold; margin-bottom: 0; color: #333;">
|
||||||
|
{{ getChildStandIdByIndex(index) }}
|
||||||
|
</div>
|
||||||
|
<el-form ref="confirmRef" :model="entity" :label-position="labelPosition" label-width="158px"
|
||||||
|
style="max-width: 100%" :rules="confirmRules" status-icon>
|
||||||
|
<div style="display: flex; flex-wrap: wrap;">
|
||||||
|
<div style="width: 50%; display: flex; flex-direction: column;">
|
||||||
|
<el-form-item label="合并任务号" prop="mixTaskId">
|
||||||
|
<el-input v-model="entity.mixTaskId" disabled/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="原载具号" prop="sourceVehicleId">
|
||||||
|
<el-input v-model="entity.sourceVehicleId" disabled/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="系统数量" prop="stockNum">
|
||||||
|
<el-input v-model="entity.stockNum" disabled/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
<div style="width: 50%; display: flex; flex-direction: column;">
|
||||||
|
<el-form-item label="物料号" prop="goodsId">
|
||||||
|
<el-input v-model="entity.goodsId" disabled/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="合并目标箱号" prop="targetVehicleId">
|
||||||
|
<el-input v-model="entity.targetVehicleId"
|
||||||
|
@input="onTargetVehicleIdChange(entity)"
|
||||||
|
disabled/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="确认数量" prop="confirmNum">
|
||||||
|
<el-input-number
|
||||||
|
style="width: 196px"
|
||||||
|
v-model.number="entity.confirmNum"
|
||||||
|
controls-position="right"
|
||||||
|
:min="0"
|
||||||
|
:max="entity.stockNum"
|
||||||
|
:precision="0"/>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: center; gap: 80px; margin-top: 20px;">
|
||||||
|
<el-button
|
||||||
|
:type="isSameVehicle(entity) ? 'success' : 'warning'"
|
||||||
|
style="height: 50px; width: 100px; margin: auto 5px auto 5px; font-size: large; color: black;"
|
||||||
|
@click="confirmOrRelease(index)">
|
||||||
|
确认合并
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-container>
|
||||||
|
</el-config-provider>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import store from '@/store'
|
||||||
|
import {nextTick, onBeforeUnmount, onMounted, reactive, ref, watch, h} from 'vue'
|
||||||
|
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import {errorBox, warningBox} from "@/utils/myMessageBox";
|
||||||
|
import {ElMessage, ElMessageBox} from "element-plus";
|
||||||
|
import {labelPosition} from "@/constant/form";
|
||||||
|
import {loading} from "@/utils/loading";
|
||||||
|
import {getInventoryConfirm, confirmMixStock} from '@/api/task'; // 使用盘点相关的API
|
||||||
|
|
||||||
|
const STAND_ID = store.getters.getStandId
|
||||||
|
const USER_NAME = store.getters.getUserName
|
||||||
|
let timer = ref()
|
||||||
|
const route = useRoute()// 路由
|
||||||
|
let confirmRef = ref()
|
||||||
|
|
||||||
|
// 创建三个确认实体
|
||||||
|
let confirmEntities = reactive([
|
||||||
|
{
|
||||||
|
mixTaskId: '',
|
||||||
|
sourceVehicleId: '',
|
||||||
|
targetVehicleId: '',
|
||||||
|
goodsId: '',
|
||||||
|
stockNum: null,
|
||||||
|
confirmNum: 0, // 默认设置为0
|
||||||
|
locationId: '',
|
||||||
|
status: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mixTaskId: '',
|
||||||
|
sourceVehicleId: '',
|
||||||
|
targetVehicleId: '',
|
||||||
|
goodsId: '',
|
||||||
|
stockNum: null,
|
||||||
|
confirmNum: 0, // 默认设置为0
|
||||||
|
locationId: '',
|
||||||
|
status: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mixTaskId: '',
|
||||||
|
sourceVehicleId: '',
|
||||||
|
targetVehicleId: '',
|
||||||
|
goodsId: '',
|
||||||
|
stockNum: null,
|
||||||
|
confirmNum: 0, // 默认设置为0
|
||||||
|
locationId: '',
|
||||||
|
status: ''
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const confirmRules = reactive({})
|
||||||
|
let pauseGetPickFlag = ref(false)
|
||||||
|
|
||||||
|
// 系统
|
||||||
|
onMounted(() => {
|
||||||
|
nextTick(() => {
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
timerTask_1()
|
||||||
|
}, 1000)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(timer.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监视路由
|
||||||
|
watch(() => route.path, (newVal, oldVal) => {
|
||||||
|
if (newVal === '/stockMixConfirm') {
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
timerTask_1()
|
||||||
|
}, 1000)
|
||||||
|
} else {
|
||||||
|
clearInterval(timer.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定时器任务1
|
||||||
|
const timerTask_1 = () => {
|
||||||
|
// 查询合并任务列表
|
||||||
|
getMixTasks()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询合并任务信息 - 使用盘点接口
|
||||||
|
const getMixTasks = () => {
|
||||||
|
if (pauseGetPickFlag.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据主站台ID确定需要显示的子站台顺序
|
||||||
|
let childStandOrder = []
|
||||||
|
if (STAND_ID === 'P1') {
|
||||||
|
childStandOrder = ['P13', 'P12', 'P11']
|
||||||
|
} else if (STAND_ID === 'P2') {
|
||||||
|
childStandOrder = ['P16', 'P15', 'P14']
|
||||||
|
} else if (STAND_ID === 'P3') {
|
||||||
|
childStandOrder = ['P19', 'P18', 'P17']
|
||||||
|
} else {
|
||||||
|
childStandOrder = ['P23', 'P22', 'P21']
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有子站台的合并任务信息
|
||||||
|
const promises = childStandOrder.map(standId => {
|
||||||
|
const request = {
|
||||||
|
standId: standId,
|
||||||
|
userName: USER_NAME
|
||||||
|
}
|
||||||
|
// 使用盘点确认接口
|
||||||
|
return getInventoryConfirm(request)
|
||||||
|
})
|
||||||
|
|
||||||
|
Promise.all(promises).then(responses => {
|
||||||
|
responses.forEach((res, index) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
const confirmVo = response.data
|
||||||
|
const entity = confirmEntities[index]
|
||||||
|
|
||||||
|
// 保存用户输入的确认数量
|
||||||
|
const userInputConfirmNum = entity.confirmNum
|
||||||
|
|
||||||
|
entity.mixTaskId = confirmVo.inventoryId || ''
|
||||||
|
entity.sourceVehicleId = confirmVo.vehicleId || ''
|
||||||
|
entity.targetVehicleId = confirmVo.mixVehicle || ''
|
||||||
|
entity.goodsId = confirmVo.goodsId || ''
|
||||||
|
entity.stockNum = confirmVo.stockNum || null
|
||||||
|
entity.locationId = confirmVo.locationId || ''
|
||||||
|
entity.status = confirmVo.status || '待合并'
|
||||||
|
|
||||||
|
// 根据载具是否相同设置确认数量
|
||||||
|
if (isDifferentVehicle(entity)) {
|
||||||
|
// 载具不同时,默认为0,但保留用户输入的值
|
||||||
|
if (userInputConfirmNum !== null && userInputConfirmNum !== undefined) {
|
||||||
|
entity.confirmNum = userInputConfirmNum
|
||||||
|
} else {
|
||||||
|
entity.confirmNum = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 载具相同时,优先使用服务器返回的值,否则保留用户输入
|
||||||
|
entity.confirmNum = confirmVo.confirmNum || userInputConfirmNum || 0
|
||||||
|
}
|
||||||
|
} else if (response.code === 400) {
|
||||||
|
// 警告,清空对应实体
|
||||||
|
clearConfirmEntity(index)
|
||||||
|
warningBox(response.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pauseGetPickFlag.value = true
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
pauseGetPickFlag.value = true
|
||||||
|
errorBox('请求错误,请检查完原因后刷新界面。')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据索引获取子站台ID
|
||||||
|
const getChildStandIdByIndex = (index) => {
|
||||||
|
// 根据主站台ID确定需要显示的子站台顺序
|
||||||
|
let childStandOrder = []
|
||||||
|
if (STAND_ID === 'P1') {
|
||||||
|
childStandOrder = ['P13', 'P12', 'P11']
|
||||||
|
} else if (STAND_ID === 'P2') {
|
||||||
|
childStandOrder = ['P16', 'P15', 'P14']
|
||||||
|
} else if (STAND_ID === 'P3') {
|
||||||
|
childStandOrder = ['P19', 'P18', 'P17']
|
||||||
|
} else {
|
||||||
|
childStandOrder = ['P23', 'P22', 'P21']
|
||||||
|
}
|
||||||
|
|
||||||
|
return childStandOrder[index] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空指定索引的确认信息
|
||||||
|
const clearConfirmEntity = (index) => {
|
||||||
|
if (index >= 0 && index < confirmEntities.length) {
|
||||||
|
const entity = confirmEntities[index]
|
||||||
|
entity.mixTaskId = ''
|
||||||
|
entity.sourceVehicleId = ''
|
||||||
|
entity.targetVehicleId = ''
|
||||||
|
entity.goodsId = ''
|
||||||
|
entity.stockNum = null
|
||||||
|
entity.confirmNum = 0 // 重置为默认值
|
||||||
|
entity.locationId = ''
|
||||||
|
entity.status = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断原载具号与合并目标箱号是否相同
|
||||||
|
const isSameVehicle = (entity) => {
|
||||||
|
return entity.sourceVehicleId && entity.targetVehicleId &&
|
||||||
|
entity.sourceVehicleId === entity.targetVehicleId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断原载具号与合并目标箱号是否不同
|
||||||
|
const isDifferentVehicle = (entity) => {
|
||||||
|
return entity.sourceVehicleId && entity.targetVehicleId &&
|
||||||
|
entity.sourceVehicleId !== entity.targetVehicleId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当目标载具号改变时的处理
|
||||||
|
const onTargetVehicleIdChange = (entity) => {
|
||||||
|
// 不再自动重置确认数量,让用户体验更好
|
||||||
|
// 用户可以根据实际情况手动调整确认数量
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改确认合并函数
|
||||||
|
const confirmOrRelease = async (index) => {
|
||||||
|
const entity = confirmEntities[index]
|
||||||
|
|
||||||
|
// 根据载具号是否相同决定不同的确认逻辑
|
||||||
|
if (isDifferentVehicle(entity)) {
|
||||||
|
// 原载具号与合并目标箱号不同时,提示用户放置物料到目标容器
|
||||||
|
try {
|
||||||
|
await ElMessageBox({
|
||||||
|
title: '操作提示',
|
||||||
|
message: h('div', null, [
|
||||||
|
h('p', { style: 'font-size: 16px; color: #333; margin-bottom: 10px;' }, '请将物料从原载具'),
|
||||||
|
h('p', { style: 'font-size: 18px; color: #f56c6c; font-weight: bold; margin: 10px 0;' }, entity.sourceVehicleId),
|
||||||
|
h('p', { style: 'font-size: 16px; color: #333; margin-top: 10px;' }, '转移到目标容器'),
|
||||||
|
h('p', { style: 'font-size: 18px; color: #409eff; font-weight: bold; margin: 10px 0;' }, entity.targetVehicleId),
|
||||||
|
h('p', { style: 'font-size: 14px; color: #909399; margin-top: 15px;' }, `确认已放置后点击确定继续操作,当前确认数量:${entity.confirmNum}`)
|
||||||
|
]),
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 保留用户输入的确认数量,不自动设为0
|
||||||
|
} catch {
|
||||||
|
// 用户取消操作
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if (isSameVehicle(entity)) {
|
||||||
|
// 原载具号与合并目标箱号相同时,需要弹窗确认合并操作
|
||||||
|
try {
|
||||||
|
await ElMessageBox({
|
||||||
|
title: '确认合并',
|
||||||
|
message: h('div', null, [
|
||||||
|
h('p', { style: 'font-size: 16px; color: #333; margin-bottom: 10px;' }, '请核对好数量!'),
|
||||||
|
h('p', { style: 'font-size: 18px; color: #e6a23c; font-weight: bold; margin: 10px 0;' }, `当前确认数量:${entity.confirmNum}`),
|
||||||
|
]),
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
} catch {
|
||||||
|
// 用户取消操作
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证确认数量是否有效
|
||||||
|
if (entity.confirmNum === null || entity.confirmNum < 0 || entity.confirmNum > entity.stockNum) {
|
||||||
|
ElMessage.error(`请填写有效的确认数量(0-${entity.stockNum})`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果目标载具号为空,不允许操作
|
||||||
|
ElMessage.error('请填写合并目标箱号')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认合并
|
||||||
|
const request = {
|
||||||
|
inventoryId: entity.mixTaskId,
|
||||||
|
vehicleId: entity.sourceVehicleId,
|
||||||
|
targetVehicleId: entity.targetVehicleId,
|
||||||
|
goodsId: entity.goodsId,
|
||||||
|
confirmNum: entity.confirmNum,
|
||||||
|
needAddNum: entity.stockNum - entity.confirmNum,
|
||||||
|
standId: getChildStandIdByIndex(index),
|
||||||
|
userName: USER_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.open('处理中...')
|
||||||
|
|
||||||
|
confirmMixStock(request).then(res => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.code === 0) {
|
||||||
|
clearConfirmEntity(index)
|
||||||
|
ElMessage.success(response.message)
|
||||||
|
pauseGetPickFlag.value = false
|
||||||
|
// 刷新列表
|
||||||
|
getMixTasks()
|
||||||
|
} else if (response.code === 400) {
|
||||||
|
clearConfirmEntity(index)
|
||||||
|
warningBox(response.message)
|
||||||
|
pauseGetPickFlag.value = false
|
||||||
|
} else {
|
||||||
|
errorBox(response.message)
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
console.log(err)
|
||||||
|
errorBox('请求错误,请检查完原因后刷新界面。')
|
||||||
|
}).finally(() => {
|
||||||
|
loading.close()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.work-area {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-area {
|
||||||
|
margin: auto;
|
||||||
|
min-height: fit-content;
|
||||||
|
max-height: 100%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
min-width: inherit;
|
||||||
|
border: solid 1px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0px 15px 10px -15px #000;
|
||||||
|
overflow: auto;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
margin: 10px 5px 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-form-item .el-input {
|
||||||
|
width: 196px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-class {
|
||||||
|
margin: 5px 5px 5px 5px;
|
||||||
|
width: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 特殊库存字段标红醒目显示 */
|
||||||
|
.special-inventory-item :deep(.el-form-item__label) {
|
||||||
|
color: #ff8888;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
343
dev_wms_client/src/layout/wmsChart.vue
Normal file
343
dev_wms_client/src/layout/wmsChart.vue
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
<template>
|
||||||
|
<el-container class="chart-container">
|
||||||
|
<el-main>
|
||||||
|
<div class="chart-header">
|
||||||
|
<h2>仓库数据分析图表</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 每日出入库数量图表 -->
|
||||||
|
<el-card class="chart-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>每日出入库数量统计</span>
|
||||||
|
<div class="chart-controls">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="dateRange"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
format="YYYY-MM-DD"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
@change="fetchDailyData"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="fetchDailyData"
|
||||||
|
style="margin-left: 10px;"
|
||||||
|
>
|
||||||
|
刷新数据
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div id="daily-chart" class="chart"></div>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<!-- 在库时间数量图表 -->
|
||||||
|
<el-card class="chart-card">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>库存龄期分布统计</span>
|
||||||
|
<div class="chart-controls">
|
||||||
|
<!-- <el-select-->
|
||||||
|
<!-- v-model="agingPeriod"-->
|
||||||
|
<!-- placeholder="选择统计周期"-->
|
||||||
|
<!-- @change="fetchAgingData"-->
|
||||||
|
<!-- style="margin-right: 10px;"-->
|
||||||
|
<!-- >-->
|
||||||
|
<!-- <el-option label="按天统计" value="daily" />-->
|
||||||
|
<!-- <el-option label="按周统计" value="weekly" />-->
|
||||||
|
<!-- <el-option label="按月统计" value="monthly" />-->
|
||||||
|
<!-- </el-select>-->
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="fetchAgingData"
|
||||||
|
>
|
||||||
|
刷新数据
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div id="aging-chart" class="chart"></div>
|
||||||
|
</el-card>
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, nextTick } from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
// 导入现有API
|
||||||
|
import { queryInOutBoundStatistics, queryStockAgeDistribution } from '@/api/task'
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const dailyChartRef = ref(null)
|
||||||
|
const agingChartRef = ref(null)
|
||||||
|
const dateRange = ref([])
|
||||||
|
const agingPeriod = ref('daily')
|
||||||
|
|
||||||
|
// 图表实例
|
||||||
|
let dailyChart = null
|
||||||
|
let agingChart = null
|
||||||
|
|
||||||
|
// 默认日期范围为最近30天
|
||||||
|
const getDefaultDateRange = () => {
|
||||||
|
const endDate = new Date()
|
||||||
|
const startDate = new Date()
|
||||||
|
startDate.setDate(endDate.getDate() - 30)
|
||||||
|
return [
|
||||||
|
startDate.toISOString().split('T')[0],
|
||||||
|
endDate.toISOString().split('T')[0]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成测试数据 - 库存龄期数据
|
||||||
|
const generateAgingTestData = () => {
|
||||||
|
return [
|
||||||
|
{ name: '0-7天', value: Math.floor(Math.random() * 100) + 100 },
|
||||||
|
{ name: '8-30天', value: Math.floor(Math.random() * 80) + 80 },
|
||||||
|
{ name: '1-3个月', value: Math.floor(Math.random() * 50) + 40 },
|
||||||
|
{ name: '3-6个月', value: Math.floor(Math.random() * 30) + 20 },
|
||||||
|
{ name: '6个月以上', value: Math.floor(Math.random() * 20) + 10 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化日期范围
|
||||||
|
onMounted(async () => {
|
||||||
|
dateRange.value = getDefaultDateRange()
|
||||||
|
|
||||||
|
await nextTick()
|
||||||
|
initCharts()
|
||||||
|
fetchDailyData()
|
||||||
|
fetchAgingData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化图表
|
||||||
|
const initCharts = () => {
|
||||||
|
dailyChart = echarts.init(document.getElementById('daily-chart'))
|
||||||
|
agingChart = echarts.init(document.getElementById('aging-chart'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取每日出入库数据(使用现有API)
|
||||||
|
const fetchDailyData = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
startDate: dateRange.value[0],
|
||||||
|
endDate: dateRange.value[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await queryInOutBoundStatistics(params)
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
renderDailyChart(response.data.data)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.data.message || '获取数据失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取每日出入库数据失败:', error)
|
||||||
|
ElMessage.error('获取数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染每日出入库图表
|
||||||
|
const renderDailyChart = (data) => {
|
||||||
|
const option = {
|
||||||
|
title: {
|
||||||
|
text: '每日出入库数量趋势',
|
||||||
|
subtext: `数据更新时间: ${new Date().toLocaleString()}`,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16
|
||||||
|
},
|
||||||
|
subtextStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#666'
|
||||||
|
},
|
||||||
|
top: '0%', // 调整标题位置,提供更多空间
|
||||||
|
left: 'center' // 居中对齐
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'shadow' // 修改: 使用阴影模式,更适合柱状图
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ['入库数量', '出库数量'],
|
||||||
|
top: '12%', // 调整图例位置,避免与标题重叠
|
||||||
|
left: 'center' // 居中对齐
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
feature: {
|
||||||
|
saveAsImage: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '3%',
|
||||||
|
right: '4%',
|
||||||
|
top: '20%', // 调整网格顶部边距,为标题和图例留出空间
|
||||||
|
bottom: '3%',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: true, // 修改: 对于柱状图设置为true,使柱子不贴边
|
||||||
|
data: data.dates
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '数量'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '入库数量',
|
||||||
|
type: 'bar',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: data.inbound
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '出库数量',
|
||||||
|
type: 'bar',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series'
|
||||||
|
},
|
||||||
|
data: data.outbound
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
dailyChart.setOption(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 获取库存龄期数据(使用测试数据)
|
||||||
|
const fetchAgingData = async () => {
|
||||||
|
try {
|
||||||
|
// 调用后端API获取数据
|
||||||
|
const response = await queryStockAgeDistribution({})
|
||||||
|
if (response.data.code === 0) {
|
||||||
|
renderAgingChart(response.data.data)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.data.message || '获取数据失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取库存龄期数据失败:', error)
|
||||||
|
ElMessage.error('获取数据失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 渲染库存龄期图表
|
||||||
|
const renderAgingChart = (data) => {
|
||||||
|
const option = {
|
||||||
|
title: {
|
||||||
|
text: '库存龄期分布统计',
|
||||||
|
subtext: `统计周期: ${getPeriodText(agingPeriod.value)}`,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16
|
||||||
|
},
|
||||||
|
subtextStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: '#666'
|
||||||
|
},
|
||||||
|
top: '1%', // 调整标题位置,向上移动
|
||||||
|
left: 'center' // 居中对齐
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/}{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
orient: 'vertical',
|
||||||
|
left: 'left',
|
||||||
|
top: '8%' // 调整图例位置
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '库存龄期',
|
||||||
|
type: 'pie',
|
||||||
|
radius: ['40%', '70%'],
|
||||||
|
center: ['60%', '60%'], // 调整饼图中心位置,向下移动(从50%改为55%)
|
||||||
|
avoidLabelOverlap: false,
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: 10,
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
formatter: '{b}: {c} ({d}%)'
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
fontSize: '18',
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: true
|
||||||
|
},
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
agingChart.setOption(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取周期文本
|
||||||
|
const getPeriodText = (period) => {
|
||||||
|
switch(period) {
|
||||||
|
case 'daily': return '按天统计'
|
||||||
|
case 'weekly': return '按周统计'
|
||||||
|
case 'monthly': return '按月统计'
|
||||||
|
default: return '未知周期'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面大小改变时重新调整图表大小
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
if (dailyChart) dailyChart.resize()
|
||||||
|
if (agingChart) agingChart.resize()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.chart-container {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-header {
|
||||||
|
margin-bottom: 10px; /* 从20px减少到10px */
|
||||||
|
margin-top: -40px; /* 向上移动10px */
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-card {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
height: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -30,6 +30,10 @@ const routes = [
|
||||||
{path: '/outsMonitor', component: () => import('@/layout/OutsMonitor.vue')},// 任务表单
|
{path: '/outsMonitor', component: () => import('@/layout/OutsMonitor.vue')},// 任务表单
|
||||||
{path: '/clcKanban', component: () => import('@/layout/clcKanban.vue')},// 需求看板
|
{path: '/clcKanban', component: () => import('@/layout/clcKanban.vue')},// 需求看板
|
||||||
{path: '/batchInventory', component: () => import('@/layout/batchInventory.vue')},// 批量盘点
|
{path: '/batchInventory', component: () => import('@/layout/batchInventory.vue')},// 批量盘点
|
||||||
|
{path: '/excelInventory', component: () => import('@/layout/excelInventory.vue')},// Excel盘点
|
||||||
|
{path: '/stockMix', component: () => import('@/layout/stockMix.vue')},// 库存合并
|
||||||
|
{path: '/wmsChart', component: () => import('@/layout/wmsChart.vue')},// 库存合并
|
||||||
|
{path: '//stockMixConfirm', component: () => import('@/layout//stockMixConfirm.vue')},
|
||||||
{path: '/stockCompare', component: () => import('@/layout/stockCompare.vue')},
|
{path: '/stockCompare', component: () => import('@/layout/stockCompare.vue')},
|
||||||
{path: '/stockUpdateRecord', component: () => import('@/layout/stockUpdateRecord.vue')},// 库存更新记录
|
{path: '/stockUpdateRecord', component: () => import('@/layout/stockUpdateRecord.vue')},// 库存更新记录
|
||||||
{path: '/roleUser', component: () => import('@/layout/role_user.vue')},// 角色——用户列表
|
{path: '/roleUser', component: () => import('@/layout/role_user.vue')},// 角色——用户列表
|
||||||
|
|
@ -50,6 +54,16 @@ const routes = [
|
||||||
name: 'login',
|
name: 'login',
|
||||||
component: login
|
component: login
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/pda-center',
|
||||||
|
name: 'PDACenter',
|
||||||
|
component: () => import('@/views/PDACenter.vue')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/pda-secondIn',
|
||||||
|
name: 'pdaSecondIn',
|
||||||
|
component: () => import('@/layout/pdaSecondIn.vue') // 假设这是具体功能页面
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/pda',
|
path: '/pda',
|
||||||
name: 'pda',
|
name: 'pda',
|
||||||
|
|
|
||||||
60
dev_wms_client/src/views/PDACenter.vue
Normal file
60
dev_wms_client/src/views/PDACenter.vue
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
<template>
|
||||||
|
<body id="pda-login-page">
|
||||||
|
<el-form class="pda-login-container" label-position="left" label-width="0px">
|
||||||
|
<h3 class="pda_login_title">PDA系统功能选择</h3>
|
||||||
|
<el-form-item style="width: 100%">
|
||||||
|
<el-button color="#87CEFA" style="width: 100%; border: none" @click="goToPDAFunction1">PDA拣选功能</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item style="width: 100%">
|
||||||
|
<el-button color="#87CEFA" style="width: 100%; border: none" @click="goToPDAFunction2">PDA呼叫料箱</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</body>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
// PDA功能1页面跳转
|
||||||
|
const goToPDAFunction1 = () => {
|
||||||
|
router.push('/pda')
|
||||||
|
}
|
||||||
|
|
||||||
|
// PDA功能2页面跳转
|
||||||
|
const goToPDAFunction2 = () => {
|
||||||
|
router.push('/pda-secondIn')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#pda-login-page {
|
||||||
|
background-position: center;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-size: cover;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pda-login-container {
|
||||||
|
border-radius: 15px;
|
||||||
|
background-clip: padding-box;
|
||||||
|
margin: 90px auto;
|
||||||
|
width: 350px;
|
||||||
|
padding: 35px 35px 15px 35px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #eaeaea;
|
||||||
|
box-shadow: 0 0 25px #cac6c6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pda_login_title {
|
||||||
|
margin: 0px auto 40px auto;
|
||||||
|
text-align: center;
|
||||||
|
color: #505458;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -39,7 +39,7 @@ const token = store.getters.getToken// 密码
|
||||||
const loginToWms = () => {
|
const loginToWms = () => {
|
||||||
router.replace({ path: '/home' })
|
router.replace({ path: '/home' })
|
||||||
}
|
}
|
||||||
// 登录到PDA系统
|
// 登录到PDA系统 - 修改此函数
|
||||||
const PdaToWms = () => {
|
const PdaToWms = () => {
|
||||||
// 先检查用户是否有PDA权限
|
// 先检查用户是否有PDA权限
|
||||||
const params = {
|
const params = {
|
||||||
|
|
@ -53,8 +53,8 @@ const PdaToWms = () => {
|
||||||
// 解析权限字符串,检查是否包含"E"(PDA权限)
|
// 解析权限字符串,检查是否包含"E"(PDA权限)
|
||||||
const permissionStr = res.data.message || ''
|
const permissionStr = res.data.message || ''
|
||||||
if (permissionStr.includes('E')) {
|
if (permissionStr.includes('E')) {
|
||||||
// 有PDA权限,允许进入PDA系统
|
// 有PDA权限,跳转到PDA系统选择页面
|
||||||
router.replace({ path: '/pda' })
|
router.replace({ path: '/pda-center' })
|
||||||
} else {
|
} else {
|
||||||
// 无PDA权限提示
|
// 无PDA权限提示
|
||||||
ElMessage.error('您没有访问PDA系统的权限')
|
ElMessage.error('您没有访问PDA系统的权限')
|
||||||
|
|
@ -67,6 +67,7 @@ const PdaToWms = () => {
|
||||||
ElMessage.error('权限检查失败')
|
ElMessage.error('权限检查失败')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 登录到工作图纸系统
|
// 登录到工作图纸系统
|
||||||
const loginToImage = () => {
|
const loginToImage = () => {
|
||||||
router.replace({ path: '/imageDisplay' })
|
router.replace({ path: '/imageDisplay' })
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ import lombok.Getter;
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum WmsInvTypeEnums {
|
public enum WmsInvTypeEnums {
|
||||||
INV_TYPE_1(1, "明盘"),
|
INV_TYPE_1(1, "明盘"),
|
||||||
INV_TYPE_2(2, "盲盘");
|
INV_TYPE_2(2, "盲盘"),
|
||||||
|
MIX_STOCK(3, "合并库存"),
|
||||||
|
;
|
||||||
private final Integer code;
|
private final Integer code;
|
||||||
private final String desc;
|
private final String desc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -240,4 +240,70 @@ public class DataController {
|
||||||
return "获取拣选任务失败: " + e.getMessage();
|
return "获取拣选任务失败: " + e.getMessage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询指定日期范围内的入库和出库统计数据
|
||||||
|
*/
|
||||||
|
@PostMapping("/queryInOutBoundStatistics")
|
||||||
|
public Map<String, Object> queryInOutBoundStatistics(@RequestBody Map<String, String> requestParams) {
|
||||||
|
try {
|
||||||
|
// 从请求体中提取参数
|
||||||
|
String startDate = requestParams.get("startDate");
|
||||||
|
String endDate = requestParams.get("endDate");
|
||||||
|
|
||||||
|
// 验证参数
|
||||||
|
if (startDate == null || startDate.isEmpty() || endDate == null || endDate.isEmpty()) {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("code", -1);
|
||||||
|
response.put("message", "开始日期和结束日期不能为空");
|
||||||
|
response.put("data", null);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用服务层查询统计数据
|
||||||
|
Map<String, Object> result = dataControllerService.queryInOutBoundStatistics(startDate, endDate);
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("code", 0);
|
||||||
|
response.put("message", "success");
|
||||||
|
response.put("data", result);
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("code", -1);
|
||||||
|
response.put("message", "查询失败: " + e.getMessage());
|
||||||
|
response.put("data", null);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存龄期分布统计接口
|
||||||
|
*/
|
||||||
|
@GetMapping("/queryStockAgeDistribution")
|
||||||
|
public Map<String, Object> queryStockAgeDistribution() {
|
||||||
|
try {
|
||||||
|
// 调用服务层查询库存龄期分布统计数据
|
||||||
|
List<Map<String, Object>> result = dataControllerService.queryStockAgeDistribution();
|
||||||
|
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("code", 0);
|
||||||
|
response.put("message", "success");
|
||||||
|
response.put("data", result);
|
||||||
|
return response;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Map<String, Object> response = new HashMap<>();
|
||||||
|
response.put("code", -1);
|
||||||
|
response.put("message", "查询失败: " + e.getMessage());
|
||||||
|
response.put("data", null);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,4 +211,20 @@ public class ExcelController {
|
||||||
public void exportLocationDetailExcel(HttpServletResponse response) throws IOException {
|
public void exportLocationDetailExcel(HttpServletResponse response) throws IOException {
|
||||||
exportExcelEasyPoi.doExportLocationAndStockExcel(response);
|
exportExcelEasyPoi.doExportLocationAndStockExcel(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入物料信息(基于模板)
|
||||||
|
* @param file 上传的 Excel 文件
|
||||||
|
* @param fileVo 文件元数据
|
||||||
|
* @return 导入结果
|
||||||
|
* @throws Exception 异常
|
||||||
|
*/
|
||||||
|
@PostMapping("/importGoods")
|
||||||
|
public BaseWmsApiResponse doImportGoods(@RequestPart("file") MultipartFile file, @RequestPart("fileVo") FileVo fileVo) throws Exception {
|
||||||
|
return importExcelEasyPoi.doImportGoods(file, fileVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,18 @@ public class StockController {
|
||||||
return stockControllerService.queryStocksByPage(stockQuery);
|
return stockControllerService.queryStocksByPage(stockQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询特殊库存字段为空且数量大于等于2的物料
|
||||||
|
* @param stockQuery 查询参数
|
||||||
|
* @return 查询结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/querySpecialEmptyStocksForMix")
|
||||||
|
public WmsApiResponse<PageVo<StockVo>> querySpecialEmptyStocksForMix(@RequestBody StockQuery stockQuery)
|
||||||
|
{
|
||||||
|
return stockControllerService.querySpecialEmptyStocksForMix(stockQuery);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
查询库存
|
查询库存
|
||||||
*/
|
*/
|
||||||
|
|
@ -44,6 +56,15 @@ public class StockController {
|
||||||
return stockControllerService.queryStocks(stockQuery);
|
return stockControllerService.queryStocks(stockQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
查询非限制库存
|
||||||
|
*/
|
||||||
|
@PostMapping("/queryStocksBySpecial")
|
||||||
|
public WmsApiResponse<PageVo<StockVo>> queryStocksBySpecial(@RequestBody StockQuery stockQuery)
|
||||||
|
{
|
||||||
|
return stockControllerService.queryStocksBySpecial(stockQuery);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询库存更新记录
|
* 分页查询库存更新记录
|
||||||
* @param stockUpdateQuery 查询参数
|
* @param stockUpdateQuery 查询参数
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,16 @@ public class TaskController {
|
||||||
return taskControllerService.confirmInventory(inventoryConfirmRequest);
|
return taskControllerService.confirmInventory(inventoryConfirmRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认合并信息
|
||||||
|
* @param inventoryConfirmRequest 确认请求
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/confirmMixStock")
|
||||||
|
public BaseWmsApiResponse confirmMixStock(@RequestBody InventoryConfirmRequest inventoryConfirmRequest) {
|
||||||
|
return taskControllerService.confirmMixStock(inventoryConfirmRequest);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取缺料数量,当存在库存时,返回库存与需求的较小值
|
* 获取缺料数量,当存在库存时,返回库存与需求的较小值
|
||||||
* @param goodsId 料号
|
* @param goodsId 料号
|
||||||
|
|
@ -298,4 +308,48 @@ public class TaskController {
|
||||||
public int getLackQty(@RequestParam("goodsId") String goodsId, @RequestParam("workOrder") String workOrder) {
|
public int getLackQty(@RequestParam("goodsId") String goodsId, @RequestParam("workOrder") String workOrder) {
|
||||||
return taskControllerService.getLackQty(goodsId, workOrder);
|
return taskControllerService.getLackQty(goodsId, workOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据混合库存数据创建盘点任务
|
||||||
|
* 将传入的载具和物料信息转化为盘点任务
|
||||||
|
* @param mixStockRequest 包含载具号、物料号列表和绑定箱号的请求参数
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/createInventoryFromMixStock")
|
||||||
|
public BaseWmsApiResponse createInventoryFromMixStock(@RequestBody MixStockRequest mixStockRequest) {
|
||||||
|
return taskControllerService.createInventoryFromMixStock(mixStockRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA手动生成出库任务
|
||||||
|
* @param manualOutTaskRequest 手动出库任务请求参数
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/pdaOutTask")
|
||||||
|
public BaseWmsApiResponse manualCreateOutTask(@RequestBody InventoryRequest manualOutTaskRequest) {
|
||||||
|
return taskControllerService.pdaOutTask(manualOutTaskRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * 测试调用EWM系统验证容器接口
|
||||||
|
// * @return 调用结果
|
||||||
|
// */
|
||||||
|
// @GetMapping("/testEwmCheckContainer")
|
||||||
|
// public EwmApiBackResponse testEwmCheckContainer() {
|
||||||
|
// // 创建测试请求对象
|
||||||
|
// SendEwmCheckContainerNo request = new SendEwmCheckContainerNo();
|
||||||
|
// request.setCheckKey("送件区域:洪字");
|
||||||
|
// request.setContainerNo("BASR202509060003");
|
||||||
|
// request.setFirstOrSecond(false);
|
||||||
|
// request.setType("GI");
|
||||||
|
// // 调用EWM服务
|
||||||
|
// return ewmApiService.sendEwmCheckContainerNo(request);
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,17 @@ public class TaskQueryController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新出库单任务状态
|
||||||
|
*
|
||||||
|
* @param batchEditDateVo 出库单信息
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@PostMapping("/updateOutsTaskStatus")
|
||||||
|
public WmsApiResponse<String> updateOutsTaskStatus(@RequestBody OutsBatchEditDateVo batchEditDateVo) {
|
||||||
|
return taskQueryControllerService.updateOutsTaskStatus(batchEditDateVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 出库提高优先级
|
* 出库提高优先级
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
package com.wms_main.excel.easypoi.excelTemplate;
|
||||||
|
|
||||||
|
import cn.afterturn.easypoi.excel.annotation.Excel;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class GoodsImportTemplate {
|
||||||
|
|
||||||
|
@Excel(name = "物料号", orderNum = "0")
|
||||||
|
private String goodsId;
|
||||||
|
|
||||||
|
@Excel(name = "物料描述", orderNum = "1")
|
||||||
|
private String goodsDesc;
|
||||||
|
|
||||||
|
@Excel(name = "特殊库存标识", orderNum = "2")
|
||||||
|
private String specialStock;
|
||||||
|
|
||||||
|
@Excel(name = "特殊库存编号", orderNum = "3")
|
||||||
|
private String specialStockNo;
|
||||||
|
|
||||||
|
@Excel(name = "销售订单行号", orderNum = "4")
|
||||||
|
private String specialStockItemNo;
|
||||||
|
|
||||||
|
@Excel(name = "账面数量", orderNum = "5")
|
||||||
|
private Double accountQty;
|
||||||
|
|
||||||
|
@Excel(name = "站点", orderNum = "6")
|
||||||
|
private String stand;
|
||||||
|
}
|
||||||
|
|
@ -45,4 +45,6 @@ public interface IExportExcelEasyPoi extends IBaseExportExcelEasyPoi {
|
||||||
* 导出库位及库存详情
|
* 导出库位及库存详情
|
||||||
*/
|
*/
|
||||||
void doExportLocationAndStockExcel(HttpServletResponse response) throws IOException;
|
void doExportLocationAndStockExcel(HttpServletResponse response) throws IOException;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,6 @@ public interface IImportExcelEasyPoi extends IBaseImportExcelEasyPoi {
|
||||||
* @throws Exception 异常
|
* @throws Exception 异常
|
||||||
*/
|
*/
|
||||||
BaseWmsApiResponse doImportInventoryRequest(MultipartFile file, FileVo fileVo) throws Exception;
|
BaseWmsApiResponse doImportInventoryRequest(MultipartFile file, FileVo fileVo) throws Exception;
|
||||||
|
|
||||||
|
BaseWmsApiResponse doImportGoods(MultipartFile file, FileVo fileVo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,26 +9,30 @@ import com.wms_main.dao.ITAppGoodsService;
|
||||||
import com.wms_main.dao.ITAppStockService;
|
import com.wms_main.dao.ITAppStockService;
|
||||||
import com.wms_main.dao.ITAppStockUpdateService;
|
import com.wms_main.dao.ITAppStockUpdateService;
|
||||||
import com.wms_main.dao.ITAppTaskBakService;
|
import com.wms_main.dao.ITAppTaskBakService;
|
||||||
import com.wms_main.excel.easypoi.excelTemplate.GoodsExcelTemplate;
|
import com.wms_main.excel.easypoi.excelTemplate.*;
|
||||||
import com.wms_main.excel.easypoi.excelTemplate.StockExcelTemplate;
|
|
||||||
import com.wms_main.excel.easypoi.excelTemplate.StockUpdateExcelTemplate;
|
|
||||||
import com.wms_main.excel.easypoi.excelTemplate.TaskRecordExcelTemplate;
|
|
||||||
import com.wms_main.excel.easypoi.service.base.IBaseExportExcelEasyPoi;
|
import com.wms_main.excel.easypoi.service.base.IBaseExportExcelEasyPoi;
|
||||||
import com.wms_main.model.dto.query.GoodsQuery;
|
import com.wms_main.model.dto.query.GoodsQuery;
|
||||||
import com.wms_main.model.dto.query.StockQuery;
|
import com.wms_main.model.dto.query.StockQuery;
|
||||||
import com.wms_main.model.dto.query.StockUpdateQuery;
|
import com.wms_main.model.dto.query.StockUpdateQuery;
|
||||||
import com.wms_main.model.dto.query.WmsTaskQuery;
|
import com.wms_main.model.dto.query.WmsTaskQuery;
|
||||||
|
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
||||||
import com.wms_main.model.po.TAppGoods;
|
import com.wms_main.model.po.TAppGoods;
|
||||||
import com.wms_main.model.po.TAppStock;
|
import com.wms_main.model.po.TAppStock;
|
||||||
import com.wms_main.model.po.TAppStockUpdate;
|
import com.wms_main.model.po.TAppStockUpdate;
|
||||||
import com.wms_main.model.po.TAppTaskBak;
|
import com.wms_main.model.po.TAppTaskBak;
|
||||||
|
import com.wms_main.model.vo.others.FileVo;
|
||||||
import com.wms_main.repository.utils.StringUtils;
|
import com.wms_main.repository.utils.StringUtils;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
||||||
|
import cn.afterturn.easypoi.excel.ExcelImportUtil;
|
||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
@ -314,6 +318,9 @@ public class BaseExportExcelEasyPoi implements IBaseExportExcelEasyPoi {
|
||||||
doWriteExcel("出库记录", response, resultList, TaskRecordExcelTemplate.class);
|
doWriteExcel("出库记录", response, resultList, TaskRecordExcelTemplate.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 写入excel
|
* 写入excel
|
||||||
* @param fileDesc 文件描述
|
* @param fileDesc 文件描述
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,13 @@ import com.wms_main.dao.*;
|
||||||
import com.wms_main.excel.easypoi.excelTemplate.*;
|
import com.wms_main.excel.easypoi.excelTemplate.*;
|
||||||
import com.wms_main.excel.easypoi.service.IImportExcelEasyPoi;
|
import com.wms_main.excel.easypoi.service.IImportExcelEasyPoi;
|
||||||
import com.wms_main.excel.easypoi.service.base.impl.BaseImportExcelEasyPoi;
|
import com.wms_main.excel.easypoi.service.base.impl.BaseImportExcelEasyPoi;
|
||||||
|
import com.wms_main.model.dto.request.wms.BatchInventoryRequest;
|
||||||
import com.wms_main.model.po.*;
|
import com.wms_main.model.po.*;
|
||||||
import com.wms_main.model.vo.others.FileVo;
|
import com.wms_main.model.vo.others.FileVo;
|
||||||
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
||||||
import com.wms_main.repository.utils.StringUtils;
|
import com.wms_main.repository.utils.StringUtils;
|
||||||
import com.wms_main.repository.utils.UUIDUtils;
|
import com.wms_main.repository.utils.UUIDUtils;
|
||||||
|
import com.wms_main.service.controller.ITaskControllerService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
@ -25,6 +27,8 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
@ -42,6 +46,7 @@ public class ImportExcelEasyPoi extends BaseImportExcelEasyPoi implements IImpor
|
||||||
private final ITAppInventoryService tAppInventoryService;// 盘点请求服务
|
private final ITAppInventoryService tAppInventoryService;// 盘点请求服务
|
||||||
private final ITAppStockService tAppStockService;// 库存服务
|
private final ITAppStockService tAppStockService;// 库存服务
|
||||||
private final AppCommon appCommon;
|
private final AppCommon appCommon;
|
||||||
|
private final ITaskControllerService taskControllerService; // 添加任务控制器服务
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入dbs的实现
|
* 导入dbs的实现
|
||||||
|
|
@ -466,6 +471,116 @@ public class ImportExcelEasyPoi extends BaseImportExcelEasyPoi implements IImpor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导入物料信息(基于模板)
|
||||||
|
* @param file 上传的 Excel 文件
|
||||||
|
* @param fileVo 文件信息
|
||||||
|
* @return 导入结果
|
||||||
|
*/
|
||||||
|
public BaseWmsApiResponse doImportGoods(MultipartFile file, FileVo fileVo) {
|
||||||
|
if (file == null || file.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("上传文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String originalFilename = file.getOriginalFilename();
|
||||||
|
if (originalFilename == null ||
|
||||||
|
(!originalFilename.toLowerCase().endsWith(".xlsx") && !originalFilename.toLowerCase().endsWith(".xls"))) {
|
||||||
|
throw new IllegalArgumentException("仅支持 .xlsx 或 .xls 格式文件");
|
||||||
|
}
|
||||||
|
|
||||||
|
try (InputStream inputStream = file.getInputStream()) {
|
||||||
|
ImportParams params = new ImportParams();
|
||||||
|
params.setTitleRows(0); // 第一行是标题
|
||||||
|
params.setHeadRows(1); // 数据从第二行开始
|
||||||
|
|
||||||
|
List<GoodsImportTemplate> importList = ExcelImportUtil.importExcel(inputStream, GoodsImportTemplate.class, params);
|
||||||
|
|
||||||
|
// 数据校验与去重
|
||||||
|
List<GoodsImportTemplate> validItems = new ArrayList<>();
|
||||||
|
List<String> errorMessages = new ArrayList<>();
|
||||||
|
|
||||||
|
for (GoodsImportTemplate item : importList) {
|
||||||
|
if (StringUtils.isEmpty(item.getGoodsId())) {
|
||||||
|
errorMessages.add("物料号不能为空");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(item.getStand())) {
|
||||||
|
errorMessages.add("站台号不能为空,物料号:" + item.getGoodsId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查库存是否存在
|
||||||
|
LambdaQueryWrapper<TAppStock> wrapper = new LambdaQueryWrapper<TAppStock>()
|
||||||
|
.eq(TAppStock::getGoodsId, item.getGoodsId())
|
||||||
|
.eq(StringUtils.isNotEmpty(item.getSpecialStock()), TAppStock::getSpecialStock, item.getSpecialStock())
|
||||||
|
.eq(StringUtils.isNotEmpty(item.getSpecialStockNo()), TAppStock::getSpecialStockNo, item.getSpecialStockNo())
|
||||||
|
.eq(StringUtils.isNotEmpty(item.getSpecialStockItemNo()), TAppStock::getSpecialStockItemNo, item.getSpecialStockItemNo());
|
||||||
|
|
||||||
|
List<TAppStock> stockList = tAppStockService.list(wrapper);
|
||||||
|
if (stockList.isEmpty()) {
|
||||||
|
errorMessages.add("物料号:" + item.getGoodsId() + ",特殊库存:" + item.getSpecialStock() + ",特殊库存编号:" + item.getSpecialStockNo() + ",销售订单行号:" + item.getSpecialStockItemNo() + " 在库存表中不存在" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
validItems.add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有错误,返回失败
|
||||||
|
if (!errorMessages.isEmpty()) {
|
||||||
|
return BaseWmsApiResponse.error(String.join("\n", errorMessages));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 逐个处理盘点请求
|
||||||
|
int successCount = 0;
|
||||||
|
List<String> processErrors = new ArrayList<>();
|
||||||
|
|
||||||
|
for (GoodsImportTemplate item : validItems) {
|
||||||
|
// 创建单个盘点请求
|
||||||
|
com.wms_main.model.dto.request.wms.InventoryRequest inventoryRequest = new com.wms_main.model.dto.request.wms.InventoryRequest();
|
||||||
|
inventoryRequest.setStandId(item.getStand()); // 使用Excel中的stand字段作为站台号
|
||||||
|
inventoryRequest.setGoodsId(item.getGoodsId());
|
||||||
|
inventoryRequest.setVehicleId(null); // 使用Excel中的vehicleId,如果有的话
|
||||||
|
inventoryRequest.setSpecialStock(item.getSpecialStock());
|
||||||
|
inventoryRequest.setSpecialStockNo(item.getSpecialStockNo());
|
||||||
|
inventoryRequest.setSpecialStockItemNo(item.getSpecialStockItemNo());
|
||||||
|
inventoryRequest.setBatchNo(null);
|
||||||
|
inventoryRequest.setUserName(fileVo.getUserName()); // 使用文件信息中的用户名
|
||||||
|
|
||||||
|
// 调用现有的单个盘点请求方法
|
||||||
|
BaseWmsApiResponse result = taskControllerService.requestInventory(inventoryRequest);
|
||||||
|
|
||||||
|
if (result != null && Objects.equals(result.getCode(), 0)) { // 检查成功状态
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
processErrors.add("物料号:" + item.getGoodsId() + " 站台:" + item.getStand() + " 。盘点请求失败,原因:" + result.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有成功的请求,记录文件导入信息
|
||||||
|
if (successCount > 0) {
|
||||||
|
saveFileVo(fileVo); // 记录导入文件信息
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回处理结果
|
||||||
|
if (!processErrors.isEmpty()) {
|
||||||
|
String errorMsg = "成功创建 " + successCount + " 条盘点任务,请刷新后查看\n" + String.join("\n", processErrors);
|
||||||
|
return successCount > 0 ? BaseWmsApiResponse.warn(errorMsg) : BaseWmsApiResponse.error(errorMsg);
|
||||||
|
} else {
|
||||||
|
return BaseWmsApiResponse.success("成功创建 " + successCount + " 条盘点任务");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("文件读取失败:" + e.getMessage(), e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Excel解析失败:" + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入盘点请求---实现
|
* 导入盘点请求---实现
|
||||||
* @param file 文件
|
* @param file 文件
|
||||||
|
|
@ -569,9 +684,8 @@ public class ImportExcelEasyPoi extends BaseImportExcelEasyPoi implements IImpor
|
||||||
null,
|
null,
|
||||||
orderId,
|
orderId,
|
||||||
null,
|
null,
|
||||||
null
|
null,
|
||||||
,
|
null,null, null
|
||||||
null,null
|
|
||||||
);
|
);
|
||||||
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
||||||
vehicleList.add(stock.getVehicleId());
|
vehicleList.add(stock.getVehicleId());
|
||||||
|
|
@ -614,7 +728,7 @@ public class ImportExcelEasyPoi extends BaseImportExcelEasyPoi implements IImpor
|
||||||
orderId,
|
orderId,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,null
|
null,null, null
|
||||||
);
|
);
|
||||||
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
||||||
thisTimeAddVehicleList.add(stock.getVehicleId());
|
thisTimeAddVehicleList.add(stock.getVehicleId());
|
||||||
|
|
|
||||||
|
|
@ -58,4 +58,18 @@ public class InventoryConfirmRequest extends BaseWmsRequest {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("specialStockItemNo")
|
@JsonProperty("specialStockItemNo")
|
||||||
private String specialStockItemNo;
|
private String specialStockItemNo;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认数量
|
||||||
|
*/
|
||||||
|
@JsonProperty("needAddNum")
|
||||||
|
private Integer needAddNum;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存合并的目标箱子号
|
||||||
|
*/
|
||||||
|
@JsonProperty("targetVehicleId")
|
||||||
|
private String targetVehicleId;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,4 +49,10 @@ public class InventoryRequest extends BaseWmsRequest {
|
||||||
@JsonProperty("batchNo")
|
@JsonProperty("batchNo")
|
||||||
private String batchNo;
|
private String batchNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 起点
|
||||||
|
*/
|
||||||
|
@JsonProperty("origin")
|
||||||
|
private String origin;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
package com.wms_main.model.dto.request.wms;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class MixStockRequest extends BaseWmsRequest {
|
||||||
|
private List<StockItem> stockItems;
|
||||||
|
private String bindBoxNo;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class StockItem {
|
||||||
|
private String vehicleNo; // 载具号
|
||||||
|
private String materialNo; // 物料号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -114,4 +114,7 @@ public class TAppInventory {
|
||||||
*/
|
*/
|
||||||
@TableField(value = "batch_no")
|
@TableField(value = "batch_no")
|
||||||
private String batchNo; // 批次号
|
private String batchNo; // 批次号
|
||||||
|
|
||||||
|
@TableField(value = "mix_vehicle")
|
||||||
|
private String mixVehicle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,10 @@ public class TAppOuts {
|
||||||
*/
|
*/
|
||||||
@TableId(value = "task_id")
|
@TableId(value = "task_id")
|
||||||
private String taskId;
|
private String taskId;
|
||||||
|
|
||||||
|
|
||||||
|
@TableField(value = "task_status")
|
||||||
|
private int taskStatus;
|
||||||
/**
|
/**
|
||||||
* 料号
|
* 料号
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -67,4 +67,10 @@ public class InventoryConfirmVo {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("batchNo")
|
@JsonProperty("batchNo")
|
||||||
private String batchNo;
|
private String batchNo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并目标箱子号
|
||||||
|
*/
|
||||||
|
@JsonProperty("mixVehicle")
|
||||||
|
private String mixVehicle;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ public class OutsVo {
|
||||||
*/
|
*/
|
||||||
@JsonProperty("taskId")
|
@JsonProperty("taskId")
|
||||||
private String taskId;
|
private String taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务状态
|
||||||
|
*/
|
||||||
|
@JsonProperty("taskStatus")
|
||||||
|
private int taskStatus;
|
||||||
/**
|
/**
|
||||||
* 料号
|
* 料号
|
||||||
*/
|
*/
|
||||||
|
|
@ -126,6 +132,7 @@ public class OutsVo {
|
||||||
}
|
}
|
||||||
return new OutsVo(
|
return new OutsVo(
|
||||||
po.getTaskId(),
|
po.getTaskId(),
|
||||||
|
po.getTaskStatus(),
|
||||||
po.getGoodsId(),
|
po.getGoodsId(),
|
||||||
po.getVehicleId(),
|
po.getVehicleId(),
|
||||||
po.getNeedNum(),
|
po.getNeedNum(),
|
||||||
|
|
@ -156,6 +163,7 @@ public class OutsVo {
|
||||||
}
|
}
|
||||||
return new OutsVo(
|
return new OutsVo(
|
||||||
po.getTaskId(),
|
po.getTaskId(),
|
||||||
|
1,
|
||||||
po.getGoodsId(),
|
po.getGoodsId(),
|
||||||
po.getVehicleId(),
|
po.getVehicleId(),
|
||||||
po.getNeedNum(),
|
po.getNeedNum(),
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WCS HTTP 请求类
|
* WCS HTTP 请求类
|
||||||
*/
|
*/
|
||||||
|
|
@ -20,7 +23,7 @@ public class HttpRequest {
|
||||||
/**
|
/**
|
||||||
* 超时时长
|
* 超时时长
|
||||||
*/
|
*/
|
||||||
private Integer timeout = 5000;
|
private Integer timeout = 10000;
|
||||||
/**
|
/**
|
||||||
* 请求方式
|
* 请求方式
|
||||||
*/
|
*/
|
||||||
|
|
@ -37,6 +40,10 @@ public class HttpRequest {
|
||||||
* token
|
* token
|
||||||
*/
|
*/
|
||||||
private String token;
|
private String token;
|
||||||
|
/**
|
||||||
|
* 额外的请求头
|
||||||
|
*/
|
||||||
|
private Map<String, String> headers = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建一个POST请求
|
* 构建一个POST请求
|
||||||
|
|
@ -55,7 +62,30 @@ public class HttpRequest {
|
||||||
if (StringUtils.isEmpty(contentType)) {
|
if (StringUtils.isEmpty(contentType)) {
|
||||||
contentType = "application/json";
|
contentType = "application/json";
|
||||||
}
|
}
|
||||||
return new HttpRequest(url.trim(), timeout, HttpMethodEnum.POST, contentType, StringUtils.objectToString(data), token);
|
HttpRequest request = new HttpRequest(url.trim(), timeout, HttpMethodEnum.POST, contentType, StringUtils.objectToString(data), token, new HashMap<>());
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建一个POST请求(带额外请求头)
|
||||||
|
* @param url 接口地址
|
||||||
|
* @param data 数据
|
||||||
|
* @param timeout 超时时长
|
||||||
|
* @param contentType 请求头
|
||||||
|
* @param token token
|
||||||
|
* @param headers 额外请求头
|
||||||
|
* @return post请求体
|
||||||
|
* @param <T> 数据类型
|
||||||
|
*/
|
||||||
|
public static <T> HttpRequest postInstanceOfWithHeaders(String url, T data, Integer timeout, String contentType, String token, Map<String, String> headers) {
|
||||||
|
if (timeout == null || timeout <= 1000) {
|
||||||
|
timeout = 5000;
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(contentType)) {
|
||||||
|
contentType = "application/json";
|
||||||
|
}
|
||||||
|
HttpRequest request = new HttpRequest(url.trim(), timeout, HttpMethodEnum.POST, contentType, StringUtils.objectToString(data), token, headers);
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -68,4 +98,16 @@ public class HttpRequest {
|
||||||
public static <T> HttpRequest postInstanceOf(String url, T data) {
|
public static <T> HttpRequest postInstanceOf(String url, T data) {
|
||||||
return postInstanceOf(url.trim(), data, 5000, "application/json", "");
|
return postInstanceOf(url.trim(), data, 5000, "application/json", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加请求头
|
||||||
|
* @param key 请求头键
|
||||||
|
* @param value 请求头值
|
||||||
|
*/
|
||||||
|
public void addHeader(String key, String value) {
|
||||||
|
if (this.headers == null) {
|
||||||
|
this.headers = new HashMap<>();
|
||||||
|
}
|
||||||
|
this.headers.put(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import com.alibaba.fastjson2.JSON;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import org.springframework.util.DigestUtils;
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串工具类
|
* 字符串工具类
|
||||||
*/
|
*/
|
||||||
|
|
@ -268,6 +270,26 @@ public class StringUtils {
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 比较两个字符串是否相等,将null和空字符串视为相等
|
||||||
|
* @param str1 字符串1
|
||||||
|
* @param str2 字符串2
|
||||||
|
* @return 是否相等
|
||||||
|
*/
|
||||||
|
public static boolean isStringEqual(String str1, String str2) {
|
||||||
|
// 如果两个都是null,返回相等
|
||||||
|
if (str1 == null && str2 == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 如果其中一个为null,另一个为空字符串,返回相等
|
||||||
|
if ((str1 == null && str2.isEmpty()) || (str2 == null && str1.isEmpty())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 其他情况使用标准equals比较
|
||||||
|
return Objects.equals(str1, str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取字符串---依据最大程度,并去除空白与换行符
|
* 截取字符串---依据最大程度,并去除空白与换行符
|
||||||
* @param originStr 原始字符串
|
* @param originStr 原始字符串
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,16 @@ import com.wms_main.repository.http.entity.HttpResponse;
|
||||||
import com.wms_main.service.api.IEwmApiService;
|
import com.wms_main.service.api.IEwmApiService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.net.http.HttpHeaders;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ewm接口服务实现
|
* Ewm接口服务实现
|
||||||
|
|
@ -41,7 +50,7 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_VEHICLE_URL.getKey()),
|
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_VEHICLE_URL.getKey()),
|
||||||
request,
|
request,
|
||||||
30000,
|
30000,
|
||||||
"application/json",
|
"application/json;charset=UTF-8",
|
||||||
"Basic " + encodedAuth);
|
"Basic " + encodedAuth);
|
||||||
|
|
||||||
// 记录即将发送的请求数据
|
// 记录即将发送的请求数据
|
||||||
|
|
@ -78,7 +87,7 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_WAREHOUSE_IN_COMPLETED_URL.getKey()),
|
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_WAREHOUSE_IN_COMPLETED_URL.getKey()),
|
||||||
request,
|
request,
|
||||||
30000,
|
30000,
|
||||||
"application/json",
|
"application/json;charset=UTF-8",
|
||||||
"Basic " + encodedAuth);
|
"Basic " + encodedAuth);
|
||||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||||
|
|
||||||
|
|
@ -106,7 +115,7 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_WAREHOUSE_OUT_COMPLETED_URL.getKey()),
|
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_SEND_WAREHOUSE_OUT_COMPLETED_URL.getKey()),
|
||||||
request,
|
request,
|
||||||
60000,
|
60000,
|
||||||
"application/json",
|
"application/json;charset=UTF-8",
|
||||||
"Basic " + encodedAuth);
|
"Basic " + encodedAuth);
|
||||||
|
|
||||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||||
|
|
@ -142,7 +151,7 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
finalUrl,
|
finalUrl,
|
||||||
request,
|
request,
|
||||||
30000,
|
30000,
|
||||||
"application/json",
|
"application/json;charset=UTF-8",
|
||||||
"Basic " + encodedAuth);
|
"Basic " + encodedAuth);
|
||||||
|
|
||||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||||
|
|
@ -170,7 +179,7 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_GET_STOCK_LIST_URL.getKey()),
|
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_GET_STOCK_LIST_URL.getKey()),
|
||||||
request,
|
request,
|
||||||
30000,
|
30000,
|
||||||
"application/json",
|
"application/json;charset=UTF-8",
|
||||||
"Basic " + encodedAuth);
|
"Basic " + encodedAuth);
|
||||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||||
|
|
||||||
|
|
@ -185,24 +194,39 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EwmApiBackResponse sendEwmCheckContainerNo(SendEwmCheckContainerNo request) {
|
public EwmApiBackResponse sendEwmCheckContainerNo(SendEwmCheckContainerNo request) {
|
||||||
try {
|
try {
|
||||||
|
log.info("发送请求验证EWM系统参数: {}", request);
|
||||||
|
|
||||||
|
// 1. 构建请求头
|
||||||
|
org.springframework.http.HttpHeaders headers = new org.springframework.http.HttpHeaders();
|
||||||
|
headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON); // 设置Content-Type
|
||||||
|
headers.add("Accept-Charset", "UTF-8"); // 使用add方法设置Accept-Charset
|
||||||
|
|
||||||
// 构建Basic Auth认证信息
|
// 构建Basic Auth认证信息
|
||||||
String auth = "asrs:mom@123456";
|
String auth = "asrs:mom@123456";
|
||||||
String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes());
|
String encodedAuth = java.util.Base64.getEncoder().encodeToString(auth.getBytes());
|
||||||
|
headers.set("Authorization", "Basic " + encodedAuth); // Basic Auth
|
||||||
|
|
||||||
// 设置http请求
|
// 2. 构建请求体
|
||||||
HttpRequest httpRequest = HttpRequest.postInstanceOf(
|
HttpEntity<SendEwmCheckContainerNo> entity = new HttpEntity<>(request, headers);
|
||||||
|
|
||||||
|
// 3. 发送 POST 请求
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<EwmApiBackResponse> response = restTemplate.postForEntity(
|
||||||
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_CHECK_CONTAINER_NO_URL.getKey()),
|
appCommon.getConfigByKey(AppConfigKeyEnums.EWM_CHECK_CONTAINER_NO_URL.getKey()),
|
||||||
request,
|
entity,
|
||||||
30000,
|
EwmApiBackResponse.class
|
||||||
"application/json",
|
);
|
||||||
"Basic " + encodedAuth);
|
|
||||||
HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
|
||||||
|
|
||||||
if (httpResponse != null && httpResponse.isSuccess()) {
|
// 4. 处理响应
|
||||||
return httpResponse.getData(EwmApiBackResponse.class);
|
if (response.getStatusCode().is2xxSuccessful()) {
|
||||||
|
EwmApiBackResponse result = response.getBody();
|
||||||
|
log.info("EWM系统响应: {}", result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
log.warn("请求验证EWM系统返回空响应或请求失败,请求参数: {}", request);
|
log.warn("请求验证EWM系统返回空响应或请求失败,请求参数: {}", request);
|
||||||
|
|
@ -212,4 +236,64 @@ public class EwmApiServiceImpl implements IEwmApiService {
|
||||||
return EwmApiBackResponse.error("调用EWM系统接口异常: " + e.getMessage());
|
return EwmApiBackResponse.error("调用EWM系统接口异常: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// public EwmApiBackResponse sendEwmCheckContainerNo(SendEwmCheckContainerNo request) {
|
||||||
|
// try {
|
||||||
|
// log.info("发送请求验证EWM系统参数: {}", request);
|
||||||
|
//
|
||||||
|
// // 构建Basic Auth认证信息
|
||||||
|
// String auth = "asrs:mom@123456";
|
||||||
|
// String encodedAuth = java.util.Base64.getEncoder()
|
||||||
|
// .encodeToString(auth.getBytes(java.nio.charset.StandardCharsets.UTF_8));
|
||||||
|
//
|
||||||
|
// // 将请求对象转换为JSON字符串,明确指定UTF-8编码
|
||||||
|
// ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
// String requestBody = objectMapper.writeValueAsString(request);
|
||||||
|
//
|
||||||
|
// // 设置http请求
|
||||||
|
// HttpRequest httpRequest = HttpRequest.postInstanceOf(
|
||||||
|
// appCommon.getConfigByKey(AppConfigKeyEnums.EWM_CHECK_CONTAINER_NO_URL.getKey()),
|
||||||
|
// requestBody, // 直接传递JSON字符串
|
||||||
|
// 30000,
|
||||||
|
// "application/json;charset=UTF-8",
|
||||||
|
// "Basic " + encodedAuth);
|
||||||
|
//
|
||||||
|
// // 添加必要的请求头
|
||||||
|
// httpRequest.addHeader("Accept-Charset", "UTF-8");
|
||||||
|
// httpRequest.addHeader("Accept", "application/json;charset=UTF-8");
|
||||||
|
// httpRequest.addHeader("Content-Type", "application/json;charset=UTF-8");
|
||||||
|
//
|
||||||
|
// // 如果HttpClient支持设置字符编码,添加以下代码
|
||||||
|
// if (httpRequest instanceof ConfigurableHttpRequest) {
|
||||||
|
// ((ConfigurableHttpRequest) httpRequest).setCharset(StandardCharsets.UTF_8);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// HttpResponse httpResponse = httpClient.httpPost(httpRequest);
|
||||||
|
//
|
||||||
|
// if (httpResponse != null && httpResponse.isSuccess()) {
|
||||||
|
// // 明确指定使用UTF-8解析响应
|
||||||
|
// String responseBody = httpResponse.getResponseBody();
|
||||||
|
// if (responseBody != null) {
|
||||||
|
// EwmApiBackResponse response = objectMapper.readValue(
|
||||||
|
// responseBody,
|
||||||
|
// EwmApiBackResponse.class
|
||||||
|
// );
|
||||||
|
// log.info("EWM系统响应: {}", response);
|
||||||
|
// return response;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// log.warn("请求验证EWM系统返回空响应或请求失败,请求参数: {}", request);
|
||||||
|
// return EwmApiBackResponse.error("EWM系统返回空响应或请求失败");
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.error("调用EWM系统接口异常,请求参数: {}", request, e);
|
||||||
|
// return EwmApiBackResponse.error("调用EWM系统接口异常: " + e.getMessage());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -662,6 +662,7 @@ public class ConveyTaskServiceImpl implements IConveyTaskService {
|
||||||
inventoryConfirmVo.setSpecialStockNo(inventory.getSpecialStockNo());
|
inventoryConfirmVo.setSpecialStockNo(inventory.getSpecialStockNo());
|
||||||
inventoryConfirmVo.setSpecialStockItemNo(inventory.getSpecialStockItemNo());
|
inventoryConfirmVo.setSpecialStockItemNo(inventory.getSpecialStockItemNo());
|
||||||
inventoryConfirmVo.setBatchNo(inventory.getBatchNo());
|
inventoryConfirmVo.setBatchNo(inventory.getBatchNo());
|
||||||
|
inventoryConfirmVo.setMixVehicle(inventory.getMixVehicle());
|
||||||
// 返回结果
|
// 返回结果
|
||||||
return inventoryConfirmVo;
|
return inventoryConfirmVo;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,39 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (TAppTempEwmInboundData tempEwmInboundData : tempEwmInboundDataList){
|
for (TAppTempEwmInboundData tempEwmInboundData : tempEwmInboundDataList){
|
||||||
// 新库存,增加库存信息
|
// 先查询tempEwmInboundData在这个载具上是否有库存,如果有则更新数量,没有就作为新库存
|
||||||
|
List<TAppStock> existingStockWithSameGoodsId = thisVehicleStocks.stream()
|
||||||
|
.filter(stock -> Objects.equals(stock.getGoodsId(), tempEwmInboundData.getMatNo()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
if (!existingStockWithSameGoodsId.isEmpty()) {
|
||||||
|
// 存在相同料号的库存,更新数量
|
||||||
|
TAppStock matchingStock = existingStockWithSameGoodsId.getFirst();
|
||||||
|
matchingStock.setRealNum(matchingStock.getRealNum() + tempEwmInboundData.getSkuQty().intValue());
|
||||||
|
matchingStock.setRemainNum(matchingStock.getRemainNum() + tempEwmInboundData.getSkuQty().intValue());
|
||||||
|
matchingStock.setTotalNum(matchingStock.getTotalNum() + tempEwmInboundData.getSkuQty().intValue());
|
||||||
|
matchingStock.setStockStatus(WmsStockStatusEnums.OK.getCode());
|
||||||
|
matchingStock.setLastUpdateTime(thisVehicleInTask.getCreateTime());
|
||||||
|
matchingStock.setLastUpdateUser(thisVehicleInTask.getOpUser());
|
||||||
|
matchingStock.setLocationId(thisVehicleInTask.getDestination());
|
||||||
|
|
||||||
|
newStockList.add(matchingStock);
|
||||||
|
|
||||||
|
// 更新库存更新记录
|
||||||
|
TAppStockUpdate stockUpdate = new TAppStockUpdate(
|
||||||
|
UUIDUtils.getNewUUID(),
|
||||||
|
vehicleId,
|
||||||
|
tempEwmInboundData.getMatNo(),
|
||||||
|
thisVehicleInTask.getCreateTime(),
|
||||||
|
matchingStock.getRealNum() - tempEwmInboundData.getSkuQty().intValue(),
|
||||||
|
matchingStock.getRealNum(),
|
||||||
|
thisVehicleInTask.getOrigin() + ":入库合并",
|
||||||
|
LocalDateTime.now(),
|
||||||
|
thisVehicleInTask.getOpUser()
|
||||||
|
);
|
||||||
|
stockUpdateList.add(stockUpdate);
|
||||||
|
} else {
|
||||||
|
// 没有找到相同料号的库存,创建新的库存记录
|
||||||
TAppStock thisTimeNewStock = new TAppStock(
|
TAppStock thisTimeNewStock = new TAppStock(
|
||||||
UUIDUtils.getNewUUID(),
|
UUIDUtils.getNewUUID(),
|
||||||
vehicleId,
|
vehicleId,
|
||||||
|
|
@ -493,6 +525,8 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
|
||||||
thisVehicleInTask.getOpUser()
|
thisVehicleInTask.getOpUser()
|
||||||
);
|
);
|
||||||
stockUpdateList.add(stockUpdate);
|
stockUpdateList.add(stockUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
needDeleteTempIds.add(tempEwmInboundData.getId());
|
needDeleteTempIds.add(tempEwmInboundData.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,11 @@ public interface IDataControllerService {
|
||||||
*/
|
*/
|
||||||
List<TAppPickTask> getPickTaskDataP3(int pageNum, int pageSize);
|
List<TAppPickTask> getPickTaskDataP3(int pageNum, int pageSize);
|
||||||
|
|
||||||
|
Map<String, Object> queryInOutBoundStatistics(String startDate, String endDate);
|
||||||
|
|
||||||
|
List<Map<String, Object>> queryStockAgeDistribution();
|
||||||
|
|
||||||
|
|
||||||
List<Map<String, Object>> queryRecentTask();
|
List<Map<String, Object>> queryRecentTask();
|
||||||
|
|
||||||
List<Map<String, Object>> queryStockDetail(String locationId);
|
List<Map<String, Object>> queryStockDetail(String locationId);
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,15 @@ public interface IStockControllerService {
|
||||||
*/
|
*/
|
||||||
WmsApiResponse<PageVo<StockVo>> queryStocksByPage(StockQuery stockQuery);
|
WmsApiResponse<PageVo<StockVo>> queryStocksByPage(StockQuery stockQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询特殊库存字段为空且数量大于等于2的物料
|
||||||
|
* @param stockQuery 查询参数
|
||||||
|
* @return 查询结果
|
||||||
|
*/
|
||||||
|
WmsApiResponse<PageVo<StockVo>> querySpecialEmptyStocksForMix(StockQuery stockQuery);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询库存更新记录---分页
|
* 查询库存更新记录---分页
|
||||||
* @param stockUpdateQuery 查询参数
|
* @param stockUpdateQuery 查询参数
|
||||||
|
|
@ -30,4 +39,11 @@ public interface IStockControllerService {
|
||||||
* @return 所有库存信息
|
* @return 所有库存信息
|
||||||
*/
|
*/
|
||||||
WmsApiResponse<PageVo<StockVo>> queryStocks(StockQuery stockQuery);
|
WmsApiResponse<PageVo<StockVo>> queryStocks(StockQuery stockQuery);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有非限制库存信息
|
||||||
|
* @return 所有库存信息
|
||||||
|
*/
|
||||||
|
WmsApiResponse<PageVo<StockVo>> queryStocksBySpecial(StockQuery stockQuery);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import com.wms_main.model.dto.response.wcs.BaseWcsApiResponse;
|
||||||
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
|
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
|
||||||
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
import com.wms_main.model.dto.response.wms.BaseWmsApiResponse;
|
||||||
import com.wms_main.model.dto.response.wms.WmsApiResponse;
|
import com.wms_main.model.dto.response.wms.WmsApiResponse;
|
||||||
|
import com.wms_main.model.po.TAppInventory;
|
||||||
import com.wms_main.model.po.TAppStockCompare;
|
import com.wms_main.model.po.TAppStockCompare;
|
||||||
import com.wms_main.model.vo.wms.InventoryConfirmVo;
|
import com.wms_main.model.vo.wms.InventoryConfirmVo;
|
||||||
import com.wms_main.model.vo.wms.TaskConfirmVo;
|
import com.wms_main.model.vo.wms.TaskConfirmVo;
|
||||||
|
|
@ -109,6 +110,8 @@ public interface ITaskControllerService {
|
||||||
*/
|
*/
|
||||||
BaseWmsApiResponse requestInventory(InventoryRequest inventoryRequest);
|
BaseWmsApiResponse requestInventory(InventoryRequest inventoryRequest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量下发盘点请求
|
* 批量下发盘点请求
|
||||||
* @param batchInventoryRequest 批量盘点请求
|
* @param batchInventoryRequest 批量盘点请求
|
||||||
|
|
@ -131,6 +134,13 @@ public interface ITaskControllerService {
|
||||||
*/
|
*/
|
||||||
BaseWmsApiResponse confirmInventory(InventoryConfirmRequest inventoryConfirmRequest);
|
BaseWmsApiResponse confirmInventory(InventoryConfirmRequest inventoryConfirmRequest);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认合并信息
|
||||||
|
* @param inventoryConfirmRequest 确认请求
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
BaseWmsApiResponse confirmMixStock(InventoryConfirmRequest inventoryConfirmRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取对应工单的缺料数量
|
* 获取对应工单的缺料数量
|
||||||
* 最小值为0,最大值为库存数量
|
* 最小值为0,最大值为库存数量
|
||||||
|
|
@ -149,6 +159,9 @@ public interface ITaskControllerService {
|
||||||
EwmApiBackResponse ewmRequestOutTask(EwmOutTaskRequest ewmOutTaskRequest);
|
EwmApiBackResponse ewmRequestOutTask(EwmOutTaskRequest ewmOutTaskRequest);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//BaseWmsApiResponse requestInventoryByMixStock(InventoryRequest inventoryRequest, List<TAppInventory> inventory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EWM获取库存信息
|
* EWM获取库存信息
|
||||||
* @param request 获取库存信息请求
|
* @param request 获取库存信息请求
|
||||||
|
|
@ -170,4 +183,20 @@ public interface ITaskControllerService {
|
||||||
*/
|
*/
|
||||||
EwmApiBackResponse cancelOrderInTasks(SendWarehouseInCompletedRequest request);
|
EwmApiBackResponse cancelOrderInTasks(SendWarehouseInCompletedRequest request);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建混合库存盘点任务
|
||||||
|
* @param mixStockRequest 盘点请求
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
BaseWmsApiResponse createInventoryFromMixStock(MixStockRequest mixStockRequest);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手动生成出库任务
|
||||||
|
* @param manualOutTaskRequest 手动出库任务请求参数
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
BaseWmsApiResponse pdaOutTask(InventoryRequest manualOutTaskRequest);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,4 +74,7 @@ public interface ITaskQueryControllerService {
|
||||||
* @return 更新结果
|
* @return 更新结果
|
||||||
*/
|
*/
|
||||||
WmsApiResponse<String> updateOutsInfo(TAppPickTask appTask);
|
WmsApiResponse<String> updateOutsInfo(TAppPickTask appTask);
|
||||||
|
|
||||||
|
|
||||||
|
WmsApiResponse<String> updateOutsTaskStatus(OutsBatchEditDateVo batchEditDateVo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,144 @@ public class DataControllerServiceImpl implements IDataControllerService {
|
||||||
return tAppPickTaskService.page(new Page<>(pageNum, pageSize), queryWrapper).getRecords();
|
return tAppPickTaskService.page(new Page<>(pageNum, pageSize), queryWrapper).getRecords();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> queryInOutBoundStatistics(String startDate, String endDate) {
|
||||||
|
// 验证日期参数
|
||||||
|
if (startDate == null || endDate == null) {
|
||||||
|
throw new IllegalArgumentException("开始日期和结束日期不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析日期范围
|
||||||
|
LocalDate start = LocalDate.parse(startDate);
|
||||||
|
LocalDate end = LocalDate.parse(endDate);
|
||||||
|
|
||||||
|
// 生成日期列表
|
||||||
|
List<String> dateList = new ArrayList<>();
|
||||||
|
LocalDate currentDate = start;
|
||||||
|
while (!currentDate.isAfter(end)) {
|
||||||
|
dateList.add(currentDate.toString());
|
||||||
|
currentDate = currentDate.plusDays(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化统计映射
|
||||||
|
Map<String, Integer> inboundMap = new HashMap<>();
|
||||||
|
Map<String, Integer> outboundMap = new HashMap<>();
|
||||||
|
|
||||||
|
// 初始化所有日期的计数为0
|
||||||
|
for (String date : dateList) {
|
||||||
|
inboundMap.put(date, 0);
|
||||||
|
outboundMap.put(date, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造查询条件,查询指定日期范围内的任务
|
||||||
|
LambdaQueryWrapper<TAppTaskBak> queryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
queryWrapper.ge(TAppTaskBak::getCreateTime, start.atStartOfDay())
|
||||||
|
.le(TAppTaskBak::getCreateTime, end.atTime(23, 59, 59));
|
||||||
|
|
||||||
|
List<TAppTaskBak> taskList = tAppTaskBakService.list(queryWrapper);
|
||||||
|
|
||||||
|
// 统计入库和出库任务数量
|
||||||
|
for (TAppTaskBak task : taskList) {
|
||||||
|
// 提取日期部分
|
||||||
|
String taskDate = task.getCreateTime().toLocalDate().toString();
|
||||||
|
|
||||||
|
if (task.getTaskType() != null) {
|
||||||
|
switch (task.getTaskType()) {
|
||||||
|
case 1: // 入库任务
|
||||||
|
inboundMap.put(taskDate, inboundMap.getOrDefault(taskDate, 0) + 1);
|
||||||
|
break;
|
||||||
|
case 2: // 出库任务
|
||||||
|
outboundMap.put(taskDate, outboundMap.getOrDefault(taskDate, 0) + 1);
|
||||||
|
break;
|
||||||
|
// 其他任务类型不统计
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建结果数据
|
||||||
|
List<Integer> inboundCounts = new ArrayList<>();
|
||||||
|
List<Integer> outboundCounts = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String date : dateList) {
|
||||||
|
inboundCounts.add(inboundMap.get(date));
|
||||||
|
outboundCounts.add(outboundMap.get(date));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
result.put("dates", dateList);
|
||||||
|
result.put("inbound", inboundCounts);
|
||||||
|
result.put("outbound", outboundCounts);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> queryStockAgeDistribution() {
|
||||||
|
// 查询所有库存数据
|
||||||
|
List<TAppStock> stockList = tAppStockService.list();
|
||||||
|
|
||||||
|
// 定义时间区间统计变量
|
||||||
|
int range0To7Days = 0; // 0-7天
|
||||||
|
int range8To30Days = 0; // 8-30天
|
||||||
|
int range1To3Months = 0; // 1-3个月
|
||||||
|
int range3To6Months = 0; // 3-6个月
|
||||||
|
int rangeAbove6Months = 0; // 6个月以上
|
||||||
|
|
||||||
|
LocalDate now = LocalDate.now();
|
||||||
|
|
||||||
|
for (TAppStock stock : stockList) {
|
||||||
|
// 使用 first_in_time 字段计算库存龄期(入库时间)
|
||||||
|
if (stock.getFirstInTime() != null) {
|
||||||
|
LocalDate firstInDate = stock.getFirstInTime().toLocalDate();
|
||||||
|
long daysBetween = java.time.temporal.ChronoUnit.DAYS.between(firstInDate, now);
|
||||||
|
|
||||||
|
if (daysBetween <= 7) {
|
||||||
|
range0To7Days++;
|
||||||
|
} else if (daysBetween <= 30) {
|
||||||
|
range8To30Days++;
|
||||||
|
} else if (daysBetween <= 90) { // 3个月
|
||||||
|
range1To3Months++;
|
||||||
|
} else if (daysBetween <= 180) { // 6个月
|
||||||
|
range3To6Months++;
|
||||||
|
} else {
|
||||||
|
rangeAbove6Months++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建返回数据
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
|
||||||
|
Map<String, Object> range0_7 = new HashMap<>();
|
||||||
|
range0_7.put("name", "0-7天");
|
||||||
|
range0_7.put("value", range0To7Days);
|
||||||
|
result.add(range0_7);
|
||||||
|
|
||||||
|
Map<String, Object> range8_30 = new HashMap<>();
|
||||||
|
range8_30.put("name", "8-30天");
|
||||||
|
range8_30.put("value", range8To30Days);
|
||||||
|
result.add(range8_30);
|
||||||
|
|
||||||
|
Map<String, Object> range1_3 = new HashMap<>();
|
||||||
|
range1_3.put("name", "1-3个月");
|
||||||
|
range1_3.put("value", range1To3Months);
|
||||||
|
result.add(range1_3);
|
||||||
|
|
||||||
|
Map<String, Object> range3_6 = new HashMap<>();
|
||||||
|
range3_6.put("name", "3-6个月");
|
||||||
|
range3_6.put("value", range3To6Months);
|
||||||
|
result.add(range3_6);
|
||||||
|
|
||||||
|
Map<String, Object> range6Plus = new HashMap<>();
|
||||||
|
range6Plus.put("name", "6个月以上");
|
||||||
|
range6Plus.put("value", rangeAbove6Months);
|
||||||
|
result.add(range6Plus);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Map<String, Object>> queryRecentTask() {
|
public List<Map<String, Object>> queryRecentTask() {
|
||||||
List<Map<String, Object>> result = new ArrayList<>();
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,11 @@ import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 库存控制类 服务实现
|
* 库存控制类 服务实现
|
||||||
|
|
@ -66,6 +71,99 @@ public class StockControllerServiceImpl implements IStockControllerService {
|
||||||
return WmsApiResponse.success("查询库存数据成功", pageVo);
|
return WmsApiResponse.success("查询库存数据成功", pageVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WmsApiResponse<PageVo<StockVo>> querySpecialEmptyStocksForMix(StockQuery stockQuery) {
|
||||||
|
if (stockQuery == null) {
|
||||||
|
return WmsApiResponse.error("查询参数不能为NULL", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建查询条件,查找特殊库存字段为空的记录
|
||||||
|
LambdaQueryWrapper<TAppStock> lambdaQueryWrapper = new LambdaQueryWrapper<TAppStock>()
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getVehicleId()), TAppStock::getVehicleId, stockQuery.getVehicleId())
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getLocationId()), TAppStock::getLocationId, stockQuery.getLocationId())
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getGoodsId()), TAppStock::getGoodsId, stockQuery.getGoodsId())
|
||||||
|
.eq(stockQuery.getStockStatus() != null, TAppStock::getStockStatus, stockQuery.getStockStatus())
|
||||||
|
.eq(stockQuery.getGoodsStatus() != null, TAppStock::getGoodsStatus, stockQuery.getGoodsStatus());
|
||||||
|
|
||||||
|
// 添加特殊库存字段为空的条件:specialStock、specialStockNo、specialStockItemNo、batchNo 为 null 或 empty
|
||||||
|
lambdaQueryWrapper.and(wrapper -> wrapper
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStock).or().eq(TAppStock::getSpecialStock, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStockNo).or().eq(TAppStock::getSpecialStockNo, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStockItemNo).or().eq(TAppStock::getSpecialStockItemNo, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getBatchNo).or().eq(TAppStock::getBatchNo, ""))
|
||||||
|
);
|
||||||
|
|
||||||
|
// 查询所有符合条件的记录
|
||||||
|
List<TAppStock> allRecords = appStockService.list(lambdaQueryWrapper);
|
||||||
|
|
||||||
|
// 按 goodsId 分组并统计
|
||||||
|
Map<String, List<TAppStock>> groupedByGoodsId = allRecords.stream()
|
||||||
|
.collect(Collectors.groupingBy(TAppStock::getGoodsId));
|
||||||
|
|
||||||
|
// 创建汇总后的记录列表,只包含记录数大于1的分组
|
||||||
|
List<TAppStock> aggregatedRecords = groupedByGoodsId.values().stream()
|
||||||
|
.filter(records -> records.size() > 1) // 只处理有多条记录的分组
|
||||||
|
.map(records -> {
|
||||||
|
// 取第一条记录作为基础,创建新对象并复制属性
|
||||||
|
TAppStock firstRecord = records.getFirst();
|
||||||
|
TAppStock aggregatedRecord = new TAppStock();
|
||||||
|
|
||||||
|
// 复制基础属性(根据实际的TAppStock类字段进行调整)
|
||||||
|
aggregatedRecord.setGoodsId(firstRecord.getGoodsId());
|
||||||
|
aggregatedRecord.setGoodsDesc(firstRecord.getGoodsDesc());
|
||||||
|
aggregatedRecord.setRealNum(records.size()); // 设置记录条数
|
||||||
|
// 根据实际需要复制其他必要字段...
|
||||||
|
|
||||||
|
// 使用 remainNum 作为统计字段
|
||||||
|
int totalQuantity = records.stream()
|
||||||
|
.mapToInt(TAppStock::getRemainNum)
|
||||||
|
.sum();
|
||||||
|
// 设置总数量
|
||||||
|
aggregatedRecord.setRemainNum(totalQuantity);
|
||||||
|
|
||||||
|
return aggregatedRecord;
|
||||||
|
})
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
// 获取分页参数
|
||||||
|
Page<TAppStock> page = stockQuery.toMpPage();
|
||||||
|
int pageNum = (int) page.getCurrent();
|
||||||
|
int pageSize = (int) page.getSize();
|
||||||
|
|
||||||
|
// 手动分页处理
|
||||||
|
int start = (pageNum - 1) * pageSize;
|
||||||
|
int end = Math.min(start + pageSize, aggregatedRecords.size());
|
||||||
|
|
||||||
|
List<TAppStock> pagedRecords;
|
||||||
|
if (start >= aggregatedRecords.size()) {
|
||||||
|
pagedRecords = new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
pagedRecords = aggregatedRecords.subList(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建分页结果
|
||||||
|
Page<TAppStock> resultPage = new Page<>();
|
||||||
|
resultPage.setRecords(pagedRecords);
|
||||||
|
resultPage.setCurrent(pageNum);
|
||||||
|
resultPage.setSize(pageSize);
|
||||||
|
resultPage.setTotal(aggregatedRecords.size());
|
||||||
|
|
||||||
|
PageVo<StockVo> pageVo = PageVo.of(resultPage, StockVo::ofPo);
|
||||||
|
return WmsApiResponse.success("查询特殊空库存成功", pageVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询库存更新记录(分页)---实现
|
* 查询库存更新记录(分页)---实现
|
||||||
* @param stockUpdateQuery 查询参数
|
* @param stockUpdateQuery 查询参数
|
||||||
|
|
@ -125,4 +223,43 @@ public class StockControllerServiceImpl implements IStockControllerService {
|
||||||
return WmsApiResponse.success("查询库存数据成功", pageVo);
|
return WmsApiResponse.success("查询库存数据成功", pageVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WmsApiResponse<PageVo<StockVo>> queryStocksBySpecial(StockQuery stockQuery) {
|
||||||
|
if (stockQuery == null) {
|
||||||
|
return WmsApiResponse.error("查询参数不能为NULL", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Page<TAppStock> page = stockQuery.toMpPage();
|
||||||
|
LambdaQueryWrapper<TAppStock> lambdaQueryWrapper = new LambdaQueryWrapper<TAppStock>()
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getVehicleId()), TAppStock::getVehicleId, stockQuery.getVehicleId())
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getLocationId()), TAppStock::getLocationId, stockQuery.getLocationId())
|
||||||
|
.like(StringUtils.isNotEmpty(stockQuery.getGoodsId()), TAppStock::getGoodsId, stockQuery.getGoodsId())
|
||||||
|
.eq(stockQuery.getStockStatus() != null, TAppStock::getStockStatus, stockQuery.getStockStatus())
|
||||||
|
.eq(stockQuery.getGoodsStatus() != null, TAppStock::getGoodsStatus, stockQuery.getGoodsStatus());
|
||||||
|
|
||||||
|
if (stockQuery.getFromDate() != null) {
|
||||||
|
lambdaQueryWrapper.ge(TAppStock::getFirstInTime, LocalDateTime.of(stockQuery.getFromDate(), LocalDateTime.MIN.toLocalTime()));
|
||||||
|
}
|
||||||
|
if (stockQuery.getToDate() != null) {
|
||||||
|
lambdaQueryWrapper.le(TAppStock::getFirstInTime, LocalDateTime.of(stockQuery.getToDate(), LocalDateTime.MAX.toLocalTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加特殊库存字段为空的条件:specialStock、specialStockNo、specialStockItemNo、batchNo 为 null 或 empty
|
||||||
|
lambdaQueryWrapper.and(wrapper -> wrapper
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStock).or().eq(TAppStock::getSpecialStock, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStockNo).or().eq(TAppStock::getSpecialStockNo, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getSpecialStockItemNo).or().eq(TAppStock::getSpecialStockItemNo, ""))
|
||||||
|
.or()
|
||||||
|
.and(w -> w.isNull(TAppStock::getBatchNo).or().eq(TAppStock::getBatchNo, ""))
|
||||||
|
);
|
||||||
|
|
||||||
|
Page<TAppStock> stockPage = appStockService.page(page, lambdaQueryWrapper);
|
||||||
|
PageVo<StockVo> pageVo = PageVo.of(stockPage, StockVo::ofPo);
|
||||||
|
|
||||||
|
return WmsApiResponse.success("查询特殊库存数据成功", pageVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import com.wms_main.model.dto.response.wms.WmsApiResponse;
|
||||||
import com.wms_main.model.po.*;
|
import com.wms_main.model.po.*;
|
||||||
import com.wms_main.model.vo.wms.InventoryConfirmVo;
|
import com.wms_main.model.vo.wms.InventoryConfirmVo;
|
||||||
import com.wms_main.model.vo.wms.TaskConfirmVo;
|
import com.wms_main.model.vo.wms.TaskConfirmVo;
|
||||||
import com.wms_main.model.vo.wms.WorkConfirmVo;
|
|
||||||
import com.wms_main.repository.utils.ConvertUtils;
|
import com.wms_main.repository.utils.ConvertUtils;
|
||||||
import com.wms_main.repository.utils.DbTransUtils;
|
import com.wms_main.repository.utils.DbTransUtils;
|
||||||
import com.wms_main.repository.utils.StringUtils;
|
import com.wms_main.repository.utils.StringUtils;
|
||||||
|
|
@ -48,7 +47,6 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务控制类 服务实现
|
* 任务控制类 服务实现
|
||||||
|
|
@ -76,6 +74,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
private final ITAppInventoryRecordService appInventoryRecordService;// 盘点记录服务
|
private final ITAppInventoryRecordService appInventoryRecordService;// 盘点记录服务
|
||||||
private final ITAppWorkService appWorkService;// 工作详情服务
|
private final ITAppWorkService appWorkService;// 工作详情服务
|
||||||
private final AppCommon appCommon;
|
private final AppCommon appCommon;
|
||||||
|
private final ITAppTaskService appTaskService;
|
||||||
private final IEwmApiService ewmApiService;
|
private final IEwmApiService ewmApiService;
|
||||||
// 在其他依赖注入后面添加
|
// 在其他依赖注入后面添加
|
||||||
private final ITempEwmInboundDataService tempEwmInboundDataService;
|
private final ITempEwmInboundDataService tempEwmInboundDataService;
|
||||||
|
|
@ -291,6 +290,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
// 添加任务
|
// 添加任务
|
||||||
TAppOuts task = new TAppOuts(
|
TAppOuts task = new TAppOuts(
|
||||||
UUIDUtils.getNewUUID(),
|
UUIDUtils.getNewUUID(),
|
||||||
|
0,
|
||||||
stockOutRequest.getGoodsId(),
|
stockOutRequest.getGoodsId(),
|
||||||
stockOutRequest.getVehicleId(),
|
stockOutRequest.getVehicleId(),
|
||||||
stockOutRequest.getNeedNum(),
|
stockOutRequest.getNeedNum(),
|
||||||
|
|
@ -466,6 +466,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
// 添加任务
|
// 添加任务
|
||||||
TAppOuts task = new TAppOuts(
|
TAppOuts task = new TAppOuts(
|
||||||
UUIDUtils.getNewUUID(),
|
UUIDUtils.getNewUUID(),
|
||||||
|
-1,
|
||||||
stockOutRequest.getGoodsId(),
|
stockOutRequest.getGoodsId(),
|
||||||
stockOutRequest.getVehicleId(),
|
stockOutRequest.getVehicleId(),
|
||||||
stockOutRequest.getNeedNum(),
|
stockOutRequest.getNeedNum(),
|
||||||
|
|
@ -635,6 +636,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
}
|
}
|
||||||
TAppOuts outs = new TAppOuts(
|
TAppOuts outs = new TAppOuts(
|
||||||
task.getTaskNo(),
|
task.getTaskNo(),
|
||||||
|
-1,
|
||||||
task.getMatNo(),
|
task.getMatNo(),
|
||||||
null,
|
null,
|
||||||
task.getPickingQty().intValue(),
|
task.getPickingQty().intValue(),
|
||||||
|
|
@ -680,6 +682,337 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BaseWmsApiResponse createInventoryFromMixStock(MixStockRequest mixStockRequest) {
|
||||||
|
// 验证请求参数
|
||||||
|
if (mixStockRequest == null) {
|
||||||
|
return BaseWmsApiResponse.error("请求参数不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mixStockRequest.getStockItems() == null || mixStockRequest.getStockItems().isEmpty()) {
|
||||||
|
return BaseWmsApiResponse.error("库存项列表不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 用于存储已创建的盘点任务ID,以便在出现错误时进行回滚删除
|
||||||
|
List<TAppInventory> inventory = new ArrayList<>();
|
||||||
|
|
||||||
|
// 遍历混合库存数据,逐个创建盘点任务
|
||||||
|
for (MixStockRequest.StockItem stockItem : mixStockRequest.getStockItems()) {
|
||||||
|
if (stockItem == null ||
|
||||||
|
StringUtils.isEmpty(stockItem.getVehicleNo()) ||
|
||||||
|
StringUtils.isEmpty(stockItem.getMaterialNo())) {
|
||||||
|
continue; // 跳过无效的库存项
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建盘点请求对象,复用现有的requestInventory方法
|
||||||
|
InventoryRequest inventoryRequest = new InventoryRequest();
|
||||||
|
inventoryRequest.setGoodsId(stockItem.getMaterialNo()); // 物料号
|
||||||
|
inventoryRequest.setVehicleId(stockItem.getVehicleNo()); // 载具号
|
||||||
|
inventoryRequest.setStandId(mixStockRequest.getStandId()); // 系统默认站台,可根据实际需求调整
|
||||||
|
inventoryRequest.setUserName("SystemByMix"); // 系统用户
|
||||||
|
inventoryRequest.setSpecialStock(null); // 特殊库存
|
||||||
|
inventoryRequest.setSpecialStockNo(null); // 特殊库存号
|
||||||
|
inventoryRequest.setSpecialStockItemNo(null); // 特殊库存项目号
|
||||||
|
inventoryRequest.setBatchNo(null); // 批次号
|
||||||
|
|
||||||
|
// 调用现有的盘点任务生成方法
|
||||||
|
BaseWmsApiResponse response = requestInventoryByMixStock(inventoryRequest,inventory,mixStockRequest.getBindBoxNo());
|
||||||
|
if (response.getCode() != 0) {
|
||||||
|
log.error("创建合并任务失败,载具号: {}, 物料号: {},错误信息: {}",
|
||||||
|
stockItem.getVehicleNo(), stockItem.getMaterialNo(), response.getMessage());
|
||||||
|
|
||||||
|
return BaseWmsApiResponse.error("创建合并任务失败,载具号: " + stockItem.getVehicleNo() +
|
||||||
|
",物料号: " + stockItem.getMaterialNo() + ",错误信息: " + response.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!inventory.isEmpty()){
|
||||||
|
appInventoryService.saveBatch(inventory);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BaseWmsApiResponse.success("合并库存任务创建完成,共创建 " + inventory.size() + " 个出库任务");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("创建混合库存盘点任务时发生异常", e);
|
||||||
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||||
|
return BaseWmsApiResponse.error("创建合并任务时发生异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BaseWmsApiResponse pdaOutTask(InventoryRequest manualOutTaskRequest) {
|
||||||
|
try {
|
||||||
|
// 验证请求参数
|
||||||
|
if (manualOutTaskRequest == null) {
|
||||||
|
return BaseWmsApiResponse.error("请求参数不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(manualOutTaskRequest.getVehicleId())) {
|
||||||
|
return BaseWmsApiResponse.error("载具ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String vehicleId = manualOutTaskRequest.getVehicleId();
|
||||||
|
String origin = manualOutTaskRequest.getOrigin();
|
||||||
|
String remark = "PDA手持呼叫";
|
||||||
|
|
||||||
|
// 生成出库任务
|
||||||
|
TAppTask outTask = new TAppTask(
|
||||||
|
UUIDUtils.getNewUUID(),
|
||||||
|
WmsTaskTypeEnums.OUT.getCode(),
|
||||||
|
0,
|
||||||
|
9,
|
||||||
|
vehicleId,
|
||||||
|
origin,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
LocalDateTime.now(),
|
||||||
|
null,
|
||||||
|
AppConstant.EMPTY_GOODS_ID,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
"",
|
||||||
|
remark,
|
||||||
|
"P21",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
|
||||||
|
boolean taskSaveSuccess = appWmsTaskService.save(outTask);
|
||||||
|
if (!taskSaveSuccess) {
|
||||||
|
log.error("保存出库任务失败,载具ID: {}", vehicleId);
|
||||||
|
return BaseWmsApiResponse.error("保存出库任务失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到达即删除的拣选任务
|
||||||
|
TAppPickTask pickTask = new TAppPickTask(
|
||||||
|
UUIDUtils.getNewUUID(),
|
||||||
|
"P21", // 与出库任务的目标站台一致
|
||||||
|
vehicleId,
|
||||||
|
WmsPickTaskStatusEnum.TEMP.getCode(),
|
||||||
|
LocalDateTime.now(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
3 // 类型设置为3,表示到达即删除
|
||||||
|
);
|
||||||
|
|
||||||
|
boolean pickTaskSaveSuccess = appPickTaskService.save(pickTask);
|
||||||
|
if (!pickTaskSaveSuccess) {
|
||||||
|
log.error("保存拣选任务失败,载具ID: {}", vehicleId);
|
||||||
|
// 尝试删除已保存的出库任务以保持数据一致性
|
||||||
|
try {
|
||||||
|
appWmsTaskService.removeById(outTask.getTaskId());
|
||||||
|
} catch (Exception rollbackEx) {
|
||||||
|
log.error("回滚删除出库任务失败,任务ID: {}", outTask.getTaskId(), rollbackEx);
|
||||||
|
}
|
||||||
|
return BaseWmsApiResponse.error("保存拣选任务失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新载具状态为出库中
|
||||||
|
boolean vehicleUpdateSuccess = appVehicleService.update(
|
||||||
|
new LambdaUpdateWrapper<TAppVehicle>()
|
||||||
|
.set(TAppVehicle::getVehicleStatus, WmsVehicleStatusEnums.OUT.getCode())
|
||||||
|
.eq(TAppVehicle::getVehicleId, vehicleId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!vehicleUpdateSuccess) {
|
||||||
|
log.warn("更新载具状态失败,载具ID: {}", vehicleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新库存状态为出库中
|
||||||
|
boolean stockUpdateSuccess = appStockService.update(
|
||||||
|
new LambdaUpdateWrapper<TAppStock>()
|
||||||
|
.set(TAppStock::getStockStatus, WmsStockStatusEnums.OUTING.getCode())
|
||||||
|
.eq(TAppStock::getVehicleId, vehicleId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!stockUpdateSuccess) {
|
||||||
|
log.warn("更新库存状态失败,载具ID: {}", vehicleId);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("PDA手持呼叫出库任务创建成功,载具ID: {}", vehicleId);
|
||||||
|
return BaseWmsApiResponse.success("PDA手持呼叫出库任务创建成功");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("PDA手持呼叫出库任务创建过程中发生异常", e);
|
||||||
|
return BaseWmsApiResponse.error("创建出库任务时发生异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求盘点---实现
|
||||||
|
*
|
||||||
|
* @param inventoryRequest 盘点请求
|
||||||
|
* @return 请求结果
|
||||||
|
*/
|
||||||
|
private BaseWmsApiResponse requestInventoryByMixStock(InventoryRequest inventoryRequest, List<TAppInventory> inventory, String bindBoxNo) {
|
||||||
|
if (inventoryRequest == null) {
|
||||||
|
return BaseWmsApiResponse.error("请求为NULL。");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getStandId())) {
|
||||||
|
return BaseWmsApiResponse.error("请求缺少信息,请输入站台号。");
|
||||||
|
}
|
||||||
|
if (!appStandService.exists(new LambdaQueryWrapper<TAppStand>().eq(TAppStand::getStandId, inventoryRequest.getStandId())
|
||||||
|
.eq(TAppStand::getStandType, 1))) {
|
||||||
|
return BaseWmsApiResponse.error("非拣选站台不允许盘点。");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getGoodsId())) {
|
||||||
|
return BaseWmsApiResponse.error("请求缺少信息,请输入料号。");
|
||||||
|
}
|
||||||
|
// 判断这个料有没有还没盘点完的任务
|
||||||
|
List<TAppInventory> inventoryList = appInventoryService.list(new LambdaQueryWrapper<TAppInventory>()
|
||||||
|
.eq(TAppInventory::getGoodsId, inventoryRequest.getGoodsId())
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStock匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStock())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppInventory::getSpecialStock)
|
||||||
|
.or()
|
||||||
|
.eq(TAppInventory::getSpecialStock, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppInventory::getSpecialStock, inventoryRequest.getSpecialStock());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStockNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStockNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppInventory::getSpecialStockNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppInventory::getSpecialStockNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppInventory::getSpecialStockNo, inventoryRequest.getSpecialStockNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStockItemNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStockItemNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppInventory::getSpecialStockItemNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppInventory::getSpecialStockItemNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppInventory::getSpecialStockItemNo, inventoryRequest.getSpecialStockItemNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// batchNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getBatchNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppInventory::getBatchNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppInventory::getBatchNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppInventory::getBatchNo, inventoryRequest.getBatchNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.eq(StringUtils.isNotEmpty(inventoryRequest.getVehicleId()), TAppInventory::getVehicleId, inventoryRequest.getVehicleId()));
|
||||||
|
if (inventoryList != null && !inventoryList.isEmpty()) {
|
||||||
|
String errMsg = StringUtils.isNotEmpty(inventoryRequest.getVehicleId()) ? "载具:" + inventoryRequest.getVehicleId() : "";
|
||||||
|
return BaseWmsApiResponse.error(errMsg + "该料号还有盘点任务未完成。");
|
||||||
|
}
|
||||||
|
// 查询库存,创建盘点任务
|
||||||
|
List<TAppStock> stockList = appStockService.list(new LambdaQueryWrapper<TAppStock>()
|
||||||
|
.eq(TAppStock::getGoodsId, inventoryRequest.getGoodsId())
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStock匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStock())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppStock::getSpecialStock)
|
||||||
|
.or()
|
||||||
|
.eq(TAppStock::getSpecialStock, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppStock::getSpecialStock, inventoryRequest.getSpecialStock());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStockNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStockNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppStock::getSpecialStockNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppStock::getSpecialStockNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppStock::getSpecialStockNo, inventoryRequest.getSpecialStockNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// specialStockItemNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getSpecialStockItemNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppStock::getSpecialStockItemNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppStock::getSpecialStockItemNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppStock::getSpecialStockItemNo, inventoryRequest.getSpecialStockItemNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.and(wrapper -> {
|
||||||
|
// batchNo匹配逻辑
|
||||||
|
if (StringUtils.isEmpty(inventoryRequest.getBatchNo())) {
|
||||||
|
// 传入空值,匹配数据库中的NULL或空字符串
|
||||||
|
wrapper.isNull(TAppStock::getBatchNo)
|
||||||
|
.or()
|
||||||
|
.eq(TAppStock::getBatchNo, "");
|
||||||
|
} else {
|
||||||
|
// 传入具体值,精确匹配
|
||||||
|
wrapper.eq(TAppStock::getBatchNo, inventoryRequest.getBatchNo());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.eq(StringUtils.isNotEmpty(inventoryRequest.getVehicleId()), TAppStock::getVehicleId, inventoryRequest.getVehicleId()));
|
||||||
|
if (stockList == null || stockList.isEmpty()) {
|
||||||
|
return BaseWmsApiResponse.error("物料" + inventoryRequest.getGoodsId() + "没有库存。");
|
||||||
|
}
|
||||||
|
// 根据载具号map一下
|
||||||
|
Map<String, TAppInventory> inventoryByVehicleMap = new HashMap<>();
|
||||||
|
// 盘点单号
|
||||||
|
String orderId = UUIDUtils.getNewUUID();
|
||||||
|
for (TAppStock stock : stockList) {
|
||||||
|
if (!inventoryByVehicleMap.containsKey(stock.getVehicleId())) {
|
||||||
|
if (stock.getStockStatus() != 0){
|
||||||
|
return BaseWmsApiResponse.error("载具:" + stock.getVehicleId() + "正在出库。");
|
||||||
|
}
|
||||||
|
// 添加盘点任务
|
||||||
|
TAppInventory inventoryTask = new TAppInventory(
|
||||||
|
UUIDUtils.getNewUUID(),
|
||||||
|
inventoryRequest.getGoodsId(),
|
||||||
|
stock.getVehicleId(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
inventoryRequest.getStandId(),
|
||||||
|
inventoryRequest.getUserName(),
|
||||||
|
WmsInvTypeEnums.MIX_STOCK.getCode(),
|
||||||
|
WmsInvStatusEnums.INIT.getCode(),
|
||||||
|
WmsInvResultEnums.NONE.getCode(),
|
||||||
|
LocalDateTime.now(),
|
||||||
|
null,
|
||||||
|
orderId,
|
||||||
|
inventoryRequest.getSpecialStock(),
|
||||||
|
inventoryRequest.getSpecialStockNo(),
|
||||||
|
inventoryRequest.getSpecialStockItemNo(),
|
||||||
|
inventoryRequest.getBatchNo(),
|
||||||
|
bindBoxNo
|
||||||
|
);
|
||||||
|
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!inventoryByVehicleMap.isEmpty()) {
|
||||||
|
inventory.addAll(inventoryByVehicleMap.values());
|
||||||
|
}
|
||||||
|
// 保存盘点任务
|
||||||
|
return BaseWmsApiResponse.success("创建盘点任务成功。");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -949,6 +1282,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
// 添加任务
|
// 添加任务
|
||||||
outsList.add(new TAppOuts(
|
outsList.add(new TAppOuts(
|
||||||
UUIDUtils.getNewUUID(),
|
UUIDUtils.getNewUUID(),
|
||||||
|
-1,
|
||||||
goodsId,
|
goodsId,
|
||||||
"",
|
"",
|
||||||
1,
|
1,
|
||||||
|
|
@ -1308,6 +1642,11 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(dataList.size() > 1){
|
||||||
|
log.info("EWM返回数据中存在多条不同物料号的数据,载具号: {}", vehicleNo);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!dataList.isEmpty()) {
|
if (!dataList.isEmpty()) {
|
||||||
// 批量插入时指定合理的批次大小
|
// 批量插入时指定合理的批次大小
|
||||||
boolean saveResult = tempEwmInboundDataService.saveBatch(dataList);
|
boolean saveResult = tempEwmInboundDataService.saveBatch(dataList);
|
||||||
|
|
@ -1490,6 +1829,28 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
return WcsApiResponse.error("插入了多条不符合要求的数据。", null);
|
return WcsApiResponse.error("插入了多条不符合要求的数据。", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (response.getContent() != null &&
|
||||||
|
response.getContent().getTaskDetailInfo() != null &&
|
||||||
|
!response.getContent().getTaskDetailInfo().isEmpty() &&
|
||||||
|
!stockList.isEmpty()) {
|
||||||
|
|
||||||
|
// 此时才安全地获取数据
|
||||||
|
TaskDetailInfo taskDetailInfo = response.getContent().getTaskDetailInfo().getFirst();
|
||||||
|
TAppStock stock = stockList.getFirst();
|
||||||
|
|
||||||
|
if (!Objects.equals(taskDetailInfo.getMatNo(), stock.getGoodsId())){
|
||||||
|
return WcsApiResponse.error("该载具号已存在不同料号的库存,请检查。", null);
|
||||||
|
}
|
||||||
|
// 比较特殊库存字段,将null和空字符串视为相同
|
||||||
|
if (!StringUtils.isStringEqual(taskDetailInfo.getSpecialStock(), stock.getSpecialStock()) ||
|
||||||
|
!StringUtils.isStringEqual(taskDetailInfo.getSpecialStockNo(), stock.getSpecialStockNo()) ||
|
||||||
|
!StringUtils.isStringEqual(taskDetailInfo.getSpecialStockItemNo(), stock.getSpecialStockItemNo()) ||
|
||||||
|
!StringUtils.isStringEqual(taskDetailInfo.getBatchNo(), stock.getBatchNo())) {
|
||||||
|
return WcsApiResponse.error("该载具号已存在不同特殊库存的库存,请检查。", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 根据临时表数据生成WMS任务
|
// 3. 根据临时表数据生成WMS任务
|
||||||
generateWmsTasksFromTempData(wcsVehicleInRequest);
|
generateWmsTasksFromTempData(wcsVehicleInRequest);
|
||||||
|
|
||||||
|
|
@ -1616,6 +1977,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实现
|
* 实现
|
||||||
*
|
*
|
||||||
|
|
@ -1898,14 +2260,15 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
String existingSecondPickingCode = existingCheck.getSecondPickingCode();
|
String existingSecondPickingCode = existingCheck.getSecondPickingCode();
|
||||||
String newSecondPickingCode = thisOut.getFirst().getSecondPickingCode();
|
String newSecondPickingCode = thisOut.getFirst().getSecondPickingCode();
|
||||||
|
|
||||||
boolean isSecondPickingCodeMatch = (StringUtils.isEmpty(existingSecondPickingCode) && StringUtils.isEmpty(newSecondPickingCode))
|
boolean isSecondPickingCodeEmpty = StringUtils.isEmpty(existingSecondPickingCode) && StringUtils.isEmpty(newSecondPickingCode);
|
||||||
|| Objects.equals(existingSecondPickingCode, newSecondPickingCode);
|
boolean isSecondPickingCodeMatch = isSecondPickingCodeEmpty || Objects.equals(existingSecondPickingCode, newSecondPickingCode);
|
||||||
|
|
||||||
if (!isSecondPickingCodeMatch) {
|
if (!isSecondPickingCodeMatch) {
|
||||||
return BaseWmsApiResponse.error("当前目标箱号已存在其他颗粒度物料,请检查。");
|
return BaseWmsApiResponse.error("当前目标箱号已存在其他颗粒度物料,请检查。");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 如果颗粒度一致(包括都为空),再检测工单号是否相同
|
// 2. 只有当颗粒度都为空时,才校验工单号
|
||||||
|
if (isSecondPickingCodeEmpty) {
|
||||||
String existingOrderNo = existingCheck.getOrderNo();
|
String existingOrderNo = existingCheck.getOrderNo();
|
||||||
String newOrderNo = thisOut.getFirst().getOrderNo();
|
String newOrderNo = thisOut.getFirst().getOrderNo();
|
||||||
|
|
||||||
|
|
@ -1914,6 +2277,7 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
return BaseWmsApiResponse.error("当前目标箱号已存在其他工单号物料,请检查。");
|
return BaseWmsApiResponse.error("当前目标箱号已存在其他工单号物料,请检查。");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 当前站台到达的拣选任务
|
// 当前站台到达的拣选任务
|
||||||
TAppPickTask thisPickTask = pickTaskList.getFirst();
|
TAppPickTask thisPickTask = pickTaskList.getFirst();
|
||||||
SendWarehouseOutCompletedRequest requestForCompleted = new SendWarehouseOutCompletedRequest();
|
SendWarehouseOutCompletedRequest requestForCompleted = new SendWarehouseOutCompletedRequest();
|
||||||
|
|
@ -2156,7 +2520,8 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
inventoryRequest.getSpecialStock(),
|
inventoryRequest.getSpecialStock(),
|
||||||
inventoryRequest.getSpecialStockNo(),
|
inventoryRequest.getSpecialStockNo(),
|
||||||
inventoryRequest.getSpecialStockItemNo(),
|
inventoryRequest.getSpecialStockItemNo(),
|
||||||
inventoryRequest.getBatchNo()
|
inventoryRequest.getBatchNo(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
inventoryByVehicleMap.put(stock.getVehicleId(), inventoryTask);
|
||||||
}
|
}
|
||||||
|
|
@ -2168,6 +2533,8 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
return BaseWmsApiResponse.success("创建盘点任务成功。");
|
return BaseWmsApiResponse.success("创建盘点任务成功。");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public BaseWmsApiResponse batchRequestInventory(BatchInventoryRequest batchInventoryRequest) {
|
public BaseWmsApiResponse batchRequestInventory(BatchInventoryRequest batchInventoryRequest) {
|
||||||
|
|
@ -2336,7 +2703,8 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
item.getSpecialStock(),
|
item.getSpecialStock(),
|
||||||
item.getSpecialStockNo(),
|
item.getSpecialStockNo(),
|
||||||
item.getSpecialStockItemNo(),
|
item.getSpecialStockItemNo(),
|
||||||
item.getBatchNo()
|
item.getBatchNo(),
|
||||||
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
inventoryList.add(inventory);
|
inventoryList.add(inventory);
|
||||||
|
|
@ -2454,6 +2822,14 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
.eq(TAppPickTask::getPickType,2)
|
.eq(TAppPickTask::getPickType,2)
|
||||||
);
|
);
|
||||||
if (pickTaskList == null || pickTaskList.isEmpty()) {
|
if (pickTaskList == null || pickTaskList.isEmpty()) {
|
||||||
|
List<TAppPickTask> pickTaskListType3 = appPickTaskService.list(new LambdaQueryWrapper<TAppPickTask>()
|
||||||
|
.eq(TAppPickTask::getPickStand, inventoryConfirmRequest.getStandId())
|
||||||
|
.eq(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.ARRIVE.getCode())
|
||||||
|
.eq(TAppPickTask::getPickType,4)
|
||||||
|
);
|
||||||
|
if (!pickTaskListType3.isEmpty()) {
|
||||||
|
return BaseWmsApiResponse.error("当前箱子为合并库存任务, 请转到合并库存确认页面。");
|
||||||
|
}
|
||||||
return BaseWmsApiResponse.error("当前站台没有箱子到达, 请检查。");
|
return BaseWmsApiResponse.error("当前站台没有箱子到达, 请检查。");
|
||||||
}
|
}
|
||||||
if (pickTaskList.size() > 1) {
|
if (pickTaskList.size() > 1) {
|
||||||
|
|
@ -2562,6 +2938,120 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认合并信息
|
||||||
|
*
|
||||||
|
* @param inventoryConfirmRequest 确认请求
|
||||||
|
* @return 处理结果
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public BaseWmsApiResponse confirmMixStock(InventoryConfirmRequest inventoryConfirmRequest) {
|
||||||
|
if (inventoryConfirmRequest == null) {
|
||||||
|
return BaseWmsApiResponse.error("请求信息为空。");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(inventoryConfirmRequest.getInventoryId())) {
|
||||||
|
return BaseWmsApiResponse.error("请求信息缺少关键信息,请刷新后重试!");
|
||||||
|
}
|
||||||
|
if (StringUtils.isEmpty(inventoryConfirmRequest.getStandId())) {
|
||||||
|
return BaseWmsApiResponse.error("请求信息缺少站台号。");
|
||||||
|
}
|
||||||
|
if (Objects.equals(inventoryConfirmRequest.getVehicleId(), inventoryConfirmRequest.getTargetVehicleId())){
|
||||||
|
// 查找是否还存在盘点任务
|
||||||
|
List<TAppInventory> inventoryList = appInventoryService.list(new LambdaQueryWrapper<TAppInventory>()
|
||||||
|
.eq(TAppInventory::getInvType, 3)
|
||||||
|
.eq(TAppInventory::getMixVehicle, inventoryConfirmRequest.getTargetVehicleId())
|
||||||
|
);
|
||||||
|
if (inventoryList.size() > 1){
|
||||||
|
return BaseWmsApiResponse.error("当前载具作为合并母容器!还存在 " + (inventoryList.size() - 1) + " 个合并任务!请先处理合并子容器!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 查询当前站台上的已到达的拣选任务
|
||||||
|
List<TAppPickTask> pickTaskList = appPickTaskService.list(new LambdaQueryWrapper<TAppPickTask>()
|
||||||
|
.eq(TAppPickTask::getPickStand, inventoryConfirmRequest.getStandId())
|
||||||
|
.eq(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.ARRIVE.getCode())
|
||||||
|
.eq(TAppPickTask::getPickType,4)
|
||||||
|
);
|
||||||
|
if (pickTaskList == null || pickTaskList.isEmpty()) {
|
||||||
|
List<TAppPickTask> pickTaskListType3 = appPickTaskService.list(new LambdaQueryWrapper<TAppPickTask>()
|
||||||
|
.eq(TAppPickTask::getPickStand, inventoryConfirmRequest.getStandId())
|
||||||
|
.eq(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.ARRIVE.getCode())
|
||||||
|
.eq(TAppPickTask::getPickType,2)
|
||||||
|
);
|
||||||
|
if (!pickTaskListType3.isEmpty()) {
|
||||||
|
return BaseWmsApiResponse.error("当前箱子为盘点任务, 请转到盘点确认页面。");
|
||||||
|
}
|
||||||
|
return BaseWmsApiResponse.error("当前站台没有箱子到达, 请检查。");
|
||||||
|
}
|
||||||
|
if (pickTaskList.size() > 1) {
|
||||||
|
return BaseWmsApiResponse.error("当前站台有多个箱子到达,请检查。");
|
||||||
|
}
|
||||||
|
// 当前站台到达的拣选任务
|
||||||
|
TAppPickTask thisPickTask = pickTaskList.getFirst();
|
||||||
|
if (StringUtils.isNotEmpty(inventoryConfirmRequest.getInventoryId())) {
|
||||||
|
TAppInventory targetInventory = appInventoryService.getById(inventoryConfirmRequest.getInventoryId());
|
||||||
|
if (targetInventory != null) {
|
||||||
|
if (!Objects.equals(targetInventory.getVehicleId(), thisPickTask.getVehicleId())) {
|
||||||
|
// 盘点的载具号与当前站台到达的拣选任务载具号不一致,请检查。
|
||||||
|
return BaseWmsApiResponse.error("盘点的载具号与当前站台到达的载具号不一致,请检查。");
|
||||||
|
}
|
||||||
|
if (inventoryConfirmRequest.getConfirmNum() == null || inventoryConfirmRequest.getConfirmNum() < 0) {
|
||||||
|
return BaseWmsApiResponse.error("请求信息中的盘点确认数量不正确。");
|
||||||
|
}
|
||||||
|
// 移除任务表
|
||||||
|
appInventoryService.removeById(inventoryConfirmRequest.getInventoryId());
|
||||||
|
// 根据盘点确认信息更新库存
|
||||||
|
StockConfirmEntity stockConfirm = new StockConfirmEntity();
|
||||||
|
stockConfirm.setVehicleId(targetInventory.getVehicleId());
|
||||||
|
stockConfirm.setGoodsId(targetInventory.getGoodsId());
|
||||||
|
stockConfirm.setRealRemainQty(inventoryConfirmRequest.getConfirmNum());
|
||||||
|
stockConfirm.setSpecialStock(inventoryConfirmRequest.getSpecialStock());
|
||||||
|
stockConfirm.setSpecialStockNo(inventoryConfirmRequest.getSpecialStockNo());
|
||||||
|
stockConfirm.setSpecialStockItemNo(inventoryConfirmRequest.getSpecialStockItemNo());
|
||||||
|
stockConfirm.setBatchNo(inventoryConfirmRequest.getBatchNo());
|
||||||
|
// 更新库存信息
|
||||||
|
boolean updateStockInfo = stockDataService.updateStockInfo(stockConfirm, inventoryConfirmRequest.getStandId(), inventoryConfirmRequest.getUserName(), "库存合并确认", targetInventory.getInventoryId());
|
||||||
|
if (!updateStockInfo) {
|
||||||
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||||
|
return BaseWmsApiResponse.error("库存发生变化,更新失败,请联系管理员确认!");
|
||||||
|
}else {
|
||||||
|
if (!Objects.equals(inventoryConfirmRequest.getVehicleId(), inventoryConfirmRequest.getTargetVehicleId())){
|
||||||
|
// 需要找到目标箱号的库存信息,将库存全部加过去
|
||||||
|
List<TAppStock> targetStocks = appStockService.list(
|
||||||
|
new LambdaQueryWrapper<TAppStock>()
|
||||||
|
.eq(TAppStock::getVehicleId, inventoryConfirmRequest.getTargetVehicleId())
|
||||||
|
.eq(TAppStock::getGoodsId, targetInventory.getGoodsId())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (targetStocks.size() == 1) {
|
||||||
|
// 更新库存数量
|
||||||
|
int newRealNum = targetStocks.getFirst().getRealNum() + inventoryConfirmRequest.getNeedAddNum();
|
||||||
|
targetStocks.getFirst().setRealNum(newRealNum);
|
||||||
|
|
||||||
|
// 保存更新
|
||||||
|
appStockService.updateById(targetStocks.getFirst());
|
||||||
|
|
||||||
|
} else if (targetStocks.isEmpty()){
|
||||||
|
return BaseWmsApiResponse.error("目标容器已丢失,更新失败,请联系管理员确认!");
|
||||||
|
}else {
|
||||||
|
return BaseWmsApiResponse.error("目标容器已存在多个库存,更新失败,请联系管理员确认!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return BaseWmsApiResponse.error("请求的盘点任务号未查到对应的盘点任务。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 放行
|
||||||
|
if (conveyTaskService.releaseStandVehicle(thisPickTask)) {
|
||||||
|
return BaseWmsApiResponse.success("确认成功。");
|
||||||
|
} else {
|
||||||
|
// 回滚事务
|
||||||
|
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
|
||||||
|
return BaseWmsApiResponse.error("释放箱子失败。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取对应工单对应物料的缺料数量---实现
|
* 获取对应工单对应物料的缺料数量---实现
|
||||||
* @param goodsId 料号
|
* @param goodsId 料号
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.wms_main.service.controller.serviceImpl;
|
package com.wms_main.service.controller.serviceImpl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
|
import com.wms_main.constant.enums.wms.WmsTaskTypeEnums;
|
||||||
import com.wms_main.dao.*;
|
import com.wms_main.dao.*;
|
||||||
|
|
@ -16,6 +17,9 @@ import com.wms_main.service.controller.ITaskQueryControllerService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务查询控制类 服务实现
|
* 任务查询控制类 服务实现
|
||||||
*/
|
*/
|
||||||
|
|
@ -297,6 +301,50 @@ public class TaskQueryControllerServiceImpl implements ITaskQueryControllerServi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WmsApiResponse<String> updateOutsTaskStatus(OutsBatchEditDateVo batchEditDateVo) {
|
||||||
|
if (batchEditDateVo == null || batchEditDateVo.getTaskIds() == null || batchEditDateVo.getTaskIds().isEmpty()) {
|
||||||
|
return WmsApiResponse.error("任务ID列表不能为空", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> taskIds = batchEditDateVo.getTaskIds();
|
||||||
|
|
||||||
|
// 查询所有有效的任务
|
||||||
|
List<TAppOuts> existingOuts = appOutsService.list(
|
||||||
|
new LambdaQueryWrapper<TAppOuts>()
|
||||||
|
.in(TAppOuts::getTaskId, taskIds)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingOuts.isEmpty()) {
|
||||||
|
return WmsApiResponse.error("未找到任何对应的出库单", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤出状态不是-1的任务
|
||||||
|
List<String> validTaskIds = existingOuts.stream()
|
||||||
|
.filter(outs -> outs.getTaskStatus() != 0)
|
||||||
|
.map(TAppOuts::getTaskId)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
if (validTaskIds.isEmpty()) {
|
||||||
|
return WmsApiResponse.error("所有任务状态已经为已下发,无需重复下发", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量更新
|
||||||
|
LambdaUpdateWrapper<TAppOuts> updateWrapper = new LambdaUpdateWrapper<TAppOuts>()
|
||||||
|
.set(TAppOuts::getTaskStatus, 0)
|
||||||
|
.in(TAppOuts::getTaskId, validTaskIds);
|
||||||
|
|
||||||
|
boolean updateSuccess = appOutsService.update(updateWrapper);
|
||||||
|
|
||||||
|
if (updateSuccess) {
|
||||||
|
return WmsApiResponse.success("批量更新出库单状态成功,共更新" + validTaskIds.size() + "条记录", null);
|
||||||
|
} else {
|
||||||
|
return WmsApiResponse.error("批量更新出库单状态失败", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WmsApiResponse<String> batchEditDate(OutsBatchEditDateVo batchEditDateVo) {
|
public WmsApiResponse<String> batchEditDate(OutsBatchEditDateVo batchEditDateVo) {
|
||||||
// 1. 参数校验
|
// 1. 参数校验
|
||||||
|
|
@ -390,4 +438,7 @@ public class TaskQueryControllerServiceImpl implements ITaskQueryControllerServi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ public class OutsExecutorServiceImpl implements IOutsExecutorService {
|
||||||
List<TAppOuts> appOutsList = appOutsService.list(
|
List<TAppOuts> appOutsList = appOutsService.list(
|
||||||
new LambdaQueryWrapper<TAppOuts>()
|
new LambdaQueryWrapper<TAppOuts>()
|
||||||
.le(TAppOuts::getPickingDate, LocalDate.now())
|
.le(TAppOuts::getPickingDate, LocalDate.now())
|
||||||
|
.eq(TAppOuts::getTaskStatus, 0)
|
||||||
.orderByDesc(TAppOuts::getOutType)
|
.orderByDesc(TAppOuts::getOutType)
|
||||||
).stream()
|
).stream()
|
||||||
.filter(appOuts -> appOuts.getOutType() == 1 || appOuts.getDistributeNum() < appOuts.getNeedNum())
|
.filter(appOuts -> appOuts.getOutType() == 1 || appOuts.getDistributeNum() < appOuts.getNeedNum())
|
||||||
|
|
@ -1306,13 +1307,15 @@ public class OutsExecutorServiceImpl implements IOutsExecutorService {
|
||||||
|
|
||||||
// 生成拣选任务
|
// 生成拣选任务
|
||||||
if (oldPickTasks.isEmpty() && newOldPickTasks.isEmpty()) {
|
if (oldPickTasks.isEmpty() && newOldPickTasks.isEmpty()) {
|
||||||
|
// 根据inventory的类型设置pickType
|
||||||
|
int pickType = inventory.getInvType() != null && inventory.getInvType() == 3 ? 4 : 2;
|
||||||
newPickTasks.add(new TAppPickTask(
|
newPickTasks.add(new TAppPickTask(
|
||||||
UUIDUtils.getNewUUID(),
|
UUIDUtils.getNewUUID(),
|
||||||
getOptimalSubStand(inventory.getInvStand()),
|
getOptimalSubStand(inventory.getInvStand()),
|
||||||
stock.getVehicleId(),
|
stock.getVehicleId(),
|
||||||
pickTaskStatus,
|
pickTaskStatus,
|
||||||
LocalDateTime.now(),
|
LocalDateTime.now(),
|
||||||
null, null, null, 2
|
null, null, null, pickType
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// 设置盘点状态
|
// 设置盘点状态
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,14 @@ spring:
|
||||||
# url: jdbc:mysql://112.4.208.194:3001/wms_kate_wuxi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
|
# url: jdbc:mysql://112.4.208.194:3001/wms_kate_wuxi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
|
||||||
# username: developer
|
# username: developer
|
||||||
# password: developer
|
# password: developer
|
||||||
# 本地
|
# 本地12315
|
||||||
url: jdbc:mysql://localhost:3306/wms_fengshang_yangzhou?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
|
url: jdbc:mysql://localhost:3306/wms_fengshang_yangzhou?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
|
||||||
# username: wms
|
|
||||||
# password: Admin123
|
|
||||||
username: root
|
username: root
|
||||||
password: 123456
|
password: 123456
|
||||||
|
# 测试环境12306
|
||||||
|
# url: jdbc:mysql://localhost:3306/wms_test?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
|
||||||
|
# username: root
|
||||||
|
# password: 123456
|
||||||
#在线
|
#在线
|
||||||
# url: jdbc:mysql://172.18.222.253:3306/wms_fengshang_yangzhou?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
|
# url: jdbc:mysql://172.18.222.253:3306/wms_fengshang_yangzhou?characterEncoding=utf8&serverTimezone=Asia/Shanghai&allowMultiQueries=true&rewriteBatchedStatements=true
|
||||||
# username: root
|
# username: root
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user