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 @@
<div><strong>层:</strong>{{ scope.row.layerCode || '-' }}</div>
</el-col>
</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>
</el-table-column>
<el-table-column type="selection" width="55" align="center" />
......@@ -176,6 +181,15 @@
</el-tooltip>
</template>
</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="isEnabled" width="100" fixed="right">
<template slot-scope="scope">
......@@ -212,7 +226,6 @@
@pagination="getList"
/>
<!-- 添加或修改库位对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-row :gutter="20">
......@@ -268,7 +281,6 @@
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
......@@ -281,7 +293,6 @@
<el-input v-model="form.rowCode" placeholder="请输入排" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
......@@ -298,12 +309,12 @@
<el-row :gutter="20">
<el-col :span="12">
<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-col>
<el-col :span="12">
<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-col>
</el-row>
......@@ -314,14 +325,25 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="物料" prop="materialUuids">
<div style="display: flex; align-items: center;">
<el-input v-model="form.materialNames" placeholder="" readonly style="flex: 1;" />
<el-button type="primary" size="small" @click="showMaterialSelect = true" style="margin-left: 10px">选择物料</el-button>
<el-form-item label="允许存放物料" prop="materialCodes">
<div style="display: flex; align-items: center; flex-direction: column; gap: 8px;">
<el-input
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>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="应用状态" prop="isEnabled">
......@@ -336,13 +358,14 @@
<el-input v-model.number="form.sortNo" type="number" placeholder="请输入排序" min="0" step="1" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<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-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
......@@ -350,44 +373,51 @@
</div>
</el-dialog>
<!-- 物料选择组件 -->
<MaterialSelectComponent
<el-dialog
title="选择允许存放的物料"
:visible.sync="showMaterialSelect"
@selection-confirm="handleMaterialSelectionConfirm"
@selection-cancel="handleMaterialSelectionCancel"
width="1000px"
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>
</template>
<script>
import { listLocations, getLocations, delLocations, addLocations, updateLocations } from "@/api/inventory/locations"
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 {
name: "Locations",
components: { MaterialSelectComponent },
components: { materialsSeletor },
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 库位表格数据
locationsList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 字典类型
dict: {
type: {
location_type: [
......@@ -402,7 +432,7 @@ export default {
]
}
},
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
......@@ -410,6 +440,15 @@ export default {
locationName: null,
warehousesCode: null,
locationType: null,
layerCode: null
},
form: {
id: null,
locationCode: null,
locationName: null,
warehousesCode: null,
locationType: null,
zoneCode: null,
rowCode: null,
columnCode: null,
......@@ -417,17 +456,16 @@ export default {
capacity: null,
volumeCapacity: null,
allowedHazardLevels: null,
materialCodes: null,
materialNames: null,
allowedCategoryIds: null,
allowedCategoryNames: null,
temperatureZone: null,
isEnabled: null,
isUsed: null,
sortNo: null,
createUserCode: null,
updateUserCode: null
isEnabled: 1,
isUsed: 0,
sortNo: 0
},
// 表单参数
form: {},
// 表单校验
rules: {
locationCode: [
{ required: true, message: '库位编码不能为空', trigger: 'blur' },
......@@ -447,30 +485,72 @@ export default {
{ required: true, message: '应用状态不能为空', trigger: 'change' }
]
},
// 仓库列表
warehouseOptions: [],
// 仓库加载状态
loadingWarehouse: false,
// 物料选择组件显示状态
showMaterialSelect: false
showMaterialSelect: false,
tempSelectedMaterials: {
materialCodes: [],
names: [],
categoryIds: []
},
materialCodeToNameMap: {},
materialMapLoaded: false
}
},
created() {
this.getList()
this.getWarehouseOptions()
this.initMaterialCodeToNameMap()
},
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) {
// 排除点击选择列时触发展开/折叠
if (column.type !== 'selection') {
this.$refs.locationsTable.toggleRowExpansion(row)
}
},
/** 查询库位列表 */
getList() {
this.loading = true
// 添加is_used=0条件,只查询未被使用的库位
const params = {
...this.queryParams,
isUsed: 0
......@@ -482,30 +562,14 @@ export default {
})
},
/** 查询仓库列表 */
getWarehouseOptions() {
this.loadingWarehouse = true
// 移除isUsed=0条件,查询所有仓库
listWarehouses({ pageNum: 1, pageSize: 100 }).then(response => {
// 调试:查看仓库数据结构
console.log('仓库数据:', response)
// 确保rows存在且为数组
const rows = response.rows || []
// 处理不同可能的数据结构
this.warehouseOptions = rows.map(item => {
// 根据实际数据结构调整字段名
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.warehouseOptions = rows.map(item => ({
label: `${item.warehousesName || item.name || '未命名仓库'} (${item.warehouseCode || item.code || item.warehousesCode || ''})`,
value: item.warehouseCode || item.code || item.warehousesCode || ''
})).filter(option => option.value)
this.loadingWarehouse = false
}).catch(error => {
console.error('获取仓库列表失败:', error)
......@@ -514,18 +578,17 @@ export default {
})
},
/** 根据仓库编码获取仓库名称 */
getWarehouseName(warehouseCode) {
if (!warehouseCode) return ''
const warehouse = this.warehouseOptions.find(item => item.value === warehouseCode)
return warehouse ? warehouse.label : warehouseCode
},
// 取消按钮
cancel() {
this.open = false
this.reset()
},
// 表单重置
reset() {
this.form = {
id: null,
......@@ -540,68 +603,111 @@ export default {
capacity: null,
volumeCapacity: null,
allowedHazardLevels: null,
materialUuids: null,
materialCodes: null,
materialNames: null,
allowedCategoryIds: null,
allowedCategoryNames: null,
temperatureZone: null,
isEnabled: null,
isUsed: null,
sortNo: null,
createTime: null,
createUserCode: null,
updateTime: null,
updateUserCode: null
isEnabled: 1,
isUsed: 0,
sortNo: 0
}
this.tempSelectedMaterials = {
materialCodes: [],
names: [],
categoryIds: []
}
this.resetForm("form")
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length!==1
this.multiple = !selection.length
},
/** 新增按钮操作 */
handleAdd() {
this.reset()
this.open = true
this.title = "添加库位"
},
/** 修改按钮操作 */
handleUpdate(row) {
async handleUpdate(row) {
this.reset()
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.title = "修改库位"
})
} catch (error) {
console.error('获取库位详情失败:', error)
this.$modal.msgError('获取数据失败,请重试!')
}
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
// 直接使用表单数据,不需要转换仓库编码字段名
const submitData = {
...this.form
if (this.form.materialCodes) {
this.form.materialCodes = this.form.materialCodes.split(',').filter(code => code.trim()).join(',')
}
if (this.form.materialNames) {
this.form.materialNames = this.form.materialNames.split(',').filter(name => name.trim()).join(',')
}
if (this.form.id != null) {
updateLocations(submitData).then(response => {
updateLocations(this.form).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addLocations(submitData).then(response => {
addLocations(this.form).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
......@@ -610,7 +716,7 @@ export default {
}
})
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除库位编号为"' + ids + '"的数据项?').then(function() {
......@@ -620,23 +726,87 @@ export default {
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
},
/** 导出按钮操作 */
handleExport() {
this.download('inventory/locations/export', {
...this.queryParams
}, `locations_${new Date().getTime()}.xlsx`)
},
/** 处理物料选择确认 */
handleMaterialSelectionConfirm(uuids, names) {
this.form.materialUuids = uuids
this.form.materialNames = names
handleMaterialSelectionChange(selectedData) {
this.tempSelectedMaterials = {
materialCodes: selectedData.materialCodes || [],
names: selectedData.names || [],
categoryIds: selectedData.formattedCategoryIds || []
}
},
/** 处理物料选择取消 */
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>
<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>
<div class="app-container">
<!-- 搜索表单 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="出库单号" prop="orderId">
<el-input
......@@ -33,6 +34,14 @@
@keyup.enter.native="handleQuery"
/>
</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-select v-model="queryParams.orderStatus" placeholder="请选择订单状态" clearable>
<el-option
......@@ -43,12 +52,29 @@
/>
</el-select>
</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-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-form-item>
</el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
......@@ -95,9 +121,9 @@
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<!-- 主表格 -->
<el-table v-loading="loading" :data="ordersList" @selection-change="handleSelectionChange">
<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="systemNo" width="150" />
<el-table-column label="入库类型" align="center" prop="orderTypeId" width="120">
......@@ -123,10 +149,6 @@
<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="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">
<template slot-scope="scope">
<el-button
......@@ -147,6 +169,7 @@
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show="total>0"
:total="total"
......@@ -155,9 +178,10 @@
@pagination="getList"
/>
<!-- 添加或修改出库单主对话框 -->
<!-- 添加/修改出库单主弹窗 -->
<el-dialog :title="title" :visible.sync="open" width="900px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<!-- 主表单区域 -->
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="出库单号" prop="orderId">
......@@ -196,17 +220,6 @@
</el-row>
<el-row :gutter="20">
<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-date-picker clearable
v-model="form.inboundDate"
......@@ -225,19 +238,19 @@
</el-col>
<el-col :span="12">
<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-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<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-col>
<el-col :span="12">
<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-col>
</el-row>
......@@ -248,125 +261,58 @@
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="是否使用" prop="isUsed">
<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-divider content-position="center">入库单明细信息</el-divider>
<el-row :gutter="10" class="mb8">
<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 :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-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 label="序号" align="center" prop="index" width="50"/>
<el-table-column label="货物ID" prop="materialId" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.materialId" placeholder="请输入货物ID" />
</template>
</el-table-column>
<el-table-column label="批次ID" prop="batchId" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.batchId" placeholder="请输入批次ID" />
</template>
</el-table-column>
<el-table-column label="仓库ID" prop="warehouseId" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.warehouseId" placeholder="请输入仓库ID" />
</template>
</el-table-column>
<el-table-column label="库位ID" prop="locationId" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.locationId" placeholder="请输入库位ID" />
</template>
</el-table-column>
<el-table-column label="货主ID" prop="ownerId" width="150">
<el-table-column label="货物ID" prop="materialId" width="150" />
<el-table-column label="批次ID" prop="batchId" width="150" />
<el-table-column label="仓库ID" prop="warehouseId" width="150" />
<el-table-column label="库位ID" prop="locationId" width="150" />
<el-table-column label="计划数量" prop="plannedQuantity" 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">
<el-input v-model="scope.row.ownerId" placeholder="请输入货主ID" />
<dict-tag :options="dict.type.inbound_order_item_status" :value="scope.row.itemStatus"/>
</template>
</el-table-column>
<el-table-column label="库存数量" prop="quantity" width="150">
<el-table-column label="收货时间" prop="receivedAt" width="150">
<template slot-scope="scope">
<el-input v-model="scope.row.quantity" placeholder="请输入库存数量" />
<span>{{ parseTime(scope.row.receivedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template>
</el-table-column>
<el-table-column label="锁定数量" prop="lockedQuantity" width="150">
<el-table-column label="收货人" prop="receivedBy" width="150" />
<el-table-column label="操作" align="center" width="80">
<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="请输入排序" />
<el-button
size="mini"
type="text"
icon="el-icon-edit"
@click="editDetailItem(scope.row)"
>编辑</el-button>
</template>
</el-table-column>
</el-table>
......@@ -376,23 +322,36 @@
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
<!-- 明细项添加/编辑子组件弹窗(OutboundOrderFormWithItems -->
<OutboundOrderFormWithItems
:title="detailDialogTitle"
:open="detailDialogOpen"
:init-form="currentDetailItem"
@submit="handleDetailSubmit"
@update:open="detailDialogOpen = $event"
/>
</div>
</template>
<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 {
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() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 子表选中数据
checkedInventory: [],
// 非单个禁用
single: true,
// 非多个禁用
......@@ -403,12 +362,35 @@ export default {
total: 0,
// 出库单主表格数据
ordersList: [],
// 库存表格数据
inventoryList: [],
// 弹出层标题
// 主弹窗标题
title: "",
// 是否显示弹出层
// 主弹窗是否显示
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: {
pageNum: 1,
......@@ -432,18 +414,11 @@ export default {
},
// 表单参数
form: {},
// 表单校验
// 表单校验规则
rules: {
}
}
},
// 监听仓库ID变化
watch: {
'form.warehouseId'(newVal) {
if (newVal) {
this.queryWarehouseInventory(newVal)
} else {
this.inventoryList = []
orderId: [{ required: true, message: '请输入出库单号', trigger: 'blur' }],
warehouseId: [{ required: true, message: '请输入仓库ID', trigger: 'blur' }],
inboundDate: [{ required: true, message: '请选择出库日期', trigger: 'change' }]
}
}
},
......@@ -451,6 +426,129 @@ export default {
this.getList()
},
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() {
this.loading = true
......@@ -489,32 +587,11 @@ export default {
updateTime: null,
updateUserCode: null
}
this.inventoryList = []
// 重置明细表格
this.inboundOrderItemsList = []
this.selectedInboundOrderItems = []
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() {
this.queryParams.pageNum = 1
......@@ -535,7 +612,7 @@ export default {
handleAdd() {
this.reset()
this.open = true
this.title = "添加出库单"
this.title = "添加出库单"
},
/** 修改按钮操作 */
handleUpdate(row) {
......@@ -543,35 +620,47 @@ export default {
const id = row.id || this.ids
getOrders(id).then(response => {
this.form = response.data
// 如果有inventoryList直接使用,否则根据仓库ID查询
if (response.data.inventoryList && response.data.inventoryList.length > 0) {
this.inventoryList = response.data.inventoryList
// 按货物ID分类
this.groupInventoryByMaterialId()
} else if (response.data.warehouseId) {
this.queryWarehouseInventory(response.data.warehouseId)
// 如果有明细数据,初始化明细表格
if (response.data.items) {
this.inboundOrderItemsList = response.data.items.map((item, index) => ({
...item,
// 兼容materialUuids:适配物料选择器返回的materialCodes格式
materialUuids: item.materialUuids || item.materialId || '',
index: index + 1
}))
// 计算总数量
this.calcTotalQuantity()
}
this.open = true
this.title = "修改出库单"
this.title = "修改出库单"
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
this.$refs["form"].validate(async (valid) => {
if (valid) {
this.form.inventoryList = this.inventoryList
// 组装完整数据(主表+明细)
const submitData = {
...this.form,
items: this.inboundOrderItemsList.map(item => {
const { index, ...rest } = item // 剔除序号
// 提交时确保materialId是单选的物料编码(从materialUuids/原materialId取值)
rest.materialId = rest.materialUuids || rest.materialId || ''
return rest
})
}
try {
if (this.form.id != null) {
updateOrders(this.form).then(response => {
await updateOrders(submitData)
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addOrders(this.form).then(response => {
await addOrders(submitData)
this.$modal.msgSuccess("新增成功")
}
this.open = false
this.getList()
})
} catch (error) {
this.$modal.msgError(error.msg || "操作失败")
}
}
})
......@@ -579,72 +668,12 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const ids = row.id || this.ids
this.$modal.confirm('是否确认删除出库单主编号为"' + ids + '"的数据项?').then(function() {
return delOrders(ids)
}).then(() => {
this.$modal.confirm('是否确认删除出库单编号为"' + ids + '"的数据项?').then(async () => {
await delOrders(ids)
this.getList()
this.$modal.msgSuccess("删除成功")
}).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() {
this.download('inventory/orders/export', {
......@@ -654,3 +683,24 @@ export default {
}
}
</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
List<Inventory> list = inventoryService.selectInventoryList(inventory);
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;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderItemsInventory;
import com.ruoyi.inventory.service.IOutboundOrderItemsService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;
......@@ -43,7 +43,7 @@ public class OutboundOrderItemsController extends BaseController
public TableDataInfo list(OutboundOrderItems outboundOrderItems)
{
startPage();
List<OutboundOrderItemsInventory> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
List<OutboundOrderItems> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
return getDataTable(list);
}
......@@ -55,8 +55,8 @@ public class OutboundOrderItemsController extends BaseController
@PostMapping("/export")
public void export(HttpServletResponse response, OutboundOrderItems outboundOrderItems)
{
List<OutboundOrderItemsInventory> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
ExcelUtil<OutboundOrderItemsInventory> util = new ExcelUtil<OutboundOrderItemsInventory>(OutboundOrderItemsInventory.class);
List<OutboundOrderItems> list = outboundOrderItemsService.selectOutboundOrderItemsList(outboundOrderItems);
ExcelUtil<OutboundOrderItems> util = new ExcelUtil<OutboundOrderItems>(OutboundOrderItems.class);
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
private String id;
/** 货物ID */
@Excel(name = "货物ID")
@Excel(name = "出货单号ID")
private String orderId;
/** 货物ID */
......
package com.ruoyi.inventory.mapper;
import java.util.List;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory;
/**
......@@ -65,4 +67,6 @@ public interface InventoryMapper
* @return 结果
*/
public int deleteInventoryByIds(String[] ids);
public List<Inventory> listByMatreialId(String materialId);
}
......@@ -19,6 +19,13 @@ public interface MaterialsCategoryMapper
*/
public MaterialsCategory selectMaterialsCategoryById(String id);
/**
* 查询物料分类
*
* @param id 物料分类主键
* @return 物料分类
*/
public MaterialsCategory selectMaterialsCategoryByMaterialsCode(String id);
/**
* 查询物料分类列表
*
* @param materialsCategory 物料分类
......
......@@ -23,6 +23,14 @@ public interface MaterialsMapper
public Materials selectMaterialsById(String id);
/**
* 查询物料
*
* @param id 物料主键
* @return 物料
*/
public Materials selectMaterialsByMaterialsCode(String id);
/**
* 查询物料列表
*
* @param materials 物料
......
package com.ruoyi.inventory.service;
import java.util.List;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory;
/**
......@@ -60,4 +62,6 @@ public interface IInventoryService
* @return 结果
*/
public int deleteInventoryById(String id);
public List<Inventory> listByMatreialId(String materialId);
}
......@@ -2,7 +2,7 @@ package com.ruoyi.inventory.service;
import java.util.List;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderItemsInventory;
import com.ruoyi.inventory.domain.OutboundOrderItems;
/**
* 出库单明细Service接口
......@@ -18,7 +18,7 @@ public interface IOutboundOrderItemsService
* @param id 出库单明细主键
* @return 出库单明细
*/
public OutboundOrderItemsInventory selectOutboundOrderItemsById(String id);
public OutboundOrderItems selectOutboundOrderItemsById(String id);
/**
* 查询出库单明细列表
......@@ -26,7 +26,7 @@ public interface IOutboundOrderItemsService
* @param outboundOrderItems 出库单明细
* @return 出库单明细集合
*/
public List<OutboundOrderItemsInventory> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems);
public List<OutboundOrderItems> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems);
/**
* 新增出库单明细
......
......@@ -35,6 +35,8 @@ public interface IOutboundOrderLogService
*/
public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog);
Long selectLockedQuantity(OutboundOrderLog outboundOrderLog);
/**
* 修改出库明细子(仅用于锁定数量统计)
*
......
......@@ -19,7 +19,6 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService
{
@Autowired
private InboundOrderItemsMapper inboundOrderItemsMapper;
/**
* 查询入库单明细
*
......@@ -54,6 +53,7 @@ public class InboundOrderItemsServiceImpl implements IInboundOrderItemsService
public int insertInboundOrderItems(InboundOrderItems inboundOrderItems)
{
inboundOrderItems.setCreateTime(DateUtils.getNowDate());
return inboundOrderItemsMapper.insertInboundOrderItems(inboundOrderItems);
}
......
......@@ -85,6 +85,8 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.updateInventory(inventory);
}
/**
* 批量删除库存
*
......@@ -108,4 +110,9 @@ public class InventoryServiceImpl implements IInventoryService
{
return inventoryMapper.deleteInventoryById(id);
}
@Override
public List<Inventory> listByMatreialId(String materialId) {
return inventoryMapper.listByMatreialId(materialId);
}
}
......@@ -4,7 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import com.ruoyi.common.utils.DateUtils;
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.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -26,6 +26,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
@Autowired
private InventoryServiceImpl inventoryService;
@Autowired
private OutboundOrderLogServiceImpl outboundOrderLogService;
/**
* 查询出库单明细
*
......@@ -33,16 +36,9 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
* @return 出库单明细
*/
@Override
public OutboundOrderItemsInventory selectOutboundOrderItemsById(String id)
public OutboundOrderItems selectOutboundOrderItemsById(String id)
{
OutboundOrderItems outboundOrderItems = 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;
return outboundOrderItemsMapper.selectOutboundOrderItemsById(id);
}
/**
......@@ -52,26 +48,15 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
* @return 出库单明细
*/
@Override
public List<OutboundOrderItemsInventory> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems)
public List<OutboundOrderItems> selectOutboundOrderItemsList(OutboundOrderItems outboundOrderItems)
{
List<OutboundOrderItems> itemsList = 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;
return outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems);
}
/**
* 新增出库单明细
*
* @param outboundOrderItems 出库单明细
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override
......@@ -84,7 +69,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
/**
* 修改出库单明细
*
* @param outboundOrderItems 出库单明细
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override
......
......@@ -54,7 +54,10 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService
{
return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog);
}
@Override
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog){
return outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog);
}
/**
* 修改出库明细子(仅用于锁定数量统计)
*
......
......@@ -120,15 +120,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
String id = outboundOrders.getId();
if (StringUtils.isNotNull(outboundOrderItemsList))
{
List<OutboundOrderItems> list = new ArrayList<OutboundOrderItems>();
for (OutboundOrderItems outboundOrderItems : outboundOrderItemsList)
{
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;
import java.util.List;
import com.ruoyi.common.core.domain.entity.Materials;
import com.ruoyi.common.core.domain.entity.MaterialsCategory;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
......@@ -9,6 +10,7 @@ import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.uuid.UUID;
import com.ruoyi.inventory.domain.StorageLocationsCategory;
import com.ruoyi.inventory.mapper.MaterialsCategoryMapper;
import com.ruoyi.inventory.mapper.MaterialsMapper;
import com.ruoyi.inventory.mapper.StorageLocationsCategoryMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -30,7 +32,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
@Autowired
private StorageLocationsCategoryMapper storageLocationsCategoryMapper;
@Autowired
private MaterialsCategoryMapper materialsCategoryMapper;
private MaterialsMapper materialsMapper;
/**
* 查询库位
......@@ -69,9 +71,10 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
if (storageLocations2.getAllowedCategoryIds() != null && !storageLocations2.getAllowedCategoryIds().isEmpty()){
String[] AllowedCategoryIds = storageLocations2.getAllowedCategoryIds().split(",");
for (String AllowedCategoryId : AllowedCategoryIds) {
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(AllowedCategoryId);
if (materialsCategory != null && materialsCategory.getCategoryName() != null) {
String categoryName = materialsCategory.getCategoryName().trim(); // 去除首尾空格
Materials materials = materialsMapper.selectMaterialsByMaterialsCode(AllowedCategoryId);
if (materials != null && materials.getMaterialName() != null) {
String categoryName = materials.getMaterialName().trim(); // 去除首尾空格
if (AllowedCategoryName != "") {
AllowedCategoryName += ",";
}
......@@ -110,8 +113,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory.setCategoryId(categoryId);
storageLocationsCategory.setCreateTime(DateUtils.getNowDate());
storageLocationsCategory.setCreateUserCode(String.valueOf(SecurityUtils.getUserId()));
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(categoryId);
storageLocationsCategory.setCategoryName(materialsCategory.getCategoryName());
Materials materials = materialsMapper.selectMaterialsByMaterialsCode(categoryId);
storageLocationsCategory.setCategoryName(materials.getMaterialName());
storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory);
}
}
......@@ -146,8 +149,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory.setCategoryId(categoryId);
storageLocationsCategory.setUpdateTime(DateUtils.getNowDate());
storageLocationsCategory.setUpdateUserCode(String.valueOf(SecurityUtils.getUserId()));
MaterialsCategory materialsCategory = materialsCategoryMapper.selectMaterialsCategoryById(categoryId);
storageLocationsCategory.setCategoryName(materialsCategory.getCategoryName());
Materials materials = materialsMapper.selectMaterialsByMaterialsCode(categoryId);
storageLocationsCategory.setCategoryName(materials.getMaterialName());
storageLocationsCategoryMapper.insertStorageLocationsCategory(storageLocationsCategory);
}
}
......
......@@ -66,7 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectInboundOrdersList" parameterType="InboundOrders" resultMap="InboundOrdersResult">
<include refid="selectInboundOrdersVo"/>
<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="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
......
......@@ -90,7 +90,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectInventoryVo"/>
where id = #{id}
</select>
<select id="listByMatreialId" parameterType="String" resultMap="InventoryResult">
<include refid="selectInventoryVo"/>
where material_id = #{materialId}
</select>
<insert id="insertInventory" parameterType="Inventory">
insert into inventory
<trim prefix="(" suffix=")" suffixOverrides=",">
......
......@@ -40,7 +40,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id}
order by sort_no asc
</select>
<insert id="insertMaterialsCategory" parameterType="MaterialsCategory">
insert into materials_category
<trim prefix="(" suffix=")" suffixOverrides=",">
......
......@@ -76,6 +76,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id}
order by sort_no asc
</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">
<include refid="selectMaterialsVo"/>
where category_code = #{id}
......
......@@ -37,13 +37,9 @@
select ifnull(sum(actual_quantity), 0)
from outbound_order_log
<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="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</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>
</select>
......
......@@ -91,7 +91,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select>
<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
where order_id = #{id}
</select>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论