diff --git a/wms/nladmin-ui/src/views/wms/ivt/stock/UpdateUploadDialog.vue b/wms/nladmin-ui/src/views/wms/ivt/stock/UpdateUploadDialog.vue new file mode 100644 index 0000000..0e9776e --- /dev/null +++ b/wms/nladmin-ui/src/views/wms/ivt/stock/UpdateUploadDialog.vue @@ -0,0 +1,148 @@ +<template> + <el-dialog + title="导入Excel文件" + append-to-body + :visible.sync="dialogVisible" + destroy-on-close + width="400px" + :show-close="true" + @close="close" + @open="open" + > + <el-upload + ref="upload" + class="upload-demo" + action="" + drag + :on-exceed="is_one" + :limit="1" + :auto-upload="false" + :multiple="false" + :show-file-list="true" + :on-change="uploadByJsqd" + :file-list="fileList" + accept=".xlsx,.xls" + > + <i class="el-icon-upload" /> + <div class="el-upload__text"> + 将文件拖到此处,或 + <em>点击上传</em> + </div> + <div slot="tip" class="el-upload__tip">只能上传Excel文件,且不超过10MB</div> + </el-upload> + <span slot="footer" class="dialog-footer"> + <el-button @click="dialogVisible = false">取 消</el-button> + <el-button type="primary" @click="submit">确 定</el-button> + </span> + </el-dialog> +</template> + +<script> +import crudStock, { excelUpdateImport } from './stock' +import CRUD, { crud } from '@crud/crud' +import { MessageBox } from 'element-ui' + +export default { + name: 'UpdateUploadDialog', + mixins: [crud()], + components: {}, + props: { + dialogShow: { + type: Boolean, + default: false + }, + openParam: { + type: String + } + }, + data() { + return { + dialogVisible: false, + fileList: [], + file1: '' + } + }, + watch: { + dialogShow: { + handler(newValue, oldValue) { + this.dialogVisible = newValue + } + }, + openParam: { + handler(newValue, oldValue) { + this.opendtlParam = newValue + } + } + }, + methods: { + open() { + }, + close() { + this.$emit('update:dialogShow', false) + }, + is_one() { + this.crud.notify('只能上传一个excel文件!', CRUD.NOTIFICATION_TYPE.WARNING) + }, + // 文件校验方法 + beforeAvatarUpload(file) { + // 不能导入大小超过2Mb的文件 + if (file.size > 10 * 1024 * 1024) { + return false + } + return true + }, + // 文件发生改变就会触发的事件 + uploadByJsqd(file) { + this.file1 = file + }, + submit() { + if (this.beforeAvatarUpload(this.file1)) { + // 显示确认弹窗 + MessageBox.confirm( + '您确定要上传该文件吗?', + '提示', + { + confirmButtonText: '确定', + cancelButtonText: '取消', + type: 'warning' + } + ) + .then(() => { + // 用户确认后执行上传逻辑 + this.fileList.name = this.file1.name + this.fileList.url = '' + var formdata = new FormData() + formdata.append('file', this.file1.raw) + // excelImport:请求接口 formdata:传递参数 + crudStock.excelUpdateImport(formdata).then((res) => { + this.crud.notify('导入成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + this.$emit('tableChanged4', '') + this.$emit('update:dialogShow', false) + }) + }) + .catch(() => { + // 用户取消上传 + this.crud.notify('已取消上传', CRUD.NOTIFICATION_TYPE.INFO) + }) + } else { + this.crud.notify('文件过大,请上传小于10MB的文件〜', CRUD.NOTIFICATION_TYPE.WARNING) + } + // if (this.beforeAvatarUpload(this.file1)) { + // this.fileList.name = this.file1.name + // this.fileList.url = '' + // var formdata = new FormData() + // formdata.append('file', this.file1.raw) + // // excelImport:请求接口 formdata:传递参数 + // crudStock.excelImport(formdata).then((res) => { + // this.crud.notify('导入成功', CRUD.NOTIFICATION_TYPE.SUCCESS) + // this.$emit('tableChanged3', '') + // this.$emit('update:dialogShow', false) + // }) + // } else { + // this.crud.notify('文件过大,请上传小于10MB的文件〜', CRUD.NOTIFICATION_TYPE.WARNING) + // } + } + } +} +</script> + diff --git a/wms/nladmin-ui/src/views/wms/ivt/stock/index.vue b/wms/nladmin-ui/src/views/wms/ivt/stock/index.vue index acafac7..27fb703 100644 --- a/wms/nladmin-ui/src/views/wms/ivt/stock/index.vue +++ b/wms/nladmin-ui/src/views/wms/ivt/stock/index.vue @@ -46,7 +46,7 @@ @keyup.enter.native="crud.toQuery" /> </el-form-item> - <rrOperation/> + <rrOperation /> </el-form> </div> <!--如果想在工具栏加入更多按钮,可以使用插槽方式, slot = 'left' or 'right'--> @@ -61,6 +61,16 @@ > 导入库存 </el-button> + <el-button + slot="right" + class="filter-item" + type="danger" + icon="el-icon-upload2" + size="mini" + @click="uploadUpdateShow = true" + > + 库存编码更新 + </el-button> <el-button slot="right" class="filter-item" @@ -84,38 +94,52 @@ <el-form ref="form" :model="form" :rules="rules" size="mini" label-suffix=":" label-width="90px"> <el-row :gutter="20"> <el-col :span="12"> -<!-- <el-form-item label="库位编码" prop="struct_code">--> -<!-- <el-input v-model="form.struct_code" style="width: 200px;"/>--> -<!-- </el-form-item>--> + <!-- <el-form-item label="库位编码" prop="struct_code">--> + <!-- <el-input v-model="form.struct_code" style="width: 200px;"/>--> + <!-- </el-form-item>--> <el-form-item label="库位编码" prop="struct_code"> - <el-select filterable clearable style="width: 200px;" v-model="form.struct_code" placeholder="请选择库位编码"> - <el-option v-for="item in structs" :key="item.struct_code" :label="item.struct_code" :value="item.struct_code"></el-option> + <el-select v-model="form.struct_code" filterable clearable style="width: 200px;" placeholder="请选择库位编码"> + <el-option + v-for="item in structs" + :key="item.struct_code" + :label="item.struct_code" + :value="item.struct_code" + /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="物料编码" prop="material_code"> - <el-input v-model="form.material_code" style="width: 200px;" @clear="clearMaterial" - @focus="getMaterial"/> + <el-input + v-model="form.material_code" + style="width: 200px;" + @clear="clearMaterial" + @focus="getMaterial" + /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="物料名称" prop="material_name"> - <el-input disabled v-model="form.material_name" style="width: 200px;"/> + <el-input v-model="form.material_name" disabled style="width: 200px;" /> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="数量" prop="qty"> - <el-input @input="handleInput" :rules="[{ required: true, validator: validateQty, trigger: 'blur' }]" v-model="form.qty" style="width: 200px;"/> + <el-input + v-model="form.qty" + :rules="[{ required: true, validator: validateQty, trigger: 'blur' }]" + style="width: 200px;" + @input="handleInput" + /> </el-form-item> </el-col> </el-row> <el-row :gutter="20"> <el-col :span="12"> <el-form-item label="计量单位" prop="unit"> - <el-input v-model="form.unit" style="width: 200px;"/> + <el-input v-model="form.unit" style="width: 200px;" /> </el-form-item> </el-col> <el-col :span="12"> @@ -134,7 +158,7 @@ <el-col :span="12"> <el-form-item label="备注"> <label slot="label">备 注:</label> - <el-input v-model="form.remark" style="width: 550px;" rows="2" type="textarea"/> + <el-input v-model="form.remark" style="width: 550px;" rows="2" type="textarea" /> </el-form-item> </el-col> </el-row> @@ -154,21 +178,21 @@ @selection-change="crud.selectionChangeHandler" > <!-- <el-table-column type="selection" width="55"/>--> - <el-table-column prop="id" label="库存ID" v-if="false" :min-width="flexWidth('id',crud.data,'库存ID')"/> + <el-table-column v-if="false" prop="id" label="库存ID" :min-width="flexWidth('id',crud.data,'库存ID')" /> <el-table-column prop="material_code" label="物料编码" :min-width="flexWidth('material_code',crud.data,'物料编码')"> <template slot-scope="scope"> <el-link type="warning" @click="toView(scope.row)">{{ scope.row.material_code }}</el-link> </template> </el-table-column> - <el-table-column prop="material_name" label="物料名称" :min-width="flexWidth('material_name',crud.data,'物料名称')"/> - <el-table-column prop="struct_code" label="仓位编码" :min-width="flexWidth('struct_code',crud.data,'仓位编码')"/> - <el-table-column prop="struct_name" label="仓位名称" :min-width="flexWidth('struct_name',crud.data,'仓位名称')"/> - <el-table-column prop="stor_code" label="仓库编码" :min-width="flexWidth('stor_code',crud.data,'仓库编码')"/> - <el-table-column prop="stor_name" label="仓库名称" :min-width="flexWidth('stor_name',crud.data,'仓库名称')"/> - <el-table-column prop="org_code" label="库存组织编码" :min-width="flexWidth('org_code',crud.data,'库存组织编码')"/> - <el-table-column prop="org_name" label="库存组织名称" :min-width="flexWidth('org_name',crud.data,'库存组织名称')"/> - <el-table-column prop="vehicle_code" label="载具编码" :min-width="flexWidth('vehicle_code',crud.data,'载具编码')"/> - <el-table-column prop="total_qty" label="数量" :min-width="flexWidth('total_qty',crud.data,'数量')"/> + <el-table-column prop="material_name" label="物料名称" :min-width="flexWidth('material_name',crud.data,'物料名称')" /> + <el-table-column prop="struct_code" label="仓位编码" :min-width="flexWidth('struct_code',crud.data,'仓位编码')" /> + <el-table-column prop="struct_name" label="仓位名称" :min-width="flexWidth('struct_name',crud.data,'仓位名称')" /> + <el-table-column prop="stor_code" label="仓库编码" :min-width="flexWidth('stor_code',crud.data,'仓库编码')" /> + <el-table-column prop="stor_name" label="仓库名称" :min-width="flexWidth('stor_name',crud.data,'仓库名称')" /> + <el-table-column prop="org_code" label="库存组织编码" :min-width="flexWidth('org_code',crud.data,'库存组织编码')" /> + <el-table-column prop="org_name" label="库存组织名称" :min-width="flexWidth('org_name',crud.data,'库存组织名称')" /> + <el-table-column prop="vehicle_code" label="载具编码" :min-width="flexWidth('vehicle_code',crud.data,'载具编码')" /> + <el-table-column prop="total_qty" label="数量" :min-width="flexWidth('total_qty',crud.data,'数量')" /> <!-- <el-table-column prop="remark" label="备注" :min-width="flexWidth('remark',crud.data,'备注')"--> <!-- show-overflow-tooltip/>--> <!-- <el-table-column prop="update_name" label="修改人" :min-width="flexWidth('update_name',crud.data,'修改人')"/>--> @@ -189,17 +213,18 @@ <!-- </el-table-column>--> </el-table> <!--分页组件--> - <pagination/> + <pagination /> </div> - <ViewDialog ref="itemView"/> - <MaterialDialog :dialog-show.sync="materialDialog" @tableChanged="tableChanged"/> - <UploadDialog :dialog-show.sync="uploadShow" @tableChanged3="tableChanged3"/> + <ViewDialog ref="itemView" /> + <MaterialDialog :dialog-show.sync="materialDialog" @tableChanged="tableChanged" /> + <UploadDialog :dialog-show.sync="uploadShow" @tableChanged3="tableChanged3" /> + <UpdateUploadDialog :dialog-show.sync="uploadUpdateShow" @tableChanged4="tableChanged4" /> </div> </template> <script> import crudStock from '@/views/wms/ivt/stock/stock' -import CRUD, {crud, form, header, presenter} from '@crud/crud' +import CRUD, { crud, form, header, presenter } from '@crud/crud' import rrOperation from '@crud/RR.operation' import crudOperation from '@crud/CRUD.operation' import udOperation from '@crud/UD.operation' @@ -209,7 +234,7 @@ import crudStruct from '@/views/wms/ivt/struct/structattr' import MaterialDialog from '@/views/wms/ivt/stock/MaterialDialog.vue' import ViewDialog from './ViewDialog' import UploadDialog from './UploadDialog' - +import UpdateUploadDialog from './UpdateUploadDialog' const defaultForm = { id: null, @@ -232,15 +257,24 @@ const defaultForm = { export default { name: 'Stock', dicts: ['is_used', 'SCH_TASK_TYPE_DTL', 'placement_type'], - components: {pagination, crudOperation, rrOperation, udOperation, MaterialDialog, ViewDialog, UploadDialog}, + components: { + pagination, + crudOperation, + rrOperation, + udOperation, + MaterialDialog, + ViewDialog, + UploadDialog, + UpdateUploadDialog + }, mixins: [presenter(), header(), form(defaultForm), crud()], cruds() { return CRUD({ title: '库存', - optShow: {add: true, reset: true, download: true}, + optShow: { add: true, reset: true, download: true }, url: 'api/stIvtStockDtl', idField: 'id', - crudMethod: {...crudStock}, + crudMethod: { ...crudStock } }) }, data() { @@ -262,29 +296,30 @@ export default { stors: [], structs: [], uploadShow: false, + uploadUpdateShow: false, materialDialog: false, permission: {}, rules: { struct_code: [ - {required: true, message: '仓位编码不能为空', trigger: 'blur'} + { required: true, message: '仓位编码不能为空', trigger: 'blur' } ], material_code: [ - {required: true, message: '物料编码不能为空', trigger: 'blur'} + { required: true, message: '物料编码不能为空', trigger: 'blur' } ], qty: [ - {required: true, message: '数量不能为空', trigger: 'blur'} + { required: true, message: '数量不能为空', trigger: 'blur' } ], storage_time: [ - {required: true, message: '入库时间不能为空', trigger: 'blur'} + { required: true, message: '入库时间不能为空', trigger: 'blur' } ], unit: [ - {required: true, message: '计量单位不能为空', trigger: 'blur'} - ], + { required: true, message: '计量单位不能为空', trigger: 'blur' } + ] } } }, created() { - crudStruct.getStructs("3.03.001").then(res => { + crudStruct.getStructs('3.03.001').then(res => { this.structs = res }) }, @@ -295,13 +330,13 @@ export default { }, handleInput(value) { // 只允许输入数字,过滤非数字字符 - this.form.qty = value.replace(/[^\d.]/g, '').replace(/^0+/, ''); + this.form.qty = value.replace(/[^\d.]/g, '').replace(/^0+/, '') }, validateQty(rule, value, callback) { if (value <= 0 || isNaN(value)) { - callback(new Error('数量必须大于 0')); + callback(new Error('数量必须大于 0')) } else { - callback(); + callback() } }, [CRUD.HOOK.afterToEdit](crud, form) { @@ -371,6 +406,9 @@ export default { tableChanged3() { this.crud.toQuery() }, + tableChanged4() { + this.crud.toQuery() + }, initMaterialName() { crudStock.initMaterialName().then(res => { this.crud.toQuery() diff --git a/wms/nladmin-ui/src/views/wms/ivt/stock/stock.js b/wms/nladmin-ui/src/views/wms/ivt/stock/stock.js index 32f73de..142d840 100644 --- a/wms/nladmin-ui/src/views/wms/ivt/stock/stock.js +++ b/wms/nladmin-ui/src/views/wms/ivt/stock/stock.js @@ -26,7 +26,7 @@ export function edit(data) { export function getDtl(id, material_code) { return request({ - url: 'api/stIvtStockDtl/getDtl/' + id + "/" + material_code, + url: 'api/stIvtStockDtl/getDtl/' + id + '/' + material_code, method: 'get' }) } @@ -46,4 +46,12 @@ export function initMaterialName() { }) } -export default {add, edit, del, getDtl, excelImport, initMaterialName} +export function excelUpdateImport(data) { + return request({ + url: 'api/stIvtStockDtl/excelUpdateImport', + method: 'post', + data + }) +} + +export default { add, edit, del, getDtl, excelImport, initMaterialName, excelUpdateImport } diff --git a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/controller/StIvtStockDtlController.java b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/controller/StIvtStockDtlController.java index 2048919..00b7c32 100644 --- a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/controller/StIvtStockDtlController.java +++ b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/controller/StIvtStockDtlController.java @@ -4,7 +4,6 @@ package org.nl.wms.ivt.controller; import org.nl.common.domain.query.PageQuery; import org.nl.wms.ivt.service.IStIvtStockDtlService; import org.nl.wms.ivt.service.dao.StIvtStockDtl; -import org.nl.wms.ivt.service.dto.OrgQuery; import org.nl.wms.ivt.service.dto.StockDtlQuery; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -59,6 +58,12 @@ public class StIvtStockDtlController { return new ResponseEntity<>(HttpStatus.OK); } + @PostMapping("/excelUpdateImport") + public ResponseEntity<Object> excelUpdateImport(@RequestParam("file") MultipartFile file, HttpServletRequest request) { + stockDtlService.excelUpdateImport(file, request); + return new ResponseEntity<>(HttpStatus.OK); + } + @PutMapping("/initMaterialName") public ResponseEntity<Object> initMaterialName() { stockDtlService.initMaterialName(); diff --git a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/IStIvtStockDtlService.java b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/IStIvtStockDtlService.java index a97f081..e3c487d 100644 --- a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/IStIvtStockDtlService.java +++ b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/IStIvtStockDtlService.java @@ -83,6 +83,8 @@ public interface IStIvtStockDtlService extends IService<StIvtStockDtl> { void excelImport(MultipartFile file, HttpServletRequest request); + void excelUpdateImport(MultipartFile file, HttpServletRequest request); + void initMaterialName(); diff --git a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/impl/StIvtStockDtlServiceImpl.java b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/impl/StIvtStockDtlServiceImpl.java index 4c7ace9..5d9b802 100644 --- a/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/impl/StIvtStockDtlServiceImpl.java +++ b/wms/nlsso-server/src/main/java/org/nl/wms/ivt/service/impl/StIvtStockDtlServiceImpl.java @@ -238,6 +238,88 @@ public class StIvtStockDtlServiceImpl extends ServiceImpl<StIvtStockDtlMapper, S } } + @Override + @Transactional(rollbackFor = Exception.class) + public void excelUpdateImport(MultipartFile file, HttpServletRequest request) { + if (file.isEmpty()) { + throw new BadRequestException("文件为空,请添加数据后重新导入"); + } + + InputStream inputStream = null; + try { + inputStream = file.getInputStream(); + } catch (Exception e) { + e.printStackTrace(); + } + + ExcelReader excelReader = ExcelUtil.getReader(inputStream); + List<List<Object>> read = excelReader.read(1, excelReader.getRowCount()); + + Set<String> oldMaterialCodes = new HashSet<>(); + List<MdBaseMaterial> materials = new ArrayList<>(); + List<StIvtStockDtl> newStIvtStockDtls = new ArrayList<>(); + + // Collect all old material codes first + for (List<Object> row : read) { + String oldMaterialCode = row.get(0).toString().trim(); + if (!StrUtil.isEmpty(oldMaterialCode)) { + oldMaterialCodes.add(oldMaterialCode); + } + } + + // Batch query to get all materials at once + List<MdBaseMaterial> existingMaterials = materialService.list(new LambdaQueryWrapper<MdBaseMaterial>() + .in(MdBaseMaterial::getMaterial_code, oldMaterialCodes)); + + Map<String, MdBaseMaterial> materialMap = existingMaterials.stream() + .collect(Collectors.toMap(MdBaseMaterial::getMaterial_code, material -> material)); + + // Process data in batches + for (List<Object> row : read) { + String oldMaterialCode = row.get(0).toString().trim(); + String newMaterialCode = row.get(1).toString().trim(); + String materialName = row.get(2).toString().trim(); + + if (StrUtil.isEmpty(newMaterialCode) || StrUtil.isEmpty(oldMaterialCode)) { + continue; + } + + MdBaseMaterial baseMaterial = materialMap.get(oldMaterialCode); + if (baseMaterial != null) { + baseMaterial.setMaterial_code(newMaterialCode); + baseMaterial.setMaterial_name(materialName); + materials.add(baseMaterial); + } else { + MdBaseMaterial newMaterial = new MdBaseMaterial(); + newMaterial.setMaterial_id(IdUtil.getLongId().toString()); + newMaterial.setMaterial_code(newMaterialCode); + newMaterial.setMaterial_name(materialName); + materials.add(newMaterial); + } + + List<StIvtStockDtl> stockDtls = stockDtlMapper.selectList( + new LambdaQueryWrapper<StIvtStockDtl>().eq(StIvtStockDtl::getMaterial_code, oldMaterialCode) + ); + + if (CollectionUtils.isNotEmpty(stockDtls)) { + for (StIvtStockDtl stockDtl : stockDtls) { + stockDtl.setMaterial_code(newMaterialCode); + stockDtl.setMaterial_name(materialName); + newStIvtStockDtls.add(stockDtl); + } + } + } + + // Batch insert/update + if (CollectionUtils.isNotEmpty(materials)) { + materialService.saveOrUpdateBatch(materials,5000); + } + if (CollectionUtils.isNotEmpty(newStIvtStockDtls)) { + this.updateBatchById(newStIvtStockDtls,5000); + } + } + + @Override @Transactional(rollbackFor = Exception.class) public void initMaterialName() { diff --git a/wms/nlsso-server/src/main/java/org/nl/wms/schedule/EasBillSchedule.java b/wms/nlsso-server/src/main/java/org/nl/wms/schedule/EasBillSchedule.java index 4ff7efc..06d2dd6 100644 --- a/wms/nlsso-server/src/main/java/org/nl/wms/schedule/EasBillSchedule.java +++ b/wms/nlsso-server/src/main/java/org/nl/wms/schedule/EasBillSchedule.java @@ -62,7 +62,7 @@ public class EasBillSchedule { easDataSyncService.syncAddUserInfo(); } - // @Scheduled(cron = "0/60 * * * * *") +// @Scheduled(cron = "0/60 * * * * *") public void syncEasMaterial() { easDataSyncService.syncAddMaterialInfo(); }