Commit c5a04317 by yubin

inventory

parent 2ae44490
<template>
<div class="material-select-component">
<el-dialog :title="title" :visible.sync="visible" width="900px" append-to-body>
<!-- 左右分栏布局 -->
<div class="split-layout">
<!-- 左侧分类树 -->
<div class="left-panel">
<TreeComponent
ref="treeComponent"
:tree-data="categoryTreeData"
:tree-props="treeProps"
:node-key="nodeKey"
:show-search="true"
search-placeholder="请输入分类名称"
:default-expand-all="true"
:highlight-current="true"
:loading="loadingTree"
@node-click="handleCategoryChange"
>
<!-- 自定义节点内容插槽 -->
<template #node-content="{ node, data }">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
</span>
</template>
</TreeComponent>
</div>
<!-- 右侧物料列表 -->
<div class="right-panel">
<!-- 物料列表 -->
<el-table v-loading="loading" :data="materialsList" @selection-change="handleSelectionChange" :scroll-x="true">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号" align="center" />
<el-table-column label="物料编码" align="center" prop="materialCode" />
<el-table-column label="物料名称" align="center" prop="materialName" />
<el-table-column label="SAP物料号" align="center" prop="sapNo" />
<el-table-column label="规格型号" align="center" prop="specification" />
<el-table-column label="计量单位" align="center" prop="materialUnit" />
</el-table>
<!-- 分页 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
<!-- 底部按钮 -->
<div slot="footer" class="dialog-footer">
<el-button @click="cancel">取 消</el-button>
<el-button type="primary" @click="confirmSelection">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listMaterials } from "@/api/inventory/materials"
import { listMaterials_category } from "@/api/inventory/materials_category"
import Pagination from "@/components/Pagination"
import TreeComponent from './treeComponent.vue'
export default {
name: "MaterialSelectComponent",
components: {
Pagination,
TreeComponent
},
props: {
// 对话框标题
title: {
type: String,
default: "选择物料"
},
// 是否显示对话框
visible: {
type: Boolean,
default: false
}
},
data() {
return {
// 树相关数据
categoryTreeData: [],
treeProps: {
children: 'children',
label: 'label',
value: 'sid'
},
nodeKey: 'sid',
loadingTree: false,
// 分类映射
categoryMap: {},
// 选中的分类
selectedCategory: null,
// 加载状态
loading: false,
// 总条数
total: 0,
// 物料列表
materialsList: [],
// 选中的物料
selectedMaterials: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
categoryCode: null
}
}
},
watch: {
// 监听对话框显示状态,当显示时加载物料列表和分类树
visible(newVal) {
if (newVal) {
this.getCategoryTreeData()
this.getList()
}
}
},
methods: {
/** 获取分类树数据 */
async getCategoryTreeData() {
this.loadingTree = true
try {
// 调用物料分类列表API获取所有分类
const response = await listMaterials_category({
pageNum: 1,
pageSize: 1000 // 获取足够多的数据
})
if (response.rows && response.rows.length > 0) {
// 过滤掉已禁用的分类
const activeCategories = response.rows.filter(item =>
item.isUsed !== 0 && item.isUsed !== '0'
)
// 构建树形结构
this.categoryTreeData = this.buildTreeData(activeCategories)
// 构建分类映射
this.buildCategoryMap(activeCategories)
}
} catch (error) {
console.error('获取分类树数据失败:', error)
} finally {
this.loadingTree = false
}
},
/** 构建树形结构 */
buildTreeData(list, parentId = null) {
const result = list
.filter(item => {
if (parentId === null) {
// 根节点:parentId为null、0或空
return !item.parentId || item.parentId === 0 || item.parentId === '0'
} else {
// 子节点:parentId匹配
return item.parentId == parentId
}
})
.map(item => {
const children = this.buildTreeData(list, item.id)
return {
...item,
sid: String(item.id),
label: item.categoryName,
children: children.length > 0 ? children : undefined
}
})
return result
},
/** 构建分类映射 */
buildCategoryMap(categories) {
this.categoryMap = {}
categories.forEach(item => {
this.categoryMap[item.id] = item.categoryName
})
},
/** 处理分类选择变化 */
handleCategoryChange(data) {
this.selectedCategory = data
// 更新查询参数,按选中的分类筛选物料
this.queryParams.categoryCode = data ? data.categoryCode : null
this.queryParams.pageNum = 1
this.getList()
},
/** 获取物料列表 */
async getList() {
this.loading = true
try {
const response = await listMaterials(this.queryParams)
this.materialsList = response.rows
this.total = response.total
} catch (error) {
console.error('获取物料列表失败:', error)
} finally {
this.loading = false
}
},
/** 处理选择变化 */
handleSelectionChange(selection) {
this.selectedMaterials = selection
},
/** 确认选择 */
confirmSelection() {
// 提取选中物料的uuid和名称,用逗号隔开
const uuids = this.selectedMaterials
.map(item => item.uuid || item.id) // 兼容uuid和id字段
.join(',')
const names = this.selectedMaterials
.map(item => item.materialName) // 提取物料名称
.join(',')
// 触发选择确认事件,将选中的uuid和名称传递给父组件
this.$emit('selection-confirm', uuids, names)
// 关闭对话框
this.$emit('update:visible', false)
},
/** 取消选择 */
cancel() {
// 清空选择
this.selectedMaterials = []
this.selectedCategory = null
this.queryParams.categoryCode = null
// 触发取消事件
this.$emit('selection-cancel')
// 关闭对话框
this.$emit('update:visible', false)
}
}
}
</script>
<style scoped>
.material-select-component {
.dialog-footer {
text-align: right;
}
.split-layout {
display: flex;
height: 500px;
gap: 10px;
.left-panel {
width: 250px;
border: 1px solid #e4e7ed;
border-radius: 4px;
overflow: hidden;
.tree-container {
height: 100%;
}
}
.right-panel {
flex: 1;
display: flex;
flex-direction: column;
.el-table {
flex: 1;
overflow: auto;
}
.pagination {
margin-top: 10px;
}
}
}
}
</style>
\ No newline at end of file
...@@ -127,6 +127,11 @@ ...@@ -127,6 +127,11 @@
<div><strong>层:</strong>{{ scope.row.layerCode || '-' }}</div> <div><strong>层:</strong>{{ scope.row.layerCode || '-' }}</div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" style="margin: 10px 0;">
<el-col :span="24">
<div><strong>允许存放物料名称:</strong>{{ scope.row.materialNames || '-' }}</div>
</el-col>
</el-row>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
...@@ -176,6 +181,15 @@ ...@@ -176,6 +181,15 @@
</el-tooltip> </el-tooltip>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="允许存放物料编码" align="center" prop="materialCodes" width="200">
<template slot-scope="scope">
<el-tooltip :content="scope.row.materialCodes" placement="top">
<div class="material-names">
{{ scope.row.materialCodes ? (scope.row.materialCodes.length > 20 ? scope.row.materialCodes.substring(0, 20) + '...' : scope.row.materialCodes) : '-' }}
</div>
</el-tooltip>
</template>
</el-table-column>
<el-table-column label="温区" align="center" prop="temperatureZone" width="120" /> <el-table-column label="温区" align="center" prop="temperatureZone" width="120" />
<el-table-column label="应用状态" align="center" prop="isEnabled" width="100" fixed="right"> <el-table-column label="应用状态" align="center" prop="isEnabled" width="100" fixed="right">
<template slot-scope="scope"> <template slot-scope="scope">
...@@ -212,7 +226,6 @@ ...@@ -212,7 +226,6 @@
@pagination="getList" @pagination="getList"
/> />
<!-- 添加或修改库位对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body> <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px"> <el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row :gutter="20"> <el-row :gutter="20">
...@@ -268,7 +281,6 @@ ...@@ -268,7 +281,6 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
...@@ -281,10 +293,9 @@ ...@@ -281,10 +293,9 @@
<el-input v-model="form.rowCode" placeholder="请输入排" /> <el-input v-model="form.rowCode" placeholder="请输入排" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="列" prop="columnCode"> <el-form-item label="列" prop="columnCode">
<el-input v-model="form.columnCode" placeholder="请输入列" /> <el-input v-model="form.columnCode" placeholder="请输入列" />
</el-form-item> </el-form-item>
...@@ -298,12 +309,12 @@ ...@@ -298,12 +309,12 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="库位容量(千克)" prop="capacity"> <el-form-item label="库位容量(千克)" prop="capacity">
<el-input v-model="form.capacity" placeholder="请输入库位容量(千克)" /> <el-input v-model.number="form.capacity" placeholder="请输入库位容量(千克)" type="number" min="0" step="0.01" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="体积容量(立方米)" prop="volumeCapacity"> <el-form-item label="体积容量(立方米)" prop="volumeCapacity">
<el-input v-model="form.volumeCapacity" placeholder="请输入体积容量(立方米)" /> <el-input v-model.number="form.volumeCapacity" placeholder="请输入体积容量(立方米)" type="number" min="0" step="0.01" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -314,18 +325,29 @@ ...@@ -314,18 +325,29 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="物料" prop="materialUuids"> <el-form-item label="允许存放物料" prop="materialCodes">
<div style="display: flex; align-items: center;"> <div style="display: flex; align-items: center; flex-direction: column; gap: 8px;">
<el-input v-model="form.materialNames" placeholder="" readonly style="flex: 1;" /> <el-input
<el-button type="primary" size="small" @click="showMaterialSelect = true" style="margin-left: 10px">选择物料</el-button> v-model="form.materialNames"
placeholder="请选择允许存放的物料"
readonly
style="width: 100%;"
/>
<el-button
type="primary"
size="small"
@click.stop="showMaterialSelect = true"
style="align-self: flex-end;"
>选择物料</el-button>
</div> </div>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="应用状态" prop="isEnabled"> <el-form-item label="应用状态" prop="isEnabled">
<el-radio-group v-model="form.isEnabled" style="width: 100%;"> <el-radio-group v-model="form.isEnabled" style="width: 100%;">
<el-radio :label="1"></el-radio> <el-radio :label="1"></el-radio>
<el-radio :label="0"></el-radio> <el-radio :label="0"></el-radio>
</el-radio-group> </el-radio-group>
...@@ -336,13 +358,14 @@ ...@@ -336,13 +358,14 @@
<el-input v-model.number="form.sortNo" type="number" placeholder="请输入排序" min="0" step="1" /> <el-input v-model.number="form.sortNo" type="number" placeholder="请输入排序" min="0" step="1" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24"> <el-col :span="24">
<el-form-item label="温区" prop="temperatureZone"> <el-form-item label="温区" prop="temperatureZone">
<el-input v-model="form.temperatureZone" type="textarea" placeholder="请输入内容" :rows="3" /> <el-input v-model="form.temperatureZone" type="textarea" placeholder="请输入温区信息" :rows="3" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button> <el-button type="primary" @click="submitForm">确 定</el-button>
...@@ -350,44 +373,51 @@ ...@@ -350,44 +373,51 @@
</div> </div>
</el-dialog> </el-dialog>
<!-- 物料选择组件 --> <el-dialog
<MaterialSelectComponent title="选择允许存放的物料"
:visible.sync="showMaterialSelect" :visible.sync="showMaterialSelect"
@selection-confirm="handleMaterialSelectionConfirm" width="1000px"
@selection-cancel="handleMaterialSelectionCancel" append-to-body
/> :close-on-click-modal="false"
:close-on-press-escape="false"
>
<materialsSeletor
ref="materialsSeletor"
@selection-change="handleMaterialSelectionChange"
:selected-material-codes="form.materialCodes ? form.materialCodes.split(',').filter(u => u.trim()) : []"
:multiple="true"
:default-category-codes="form.allowedCategoryIds ? form.allowedCategoryIds.split(',').filter(c => c.trim()) : []"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="handleMaterialSelectionCancel">取消</el-button>
<el-button type="primary" @click="confirmMaterialSelection">确认选择</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { listLocations, getLocations, delLocations, addLocations, updateLocations } from "@/api/inventory/locations" import { listLocations, getLocations, delLocations, addLocations, updateLocations } from "@/api/inventory/locations"
import { listWarehouses } from "@/api/inventory/warehouses" import { listWarehouses } from "@/api/inventory/warehouses"
import MaterialSelectComponent from "./MaterialSelectComponent.vue" import materialsSeletor from "../../../components/materialsSeletor.vue"
import { listMaterials } from "@/api/inventory/materials"
export default { export default {
name: "Locations", name: "Locations",
components: { MaterialSelectComponent }, components: { materialsSeletor },
data() { data() {
return { return {
// 遮罩层
loading: true, loading: true,
// 选中数组
ids: [], ids: [],
// 非单个禁用
single: true, single: true,
// 非多个禁用
multiple: true, multiple: true,
// 显示搜索条件
showSearch: true, showSearch: true,
// 总条数
total: 0, total: 0,
// 库位表格数据
locationsList: [], locationsList: [],
// 弹出层标题
title: "", title: "",
// 是否显示弹出层
open: false, open: false,
// 字典类型
dict: { dict: {
type: { type: {
location_type: [ location_type: [
...@@ -402,7 +432,7 @@ export default { ...@@ -402,7 +432,7 @@ export default {
] ]
} }
}, },
// 查询参数
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 10,
...@@ -410,6 +440,15 @@ export default { ...@@ -410,6 +440,15 @@ export default {
locationName: null, locationName: null,
warehousesCode: null, warehousesCode: null,
locationType: null, locationType: null,
layerCode: null
},
form: {
id: null,
locationCode: null,
locationName: null,
warehousesCode: null,
locationType: null,
zoneCode: null, zoneCode: null,
rowCode: null, rowCode: null,
columnCode: null, columnCode: null,
...@@ -417,17 +456,16 @@ export default { ...@@ -417,17 +456,16 @@ export default {
capacity: null, capacity: null,
volumeCapacity: null, volumeCapacity: null,
allowedHazardLevels: null, allowedHazardLevels: null,
materialCodes: null,
materialNames: null,
allowedCategoryIds: null, allowedCategoryIds: null,
allowedCategoryNames: null,
temperatureZone: null, temperatureZone: null,
isEnabled: null, isEnabled: 1,
isUsed: null, isUsed: 0,
sortNo: null, sortNo: 0
createUserCode: null,
updateUserCode: null
}, },
// 表单参数
form: {},
// 表单校验
rules: { rules: {
locationCode: [ locationCode: [
{ required: true, message: '库位编码不能为空', trigger: 'blur' }, { required: true, message: '库位编码不能为空', trigger: 'blur' },
...@@ -447,30 +485,72 @@ export default { ...@@ -447,30 +485,72 @@ export default {
{ required: true, message: '应用状态不能为空', trigger: 'change' } { required: true, message: '应用状态不能为空', trigger: 'change' }
] ]
}, },
// 仓库列表
warehouseOptions: [], warehouseOptions: [],
// 仓库加载状态
loadingWarehouse: false, loadingWarehouse: false,
// 物料选择组件显示状态
showMaterialSelect: false showMaterialSelect: false,
tempSelectedMaterials: {
materialCodes: [],
names: [],
categoryIds: []
},
materialCodeToNameMap: {},
materialMapLoaded: false
} }
}, },
created() { created() {
this.getList() this.getList()
this.getWarehouseOptions() this.getWarehouseOptions()
this.initMaterialCodeToNameMap()
}, },
methods: { methods: {
/** 处理行点击事件 */ async initMaterialCodeToNameMap() {
try {
this.materialMapLoaded = true
let pageNum = 1
const pageSize = 1000
let hasMore = true
this.materialCodeToNameMap = {}
while (hasMore) {
const response = await listMaterials({
pageNum,
pageSize,
isUsed: 1,
materialCode: null,
materialName: null
})
if (response.rows && response.rows.length) {
response.rows.forEach(item => {
if (item.materialCode && item.materialName) {
const code = item.materialCode.trim().toUpperCase()
this.materialCodeToNameMap[code] = item.materialName
}
})
hasMore = pageNum * pageSize < response.total
pageNum++
} else {
hasMore = false
}
}
console.log('物料映射表初始化完成:', this.materialCodeToNameMap)
} catch (error) {
console.error('初始化物料编码-名称映射表失败:', error)
this.materialMapLoaded = false
this.$modal.msgError('物料数据加载失败,请刷新页面重试!')
}
},
handleRowClick(row, event, column) { handleRowClick(row, event, column) {
// 排除点击选择列时触发展开/折叠
if (column.type !== 'selection') { if (column.type !== 'selection') {
this.$refs.locationsTable.toggleRowExpansion(row) this.$refs.locationsTable.toggleRowExpansion(row)
} }
}, },
/** 查询库位列表 */
getList() { getList() {
this.loading = true this.loading = true
// 添加is_used=0条件,只查询未被使用的库位
const params = { const params = {
...this.queryParams, ...this.queryParams,
isUsed: 0 isUsed: 0
...@@ -482,30 +562,14 @@ export default { ...@@ -482,30 +562,14 @@ export default {
}) })
}, },
/** 查询仓库列表 */
getWarehouseOptions() { getWarehouseOptions() {
this.loadingWarehouse = true this.loadingWarehouse = true
// 移除isUsed=0条件,查询所有仓库
listWarehouses({ pageNum: 1, pageSize: 100 }).then(response => { listWarehouses({ pageNum: 1, pageSize: 100 }).then(response => {
// 调试:查看仓库数据结构
console.log('仓库数据:', response)
// 确保rows存在且为数组
const rows = response.rows || [] const rows = response.rows || []
this.warehouseOptions = rows.map(item => ({
// 处理不同可能的数据结构 label: `${item.warehousesName || item.name || '未命名仓库'} (${item.warehouseCode || item.code || item.warehousesCode || ''})`,
this.warehouseOptions = rows.map(item => { value: item.warehouseCode || item.code || item.warehousesCode || ''
// 根据实际数据结构调整字段名 })).filter(option => option.value)
const warehouseName = item.warehousesName || item.name || '未命名仓库'
const warehouseCode = item.warehouseCode || item.code || item.warehousesCode || ''
return {
label: `${warehouseName} (${warehouseCode})`,
value: warehouseCode
}
}).filter(option => option.value) // 过滤掉无效的仓库选项
console.log('处理后的仓库选项:', this.warehouseOptions)
this.loadingWarehouse = false this.loadingWarehouse = false
}).catch(error => { }).catch(error => {
console.error('获取仓库列表失败:', error) console.error('获取仓库列表失败:', error)
...@@ -514,18 +578,17 @@ export default { ...@@ -514,18 +578,17 @@ export default {
}) })
}, },
/** 根据仓库编码获取仓库名称 */
getWarehouseName(warehouseCode) { getWarehouseName(warehouseCode) {
if (!warehouseCode) return '' if (!warehouseCode) return ''
const warehouse = this.warehouseOptions.find(item => item.value === warehouseCode) const warehouse = this.warehouseOptions.find(item => item.value === warehouseCode)
return warehouse ? warehouse.label : warehouseCode return warehouse ? warehouse.label : warehouseCode
}, },
// 取消按钮
cancel() { cancel() {
this.open = false this.open = false
this.reset() this.reset()
}, },
// 表单重置
reset() { reset() {
this.form = { this.form = {
id: null, id: null,
...@@ -540,68 +603,111 @@ export default { ...@@ -540,68 +603,111 @@ export default {
capacity: null, capacity: null,
volumeCapacity: null, volumeCapacity: null,
allowedHazardLevels: null, allowedHazardLevels: null,
materialUuids: null, materialCodes: null,
materialNames: null, materialNames: null,
allowedCategoryIds: null,
allowedCategoryNames: null,
temperatureZone: null, temperatureZone: null,
isEnabled: null, isEnabled: 1,
isUsed: null, isUsed: 0,
sortNo: null, sortNo: 0
createTime: null, }
createUserCode: null, this.tempSelectedMaterials = {
updateTime: null, materialCodes: [],
updateUserCode: null names: [],
categoryIds: []
} }
this.resetForm("form") this.resetForm("form")
}, },
/** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1 this.queryParams.pageNum = 1
this.getList() this.getList()
}, },
/** 重置按钮操作 */
resetQuery() { resetQuery() {
this.resetForm("queryForm") this.resetForm("queryForm")
this.handleQuery() this.handleQuery()
}, },
// 多选框选中数据
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.ids = selection.map(item => item.id) this.ids = selection.map(item => item.id)
this.single = selection.length!==1 this.single = selection.length!==1
this.multiple = !selection.length this.multiple = !selection.length
}, },
/** 新增按钮操作 */
handleAdd() { handleAdd() {
this.reset() this.reset()
this.open = true this.open = true
this.title = "添加库位" this.title = "添加库位"
}, },
/** 修改按钮操作 */
handleUpdate(row) { async handleUpdate(row) {
this.reset() this.reset()
const id = row.id || this.ids const id = row.id || this.ids
getLocations(id).then(response => {
this.form = response.data try {
const response = await getLocations(id)
console.log('后端返回库位详情:', response.data)
this.form = JSON.parse(JSON.stringify(response.data))
await this.initMaterialCodeToNameMap()
// 从allowedCategoryIds读取物料编码(替代缺失的materialCodes)
const rawMaterialCodes = this.form.allowedCategoryIds || row.allowedCategoryIds || ''
console.log('原始物料编码(从allowedCategoryIds读取):', rawMaterialCodes)
if (rawMaterialCodes) {
const materialCodes = rawMaterialCodes.split(',')
.map(code => code.trim().toUpperCase())
.filter(code => code)
console.log('处理后物料编码:', materialCodes)
console.log('映射表匹配:', materialCodes.map(code => ({
code,
name: this.materialCodeToNameMap[code]
})))
this.form.materialNames = materialCodes.map(code => {
return this.materialCodeToNameMap[code] || `【未匹配】${code}`
}).join(',')
// 同步赋值materialCodes(确保选择器能接收到)
this.form.materialCodes = rawMaterialCodes
this.tempSelectedMaterials = {
materialCodes: materialCodes,
names: this.form.materialNames.split(',').filter(name => name.trim()),
categoryIds: this.form.allowedCategoryIds ? this.form.allowedCategoryIds.split(',').filter(c => c.trim()) : []
}
}
this.open = true this.open = true
this.title = "修改库位" this.title = "修改库位"
}) } catch (error) {
console.error('获取库位详情失败:', error)
this.$modal.msgError('获取数据失败,请重试!')
}
}, },
/** 提交按钮 */
submitForm() { submitForm() {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(valid => {
if (valid) { if (valid) {
// 直接使用表单数据,不需要转换仓库编码字段名 if (this.form.materialCodes) {
const submitData = { this.form.materialCodes = this.form.materialCodes.split(',').filter(code => code.trim()).join(',')
...this.form }
if (this.form.materialNames) {
this.form.materialNames = this.form.materialNames.split(',').filter(name => name.trim()).join(',')
} }
if (this.form.id != null) { if (this.form.id != null) {
updateLocations(submitData).then(response => { updateLocations(this.form).then(response => {
this.$modal.msgSuccess("修改成功") this.$modal.msgSuccess("修改成功")
this.open = false this.open = false
this.getList() this.getList()
}) })
} else { } else {
addLocations(submitData).then(response => { addLocations(this.form).then(response => {
this.$modal.msgSuccess("新增成功") this.$modal.msgSuccess("新增成功")
this.open = false this.open = false
this.getList() this.getList()
...@@ -610,7 +716,7 @@ export default { ...@@ -610,7 +716,7 @@ export default {
} }
}) })
}, },
/** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id || this.ids const ids = row.id || this.ids
this.$modal.confirm('是否确认删除库位编号为"' + ids + '"的数据项?').then(function() { this.$modal.confirm('是否确认删除库位编号为"' + ids + '"的数据项?').then(function() {
...@@ -620,23 +726,87 @@ export default { ...@@ -620,23 +726,87 @@ export default {
this.$modal.msgSuccess("删除成功") this.$modal.msgSuccess("删除成功")
}).catch(() => {}) }).catch(() => {})
}, },
/** 导出按钮操作 */
handleExport() { handleExport() {
this.download('inventory/locations/export', { this.download('inventory/locations/export', {
...this.queryParams ...this.queryParams
}, `locations_${new Date().getTime()}.xlsx`) }, `locations_${new Date().getTime()}.xlsx`)
}, },
/** 处理物料选择确认 */ handleMaterialSelectionChange(selectedData) {
handleMaterialSelectionConfirm(uuids, names) { this.tempSelectedMaterials = {
this.form.materialUuids = uuids materialCodes: selectedData.materialCodes || [],
this.form.materialNames = names names: selectedData.names || [],
categoryIds: selectedData.formattedCategoryIds || []
}
}, },
/** 处理物料选择取消 */
handleMaterialSelectionCancel() { handleMaterialSelectionCancel() {
// 可以根据需要执行取消操作 this.showMaterialSelect = false
this.tempSelectedMaterials = {
materialCodes: this.form.materialCodes ? this.form.materialCodes.split(',').filter(u => u.trim()) : [],
names: this.form.materialNames ? this.form.materialNames.split(',').filter(n => n.trim()) : [],
categoryIds: this.form.allowedCategoryIds ? this.form.allowedCategoryIds.split(',').filter(c => c.trim()) : []
}
},
confirmMaterialSelection() {
if (!this.tempSelectedMaterials.materialCodes.length) {
this.$modal.msgWarning('请至少选择一个物料!')
return
}
this.form.materialCodes = this.tempSelectedMaterials.materialCodes.join(',')
this.form.materialNames = this.tempSelectedMaterials.names.join(',')
this.form.allowedCategoryIds = this.tempSelectedMaterials.categoryIds.join(',')
if (this.$refs.materialsSeletor) {
const categoryNames = this.tempSelectedMaterials.categoryIds.map(code => {
const rawCode = code.replace(/-/g, '')
return this.$refs.materialsSeletor.categoryMap[rawCode] || code
})
this.form.allowedCategoryNames = categoryNames.join(',')
}
this.showMaterialSelect = false
this.$modal.msgSuccess(`成功选择 ${this.tempSelectedMaterials.names.length} 个物料`)
} }
} }
} }
</script> </script>
<style scoped>
.app-container {
padding: 15px;
}
.mb8 {
margin-bottom: 8px;
}
.category-tags {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.material-names {
max-width: 200px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.dialog-footer {
text-align: center;
}
/deep/ .el-table .el-table__expand-icon {
color: #1989fa;
}
/deep/ .el-tooltip__popper {
max-width: 300px;
white-space: normal;
}
</style>
\ No newline at end of file
<template>
<div class="tree-container" :style="containerStyle">
<!-- 搜索框 -->
<div class="tree-header" v-if="showSearch">
<el-input
v-model="searchText"
:placeholder="searchPlaceholder"
clearable
size="small"
prefix-icon="el-icon-search"
@input="handleSearch"
style="width: 100%; margin-bottom: 10px;"
/>
</div>
<!-- 树组件 -->
<div class="tree-body" :style="treeBodyStyle">
<el-tree
v-if="treeData && treeData.length > 0"
ref="treeRef"
:data="filteredTreeData"
:props="treeProps"
:node-key="nodeKey"
:default-expand-all="defaultExpandAll"
:expand-on-click-node="expandOnClickNode"
:highlight-current="highlightCurrent"
:filter-node-method="filterNodeMethod"
:empty-text="emptyText"
:style="treeStyle"
@node-click="handleNodeClick"
@node-expand="handleNodeExpand"
@node-collapse="handleNodeCollapse"
@current-change="handleCurrentChange"
>
<!-- 自定义节点内容插槽 -->
<template #default="{ node, data }">
<slot name="node-content" :node="node" :data="data">
<span class="custom-tree-node">
<span>{{ node.label }}</span>
</span>
</slot>
</template>
</el-tree>
<!-- 空状态 -->
<div v-else class="tree-empty">
<slot name="empty">
<div style="padding: 20px; text-align: center; color: #999;">
{{ loading ? '加载中...' : '暂无数据' }}
</div>
</slot>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'TreeComponent',
props: {
// 树数据
treeData: {
type: Array,
default: () => []
},
// 树配置
treeProps: {
type: Object,
default: () => ({
children: 'children',
label: 'label',
value: 'sid'
})
},
// 节点key
nodeKey: {
type: String,
default: 'sid'
},
// 是否显示搜索框
showSearch: {
type: Boolean,
default: true
},
// 搜索框占位符
searchPlaceholder: {
type: String,
default: '请输入搜索内容'
},
// 是否默认展开所有节点
defaultExpandAll: {
type: Boolean,
default: true
},
// 是否点击节点时展开
expandOnClickNode: {
type: Boolean,
default: false
},
// 是否高亮当前选中节点
highlightCurrent: {
type: Boolean,
default: true
},
// 容器样式
containerStyle: {
type: Object,
default: () => ({
height: '100%',
padding: '10px'
})
},
// 树容器样式
treeBodyStyle: {
type: Object,
default: () => ({
height: 'calc(100% - 50px)',
overflow: 'auto'
})
},
// 树样式
treeStyle: {
type: Object,
default: () => ({})
},
// 空状态文本
emptyText: {
type: String,
default: '暂无数据'
},
// 加载状态
loading: {
type: Boolean,
default: false
},
// 初始选中的节点key
defaultSelectedKey: {
type: [String, Number],
default: null
}
},
data() {
return {
searchText: '',
filteredTreeData: [],
selectedNode: null
}
},
watch: {
treeData: {
immediate: true,
handler(newData) {
this.filteredTreeData = newData
this.$nextTick(() => {
if (this.defaultSelectedKey && this.$refs.treeRef) {
this.$refs.treeRef.setCurrentKey(this.defaultSelectedKey)
}
})
}
},
defaultSelectedKey: {
immediate: true,
handler(newKey) {
if (newKey && this.$refs.treeRef) {
this.$refs.treeRef.setCurrentKey(newKey)
}
}
}
},
methods: {
/**
* 过滤节点方法
*/
filterNodeMethod(value, data, node) {
if (!value) return true
const label = data[this.treeProps.label] || ''
return label.toLowerCase().includes(value.toLowerCase())
},
/**
* 处理搜索
*/
handleSearch(value) {
this.$refs.treeRef.filter(value)
},
/**
* 节点点击事件
*/
handleNodeClick(data, node, component) {
this.selectedNode = { data, node, component }
this.$emit('node-click', data, node, component)
},
/**
* 节点展开事件
*/
handleNodeExpand(data, node, component) {
this.$emit('node-expand', data, node, component)
},
/**
* 节点折叠事件
*/
handleNodeCollapse(data, node, component) {
this.$emit('node-collapse', data, node, component)
},
/**
* 当前节点变化事件
*/
handleCurrentChange(data, node) {
this.$emit('current-change', data, node)
},
/**
* 重置树结构
*/
resetTree() {
// 修复:使用正确的 ref 名称 treeRef
if (this.$refs.treeRef) {
this.$refs.treeRef.setCurrentKey(null);
this.searchText = '';
this.$refs.treeRef.filter(''); // 清空搜索
}
},
/**
* 设置当前选中的节点
*/
setCurrentNode(node) {
this.$refs.treeRef.setCurrentNode(node)
},
/**
* 设置当前选中的节点key
*/
setCurrentKey(key) {
this.$refs.treeRef.setCurrentKey(key)
},
/**
* 获取当前选中的节点
*/
getCurrentNode() {
return this.$refs.treeRef.getCurrentNode()
},
/**
* 获取当前选中的节点key
*/
getCurrentKey() {
return this.$refs.treeRef.getCurrentKey()
},
/**
* 展开指定节点
*/
expandNode(node) {
this.$refs.treeRef.expandNode(node)
},
/**
* 折叠指定节点
*/
collapseNode(node) {
this.$refs.treeRef.collapseNode(node)
},
/**
* 展开所有节点
*/
expandAll() {
this.$refs.treeRef.expandAll()
},
/**
* 折叠所有节点
*/
collapseAll() {
this.$refs.treeRef.collapseAll()
},
/**
* 更新节点数据
*/
updateKeyChildren(key, data) {
this.$refs.treeRef.updateKeyChildren(key, data)
},
/**
* 获取节点信息
*/
getNode(key) {
return this.$refs.treeRef.getNode(key)
},
/**
* 移除节点
*/
remove(key) {
this.$refs.treeRef.remove(key)
},
/**
* 追加节点数据
*/
append(data, parentNode) {
this.$refs.treeRef.append(data, parentNode)
},
/**
* 插入节点数据
*/
insertBefore(data, refNode) {
this.$refs.treeRef.insertBefore(data, refNode)
},
/**
* 插入节点数据后
*/
insertAfter(data, refNode) {
this.$refs.treeRef.insertAfter(data, refNode)
}
}
}
</script>
<style scoped>
.tree-container {
height: 100%;
display: flex;
flex-direction: column;
}
.tree-header {
flex-shrink: 0;
}
.tree-body {
flex: 1;
overflow: auto;
}
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
.tree-empty {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #999;
}
</style>
\ No newline at end of file
<template> <template>
<div class="app-container"> <div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="出库单号" prop="orderId"> <el-form-item label="出库单号" prop="orderId">
<el-input <el-input
...@@ -33,6 +34,14 @@ ...@@ -33,6 +34,14 @@
@keyup.enter.native="handleQuery" @keyup.enter.native="handleQuery"
/> />
</el-form-item> </el-form-item>
<el-form-item label="货主ID" prop="ownerId">
<el-input
v-model="queryParams.ownerId"
placeholder="请输入货主ID"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="订单状态" prop="orderStatus"> <el-form-item label="订单状态" prop="orderStatus">
<el-select v-model="queryParams.orderStatus" placeholder="请选择订单状态" clearable> <el-select v-model="queryParams.orderStatus" placeholder="请选择订单状态" clearable>
<el-option <el-option
...@@ -43,12 +52,29 @@ ...@@ -43,12 +52,29 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="出库日期" prop="inboundDate">
<el-date-picker clearable
v-model="queryParams.inboundDate"
type="date"
value-format="yyyy-MM-dd"
placeholder="请选择出库日期">
</el-date-picker>
</el-form-item>
<el-form-item label="目的地" prop="destination">
<el-input
v-model="queryParams.destination"
placeholder="请输入目的地"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button <el-button
...@@ -95,9 +121,9 @@ ...@@ -95,9 +121,9 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar> <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row> </el-row>
<!-- 主表格 -->
<el-table v-loading="loading" :data="ordersList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" :data="ordersList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="编号" align="center" prop="id" width="80" />
<el-table-column label="出库单号" align="center" prop="orderId" width="150" /> <el-table-column label="出库单号" align="center" prop="orderId" width="150" />
<el-table-column label="系统编号" align="center" prop="systemNo" width="150" /> <el-table-column label="系统编号" align="center" prop="systemNo" width="150" />
<el-table-column label="入库类型" align="center" prop="orderTypeId" width="120"> <el-table-column label="入库类型" align="center" prop="orderTypeId" width="120">
...@@ -123,10 +149,6 @@ ...@@ -123,10 +149,6 @@
<el-table-column label="实际量" align="center" prop="totalActualQuantity" width="100" /> <el-table-column label="实际量" align="center" prop="totalActualQuantity" width="100" />
<el-table-column label="总件数" align="center" prop="totalPackages" width="100" /> <el-table-column label="总件数" align="center" prop="totalPackages" width="100" />
<el-table-column label="备注" align="center" prop="remark" width="150" /> <el-table-column label="备注" align="center" prop="remark" width="150" />
<el-table-column label="是否使用" align="center" prop="isUsed" width="120" />
<el-table-column label="排序" align="center" prop="sortNo" width="80" />
<el-table-column label="创建人" align="center" prop="createUserCode" width="150" />
<el-table-column label="更新人" align="center" prop="updateUserCode" width="150" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
...@@ -147,6 +169,7 @@ ...@@ -147,6 +169,7 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<!-- 分页 -->
<pagination <pagination
v-show="total>0" v-show="total>0"
:total="total" :total="total"
...@@ -155,9 +178,10 @@ ...@@ -155,9 +178,10 @@
@pagination="getList" @pagination="getList"
/> />
<!-- 添加或修改出库单主对话框 --> <!-- 添加/修改出库单主弹窗 -->
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body> <el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px"> <el-form ref="form" :model="form" :rules="rules" label-width="120px">
<!-- 主表单区域 -->
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="出库单号" prop="orderId"> <el-form-item label="出库单号" prop="orderId">
...@@ -196,17 +220,6 @@ ...@@ -196,17 +220,6 @@
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="订单状态" prop="orderStatus">
<el-radio-group v-model="form.orderStatus">
<el-radio
v-for="dict in dict.type.inbound_order_status"
:key="dict.value"
:label="parseInt(dict.value)"
>{{dict.label}}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出库日期" prop="inboundDate"> <el-form-item label="出库日期" prop="inboundDate">
<el-date-picker clearable <el-date-picker clearable
v-model="form.inboundDate" v-model="form.inboundDate"
...@@ -225,19 +238,19 @@ ...@@ -225,19 +238,19 @@
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="计划量" prop="totalPlannedQuantity"> <el-form-item label="计划量" prop="totalPlannedQuantity">
<el-input v-model="form.totalPlannedQuantity" placeholder="请输入计划量" /> <el-input v-model.number="form.totalPlannedQuantity" placeholder="请输入计划量" type="number" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="实际量" prop="totalActualQuantity"> <el-form-item label="实际量" prop="totalActualQuantity">
<el-input v-model="form.totalActualQuantity" placeholder="请输入实际量" /> <el-input v-model.number="form.totalActualQuantity" placeholder="请输入实际量" type="number" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-form-item label="总件数" prop="totalPackages"> <el-form-item label="总件数" prop="totalPackages">
<el-input v-model="form.totalPackages" placeholder="请输入总件数" /> <el-input v-model.number="form.totalPackages" placeholder="请输入总件数" type="number" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
...@@ -248,125 +261,58 @@ ...@@ -248,125 +261,58 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20">
<el-col :span="12"> <!-- 明细表格区域 -->
<el-form-item label="是否使用" prop="isUsed"> <el-divider content-position="center">入库单明细信息</el-divider>
<el-input v-model="form.isUsed" placeholder="请输入是否使用" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="排序" prop="sortNo">
<el-input v-model="form.sortNo" placeholder="请输入排序" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="创建人" prop="createUserCode">
<el-input v-model="form.createUserCode" placeholder="请输入创建人" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="更新人" prop="updateUserCode">
<el-input v-model="form.updateUserCode" placeholder="请输入更新人" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="center">库存信息</el-divider>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAddInventoryItem">添加</el-button> <!-- 点击该按钮打开子组件弹窗 -->
<el-button type="primary" icon="el-icon-plus" size="mini" @click="openDetailDialog">添加</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
<el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDeleteInventoryItem">删除</el-button> <el-button type="danger" icon="el-icon-delete" size="mini" @click="deleteTableItem">删除</el-button>
</el-col> </el-col>
</el-row> </el-row>
<el-table :data="inventoryList" :row-class-name="rowInventoryIndex" @selection-change="handleInventorySelectionChange" ref="inventory"> <el-table
:data="inboundOrderItemsList"
:row-class-name="rowInboundOrderItemsIndex"
@selection-change="handleInboundOrderItemsSelectionChange"
ref="inboundOrderItems"
border
style="width: 100%;"
>
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" align="center" prop="index" width="50"/> <el-table-column label="序号" align="center" prop="index" width="50"/>
<el-table-column label="货物ID" prop="materialId" width="150"> <el-table-column label="货物ID" prop="materialId" width="150" />
<template slot-scope="scope"> <el-table-column label="批次ID" prop="batchId" width="150" />
<el-input v-model="scope.row.materialId" placeholder="请输入货物ID" /> <el-table-column label="仓库ID" prop="warehouseId" width="150" />
</template> <el-table-column label="库位ID" prop="locationId" width="150" />
</el-table-column> <el-table-column label="计划数量" prop="plannedQuantity" width="150" />
<el-table-column label="批次ID" prop="batchId" width="150"> <el-table-column label="实际数量" prop="actualQuantity" width="150" />
<el-table-column label="计划件数" prop="plannedPackages" width="150" />
<el-table-column label="实际件数" prop="actualPackages" width="150" />
<el-table-column label="约数" prop="divisor" width="150" />
<el-table-column label="标签颜色" prop="labelColor" width="150" />
<el-table-column label="单价" prop="unitPrice" width="150" />
<el-table-column label="状态" prop="itemStatus" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.batchId" placeholder="请输入批次ID" /> <dict-tag :options="dict.type.inbound_order_item_status" :value="scope.row.itemStatus"/>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="仓库ID" prop="warehouseId" width="150"> <el-table-column label="收货时间" prop="receivedAt" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.warehouseId" placeholder="请输入仓库ID" /> <span>{{ parseTime(scope.row.receivedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="库位ID" prop="locationId" width="150"> <el-table-column label="收货人" prop="receivedBy" width="150" />
<el-table-column label="操作" align="center" width="80">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input v-model="scope.row.locationId" placeholder="请输入库位ID" /> <el-button
</template> size="mini"
</el-table-column> type="text"
<el-table-column label="货主ID" prop="ownerId" width="150"> icon="el-icon-edit"
<template slot-scope="scope"> @click="editDetailItem(scope.row)"
<el-input v-model="scope.row.ownerId" placeholder="请输入货主ID" /> >编辑</el-button>
</template>
</el-table-column>
<el-table-column label="库存数量" prop="quantity" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.quantity" placeholder="请输入库存数量" />
</template>
</el-table-column>
<el-table-column label="锁定数量" prop="lockedQuantity" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.lockedQuantity" placeholder="请输入锁定数量" />
</template>
</el-table-column>
<el-table-column label="可用库存" width="150">
<template slot-scope="scope">
{{ (Number(scope.row.quantity) || 0) - (Number(scope.row.lockedQuantity) || 0) }}
</template>
</el-table-column>
<el-table-column label="选择数量" prop="selectQty" width="150">
<template slot-scope="scope">
<el-input
v-model.number="scope.row.selectQty"
placeholder="请输入选择数量"
@blur="validateSelectQty(scope.row)"
@input="validateSelectQty(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="库存状态" prop="inventoryStatus" width="150">
<template slot-scope="scope">
<dict-tag :options="dict.type.inventory_status" :value="scope.row.inventoryStatus"/>
</template>
</el-table-column>
<el-table-column label="库存类别" prop="inventoryType" width="150">
<template slot-scope="scope">
<dict-tag :options="dict.type.inventory_type" :value="scope.row.inventoryType"/>
</template>
</el-table-column>
<el-table-column label="单位重量" prop="unitWeight" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.unitWeight" placeholder="请输入单位重量" />
</template>
</el-table-column>
<el-table-column label="最后入库时间" prop="lastInboundTime" width="150">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.lastInboundTime" type="datetime" placeholder="选择最后入库时间" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="最后出库时间" prop="lastOutboundTime" width="150">
<template slot-scope="scope">
<el-date-picker v-model="scope.row.lastOutboundTime" type="datetime" placeholder="选择最后出库时间" value-format="yyyy-MM-dd HH:mm:ss" />
</template>
</el-table-column>
<el-table-column label="是否使用" prop="isUsed" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.isUsed" placeholder="请输入是否使用" />
</template>
</el-table-column>
<el-table-column label="排序" prop="sortNo" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.sortNo" placeholder="请输入排序" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
...@@ -376,23 +322,36 @@ ...@@ -376,23 +322,36 @@
<el-button @click="cancel"> </el-button> <el-button @click="cancel"> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<!-- 明细项添加/编辑子组件弹窗(OutboundOrderFormWithItems -->
<OutboundOrderFormWithItems
:title="detailDialogTitle"
:open="detailDialogOpen"
:init-form="currentDetailItem"
@submit="handleDetailSubmit"
@update:open="detailDialogOpen = $event"
/>
</div> </div>
</template> </template>
<script> <script>
import { listOrders, getOrders, delOrders, addOrders, updateOrders, listWarehouseInventory } from "@/api/inventory/orders" import { listOrders, getOrders, delOrders, addOrders, updateOrders } from "@/api/inventory/orders"
// 导入明细子组件
import OutboundOrderFormWithItems from './OutboundOrderFormWithItems.vue'
export default { export default {
name: "Orders", name: "Orders",
dicts: ['inbound_order_status', 'outbound_item_status', 'label_color', 'inventory_status', 'inventory_type'], dicts: ['inbound_order_status', 'inbound_order_type', 'inbound_order_item_status'],
components: {
OutboundOrderFormWithItems // 注册子组件
},
data() { data() {
return { return {
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组 // 选中数组
ids: [], ids: [],
// 子表选中数据
checkedInventory: [],
// 非单个禁用 // 非单个禁用
single: true, single: true,
// 非多个禁用 // 非多个禁用
...@@ -403,12 +362,35 @@ export default { ...@@ -403,12 +362,35 @@ export default {
total: 0, total: 0,
// 出库单主表格数据 // 出库单主表格数据
ordersList: [], ordersList: [],
// 库存表格数据 // 主弹窗标题
inventoryList: [],
// 弹出层标题
title: "", title: "",
// 是否显示弹出层 // 主弹窗是否显示
open: false, open: false,
// 明细表格数据
inboundOrderItemsList: [],
// 选中的明细行
selectedInboundOrderItems: [],
// 明细子弹窗相关
detailDialogOpen: false, // 子弹窗是否显示
detailDialogTitle: "新增明细项", // 子弹窗标题
currentDetailItem: {
materialUuids: '', // 存储物料选择器返回的materialCodes
materialId: '',
batchId: '',
warehouseId: '',
locationId: '',
plannedQuantity: '',
actualQuantity: '',
plannedPackages: '',
actualPackages: '',
divisor: '',
labelColor: '',
unitPrice: '',
itemStatus: 'pending',
receivedAt: '',
receivedBy: ''
}, // 当前编辑的明细项
isEditDetail: false, // 标记是否为编辑明细
// 查询参数 // 查询参数
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
...@@ -432,18 +414,11 @@ export default { ...@@ -432,18 +414,11 @@ export default {
}, },
// 表单参数 // 表单参数
form: {}, form: {},
// 表单校验 // 表单校验规则
rules: { rules: {
} orderId: [{ required: true, message: '请输入出库单号', trigger: 'blur' }],
} warehouseId: [{ required: true, message: '请输入仓库ID', trigger: 'blur' }],
}, inboundDate: [{ required: true, message: '请选择出库日期', trigger: 'change' }]
// 监听仓库ID变化
watch: {
'form.warehouseId'(newVal) {
if (newVal) {
this.queryWarehouseInventory(newVal)
} else {
this.inventoryList = []
} }
} }
}, },
...@@ -451,6 +426,129 @@ export default { ...@@ -451,6 +426,129 @@ export default {
this.getList() this.getList()
}, },
methods: { methods: {
// ========== 明细子弹窗相关方法 ==========
// 打开明细子弹窗(新增)
openDetailDialog() {
this.isEditDetail = false
this.detailDialogTitle = "新增明细项"
this.currentDetailItem = {
materialUuids: '', // 初始化materialUuids(接收materialCodes)
materialId: '',
batchId: '',
warehouseId: '',
locationId: '',
plannedQuantity: '',
actualQuantity: '',
plannedPackages: '',
actualPackages: '',
divisor: '',
labelColor: '',
unitPrice: '',
itemStatus: 'pending', // 默认状态
receivedAt: '',
receivedBy: ''
}
this.detailDialogOpen = true
},
// 编辑明细项
editDetailItem(row) {
this.isEditDetail = true
this.detailDialogTitle = "编辑明细项"
// 兼容materialUuids:优先取row.materialUuids,无则用materialId(适配返回的materialCodes)
this.currentDetailItem = {
...row,
materialUuids: row.materialUuids || row.materialId || ''
}
this.detailDialogOpen = true
},
// 接收子组件提交的明细数据(核心修改:适配materialCodes返回格式)
handleDetailSubmit(details) {
// 兼容子组件返回格式:如果是materialCodes结构,提取第一个值赋值给materialId
const formatDetail = (item) => {
// 处理物料选择器返回的materialCodes数组
if (item.materialUuids && Array.isArray(item.materialUuids)) {
item.materialId = item.materialUuids[0] || '' // 单选取第一个值
item.materialUuids = item.materialUuids[0] || '' // 同步更新materialUuids
}
// 兼容子组件返回的原始格式
return item
}
// 统一转为数组处理
const detailList = Array.isArray(details) ? details : [details]
// 格式化每条明细的物料字段
const formattedList = detailList.map(item => formatDetail(item))
if (this.isEditDetail) {
// 编辑模式:替换原有单条数据
const editIndex = this.inboundOrderItemsList.findIndex(item => item.index === this.currentDetailItem.index)
if (editIndex > -1) {
this.inboundOrderItemsList.splice(editIndex, 1, {
...formattedList[0],
index: this.currentDetailItem.index
})
}
this.$message.success("编辑明细成功")
} else {
// 新增模式:批量添加多条明细
const newDetails = formattedList.map((item, idx) => {
const newIndex = this.inboundOrderItemsList.length + idx + 1
return { ...item, index: newIndex }
})
this.inboundOrderItemsList = [...this.inboundOrderItemsList, ...newDetails]
// 自动计算主表总数量
this.calcTotalQuantity()
this.$message.success(`成功新增${newDetails.length}条明细`)
}
this.detailDialogOpen = false
},
// 自动计算主表的计划总量/实际总量/总件数
calcTotalQuantity() {
const totalPlanned = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.plannedQuantity) || 0), 0)
const totalActual = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.actualQuantity) || 0), 0)
const totalPackages = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.actualPackages) || 0), 0)
this.form.totalPlannedQuantity = totalPlanned
this.form.totalActualQuantity = totalActual
this.form.totalPackages = totalPackages
},
// ========== 明细表格相关方法 ==========
// 生成明细表格行序号
rowInboundOrderItemsIndex({ row, rowIndex }) {
if (!row.index) row.index = rowIndex + 1
},
// 明细表格选择事件
handleInboundOrderItemsSelectionChange(val) {
this.selectedInboundOrderItems = val
},
// 删除选中的明细行
deleteTableItem() {
if (this.selectedInboundOrderItems.length === 0) {
this.$message.warning('请选择要删除的明细行')
return
}
// 获取选中行索引并倒序删除
const selectedIndexes = this.selectedInboundOrderItems.map(item =>
this.inboundOrderItemsList.findIndex(row => row.index === item.index)
)
selectedIndexes.sort((a, b) => b - a).forEach(index => {
this.inboundOrderItemsList.splice(index, 1)
})
// 重新更新序号
this.inboundOrderItemsList.forEach((row, index) => {
row.index = index + 1
})
// 重新计算总数量
this.calcTotalQuantity()
this.$message.success('明细行删除成功')
},
// ========== 主表格/表单相关方法 ==========
/** 查询出库单主列表 */ /** 查询出库单主列表 */
getList() { getList() {
this.loading = true this.loading = true
...@@ -489,32 +587,11 @@ export default { ...@@ -489,32 +587,11 @@ export default {
updateTime: null, updateTime: null,
updateUserCode: null updateUserCode: null
} }
this.inventoryList = [] // 重置明细表格
this.inboundOrderItemsList = []
this.selectedInboundOrderItems = []
this.resetForm("form") this.resetForm("form")
}, },
// 查询仓库库存
queryWarehouseInventory(warehouseId) {
this.loading = true
listWarehouseInventory(warehouseId).then(response => {
this.inventoryList = response.rows || response.data || response
// 按货物ID分类
this.groupInventoryByMaterialId()
this.loading = false
}).catch(error => {
this.loading = false
console.error('查询库存失败:', error)
})
},
// 按货物ID分类库存数据
groupInventoryByMaterialId() {
// 这里可以根据需要实现按货物ID分类的逻辑
// 例如:将同一货物ID的库存数据合并或排序
this.inventoryList.sort((a, b) => {
if (a.materialId < b.materialId) return -1
if (a.materialId > b.materialId) return 1
return 0
})
},
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
this.queryParams.pageNum = 1 this.queryParams.pageNum = 1
...@@ -535,7 +612,7 @@ export default { ...@@ -535,7 +612,7 @@ export default {
handleAdd() { handleAdd() {
this.reset() this.reset()
this.open = true this.open = true
this.title = "添加出库单" this.title = "添加出库单"
}, },
/** 修改按钮操作 */ /** 修改按钮操作 */
handleUpdate(row) { handleUpdate(row) {
...@@ -543,35 +620,47 @@ export default { ...@@ -543,35 +620,47 @@ export default {
const id = row.id || this.ids const id = row.id || this.ids
getOrders(id).then(response => { getOrders(id).then(response => {
this.form = response.data this.form = response.data
// 如果有inventoryList直接使用,否则根据仓库ID查询 // 如果有明细数据,初始化明细表格
if (response.data.inventoryList && response.data.inventoryList.length > 0) { if (response.data.items) {
this.inventoryList = response.data.inventoryList this.inboundOrderItemsList = response.data.items.map((item, index) => ({
// 按货物ID分类 ...item,
this.groupInventoryByMaterialId() // 兼容materialUuids:适配物料选择器返回的materialCodes格式
} else if (response.data.warehouseId) { materialUuids: item.materialUuids || item.materialId || '',
this.queryWarehouseInventory(response.data.warehouseId) index: index + 1
}))
// 计算总数量
this.calcTotalQuantity()
} }
this.open = true this.open = true
this.title = "修改出库单" this.title = "修改出库单"
}) })
}, },
/** 提交按钮 */ /** 提交按钮 */
submitForm() { submitForm() {
this.$refs["form"].validate(valid => { this.$refs["form"].validate(async (valid) => {
if (valid) { if (valid) {
this.form.inventoryList = this.inventoryList // 组装完整数据(主表+明细)
if (this.form.id != null) { const submitData = {
updateOrders(this.form).then(response => { ...this.form,
this.$modal.msgSuccess("修改成功") items: this.inboundOrderItemsList.map(item => {
this.open = false const { index, ...rest } = item // 剔除序号
this.getList() // 提交时确保materialId是单选的物料编码(从materialUuids/原materialId取值)
rest.materialId = rest.materialUuids || rest.materialId || ''
return rest
}) })
} else { }
addOrders(this.form).then(response => { try {
if (this.form.id != null) {
await updateOrders(submitData)
this.$modal.msgSuccess("修改成功")
} else {
await addOrders(submitData)
this.$modal.msgSuccess("新增成功") this.$modal.msgSuccess("新增成功")
this.open = false }
this.getList() this.open = false
}) this.getList()
} catch (error) {
this.$modal.msgError(error.msg || "操作失败")
} }
} }
}) })
...@@ -579,71 +668,11 @@ export default { ...@@ -579,71 +668,11 @@ export default {
/** 删除按钮操作 */ /** 删除按钮操作 */
handleDelete(row) { handleDelete(row) {
const ids = row.id || this.ids const ids = row.id || this.ids
this.$modal.confirm('是否确认删除出库单主编号为"' + ids + '"的数据项?').then(function() { this.$modal.confirm('是否确认删除出库单编号为"' + ids + '"的数据项?').then(async () => {
return delOrders(ids) await delOrders(ids)
}).then(() => {
this.getList() this.getList()
this.$modal.msgSuccess("删除成功") this.$modal.msgSuccess("删除成功")
}).catch(() => {}) }).catch(() => {})
},
/** 库存序号 */
rowInventoryIndex({ row, rowIndex }) {
row.index = rowIndex + 1
},
/** 库存添加按钮操作 */
handleAddInventoryItem() {
let obj = {}
obj.materialId = ""
obj.batchId = ""
obj.warehouseId = ""
obj.locationId = ""
obj.ownerId = ""
obj.quantity = ""
obj.lockedQuantity = ""
obj.selectQty = ""
obj.inventoryStatus = ""
obj.inventoryType = ""
obj.unitWeight = ""
obj.lastInboundTime = null
obj.lastOutboundTime = null
obj.isUsed = ""
obj.sortNo = ""
this.inventoryList.push(obj)
},
/** 验证选择数量 */
validateSelectQty(row) {
const selectQty = Number(row.selectQty) || 0
const availableQty = (Number(row.quantity) || 0) - (Number(row.lockedQuantity) || 0)
if (selectQty < 0) {
this.$message.error('选择数量不能为负数')
row.selectQty = ''
return false
}
if (selectQty > availableQty) {
this.$message.error('选择数量不能超过可用库存')
row.selectQty = ''
return false
}
return true
},
/** 库存删除按钮操作 */
handleDeleteInventoryItem() {
if (this.checkedInventory.length == 0) {
this.$modal.msgError("请先选择要删除的库存数据")
} else {
const inventoryList = this.inventoryList
const checkedInventory = this.checkedInventory
this.inventoryList = inventoryList.filter(function(item) {
return checkedInventory.indexOf(item.index) == -1
})
}
},
/** 复选框选中数据 */
handleInventorySelectionChange(selection) {
this.checkedInventory = selection.map(item => item.index)
}, },
/** 导出按钮操作 */ /** 导出按钮操作 */
handleExport() { handleExport() {
...@@ -654,3 +683,24 @@ export default { ...@@ -654,3 +683,24 @@ export default {
} }
} }
</script> </script>
<style scoped>
/* 弹窗内表单滚动优化 */
.el-dialog__body {
max-height: 70vh;
overflow-y: auto;
padding-right: 10px;
}
/* 自定义滚动条 */
.el-dialog__body::-webkit-scrollbar {
width: 6px;
}
.el-dialog__body::-webkit-scrollbar-thumb {
background-color: #ddd;
border-radius: 3px;
}
/* 明细表格样式优化 */
.el-table {
--el-table-row-hover-bg-color: #f8f9fa;
}
</style>
\ No newline at end of file
...@@ -45,7 +45,17 @@ public class InventoryController extends BaseController ...@@ -45,7 +45,17 @@ public class InventoryController extends BaseController
List<Inventory> list = inventoryService.selectInventoryList(inventory); List<Inventory> list = inventoryService.selectInventoryList(inventory);
return getDataTable(list); return getDataTable(list);
} }
/**
* 查询库存列表
*/
@PreAuthorize("@ss.hasPermi('inventory:inventory:list')")
@GetMapping("/listByMaterialId")
public TableDataInfo listByMaterialId(String materialId)
{
startPage();
List<Inventory> list = inventoryService.listByMatreialId(materialId);
return getDataTable(list);
}
/** /**
* 导出库存列表 * 导出库存列表
*/ */
......
...@@ -17,7 +17,7 @@ import com.ruoyi.common.core.controller.BaseController; ...@@ -17,7 +17,7 @@ import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.inventory.domain.OutboundOrderItems; import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderItemsInventory;
import com.ruoyi.inventory.service.IOutboundOrderItemsService; import com.ruoyi.inventory.service.IOutboundOrderItemsService;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
...@@ -43,7 +43,7 @@ public class OutboundOrderItemsController extends BaseController ...@@ -43,7 +43,7 @@ public class OutboundOrderItemsController extends BaseController
public TableDataInfo list(OutboundOrderItems outboundOrderItems) public TableDataInfo list(OutboundOrderItems outboundOrderItems)
{ {
startPage(); startPage();
List<OutboundOrderItemsInventory> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems); List<OutboundOrderItems> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
return getDataTable(list); return getDataTable(list);
} }
...@@ -55,8 +55,8 @@ public class OutboundOrderItemsController extends BaseController ...@@ -55,8 +55,8 @@ public class OutboundOrderItemsController extends BaseController
@PostMapping("/export") @PostMapping("/export")
public void export(HttpServletResponse response, OutboundOrderItems outboundOrderItems) public void export(HttpServletResponse response, OutboundOrderItems outboundOrderItems)
{ {
List<OutboundOrderItemsInventory> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems); List<OutboundOrderItems> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
ExcelUtil<OutboundOrderItemsInventory> util = new ExcelUtil<OutboundOrderItemsInventory>(OutboundOrderItemsInventory.class); ExcelUtil<OutboundOrderItems> util = new ExcelUtil<OutboundOrderItems>(OutboundOrderItems.class);
util.exportExcel(response, list, "出库单明细数据"); util.exportExcel(response, list, "出库单明细数据");
} }
......
package com.ruoyi.inventory.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
/**
* 出库单明细库存DTO对象 outbound_order_items_inventory
*
* @author ruoyi
* @date 2025-12-03
*/
public class OutboundOrderItemsInventory
{
private static final long serialVersionUID = 1L;
/** 出库单明细 */
private OutboundOrderItems outboundOrderItems;
/** 库存信息 */
private Inventory inventory;
public OutboundOrderItems getOutboundOrderItems()
{
return outboundOrderItems;
}
public void setOutboundOrderItems(OutboundOrderItems outboundOrderItems)
{
this.outboundOrderItems = outboundOrderItems;
}
public Inventory getInventory()
{
return inventory;
}
public void setInventory(Inventory inventory)
{
this.inventory = inventory;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("outboundOrderItems", getOutboundOrderItems())
.append("inventory", getInventory())
.toString();
}
}
\ No newline at end of file
...@@ -19,7 +19,7 @@ public class OutboundOrderLog extends BaseEntity ...@@ -19,7 +19,7 @@ public class OutboundOrderLog extends BaseEntity
private String id; private String id;
/** 货物ID */ /** 货物ID */
@Excel(name = "货物ID") @Excel(name = "出货单号ID")
private String orderId; private String orderId;
/** 货物ID */ /** 货物ID */
......
package com.ruoyi.inventory.mapper; package com.ruoyi.inventory.mapper;
import java.util.List; import java.util.List;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory; import com.ruoyi.inventory.domain.Inventory;
/** /**
...@@ -65,4 +67,6 @@ public interface InventoryMapper ...@@ -65,4 +67,6 @@ public interface InventoryMapper
* @return 结果 * @return 结果
*/ */
public int deleteInventoryByIds(String[] ids); public int deleteInventoryByIds(String[] ids);
public List<Inventory> listByMatreialId(String materialId);
} }
...@@ -19,6 +19,13 @@ public interface MaterialsCategoryMapper ...@@ -19,6 +19,13 @@ public interface MaterialsCategoryMapper
*/ */
public MaterialsCategory selectMaterialsCategoryById(String id); public MaterialsCategory selectMaterialsCategoryById(String id);
/** /**
* 查询物料分类
*
* @param id 物料分类主键
* @return 物料分类
*/
public MaterialsCategory selectMaterialsCategoryByMaterialsCode(String id);
/**
* 查询物料分类列表 * 查询物料分类列表
* *
* @param materialsCategory 物料分类 * @param materialsCategory 物料分类
......
...@@ -23,6 +23,14 @@ public interface MaterialsMapper ...@@ -23,6 +23,14 @@ public interface MaterialsMapper
public Materials selectMaterialsById(String id); public Materials selectMaterialsById(String id);
/** /**
* 查询物料
*
* @param id 物料主键
* @return 物料
*/
public Materials selectMaterialsByMaterialsCode(String id);
/**
* 查询物料列表 * 查询物料列表
* *
* @param materials 物料 * @param materials 物料
......
package com.ruoyi.inventory.service; package com.ruoyi.inventory.service;
import java.util.List; import java.util.List;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory; import com.ruoyi.inventory.domain.Inventory;
/** /**
...@@ -60,4 +62,6 @@ public interface IInventoryService ...@@ -60,4 +62,6 @@ public interface IInventoryService
* @return 结果 * @return 结果
*/ */
public int deleteInventoryById(String id); public int deleteInventoryById(String id);
public List<Inventory> listByMatreialId(String materialId);
} }
...@@ -2,7 +2,7 @@ package com.ruoyi.inventory.service; ...@@ -2,7 +2,7 @@ package com.ruoyi.inventory.service;
import java.util.List; import java.util.List;
import com.ruoyi.inventory.domain.OutboundOrderItems; import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderItemsInventory; import com.ruoyi.inventory.domain.OutboundOrderItems;
/** /**
* 出库单明细Service接口 * 出库单明细Service接口
...@@ -10,7 +10,7 @@ import com.ruoyi.inventory.domain.OutboundOrderItemsInventory; ...@@ -10,7 +10,7 @@ import com.ruoyi.inventory.domain.OutboundOrderItemsInventory;
* @author ruoyi * @author ruoyi
* @date 2025-12-03 * @date 2025-12-03
*/ */
public interface IOutboundOrderItemsService public interface IOutboundOrderItemsService
{ {
/** /**
* 查询出库单明细 * 查询出库单明细
...@@ -18,7 +18,7 @@ public interface IOutboundOrderItemsService ...@@ -18,7 +18,7 @@ public interface IOutboundOrderItemsService
* @param id 出库单明细主键 * @param id 出库单明细主键
* @return 出库单明细 * @return 出库单明细
*/ */
public OutboundOrderItemsInventory selectOutboundOrderItemsById(String id); public OutboundOrderItems selectOutboundOrderItemsById(String id);
/** /**
* 查询出库单明细列表 * 查询出库单明细列表
...@@ -26,7 +26,7 @@ public interface IOutboundOrderItemsService ...@@ -26,7 +26,7 @@ public interface IOutboundOrderItemsService
* @param outboundOrderItems 出库单明细 * @param outboundOrderItems 出库单明细
* @return 出库单明细集合 * @return 出库单明细集合
*/ */
public List<OutboundOrderItemsInventory> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems); public List<OutboundOrderItems> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems);
/** /**
* 新增出库单明细 * 新增出库单明细
......
...@@ -35,6 +35,8 @@ public interface IOutboundOrderLogService ...@@ -35,6 +35,8 @@ public interface IOutboundOrderLogService
*/ */
public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog); public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog);
Long selectLockedQuantity(OutboundOrderLog outboundOrderLog);
/** /**
* 修改出库明细子(仅用于锁定数量统计) * 修改出库明细子(仅用于锁定数量统计)
* *
......
...@@ -19,7 +19,6 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService ...@@ -19,7 +19,6 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService
{ {
@Autowired @Autowired
private InboundOrderItemsMapper inboundOrderItemsMapper; private InboundOrderItemsMapper inboundOrderItemsMapper;
/** /**
* 查询入库单明细 * 查询入库单明细
* *
...@@ -54,6 +53,7 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService ...@@ -54,6 +53,7 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService
public int insertInboundOrderItems(InboundOrderItems inboundOrderItems) public int insertInboundOrderItems(InboundOrderItems inboundOrderItems)
{ {
inboundOrderItems.setCreateTime(DateUtils.getNowDate()); inboundOrderItems.setCreateTime(DateUtils.getNowDate());
return inboundOrderItemsMapper.insertInboundOrderItems(inboundOrderItems); return inboundOrderItemsMapper.insertInboundOrderItems(inboundOrderItems);
} }
......
...@@ -85,6 +85,8 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -85,6 +85,8 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.updateInventory(inventory); return inventoryMapper.updateInventory(inventory);
} }
/** /**
* 批量删除库存 * 批量删除库存
* *
...@@ -108,4 +110,9 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -108,4 +110,9 @@ public class InventoryServiceImpl implements IInventoryService
{ {
return inventoryMapper.deleteInventoryById(id); return inventoryMapper.deleteInventoryById(id);
} }
@Override
public List<Inventory> listByMatreialId(String materialId) {
return inventoryMapper.listByMatreialId(materialId);
}
} }
...@@ -4,7 +4,7 @@ import java.util.ArrayList; ...@@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.Inventory; import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderItemsInventory; import com.ruoyi.inventory.domain.OutboundOrderLog;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -26,6 +26,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -26,6 +26,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
@Autowired @Autowired
private InventoryServiceImpl inventoryService; private InventoryServiceImpl inventoryService;
@Autowired
private OutboundOrderLogServiceImpl outboundOrderLogService;
/** /**
* 查询出库单明细 * 查询出库单明细
* *
...@@ -33,16 +36,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -33,16 +36,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
* @return 出库单明细 * @return 出库单明细
*/ */
@Override @Override
public OutboundOrderItemsInventory selectOutboundOrderItemsById(String id) public OutboundOrderItems selectOutboundOrderItemsById(String id)
{ {
OutboundOrderItems outboundOrderItems = outboundOrderItemsMapper.selectOutboundOrderItemsById(id); return outboundOrderItemsMapper.selectOutboundOrderItemsById(id);
Inventory inventory = new Inventory();
BeanUtils.copyProperties(outboundOrderItems, inventory);
Inventory inventory1 = inventoryService.selectInventory(inventory);
OutboundOrderItemsInventory outboundOrderItemsInventory = new OutboundOrderItemsInventory();
outboundOrderItemsInventory.setOutboundOrderItems(outboundOrderItems);
outboundOrderItemsInventory.setInventory(inventory1);
return outboundOrderItemsInventory;
} }
/** /**
...@@ -52,26 +48,15 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -52,26 +48,15 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
* @return 出库单明细 * @return 出库单明细
*/ */
@Override @Override
public List<OutboundOrderItemsInventory> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems) public List<OutboundOrderItems> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems)
{ {
List<OutboundOrderItems> itemsList = outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems); return outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems);
List<OutboundOrderItemsInventory> resultList = new ArrayList<>();
for (OutboundOrderItems item : itemsList) {
Inventory inventory = new Inventory();
BeanUtils.copyProperties(item, inventory);
Inventory inventory1 = inventoryService.selectInventory(inventory);
OutboundOrderItemsInventory outboundOrderItemsInventory = new OutboundOrderItemsInventory();
outboundOrderItemsInventory.setOutboundOrderItems(item);
outboundOrderItemsInventory.setInventory(inventory1);
resultList.add(outboundOrderItemsInventory);
}
return resultList;
} }
/** /**
* 新增出库单明细 * 新增出库单明细
* *
* @param outboundOrderItems 出库单明细 * @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果 * @return 结果
*/ */
@Override @Override
...@@ -84,7 +69,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -84,7 +69,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
/** /**
* 修改出库单明细 * 修改出库单明细
* *
* @param outboundOrderItems 出库单明细 * @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果 * @return 结果
*/ */
@Override @Override
......
...@@ -54,7 +54,10 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService ...@@ -54,7 +54,10 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService
{ {
return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog); return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog);
} }
@Override
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog){
return outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog);
}
/** /**
* 修改出库明细子(仅用于锁定数量统计) * 修改出库明细子(仅用于锁定数量统计)
* *
......
...@@ -120,15 +120,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -120,15 +120,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
String id = outboundOrders.getId(); String id = outboundOrders.getId();
if (StringUtils.isNotNull(outboundOrderItemsList)) if (StringUtils.isNotNull(outboundOrderItemsList))
{ {
List<OutboundOrderItems> list = new ArrayList<OutboundOrderItems>();
for (OutboundOrderItems outboundOrderItems : outboundOrderItemsList) for (OutboundOrderItems outboundOrderItems : outboundOrderItemsList)
{ {
outboundOrderItems.setOrderId(id); outboundOrderItems.setOrderId(id);
list.add(outboundOrderItems);
} }
if (list.size() > 0) if (outboundOrderItemsList.size() > 0)
{ {
outboundOrdersMapper.batchOutboundOrderItems(list); outboundOrdersMapper.batchOutboundOrderItems(outboundOrderItemsList);
} }
} }
} }
......
...@@ -2,6 +2,7 @@ package com.ruoyi.inventory.service.impl; ...@@ -2,6 +2,7 @@ package com.ruoyi.inventory.service.impl;
import java.util.List; import java.util.List;
import com.ruoyi.common.core.domain.entity.Materials;
import com.ruoyi.common.core.domain.entity.MaterialsCategory; import com.ruoyi.common.core.domain.entity.MaterialsCategory;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.SecurityUtils;
...@@ -9,6 +10,7 @@ import com.ruoyi.common.utils.bean.BeanUtils; ...@@ -9,6 +10,7 @@ import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.UUID; import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.inventory.domain.StorageLocationsCategory; import com.ruoyi.inventory.domain.StorageLocationsCategory;
import com.ruoyi.inventory.mapper.MaterialsCategoryMapper; import com.ruoyi.inventory.mapper.MaterialsCategoryMapper;
import com.ruoyi.inventory.mapper.MaterialsMapper;
import com.ruoyi.inventory.mapper.StorageLocationsCategoryMapper; import com.ruoyi.inventory.mapper.StorageLocationsCategoryMapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -30,7 +32,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService ...@@ -30,7 +32,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
@Autowired @Autowired
private StorageLocationsCategoryMapper storageLocationsCategoryMapper; private StorageLocationsCategoryMapper storageLocationsCategoryMapper;
@Autowired @Autowired
private MaterialsCategoryMapper materialsCategoryMapper; private MaterialsMapper materialsMapper;
/** /**
* 查询库位 * 查询库位
...@@ -69,9 +71,10 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService ...@@ -69,9 +71,10 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
if (storageLocations2.getAllowedCategoryIds() != null && !storageLocations2.getAllowedCategoryIds().isEmpty()){ if (storageLocations2.getAllowedCategoryIds() != null && !storageLocations2.getAllowedCategoryIds().isEmpty()){
String[] AllowedCategoryIds = storageLocations2.getAllowedCategoryIds().split(","); String[] AllowedCategoryIds = storageLocations2.getAllowedCategoryIds().split(",");
for (String AllowedCategoryId : AllowedCategoryIds) { for (String AllowedCategoryId : AllowedCategoryIds) {
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(AllowedCategoryId);
if (materialsCategory != null && materialsCategory.getCategoryName() != null) { Materials materials = materialsMapper.selectMaterialsByMaterialsCode(AllowedCategoryId);
String categoryName = materialsCategory.getCategoryName().trim(); // 去除首尾空格 if (materials != null && materials.getMaterialName() != null) {
String categoryName = materials.getMaterialName().trim(); // 去除首尾空格
if (AllowedCategoryName != "") { if (AllowedCategoryName != "") {
AllowedCategoryName += ","; AllowedCategoryName += ",";
} }
...@@ -110,8 +113,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService ...@@ -110,8 +113,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory.setCategoryId(categoryId); storageLocationsCategory.setCategoryId(categoryId);
storageLocationsCategory.setCreateTime(DateUtils.getNowDate()); storageLocationsCategory.setCreateTime(DateUtils.getNowDate());
storageLocationsCategory.setCreateUserCode(String.valueOf(SecurityUtils.getUserId())); storageLocationsCategory.setCreateUserCode(String.valueOf(SecurityUtils.getUserId()));
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(categoryId); Materials materials = materialsMapper.selectMaterialsByMaterialsCode(categoryId);
storageLocationsCategory.setCategoryName(materialsCategory.getCategoryName()); storageLocationsCategory.setCategoryName(materials.getMaterialName());
storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory); storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory);
} }
} }
...@@ -146,8 +149,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService ...@@ -146,8 +149,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory.setCategoryId(categoryId); storageLocationsCategory.setCategoryId(categoryId);
storageLocationsCategory.setUpdateTime(DateUtils.getNowDate()); storageLocationsCategory.setUpdateTime(DateUtils.getNowDate());
storageLocationsCategory.setUpdateUserCode(String.valueOf(SecurityUtils.getUserId())); storageLocationsCategory.setUpdateUserCode(String.valueOf(SecurityUtils.getUserId()));
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(categoryId); Materials materials = materialsMapper.selectMaterialsByMaterialsCode(categoryId);
storageLocationsCategory.setCategoryName(materialsCategory.getCategoryName()); storageLocationsCategory.setCategoryName(materials.getMaterialName());
storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory); storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory);
} }
} }
......
...@@ -66,7 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -66,7 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectInboundOrdersList" parameterType="InboundOrders" resultMap="InboundOrdersResult"> <select id="selectInboundOrdersList" parameterType="InboundOrders" resultMap="InboundOrdersResult">
<include refid="selectInboundOrdersVo"/> <include refid="selectInboundOrdersVo"/>
<where> <where>
<if test="id != null and id != ''"> and id = #{id}</if> <if test="id != null and Id != ''"> and id = #{Id}</if>
<if test="systemNo != null and systemNo != ''"> and system_no = #{systemNo}</if> <if test="systemNo != null and systemNo != ''"> and system_no = #{systemNo}</if>
<if test="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if> <if test="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if> <if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
......
...@@ -90,7 +90,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -90,7 +90,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectInventoryVo"/> <include refid="selectInventoryVo"/>
where id = #{id} where id = #{id}
</select> </select>
<select id="listByMatreialId" parameterType="String" resultMap="InventoryResult">
<include refid="selectInventoryVo"/>
where material_id = #{materialId}
</select>
<insert id="insertInventory" parameterType="Inventory"> <insert id="insertInventory" parameterType="Inventory">
insert into inventory insert into inventory
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
......
...@@ -40,7 +40,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -40,7 +40,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id} where id = #{id}
order by sort_no asc order by sort_no asc
</select> </select>
<insert id="insertMaterialsCategory" parameterType="MaterialsCategory"> <insert id="insertMaterialsCategory" parameterType="MaterialsCategory">
insert into materials_category insert into materials_category
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
......
...@@ -76,6 +76,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -76,6 +76,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id} where id = #{id}
order by sort_no asc order by sort_no asc
</select> </select>
<select id="selectMaterialsByMaterialsCode" parameterType="String" resultMap="MaterialsResult">
<include refid="selectMaterialsVo"/>
where material_code = #{id}
order by sort_no asc
</select>
<select id="selectMaterialsByCategory" parameterType="String" resultMap="MaterialsResult"> <select id="selectMaterialsByCategory" parameterType="String" resultMap="MaterialsResult">
<include refid="selectMaterialsVo"/> <include refid="selectMaterialsVo"/>
where category_code = #{id} where category_code = #{id}
......
...@@ -37,13 +37,9 @@ ...@@ -37,13 +37,9 @@
select ifnull(sum(actual_quantity), 0) select ifnull(sum(actual_quantity), 0)
from outbound_order_log from outbound_order_log
<where> <where>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if> <if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if> <if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if> <if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
<if test="actualQuantity != null "> and actual_quantity = #{actualQuantity}</if>
<if test="itemStatus != null "> and item_status = #{itemStatus}</if>
<if test="isUsed != null "> and is_used = #{isUsed}</if>
</where> </where>
</select> </select>
......
...@@ -91,8 +91,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -91,8 +91,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectOutboundOrderItemsList" parameterType="String" resultMap="OutboundOrderItemsResult"> <select id="selectOutboundOrderItemsList" parameterType="String" resultMap="OutboundOrderItemsResult">
select id, order_id, material_id, batch_id, warehouse_id, location_id, planned_quantity, actual_quantity, planned_packages, actual_packages, divisor, label_color, voucher_number, unit_price, item_status, received_at, received_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code
from outbound_order_items from outbound_order_items
where order_id = #{id} where order_id = #{id}
</select> </select>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论