Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
M
mini-wms
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
周海峰
mini-wms
Commits
4551012a
Commit
4551012a
authored
Dec 09, 2025
by
yubin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
出库
parent
70157266
显示空白字符变更
内嵌
并排
正在显示
22 个修改的文件
包含
1310 行增加
和
434 行删除
+1310
-434
ruoyi-admin-vue/src/api/inventory/locations.js
+8
-0
ruoyi-admin-vue/src/api/inventory/materials.js
+7
-0
ruoyi-admin-vue/src/api/inventory/owners.js
+6
-0
ruoyi-admin-vue/src/api/inventory/warehouses.js
+6
-0
ruoyi-admin-vue/src/components/materialsSeletor copy.vue
+651
-0
ruoyi-admin-vue/src/components/materialsSeletor.vue
+197
-196
ruoyi-admin-vue/src/views/inventory/locations/index.vue
+176
-91
ruoyi-admin-vue/src/views/inventory/orders/OutboundOrderFormWithItems.vue
+100
-58
ruoyi-admin-vue/src/views/inventory/orders/index.vue
+49
-16
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/MaterialsMapper.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/OutboundOrderItemsMapper.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/ReturnOrderItemsMapper.java
+0
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IInventoryService.java
+1
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InventoryServiceImpl.java
+2
-3
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrderItemsServiceImpl.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrdersServiceImpl.java
+13
-2
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/StorageLocationsServiceImpl.java
+3
-3
ruoyi-inventory/src/main/resources/mapper/inventory/InboundOrderItemsMapper.xml
+6
-6
ruoyi-inventory/src/main/resources/mapper/inventory/MaterialsMapper.xml
+2
-2
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrderItemsMapper.xml
+40
-10
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrderLogMapper.xml
+15
-20
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrdersMapper.xml
+25
-23
没有找到文件。
ruoyi-admin-vue/src/api/inventory/locations.js
View file @
4551012a
...
...
@@ -52,3 +52,10 @@ export function listLocationsForSelector(query) {
params
:
query
})
}
export
function
getlocationsdicts
()
{
return
request
({
url
:
'/inventory/owners/getMapList'
,
method
:
'get'
})
}
\ No newline at end of file
ruoyi-admin-vue/src/api/inventory/materials.js
View file @
4551012a
...
...
@@ -42,3 +42,10 @@ export function delMaterials(id) {
method
:
'delete'
})
}
export
function
getMaterialsdicts
()
{
return
request
({
url
:
'/inventory/materials/getMapList'
,
method
:
'get'
})
}
ruoyi-admin-vue/src/api/inventory/owners.js
View file @
4551012a
...
...
@@ -42,3 +42,9 @@ export function delOwners(id) {
method
:
'delete'
})
}
export
function
getOwnerdicts
()
{
return
request
({
url
:
'/inventory/owners/getMapList'
,
method
:
'get'
})
}
ruoyi-admin-vue/src/api/inventory/warehouses.js
View file @
4551012a
...
...
@@ -51,3 +51,9 @@ export function listWarehousesForSelector(query) {
params
:
query
})
}
export
function
getMapList
()
{
return
request
({
url
:
'/inventory/warehouses/getMapList'
,
method
:
'get'
})
}
ruoyi-admin-vue/src/components/materialsSeletor copy.vue
0 → 100644
View file @
4551012a
<
template
>
<div
class=
"material-selector-container"
style=
"overflow: hidden;"
>
<splitpanes
class=
"default-theme"
>
<!-- 左侧分类树 -->
<pane
size=
"16"
style=
"overflow: auto;"
>
<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=
"handleTreeClick"
>
<template
#
node-content=
"
{ node, data }">
<span
class=
"custom-tree-node"
>
{{
node
.
label
}}
</span>
</
template
>
</TreeComponent>
</pane>
<!-- 右侧物料列表 -->
<pane
size=
"84"
style=
"overflow: auto;"
>
<div
style=
"padding: 10px; display: flex; flex-direction: column;"
>
<!-- 查询表单 -->
<el-form
:model=
"queryParams"
ref=
"queryForm"
size=
"small"
:inline=
"true"
label-width=
"88px"
>
<el-form-item
label=
"SAP物料号"
prop=
"sapNo"
>
<el-input
v-model=
"queryParams.sapNo"
placeholder=
"请输入SAP物料号"
clearable
@
keyup
.
enter
.
native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"物料名称"
prop=
"materialName"
>
<el-input
v-model=
"queryParams.materialName"
placeholder=
"请输入物料名称"
clearable
@
keyup
.
enter
.
native=
"handleQuery"
/>
</el-form-item>
<el-form-item
label=
"物料分类"
prop=
"categoryNameInput"
>
<el-input
v-model=
"queryParams.categoryNameInput"
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-table
ref=
"materialTable"
v-loading=
"loading"
:data=
"materialsList"
@
selection-change=
"handleSelectionChange"
:scroll-x=
"true"
:row-key=
"row => row.id"
@
row-click=
"handleRowClick"
:select-on-indeterminate=
"false"
@
select=
"handleTableSelect"
>
<!-- 修复单选/多选列:单选模式下不限制selectable,通过事件控制唯一选中 -->
<el-table-column
type=
"selection"
width=
"55"
align=
"center"
/>
<el-table-column
type=
"index"
label=
"序号"
align=
"center"
/>
<el-table-column
label=
"SAP物料号"
align=
"center"
prop=
"sapNo"
/>
<el-table-column
label=
"物料名称"
align=
"center"
prop=
"materialName"
width=
"150"
/>
<el-table-column
label=
"TS Code"
align=
"center"
prop=
"tsCode"
/>
<el-table-column
label=
"物料分类"
align=
"center"
prop=
"categoryCode"
>
<
template
slot-scope=
"scope"
>
{{
scope
.
row
.
displayCategory
||
categoryMap
[
scope
.
row
.
categoryCode
]
||
scope
.
row
.
categoryCode
||
'-'
}}
</
template
>
</el-table-column>
<el-table-column
label=
"规格型号"
align=
"center"
prop=
"specification"
/>
<el-table-column
label=
"计量单位"
align=
"center"
prop=
"materialUnit"
/>
<el-table-column
label=
"是否批次管理"
align=
"center"
prop=
"isBatchManaged"
>
<
template
slot-scope=
"scope"
>
<el-tag
:type=
"scope.row.isBatchManaged === 1 ? 'success' : 'info'"
size=
"mini"
>
{{
scope
.
row
.
isBatchManaged
===
1
?
'是'
:
'否'
}}
</el-tag>
</
template
>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination
v-show=
"total>0"
:total=
"total"
:page
.
sync=
"queryParams.pageNum"
:limit
.
sync=
"queryParams.pageSize"
@
pagination=
"getList"
/>
</div>
</pane>
</splitpanes>
</div>
</template>
<
script
>
import
{
listMaterials
}
from
"@/api/inventory/materials"
import
{
listMaterials_category
}
from
"@/api/inventory/materials_category"
import
TreeComponent
from
'@/views/inventory/materials_category/treeComponent.vue'
import
{
Splitpanes
,
Pane
}
from
'splitpanes'
import
'splitpanes/dist/splitpanes.css'
export
default
{
name
:
"MaterialSelector"
,
components
:
{
TreeComponent
,
Splitpanes
,
Pane
},
props
:
{
// 支持传入默认选中的物料ID(单选传单个ID,多选传数组)
value
:
{
type
:
[
Array
,
Number
,
String
],
default
:
()
=>
[]
},
// 是否允许多选
multiple
:
{
type
:
Boolean
,
default
:
true
},
// 默认选中的分类编码
defaultCategoryCodes
:
{
type
:
Array
,
default
:
()
=>
[]
}
},
data
()
{
return
{
// 分类树相关
categoryTreeData
:
[],
treeProps
:
{
children
:
'children'
,
label
:
'label'
,
value
:
'sid'
},
nodeKey
:
'sid'
,
loadingTree
:
false
,
categoryMap
:
{},
// 分类编码->分类名称
categoryNameToCodeMap
:
{},
// 分类名称->分类编码
categoryCodeToSidMap
:
{},
// 分类编码->树节点sid
currentNodeId
:
null
,
// 查询参数
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
sapNo
:
null
,
materialName
:
null
,
tsCode
:
null
,
categoryCode
:
null
,
categoryNameInput
:
null
,
specification
:
null
,
},
// 物料列表相关
materialsList
:
[],
total
:
0
,
loading
:
false
,
selectedRows
:
[],
// 选中的物料行数据
singleSelectedId
:
null
,
// 单选模式下的选中ID
isSelecting
:
false
// 防止选择事件重复触发的锁
}
},
watch
:
{
// 监听外部传入的选中值变化
value
:
{
immediate
:
true
,
deep
:
true
,
handler
(
val
)
{
// 防止加载中或正在选择时触发,避免锁定
if
(
this
.
loading
||
this
.
isSelecting
)
return
if
(
!
val
||
(
Array
.
isArray
(
val
)
&&
!
val
.
length
))
{
this
.
clearSelection
()
return
}
this
.
$nextTick
(()
=>
{
if
(
!
this
.
$refs
.
materialTable
||
!
this
.
materialsList
.
length
)
return
// 统一处理值格式:单选转单个ID,多选转数组
const
targetIds
=
this
.
multiple
?
Array
.
isArray
(
val
)
?
val
.
map
(
id
=>
Number
(
id
))
:
[
Number
(
val
)]
:
[
Array
.
isArray
(
val
)
?
Number
(
val
[
0
])
:
Number
(
val
)]
this
.
isSelecting
=
true
// 加锁,防止重复触发
try
{
// 清空原有选择
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
this
.
multiple
)
{
// 多选模式:选中所有匹配的行
this
.
materialsList
.
forEach
(
row
=>
{
if
(
targetIds
.
includes
(
Number
(
row
.
id
)))
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
}
})
}
else
{
// 单选模式:只选中第一个匹配的行
this
.
singleSelectedId
=
targetIds
[
0
]
||
null
const
targetRow
=
this
.
materialsList
.
find
(
row
=>
Number
(
row
.
id
)
===
this
.
singleSelectedId
)
if
(
targetRow
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
targetRow
,
true
)
}
}
}
finally
{
this
.
isSelecting
=
false
// 解锁
}
})
}
},
// 监听多选状态切换:彻底重置选择状态,避免锁定
multiple
:
{
immediate
:
true
,
handler
(
val
)
{
if
(
this
.
$refs
.
materialTable
)
{
this
.
isSelecting
=
true
try
{
// 清空所有选择状态
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
selectedRows
=
[]
this
.
singleSelectedId
=
null
// 重新初始化选中状态
this
.
$nextTick
(()
=>
{
this
.
$watchers
.
find
(
w
=>
w
.
expression
===
'value'
).
handler
(
this
.
value
)
})
}
finally
{
this
.
isSelecting
=
false
}
}
}
},
// 监听默认分类编码变化
defaultCategoryCodes
:
{
immediate
:
true
,
handler
(
val
)
{
if
(
val
&&
val
.
length
&&
this
.
categoryTreeData
.
length
)
{
this
.
$nextTick
(()
=>
{
this
.
selectCategoryNodes
(
val
)
})
}
}
}
},
async
created
()
{
// 并行加载分类数据和分类树
await
Promise
.
all
([
this
.
getCategoryList
(),
this
.
getCategoryTreeData
()
])
// 加载物料列表
this
.
getList
()
},
methods
:
{
/**
* 获取分类列表,构建编码-名称映射
*/
async
getCategoryList
()
{
try
{
const
response
=
await
listMaterials_category
({
pageNum
:
1
,
pageSize
:
1000
})
if
(
response
.
rows
&&
response
.
rows
.
length
>
0
)
{
this
.
categoryMap
=
{}
this
.
categoryNameToCodeMap
=
{}
response
.
rows
.
forEach
(
item
=>
{
// 只处理启用的分类
if
(
item
.
isUsed
!==
0
&&
item
.
isUsed
!==
'0'
)
{
const
code
=
item
.
categoryCode
this
.
categoryMap
[
code
]
=
item
.
categoryName
// 构建分类名称到编码的映射(处理同名分类)
if
(
!
this
.
categoryNameToCodeMap
[
item
.
categoryName
])
{
this
.
categoryNameToCodeMap
[
item
.
categoryName
]
=
code
}
else
if
(
!
Array
.
isArray
(
this
.
categoryNameToCodeMap
[
item
.
categoryName
]))
{
this
.
categoryNameToCodeMap
[
item
.
categoryName
]
=
[
this
.
categoryNameToCodeMap
[
item
.
categoryName
],
code
]
}
else
{
this
.
categoryNameToCodeMap
[
item
.
categoryName
].
push
(
code
)
}
}
})
}
}
catch
(
error
)
{
console
.
error
(
'获取分类列表失败:'
,
error
)
}
},
/**
* 获取分类树数据
*/
async
getCategoryTreeData
()
{
this
.
loadingTree
=
true
try
{
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
)
// 构建分类编码到树节点sid的映射
this
.
buildCategoryCodeToSidMap
(
this
.
categoryTreeData
)
}
}
catch
(
error
)
{
console
.
error
(
'获取分类树数据失败:'
,
error
)
}
finally
{
this
.
loadingTree
=
false
}
},
/**
* 构建分类树形结构
*/
buildTreeData
(
list
,
parentId
=
null
)
{
return
list
.
filter
(
item
=>
parentId
===
null
?
(
!
item
.
parentId
||
item
.
parentId
===
0
||
item
.
parentId
===
'0'
)
:
Number
(
item
.
parentId
)
===
Number
(
parentId
)
)
.
map
(
item
=>
({
...
item
,
sid
:
String
(
item
.
id
),
label
:
item
.
categoryName
,
children
:
this
.
buildTreeData
(
list
,
item
.
id
).
length
?
this
.
buildTreeData
(
list
,
item
.
id
)
:
undefined
}))
},
/**
* 构建分类编码到树节点sid的映射
*/
buildCategoryCodeToSidMap
(
treeData
)
{
treeData
.
forEach
(
node
=>
{
if
(
node
.
categoryCode
)
{
this
.
categoryCodeToSidMap
[
node
.
categoryCode
]
=
node
.
sid
// 兼容格式化的编码(如带横线的)
const
rawCode
=
node
.
categoryCode
.
replace
(
/-/g
,
''
)
if
(
rawCode
!==
node
.
categoryCode
)
{
this
.
categoryCodeToSidMap
[
rawCode
]
=
node
.
sid
}
}
if
(
node
.
children
&&
node
.
children
.
length
)
{
this
.
buildCategoryCodeToSidMap
(
node
.
children
)
}
})
},
/**
* 根据分类编码选中树节点
*/
selectCategoryNodes
(
categoryCodes
)
{
if
(
!
this
.
$refs
.
treeComponent
||
!
this
.
$refs
.
treeComponent
.
$refs
.
tree
)
return
const
tree
=
this
.
$refs
.
treeComponent
.
$refs
.
tree
categoryCodes
.
forEach
(
code
=>
{
const
rawCode
=
code
.
replace
(
/-/g
,
''
)
const
sid
=
this
.
categoryCodeToSidMap
[
rawCode
]
||
this
.
categoryCodeToSidMap
[
code
]
if
(
sid
)
{
tree
.
setCurrentKey
(
sid
)
this
.
currentNodeId
=
sid
// 展开节点
const
node
=
tree
.
getNode
(
sid
)
if
(
node
)
{
tree
.
expandNode
(
node
)
}
}
})
},
/**
* 分类树节点点击事件
*/
handleTreeClick
(
data
)
{
this
.
currentNodeId
=
data
.
sid
this
.
queryParams
.
categoryCode
=
data
.
categoryCode
this
.
queryParams
.
categoryNameInput
=
null
this
.
queryParams
.
pageNum
=
1
this
.
getList
()
},
/**
* 获取物料列表数据
*/
getList
()
{
this
.
loading
=
true
listMaterials
(
this
.
queryParams
).
then
(
response
=>
{
// 过滤启用的物料并处理分类名称显示
this
.
materialsList
=
(
response
.
rows
||
[]).
filter
(
item
=>
item
.
isUsed
!==
0
&&
item
.
isUsed
!==
'0'
).
map
(
item
=>
({
...
item
,
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
${
item
.
categoryCode
}
(未匹配分类)`
}))
this
.
total
=
response
.
total
||
0
// 列表加载完成后重新同步选中状态(延迟执行,避免DOM未更新)
setTimeout
(()
=>
{
this
.
$watchers
.
find
(
w
=>
w
.
expression
===
'value'
).
handler
(
this
.
value
)
},
100
)
}).
catch
(
error
=>
{
console
.
error
(
'获取物料列表失败:'
,
error
)
this
.
materialsList
=
[]
this
.
total
=
0
}).
finally
(()
=>
{
this
.
loading
=
false
})
},
/**
* 搜索按钮点击事件
*/
handleQuery
()
{
// 根据分类名称匹配分类编码
const
inputName
=
this
.
queryParams
.
categoryNameInput
if
(
inputName
)
{
const
matchedCode
=
this
.
categoryNameToCodeMap
[
inputName
]
if
(
matchedCode
)
{
this
.
queryParams
.
categoryCode
=
Array
.
isArray
(
matchedCode
)
?
matchedCode
[
0
]
:
matchedCode
}
else
{
// 模糊匹配分类名称
const
matchedCodes
=
Object
.
entries
(
this
.
categoryMap
)
.
filter
(([
code
,
name
])
=>
name
.
includes
(
inputName
))
.
map
(([
code
])
=>
code
)
if
(
matchedCodes
.
length
>
0
)
{
this
.
queryParams
.
categoryCode
=
matchedCodes
[
0
]
}
}
}
this
.
queryParams
.
pageNum
=
1
this
.
getList
()
},
/**
* 重置查询条件
*/
resetQuery
()
{
this
.
queryParams
=
{
pageNum
:
1
,
pageSize
:
10
,
sapNo
:
null
,
materialName
:
null
,
tsCode
:
null
,
categoryCode
:
null
,
categoryNameInput
:
null
,
specification
:
null
,
}
this
.
currentNodeId
=
null
// 清空树节点选中状态
if
(
this
.
$refs
.
treeComponent
&&
this
.
$refs
.
treeComponent
.
$refs
.
tree
)
{
this
.
$refs
.
treeComponent
.
$refs
.
tree
.
setCurrentKey
(
null
)
}
this
.
getList
()
},
/**
* 表格选择变化事件(批量选择)
*/
handleSelectionChange
(
selection
)
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
this
.
isSelecting
=
true
try
{
// 单选模式处理:确保只有一个选中项
if
(
!
this
.
multiple
)
{
if
(
selection
.
length
>
1
)
{
// 移除多余选中项,只保留最后一个
const
lastRow
=
selection
.
pop
()
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
$refs
.
materialTable
.
toggleRowSelection
(
lastRow
,
true
)
this
.
selectedRows
=
[
lastRow
]
this
.
singleSelectedId
=
Number
(
lastRow
.
id
)
}
else
{
this
.
selectedRows
=
selection
this
.
singleSelectedId
=
selection
.
length
>
0
?
Number
(
selection
[
0
].
id
)
:
null
}
}
else
{
// 多选模式
this
.
selectedRows
=
selection
}
// 组装选中数据并触发事件
const
selectedIds
=
this
.
selectedRows
.
map
(
row
=>
Number
(
row
.
id
))
const
selectedData
=
this
.
selectedRows
.
map
(
item
=>
({
id
:
Number
(
item
.
id
),
sapNo
:
item
.
sapNo
,
materialName
:
item
.
materialName
,
categoryCode
:
item
.
categoryCode
,
specification
:
item
.
specification
,
materialUnit
:
item
.
materialUnit
,
isBatchManaged
:
item
.
isBatchManaged
}))
// 触发事件:input用于v-model绑定,change返回详细数据
if
(
this
.
multiple
)
{
this
.
$emit
(
'input'
,
selectedIds
)
this
.
$emit
(
'change'
,
selectedData
)
}
else
{
const
singleId
=
selectedIds
.
length
>
0
?
selectedIds
[
0
]
:
''
const
singleData
=
selectedData
.
length
>
0
?
selectedData
[
0
]
:
null
this
.
$emit
(
'input'
,
singleId
)
this
.
$emit
(
'change'
,
singleData
)
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 表格单个选择事件(点击选择框)
*/
handleTableSelect
(
selection
,
row
)
{
if
(
this
.
isSelecting
||
this
.
multiple
)
return
// 单选模式:点击选择框时,清空其他选中项
this
.
isSelecting
=
true
try
{
const
isSelected
=
selection
.
includes
(
row
)
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
isSelected
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
this
.
singleSelectedId
=
Number
(
row
.
id
)
this
.
selectedRows
=
[
row
]
this
.
$emit
(
'input'
,
Number
(
row
.
id
))
this
.
$emit
(
'change'
,
row
)
}
else
{
this
.
singleSelectedId
=
null
this
.
selectedRows
=
[]
this
.
$emit
(
'input'
,
''
)
this
.
$emit
(
'change'
,
null
)
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 表格行点击事件
*/
handleRowClick
(
row
)
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
this
.
isSelecting
=
true
try
{
if
(
!
this
.
multiple
)
{
// 单选模式:点击行切换选中状态
const
isCurrentlySelected
=
Number
(
this
.
singleSelectedId
)
===
Number
(
row
.
id
)
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
!
isCurrentlySelected
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
this
.
singleSelectedId
=
Number
(
row
.
id
)
this
.
selectedRows
=
[
row
]
this
.
$emit
(
'input'
,
Number
(
row
.
id
))
this
.
$emit
(
'change'
,
row
)
}
else
{
this
.
singleSelectedId
=
null
this
.
selectedRows
=
[]
this
.
$emit
(
'input'
,
''
)
this
.
$emit
(
'change'
,
null
)
}
}
else
{
// 多选模式:点击行切换选中状态
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
)
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 清空选中状态(外部调用)
*/
clearSelection
()
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
this
.
isSelecting
=
true
try
{
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
selectedRows
=
[]
this
.
singleSelectedId
=
null
this
.
$emit
(
'input'
,
this
.
multiple
?
[]
:
''
)
this
.
$emit
(
'change'
,
this
.
multiple
?
[]
:
null
)
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 获取选中的物料详情(外部调用)
*/
getSelectedMaterials
()
{
return
this
.
multiple
?
[...
this
.
selectedRows
]
:
(
this
.
selectedRows
[
0
]
||
null
)
},
/**
* 设置单选选中项(外部调用)
*/
setSingleSelection
(
materialId
)
{
if
(
this
.
isSelecting
||
this
.
multiple
)
return
this
.
isSelecting
=
true
try
{
const
targetId
=
Number
(
materialId
)
this
.
singleSelectedId
=
targetId
this
.
$nextTick
(()
=>
{
this
.
$refs
.
materialTable
.
clearSelection
()
const
targetRow
=
this
.
materialsList
.
find
(
row
=>
Number
(
row
.
id
)
===
targetId
)
if
(
targetRow
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
targetRow
,
true
)
this
.
selectedRows
=
[
targetRow
]
this
.
$emit
(
'input'
,
targetId
)
this
.
$emit
(
'change'
,
targetRow
)
}
})
}
finally
{
this
.
isSelecting
=
false
}
}
}
}
</
script
>
<
style
scoped
>
.material-selector-container
{
height
:
100%
;
min-height
:
500px
;
}
.custom-tree-node
{
font-size
:
14px
;
}
/* 优化表格选择框样式,避免点击区域冲突 */
/
deep
/
.el-table
.el-table__header
.cell
{
text-align
:
center
;
}
/
deep
/
.el-table--enable-row-hover
.el-table__body
tr
:hover
>
td
{
background-color
:
#f5f7fa
;
}
/* 确保选择框可点击,无遮挡 */
/
deep
/
.el-table__fixed-right
,
/
deep
/
.el-table__fixed-left
{
pointer-events
:
auto
!important
;
}
</
style
>
\ No newline at end of file
ruoyi-admin-vue/src/components/materialsSeletor.vue
View file @
4551012a
...
...
@@ -56,19 +56,18 @@
</el-form-item>
</el-form>
<!-- 物料表格
:修复选择列逻辑,避免锁定
-->
<!-- 物料表格 -->
<el-table
ref=
"materialTable"
v-loading=
"loading"
:data=
"materialsList"
@
selection-change=
"handleSelectionChange"
:scroll-x=
"true"
:row-key=
"row => row.
id"
:row-key=
"row => row.
sapNo"
@
row-click=
"handleRowClick"
:select-on-indeterminate=
"false"
@
select=
"handleTableSelect"
>
<!-- 修复单选/多选列:单选模式下不限制selectable,通过事件控制唯一选中 -->
<el-table-column
type=
"selection"
width=
"55"
...
...
@@ -119,35 +118,34 @@ export default {
name
:
"MaterialSelector"
,
components
:
{
TreeComponent
,
Splitpanes
,
Pane
},
props
:
{
// 支持传入默认选中的物料ID(单选传单个ID,多选传数组)
value
:
{
type
:
[
Array
,
Number
,
String
],
type
:
[
Array
,
String
],
default
:
()
=>
[]
},
// 是否允许多选
multiple
:
{
type
:
Boolean
,
default
:
true
},
// 默认选中的分类编码
defaultCategoryCodes
:
{
type
:
Array
,
default
:
()
=>
[]
},
// 新增:父页面传递的反显参数(兼容原逻辑)
selectedMaterialCodes
:
{
type
:
Array
,
default
:
()
=>
[]
}
},
data
()
{
return
{
// 分类树相关
categoryTreeData
:
[],
treeProps
:
{
children
:
'children'
,
label
:
'label'
,
value
:
'sid'
},
nodeKey
:
'sid'
,
loadingTree
:
false
,
categoryMap
:
{},
// 分类编码->分类名称
categoryNameToCodeMap
:
{},
// 分类名称->分类编码
categoryCodeToSidMap
:
{},
// 分类编码->树节点sid
categoryMap
:
{},
categoryNameToCodeMap
:
{},
categoryCodeToSidMap
:
{},
currentNodeId
:
null
,
// 查询参数
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
...
...
@@ -158,126 +156,102 @@ export default {
categoryNameInput
:
null
,
specification
:
null
,
},
// 物料列表相关
materialsList
:
[],
total
:
0
,
loading
:
false
,
selectedRows
:
[],
// 选中的物料行数据
singleSelected
Id
:
null
,
// 单选模式下的选中ID
isSelecting
:
false
// 防止选择事件重复触发的锁
selectedRows
:
[],
singleSelected
SapNo
:
null
,
isSelecting
:
false
}
},
watch
:
{
//
监听外部传入的选中值变化
//
核心修复1:同时监听value和selectedMaterialCodes,兼容两种传参方式
value
:
{
immediate
:
true
,
deep
:
true
,
handler
(
val
)
{
// 防止加载中或正在选择时触发,避免锁定
if
(
this
.
loading
||
this
.
isSelecting
)
return
if
(
!
val
||
(
Array
.
isArray
(
val
)
&&
!
val
.
length
))
{
this
.
clearSelection
()
return
}
this
.
$nextTick
(()
=>
{
if
(
!
this
.
$refs
.
materialTable
||
!
this
.
materialsList
.
length
)
return
// 统一处理值格式:单选转单个ID,多选转数组
const
targetIds
=
this
.
multiple
?
Array
.
isArray
(
val
)
?
val
.
map
(
id
=>
Number
(
id
))
:
[
Number
(
val
)]
:
[
Array
.
isArray
(
val
)
?
Number
(
val
[
0
])
:
Number
(
val
)]
this
.
isSelecting
=
true
// 加锁,防止重复触发
try
{
// 清空原有选择
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
this
.
multiple
)
{
// 多选模式:选中所有匹配的行
this
.
materialsList
.
forEach
(
row
=>
{
if
(
targetIds
.
includes
(
Number
(
row
.
id
)))
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
this
.
handleValueChange
(
val
)
}
})
}
else
{
// 单选模式:只选中第一个匹配的行
this
.
singleSelectedId
=
targetIds
[
0
]
||
null
const
targetRow
=
this
.
materialsList
.
find
(
row
=>
Number
(
row
.
id
)
===
this
.
singleSelectedId
)
if
(
targetRow
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
targetRow
,
true
)
}
}
}
finally
{
this
.
isSelecting
=
false
// 解锁
},
selectedMaterialCodes
:
{
immediate
:
true
,
deep
:
true
,
handler
(
val
)
{
// 优先使用selectedMaterialCodes,兼容父页面旧传参
if
(
val
&&
val
.
length
)
{
this
.
handleValueChange
(
val
)
}
})
}
},
// 监听多选状态切换:彻底重置选择状态,避免锁定
multiple
:
{
immediate
:
true
,
handler
(
val
)
{
if
(
this
.
$refs
.
materialTable
)
{
this
.
isSelecting
=
true
try
{
// 清空所有选择状态
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
selectedRows
=
[]
this
.
singleSelectedId
=
null
// 重新初始化选中状态
this
.
$nextTick
(()
=>
{
this
.
$watchers
.
find
(
w
=>
w
.
expression
===
'value'
).
handler
(
this
.
value
)
})
this
.
singleSelectedSapNo
=
null
this
.
$nextTick
(()
=>
this
.
handleValueSync
())
}
finally
{
this
.
isSelecting
=
false
}
}
}
},
// 监听默认分类编码变化
defaultCategoryCodes
:
{
immediate
:
true
,
handler
(
val
)
{
if
(
val
&&
val
.
length
&&
this
.
categoryTreeData
.
length
)
{
this
.
$nextTick
(()
=>
{
this
.
selectCategoryNodes
(
val
)
})
this
.
$nextTick
(()
=>
this
.
selectCategoryNodes
(
val
))
}
}
}
},
async
created
()
{
// 并行加载分类数据和分类树
await
Promise
.
all
([
this
.
getCategoryList
(),
this
.
getCategoryTreeData
()
])
// 加载物料列表
await
Promise
.
all
([
this
.
getCategoryList
(),
this
.
getCategoryTreeData
()])
this
.
getList
()
},
methods
:
{
/**
* 获取分类列表,构建编码-名称映射
*/
// 新增:统一处理值变更
handleValueChange
(
val
)
{
if
(
this
.
isSelecting
)
return
// 空值直接清空选中
if
(
!
val
||
(
Array
.
isArray
(
val
)
&&
!
val
.
length
))
{
this
.
clearSelection
()
return
}
// 有值时:先清空筛选,保证列表全量
if
(
this
.
currentNodeId
||
this
.
queryParams
.
categoryCode
)
{
this
.
currentNodeId
=
null
this
.
queryParams
.
categoryCode
=
null
this
.
getList
()
return
}
// 列表未加载完成则等待,已加载则直接反显
if
(
this
.
loading
||
!
this
.
materialsList
.
length
)
{
// 延长等待时间,确保列表加载完成
const
timer
=
setTimeout
(()
=>
{
this
.
handleValueSync
()
clearTimeout
(
timer
)
},
500
)
}
else
{
this
.
handleValueSync
()
}
},
async
getCategoryList
()
{
try
{
const
response
=
await
listMaterials_category
({
pageNum
:
1
,
pageSize
:
1000
})
if
(
response
.
rows
&&
response
.
rows
.
length
>
0
)
{
this
.
categoryMap
=
{}
this
.
categoryNameToCodeMap
=
{}
response
.
rows
.
forEach
(
item
=>
{
// 只处理启用的分类
if
(
item
.
isUsed
!==
0
&&
item
.
isUsed
!==
'0'
)
{
const
code
=
item
.
categoryCode
this
.
categoryMap
[
code
]
=
item
.
categoryName
// 构建分类名称到编码的映射(处理同名分类)
if
(
!
this
.
categoryNameToCodeMap
[
item
.
categoryName
])
{
this
.
categoryNameToCodeMap
[
item
.
categoryName
]
=
code
}
else
if
(
!
Array
.
isArray
(
this
.
categoryNameToCodeMap
[
item
.
categoryName
]))
{
...
...
@@ -292,20 +266,13 @@ export default {
console
.
error
(
'获取分类列表失败:'
,
error
)
}
},
/**
* 获取分类树数据
*/
async
getCategoryTreeData
()
{
this
.
loadingTree
=
true
try
{
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
)
// 构建分类编码到树节点sid的映射
this
.
buildCategoryCodeToSidMap
(
this
.
categoryTreeData
)
}
}
catch
(
error
)
{
...
...
@@ -314,10 +281,6 @@ export default {
this
.
loadingTree
=
false
}
},
/**
* 构建分类树形结构
*/
buildTreeData
(
list
,
parentId
=
null
)
{
return
list
.
filter
(
item
=>
parentId
===
null
...
...
@@ -333,15 +296,10 @@ export default {
:
undefined
}))
},
/**
* 构建分类编码到树节点sid的映射
*/
buildCategoryCodeToSidMap
(
treeData
)
{
treeData
.
forEach
(
node
=>
{
if
(
node
.
categoryCode
)
{
this
.
categoryCodeToSidMap
[
node
.
categoryCode
]
=
node
.
sid
// 兼容格式化的编码(如带横线的)
const
rawCode
=
node
.
categoryCode
.
replace
(
/-/g
,
''
)
if
(
rawCode
!==
node
.
categoryCode
)
{
this
.
categoryCodeToSidMap
[
rawCode
]
=
node
.
sid
...
...
@@ -352,13 +310,8 @@ export default {
}
})
},
/**
* 根据分类编码选中树节点
*/
selectCategoryNodes
(
categoryCodes
)
{
if
(
!
this
.
$refs
.
treeComponent
||
!
this
.
$refs
.
treeComponent
.
$refs
.
tree
)
return
const
tree
=
this
.
$refs
.
treeComponent
.
$refs
.
tree
categoryCodes
.
forEach
(
code
=>
{
const
rawCode
=
code
.
replace
(
/-/g
,
''
)
...
...
@@ -366,18 +319,11 @@ export default {
if
(
sid
)
{
tree
.
setCurrentKey
(
sid
)
this
.
currentNodeId
=
sid
// 展开节点
const
node
=
tree
.
getNode
(
sid
)
if
(
node
)
{
tree
.
expandNode
(
node
)
}
if
(
node
)
tree
.
expandNode
(
node
)
}
})
},
/**
* 分类树节点点击事件
*/
handleTreeClick
(
data
)
{
this
.
currentNodeId
=
data
.
sid
this
.
queryParams
.
categoryCode
=
data
.
categoryCode
...
...
@@ -385,24 +331,20 @@ export default {
this
.
queryParams
.
pageNum
=
1
this
.
getList
()
},
/**
* 获取物料列表数据
*/
getList
()
{
this
.
loading
=
true
listMaterials
(
this
.
queryParams
).
then
(
response
=>
{
// 过滤启用的物料并处理分类名称显示
this
.
materialsList
=
(
response
.
rows
||
[]).
filter
(
item
=>
item
.
isUsed
!==
0
&&
item
.
isUsed
!==
'0'
).
map
(
item
=>
({
...
item
,
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
${
item
.
categoryCode
}
(未匹配分类)`
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
${
item
.
categoryCode
}
(未匹配分类)`
,
// 核心修复2:存储SAP号的大写和原始值,用于反显匹配
sapNoUpper
:
item
.
sapNo
?
item
.
sapNo
.
trim
().
toUpperCase
()
:
''
}))
this
.
total
=
response
.
total
||
0
// 列表加载完成后重新同步选中状态(延迟执行,避免DOM未更新)
setTimeout
(()
=>
{
this
.
$watchers
.
find
(
w
=>
w
.
expression
===
'value'
).
handler
(
this
.
value
)
},
100
)
// 确保列表渲染完成后再反显
this
.
$nextTick
(()
=>
{
setTimeout
(()
=>
this
.
handleValueSync
(),
300
)
})
}).
catch
(
error
=>
{
console
.
error
(
'获取物料列表失败:'
,
error
)
this
.
materialsList
=
[]
...
...
@@ -411,19 +353,13 @@ export default {
this
.
loading
=
false
})
},
/**
* 搜索按钮点击事件
*/
handleQuery
()
{
// 根据分类名称匹配分类编码
const
inputName
=
this
.
queryParams
.
categoryNameInput
if
(
inputName
)
{
const
matchedCode
=
this
.
categoryNameToCodeMap
[
inputName
]
if
(
matchedCode
)
{
this
.
queryParams
.
categoryCode
=
Array
.
isArray
(
matchedCode
)
?
matchedCode
[
0
]
:
matchedCode
}
else
{
// 模糊匹配分类名称
const
matchedCodes
=
Object
.
entries
(
this
.
categoryMap
)
.
filter
(([
code
,
name
])
=>
name
.
includes
(
inputName
))
.
map
(([
code
])
=>
code
)
...
...
@@ -435,10 +371,7 @@ export default {
this
.
queryParams
.
pageNum
=
1
this
.
getList
()
},
/**
* 重置查询条件
*/
// 核心修复:重置所有状态(对外暴露)
resetQuery
()
{
this
.
queryParams
=
{
pageNum
:
1
,
...
...
@@ -451,131 +384,132 @@ export default {
specification
:
null
,
}
this
.
currentNodeId
=
null
// 清空树节点选中状态
if
(
this
.
$refs
.
treeComponent
&&
this
.
$refs
.
treeComponent
.
$refs
.
tree
)
{
this
.
$refs
.
treeComponent
.
$refs
.
tree
.
setCurrentKey
(
null
)
}
this
.
clearSelection
()
this
.
getList
()
},
/**
* 表格选择变化事件(批量选择)
*/
handleSelectionChange
(
selection
)
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
this
.
isSelecting
=
true
try
{
// 单选模式处理:确保只有一个选中项
if
(
!
this
.
multiple
)
{
if
(
selection
.
length
>
1
)
{
// 移除多余选中项,只保留最后一个
const
lastRow
=
selection
.
pop
()
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
$refs
.
materialTable
.
toggleRowSelection
(
lastRow
,
true
)
this
.
selectedRows
=
[
lastRow
]
this
.
singleSelected
Id
=
Number
(
lastRow
.
id
)
this
.
singleSelected
SapNo
=
lastRow
.
sapNo
}
else
{
this
.
selectedRows
=
selection
this
.
singleSelected
Id
=
selection
.
length
>
0
?
Number
(
selection
[
0
].
id
)
:
null
this
.
singleSelected
SapNo
=
selection
.
length
>
0
?
selection
[
0
].
sapNo
:
null
}
}
else
{
// 多选模式
this
.
selectedRows
=
selection
}
// 组装选中数据并触发事件
const
selectedIds
=
this
.
selectedRows
.
map
(
row
=>
Number
(
row
.
id
))
const
selectedSapNos
=
this
.
selectedRows
.
map
(
row
=>
row
.
sapNo
)
const
selectedData
=
this
.
selectedRows
.
map
(
item
=>
({
id
:
Number
(
item
.
id
),
sapNo
:
item
.
sapNo
,
materialName
:
item
.
materialName
,
categoryCode
:
item
.
categoryCode
,
specification
:
item
.
specification
,
materialUnit
:
item
.
materialUnit
,
isBatchManaged
:
item
.
isBatchManaged
categoryId
:
item
.
categoryCode
||
''
}))
// 触发事件:input用于v-model绑定,change返回详细数据
// 核心修复3:新增selection-change事件,兼容父页面旧逻辑
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
selectedSapNos
,
names
:
selectedData
.
map
(
item
=>
item
.
materialName
),
categoryIds
:
selectedData
.
map
(
item
=>
item
.
categoryId
)
})
if
(
this
.
multiple
)
{
this
.
$emit
(
'input'
,
selected
Id
s
)
this
.
$emit
(
'input'
,
selected
SapNo
s
)
this
.
$emit
(
'change'
,
selectedData
)
}
else
{
const
single
Id
=
selectedIds
.
length
>
0
?
selectedId
s
[
0
]
:
''
const
single
SapNo
=
selectedSapNos
.
length
>
0
?
selectedSapNo
s
[
0
]
:
''
const
singleData
=
selectedData
.
length
>
0
?
selectedData
[
0
]
:
null
this
.
$emit
(
'input'
,
single
Id
)
this
.
$emit
(
'input'
,
single
SapNo
)
this
.
$emit
(
'change'
,
singleData
)
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 表格单个选择事件(点击选择框)
*/
handleTableSelect
(
selection
,
row
)
{
if
(
this
.
isSelecting
||
this
.
multiple
)
return
// 单选模式:点击选择框时,清空其他选中项
this
.
isSelecting
=
true
try
{
const
isSelected
=
selection
.
includes
(
row
)
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
isSelected
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
this
.
singleSelected
Id
=
Number
(
row
.
id
)
this
.
singleSelected
SapNo
=
row
.
sapNo
this
.
selectedRows
=
[
row
]
this
.
$emit
(
'input'
,
Number
(
row
.
id
))
this
.
$emit
(
'change'
,
row
)
this
.
$emit
(
'input'
,
row
.
sapNo
)
this
.
$emit
(
'change'
,
{
sapNo
:
row
.
sapNo
,
materialName
:
row
.
materialName
})
// 兼容selection-change事件
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[
row
.
sapNo
],
names
:
[
row
.
materialName
],
categoryIds
:
[
row
.
categoryCode
||
''
]
})
}
else
{
this
.
singleSelected
Id
=
null
this
.
singleSelected
SapNo
=
null
this
.
selectedRows
=
[]
this
.
$emit
(
'input'
,
''
)
this
.
$emit
(
'change'
,
null
)
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[],
names
:
[],
categoryIds
:
[]
})
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 表格行点击事件
*/
handleRowClick
(
row
)
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
this
.
isSelecting
=
true
try
{
if
(
!
this
.
multiple
)
{
// 单选模式:点击行切换选中状态
const
isCurrentlySelected
=
Number
(
this
.
singleSelectedId
)
===
Number
(
row
.
id
)
const
isCurrentlySelected
=
this
.
singleSelectedSapNo
===
row
.
sapNo
this
.
$refs
.
materialTable
.
clearSelection
()
if
(
!
isCurrentlySelected
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
this
.
singleSelected
Id
=
Number
(
row
.
id
)
this
.
singleSelected
SapNo
=
row
.
sapNo
this
.
selectedRows
=
[
row
]
this
.
$emit
(
'input'
,
Number
(
row
.
id
))
this
.
$emit
(
'change'
,
row
)
this
.
$emit
(
'input'
,
row
.
sapNo
)
this
.
$emit
(
'change'
,
{
sapNo
:
row
.
sapNo
,
materialName
:
row
.
materialName
})
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[
row
.
sapNo
],
names
:
[
row
.
materialName
],
categoryIds
:
[
row
.
categoryCode
||
''
]
})
}
else
{
this
.
singleSelected
Id
=
null
this
.
singleSelected
SapNo
=
null
this
.
selectedRows
=
[]
this
.
$emit
(
'input'
,
''
)
this
.
$emit
(
'change'
,
null
)
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[],
names
:
[],
categoryIds
:
[]
})
}
}
else
{
// 多选模式:点击行切换选中状态
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
)
}
}
finally
{
this
.
isSelecting
=
false
}
},
/**
* 清空选中状态(外部调用)
*/
// 核心修复:彻底清空选中状态并同步父页面(对外暴露)
clearSelection
()
{
if
(
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
...
...
@@ -583,39 +517,109 @@ export default {
try
{
this
.
$refs
.
materialTable
.
clearSelection
()
this
.
selectedRows
=
[]
this
.
singleSelected
Id
=
null
this
.
singleSelected
SapNo
=
null
this
.
$emit
(
'input'
,
this
.
multiple
?
[]
:
''
)
this
.
$emit
(
'change'
,
this
.
multiple
?
[]
:
null
)
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[],
names
:
[],
categoryIds
:
[]
})
}
finally
{
this
.
isSelecting
=
false
}
},
// 核心修复4:增强反显同步逻辑,兼容大小写和多页数据
handleValueSync
()
{
if
(
this
.
loading
||
this
.
isSelecting
||
!
this
.
$refs
.
materialTable
)
return
/**
* 获取选中的物料详情(外部调用)
*/
getSelectedMaterials
()
{
return
this
.
multiple
?
[...
this
.
selectedRows
]
:
(
this
.
selectedRows
[
0
]
||
null
)
// 优先使用selectedMaterialCodes,兼容父页面传参
const
val
=
this
.
selectedMaterialCodes
.
length
?
this
.
selectedMaterialCodes
:
this
.
value
if
(
!
val
||
(
Array
.
isArray
(
val
)
&&
!
val
.
length
))
{
this
.
clearSelection
()
return
}
// 统一处理值格式:转数组 + 去空 + 转大写(用于匹配)
const
targetSapNos
=
this
.
multiple
?
Array
.
isArray
(
val
)
?
val
:
[
val
]
:
[
Array
.
isArray
(
val
)
?
val
[
0
]
:
val
]
const
targetSapNosUpper
=
targetSapNos
.
map
(
code
=>
code
?
code
.
trim
().
toUpperCase
()
:
''
)
.
filter
(
code
=>
code
)
this
.
isSelecting
=
true
try
{
this
.
$refs
.
materialTable
.
clearSelection
()
// 遍历列表匹配(兼容原始值和大写值)
this
.
materialsList
.
forEach
(
row
=>
{
const
rowSapUpper
=
row
.
sapNoUpper
||
row
.
sapNo
.
trim
().
toUpperCase
()
if
(
targetSapNos
.
includes
(
row
.
sapNo
)
||
targetSapNosUpper
.
includes
(
rowSapUpper
))
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
row
,
true
)
}
})
// 更新选中行数据
this
.
selectedRows
=
this
.
materialsList
.
filter
(
row
=>
{
const
rowSapUpper
=
row
.
sapNoUpper
||
row
.
sapNo
.
trim
().
toUpperCase
()
return
targetSapNos
.
includes
(
row
.
sapNo
)
||
targetSapNosUpper
.
includes
(
rowSapUpper
)
})
this
.
singleSelectedSapNo
=
this
.
multiple
?
null
:
(
this
.
selectedRows
[
0
]?.
sapNo
||
null
)
}
finally
{
this
.
isSelecting
=
false
}
},
// 核心修复5:对外暴露反显方法,供父页面主动调用
setSelectedCodes
(
codes
)
{
if
(
this
.
isSelecting
)
return
/**
* 设置单选选中项(外部调用)
*/
setSingleSelection
(
materialId
)
{
this
.
isSelecting
=
true
try
{
// 先清空筛选,保证列表全量
this
.
currentNodeId
=
null
this
.
queryParams
.
categoryCode
=
null
// 重新加载列表后再反显
this
.
getList
().
then
(()
=>
{
this
.
$nextTick
(()
=>
{
// 赋值给selectedMaterialCodes触发反显
this
.
$props
.
selectedMaterialCodes
=
codes
this
.
handleValueSync
()
})
})
}
finally
{
this
.
isSelecting
=
false
}
},
getSelectedMaterials
()
{
if
(
this
.
multiple
)
{
return
this
.
selectedRows
.
map
(
row
=>
({
sapNo
:
row
.
sapNo
,
materialName
:
row
.
materialName
}))
}
else
{
return
this
.
selectedRows
[
0
]
?
{
sapNo
:
this
.
selectedRows
[
0
].
sapNo
,
materialName
:
this
.
selectedRows
[
0
].
materialName
}
:
null
}
},
setSingleSelection
(
sapNo
)
{
if
(
this
.
isSelecting
||
this
.
multiple
)
return
this
.
isSelecting
=
true
try
{
const
targetId
=
Number
(
materialId
)
this
.
singleSelectedId
=
targetId
this
.
singleSelectedSapNo
=
sapNo
this
.
$nextTick
(()
=>
{
this
.
$refs
.
materialTable
.
clearSelection
()
const
targetRow
=
this
.
materialsList
.
find
(
row
=>
Number
(
row
.
id
)
===
targetId
)
const
targetRow
=
this
.
materialsList
.
find
(
row
=>
{
const
rowSapUpper
=
row
.
sapNoUpper
||
row
.
sapNo
.
trim
().
toUpperCase
()
return
row
.
sapNo
===
sapNo
||
rowSapUpper
===
sapNo
.
trim
().
toUpperCase
()
})
if
(
targetRow
)
{
this
.
$refs
.
materialTable
.
toggleRowSelection
(
targetRow
,
true
)
this
.
selectedRows
=
[
targetRow
]
this
.
$emit
(
'input'
,
targetId
)
this
.
$emit
(
'change'
,
targetRow
)
this
.
$emit
(
'input'
,
sapNo
)
this
.
$emit
(
'change'
,
{
sapNo
:
targetRow
.
sapNo
,
materialName
:
targetRow
.
materialName
})
this
.
$emit
(
'selection-change'
,
{
materialCodes
:
[
targetRow
.
sapNo
],
names
:
[
targetRow
.
materialName
],
categoryIds
:
[
targetRow
.
categoryCode
||
''
]
})
}
})
}
finally
{
...
...
@@ -634,15 +638,12 @@ export default {
.custom-tree-node
{
font-size
:
14px
;
}
/* 优化表格选择框样式,避免点击区域冲突 */
/
deep
/
.el-table
.el-table__header
.cell
{
text-align
:
center
;
}
/
deep
/
.el-table--enable-row-hover
.el-table__body
tr
:hover
>
td
{
background-color
:
#f5f7fa
;
}
/* 确保选择框可点击,无遮挡 */
/
deep
/
.el-table__fixed-right
,
/
deep
/
.el-table__fixed-left
{
pointer-events
:
auto
!important
;
...
...
ruoyi-admin-vue/src/views/inventory/locations/index.vue
View file @
4551012a
...
...
@@ -192,15 +192,6 @@
</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=
"100"
/>
<el-table-column
label=
"应用状态"
align=
"center"
prop=
"isEnabled"
width=
"100"
>
<
template
slot-scope=
"scope"
>
...
...
@@ -351,7 +342,7 @@
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
label=
"允许存放物料"
prop=
"
materialCode
s"
>
<el-form-item
label=
"允许存放物料"
prop=
"
allowedCategoryId
s"
>
<div
style=
"display: flex; align-items: center; flex-direction: column; gap: 8px;"
>
<el-input
v-model=
"form.materialNames"
...
...
@@ -362,10 +353,13 @@
<el-button
type=
"primary"
size=
"small"
@
click
.
stop=
"
showMaterialSelect = true
"
@
click
.
stop=
"
openMaterialSelector
"
style=
"align-self: flex-end;"
>
选择物料
</el-button>
</div>
<div
style=
"margin-top: 8px; font-size: 12px; color: #666;"
>
已选SAP号:{{ form.allowedCategoryIds || '无' }}
</div>
</el-form-item>
</el-col>
</el-row>
...
...
@@ -412,13 +406,16 @@
append-to-body
:close-on-click-modal=
"false"
:close-on-press-escape=
"false"
@
open=
"initMaterialSelector"
>
<!-- 关键修复:v-if确保弹窗打开时才初始化组件 -->
<materialsSeletor
v-if=
"showMaterialSelect"
ref=
"materialsSeletor"
@
selection-change=
"handleMaterialSelectionChange"
:selected-material-codes=
"
form.materialCodes ? form.materialCodes.split(',').filter(u => u.trim()) : []
"
:selected-material-codes=
"
selectedSapCodes
"
:multiple=
"true"
:default-category-codes=
"
form.allowedCategoryIds ? form.allowedCategoryIds.split(',').filter(c => c.trim()) :
[]"
:default-category-codes=
"[]"
/>
<div
slot=
"footer"
class=
"dialog-footer"
>
...
...
@@ -442,14 +439,14 @@
<
script
>
import
{
listLocations
,
getLocations
,
delLocations
,
addLocations
,
updateLocations
}
from
"@/api/inventory/locations"
import
{
listWarehouses
}
from
"@/api/inventory/warehouses"
import
materialsSeletor
from
"
../../..
/components/materialsSeletor.vue"
import
materialsSeletor
from
"
@
/components/materialsSeletor.vue"
import
ImportExcel
from
"@/components/ImportExcel/index"
import
{
listMaterials
}
from
"@/api/inventory/materials"
export
default
{
name
:
"Locations"
,
components
:
{
materialsSeletor
,
ImportExcel
},
dicts
:
[
'sys_normal_disable'
],
dicts
:
[
'sys_normal_disable'
,
'location_type'
],
data
()
{
return
{
loading
:
true
,
...
...
@@ -500,10 +497,9 @@ export default {
capacity
:
null
,
volumeCapacity
:
null
,
allowedHazardLevels
:
null
,
materialCodes
:
null
,
materialNames
:
null
,
allowedCategoryIds
:
null
,
allowedCategoryNames
:
null
,
allowedCategoryIds
:
null
,
// 核心字段:存储逗号分隔的SAP号
materialNames
:
null
,
// 存储物料名称(逗号分隔,用于显示)
allowedCategoryNames
:
null
,
// 存储物料分类名称(逗号分隔)
temperatureZone
:
null
,
isEnabled
:
1
,
isUsed
:
0
,
...
...
@@ -527,6 +523,9 @@ export default {
],
isEnabled
:
[
{
required
:
true
,
message
:
'应用状态不能为空'
,
trigger
:
'change'
}
],
allowedCategoryIds
:
[
{
required
:
true
,
message
:
'请选择允许存放的物料'
,
trigger
:
'blur'
}
]
},
...
...
@@ -534,24 +533,36 @@ export default {
loadingWarehouse
:
false
,
showMaterialSelect
:
false
,
tempSelectedMaterials
:
{
materialCodes
:
[],
names
:
[],
categoryIds
:
[]
tempSelectedMaterials
:
{
// 临时存储选择的物料数据
materialCodes
:
[],
// SAP号数组
names
:
[],
// 物料名称数组
categoryIds
:
[]
// 分类ID数组
},
materialCodeToNameMap
:
{},
materialMapLoaded
:
false
materialCodeToNameMap
:
{},
// SAP号→物料名称映射表
materialMapLoaded
:
false
// 映射表加载状态
}
},
computed
:
{
// 计算属性:统一处理SAP号大小写,确保反显参数正确
selectedSapCodes
()
{
if
(
!
this
.
form
.
allowedCategoryIds
)
return
[]
// 核心修复:转大写 + 去空 + 去重
return
this
.
form
.
allowedCategoryIds
.
split
(
','
)
.
map
(
code
=>
code
.
trim
().
toUpperCase
())
.
filter
(
code
=>
code
)
.
filter
((
code
,
index
,
self
)
=>
self
.
indexOf
(
code
)
===
index
)
}
},
created
()
{
this
.
getList
()
this
.
getWarehouseOptions
()
this
.
initMaterialCodeToNameMap
()
this
.
initMaterialCodeToNameMap
()
// 初始化SAP号-名称映射
},
methods
:
{
/** 初始化SAP号→物料名称映射表(用于反显) */
async
initMaterialCodeToNameMap
()
{
try
{
this
.
materialMapLoaded
=
tru
e
this
.
materialMapLoaded
=
fals
e
let
pageNum
=
1
const
pageSize
=
1000
let
hasMore
=
true
...
...
@@ -561,16 +572,14 @@ export default {
const
response
=
await
listMaterials
({
pageNum
,
pageSize
,
isUsed
:
1
,
materialCode
:
null
,
materialName
:
null
isUsed
:
1
// 只查询启用的物料
})
if
(
response
.
rows
&&
response
.
rows
.
length
)
{
response
.
rows
.
forEach
(
item
=>
{
if
(
item
.
materialCode
&&
item
.
materialName
)
{
const
code
=
item
.
materialCode
.
trim
().
toUpperCase
()
this
.
materialCodeToNameMap
[
c
ode
]
=
item
.
materialName
if
(
item
.
sapNo
&&
item
.
materialName
)
{
const
sapCode
=
item
.
sapNo
.
trim
().
toUpperCase
()
// SAP号统一大写存储
this
.
materialCodeToNameMap
[
sapC
ode
]
=
item
.
materialName
}
})
hasMore
=
pageNum
*
pageSize
<
response
.
total
...
...
@@ -579,25 +588,28 @@ export default {
hasMore
=
false
}
}
console
.
log
(
'物料映射表初始化完成:'
,
this
.
materialCodeToNameMap
)
this
.
materialMapLoaded
=
true
console
.
log
(
'SAP号-物料名称映射表初始化完成:'
,
this
.
materialCodeToNameMap
)
}
catch
(
error
)
{
console
.
error
(
'初始化
物料编码-
名称映射表失败:'
,
error
)
console
.
error
(
'初始化
SAP号-物料
名称映射表失败:'
,
error
)
this
.
materialMapLoaded
=
false
this
.
$modal
.
msgError
(
'物料数据加载失败,请刷新页面重试!'
)
}
},
/** 表格行点击展开详情 */
handleRowClick
(
row
,
event
,
column
)
{
if
(
column
.
type
!==
'selection'
)
{
this
.
$refs
.
locationsTable
.
toggleRowExpansion
(
row
)
}
},
/** 获取库位列表 */
getList
()
{
this
.
loading
=
true
const
params
=
{
...
this
.
queryParams
,
isUsed
:
0
isUsed
:
0
// 只查询未删除的库位
}
listLocations
(
params
).
then
(
response
=>
{
this
.
locationsList
=
response
.
rows
...
...
@@ -606,6 +618,7 @@ export default {
})
},
/** 获取仓库下拉选项 */
getWarehouseOptions
()
{
this
.
loadingWarehouse
=
true
listWarehouses
({
pageNum
:
1
,
pageSize
:
100
}).
then
(
response
=>
{
...
...
@@ -622,17 +635,20 @@ 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
()
this
.
reset
()
// 重置表单状态,避免数据残留
},
/** 重置表单(关键:清空所有状态,避免数据残留) */
reset
()
{
this
.
form
=
{
id
:
null
,
...
...
@@ -647,83 +663,101 @@ export default {
capacity
:
null
,
volumeCapacity
:
null
,
allowedHazardLevels
:
null
,
materialCodes
:
null
,
materialNames
:
null
,
allowedCategoryIds
:
null
,
allowedCategoryNames
:
null
,
allowedCategoryIds
:
null
,
// 清空SAP号
materialNames
:
null
,
// 清空物料名称
allowedCategoryNames
:
null
,
// 清空分类名称
temperatureZone
:
null
,
isEnabled
:
1
,
isUsed
:
0
,
sortNo
:
0
}
// 清空临时选择的物料数据
this
.
tempSelectedMaterials
=
{
materialCodes
:
[],
names
:
[],
categoryIds
:
[]
}
this
.
resetForm
(
"form"
)
// 重置物料选择器(关键:避免切换时残留选中状态)
if
(
this
.
$refs
.
materialsSeletor
)
{
// 调用选择器内部的清空方法(需组件支持)
if
(
typeof
this
.
$refs
.
materialsSeletor
.
clearSelection
===
'function'
)
{
this
.
$refs
.
materialsSeletor
.
clearSelection
()
}
if
(
typeof
this
.
$refs
.
materialsSeletor
.
resetQuery
===
'function'
)
{
this
.
$refs
.
materialsSeletor
.
resetQuery
()
}
}
// 重置表单校验
if
(
this
.
$refs
.
form
)
{
this
.
$refs
.
form
.
resetFields
()
}
this
.
showMaterialSelect
=
false
},
/** 查询库位列表 */
handleQuery
()
{
this
.
queryParams
.
pageNum
=
1
this
.
getList
()
},
/** 重置查询条件 */
resetQuery
()
{
this
.
resetForm
(
"queryForm"
)
if
(
this
.
$refs
.
queryForm
)
{
this
.
$refs
.
queryForm
.
resetFields
()
}
this
.
handleQuery
()
},
/** 表格选择事件 */
handleSelectionChange
(
selection
)
{
this
.
ids
=
selection
.
map
(
item
=>
item
.
id
)
this
.
single
=
selection
.
length
!==
1
this
.
single
=
selection
.
length
!==
1
this
.
multiple
=
!
selection
.
length
},
/** 新增库位 */
handleAdd
()
{
this
.
reset
()
this
.
reset
()
// 新增前先重置,避免残留修改的数据
this
.
open
=
true
this
.
title
=
"添加库位"
},
/** 修改库位(反显数据,基于allowedCategoryIds存储的SAP号) */
async
handleUpdate
(
row
)
{
this
.
reset
()
this
.
reset
()
// 修改前先重置,避免数据残留
const
id
=
row
.
id
||
this
.
ids
try
{
const
response
=
await
getLocations
(
id
)
cons
ole
.
log
(
'后端返回库位详情:'
,
response
.
data
)
this
.
form
=
JSON
.
parse
(
JSON
.
stringify
(
response
.
data
))
cons
t
data
=
response
.
data
||
{}
this
.
form
=
{
...
this
.
form
,
...
data
}
// 赋值基础字段
// 等待映射表加载完成,再处理SAP号反显
if
(
!
this
.
materialMapLoaded
)
{
await
this
.
initMaterialCodeToNameMap
()
}
// 从allowedCategoryIds读取物料编码(替代缺失的materialCodes)
const
rawMaterialCodes
=
this
.
form
.
allowedCategoryIds
||
row
.
allowedCategoryIds
||
''
console
.
log
(
'原始物料编码(从allowedCategoryIds读取):'
,
rawMaterialCodes
)
// 核心修复:统一转大写,确保匹配映射表
const
sapCodes
=
this
.
form
.
allowedCategoryIds
?
this
.
form
.
allowedCategoryIds
.
split
(
','
).
map
(
code
=>
code
.
trim
().
toUpperCase
()).
filter
(
code
=>
code
)
:
[]
if
(
rawMaterialCodes
)
{
const
materialCodes
=
rawMaterialCodes
.
split
(
','
)
.
map
(
code
=>
code
.
trim
().
toUpperCase
())
.
filter
(
code
=>
code
)
console
.
log
(
'处理后物料编码:'
,
materialCodes
)
console
.
log
(
'映射表匹配:'
,
materialCodes
.
map
(
code
=>
({
console
.
log
(
'反显的SAP号(转大写后):'
,
sapCodes
)
console
.
log
(
'映射表匹配结果:'
,
sapCodes
.
map
(
code
=>
({
code
,
name
:
this
.
materialCodeToNameMap
[
code
]
})))
this
.
form
.
materialNames
=
materialCodes
.
map
(
code
=>
{
// 匹配物料名称
this
.
form
.
materialNames
=
sapCodes
.
map
(
code
=>
{
return
this
.
materialCodeToNameMap
[
code
]
||
`【未匹配】
${
code
}
`
}).
join
(
','
)
// 同步赋值materialCodes(确保选择器能接收到)
this
.
form
.
materialCodes
=
rawMaterialCodes
// 临时存储选中的物料数据(用于物料选择器回显)
this
.
tempSelectedMaterials
=
{
materialCodes
:
material
Codes
,
materialCodes
:
sap
Codes
,
names
:
this
.
form
.
materialNames
.
split
(
','
).
filter
(
name
=>
name
.
trim
()),
categoryIds
:
this
.
form
.
allowedCategoryIds
?
this
.
form
.
allowedCategoryIds
.
split
(
','
).
filter
(
c
=>
c
.
trim
())
:
[]
}
categoryIds
:
[]
// 分类ID按需从后端获取,此处暂空
}
this
.
open
=
true
...
...
@@ -734,16 +768,26 @@ export default {
}
},
/** 提交表单(新增/修改) */
submitForm
()
{
this
.
$refs
[
"form"
].
validate
(
valid
=>
{
if
(
valid
)
{
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
(
','
)
}
// 处理SAP号:去重、去空、统一大写,用逗号分隔
const
sapCodes
=
this
.
form
.
allowedCategoryIds
?
this
.
form
.
allowedCategoryIds
.
split
(
','
)
.
map
(
code
=>
code
.
trim
().
toUpperCase
())
.
filter
(
code
=>
code
)
.
filter
((
code
,
index
,
self
)
=>
self
.
indexOf
(
code
)
===
index
)
// 去重
:
[]
this
.
form
.
allowedCategoryIds
=
sapCodes
.
join
(
','
)
// 重新赋值SAP号
// 物料名称与SAP号保持一致
this
.
form
.
materialNames
=
sapCodes
.
map
(
code
=>
{
return
this
.
materialCodeToNameMap
[
code
]
||
`【未匹配】
${
code
}
`
}).
join
(
','
)
// 提交到后端
if
(
this
.
form
.
id
!=
null
)
{
updateLocations
(
this
.
form
).
then
(
response
=>
{
this
.
$modal
.
msgSuccess
(
"修改成功"
)
...
...
@@ -761,6 +805,7 @@ export default {
})
},
/** 删除库位 */
handleDelete
(
row
)
{
const
ids
=
row
.
id
||
this
.
ids
this
.
$modal
.
confirm
(
row
.
id
?
`是否确认删除库位编号为"
${
row
.
locationCode
}
"的数据项?`
:
`是否确认删除选中的
${
ids
.
length
}
条库位数据项?`
).
then
(
function
()
{
...
...
@@ -771,52 +816,78 @@ export default {
}).
catch
(()
=>
{})
},
/** 导出库位数据 */
handleExport
()
{
this
.
download
(
'inventory/locations/export'
,
{
...
this
.
queryParams
},
`locations_
${
new
Date
().
getTime
()}
.xlsx`
)
},
/** 打开物料选择器(封装逻辑,确保数据加载完成) */
openMaterialSelector
()
{
// 确保映射表加载完成
if
(
!
this
.
materialMapLoaded
)
{
this
.
$modal
.
msgWarning
(
'物料数据正在加载,请稍候!'
)
this
.
initMaterialCodeToNameMap
().
then
(()
=>
{
this
.
showMaterialSelect
=
true
})
return
}
this
.
showMaterialSelect
=
true
},
/** 初始化物料选择器(弹窗打开时触发) */
initMaterialSelector
()
{
// 主动触发选择器反显(需组件支持setSelectedCodes方法)
if
(
this
.
$refs
.
materialsSeletor
&&
typeof
this
.
$refs
.
materialsSeletor
.
setSelectedCodes
===
'function'
)
{
this
.
$refs
.
materialsSeletor
.
setSelectedCodes
(
this
.
selectedSapCodes
)
}
console
.
log
(
'物料选择器反显参数:'
,
this
.
selectedSapCodes
)
},
/** 物料选择器选择事件(接收选中的物料数据) */
handleMaterialSelectionChange
(
selectedData
)
{
this
.
tempSelectedMaterials
=
{
materialCodes
:
selectedData
.
materialCodes
||
[],
names
:
selectedData
.
names
||
[],
categoryIds
:
selectedData
.
formattedCategoryIds
||
[]
materialCodes
:
selectedData
.
materialCodes
||
[],
// SAP号数组
names
:
selectedData
.
names
||
[],
// 物料名称数组
categoryIds
:
selectedData
.
categoryIds
||
[]
// 分类ID数组
}
},
/** 取消物料选择 */
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
())
:
[]
materialCodes
:
this
.
form
.
allowedCategoryIds
?
this
.
form
.
allowedCategoryIds
.
split
(
','
).
filter
(
code
=>
code
.
trim
()).
map
(
code
=>
code
.
toUpperCase
())
:
[],
names
:
this
.
form
.
materialNames
?
this
.
form
.
materialNames
.
split
(
','
).
filter
(
n
ame
=>
name
.
trim
())
:
[],
categoryIds
:
[]
}
},
/** 确认选择物料(将选中的SAP号赋值给allowedCategoryIds) */
confirmMaterialSelection
()
{
if
(
!
this
.
tempSelectedMaterials
.
materialCodes
.
length
)
{
const
{
materialCodes
,
names
,
categoryIds
}
=
this
.
tempSelectedMaterials
if
(
!
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
(
','
)
}
// 核心:将选中的SAP号用逗号分隔存储到allowedCategoryIds
this
.
form
.
allowedCategoryIds
=
materialCodes
.
join
(
','
)
// 存储物料名称(用于显示)
this
.
form
.
materialNames
=
names
.
join
(
','
)
// 存储分类名称(按需处理)
this
.
form
.
allowedCategoryNames
=
categoryIds
.
map
(
id
=>
{
return
this
.
$refs
.
materialsSeletor
?.
categoryMap
[
id
]
||
id
}).
join
(
','
)
this
.
showMaterialSelect
=
false
this
.
$modal
.
msgSuccess
(
`成功选择
${
this
.
tempSelectedMaterials
.
names
.
length
}
个物料
`
)
this
.
$modal
.
msgSuccess
(
`成功选择
${
materialCodes
.
length
}
个物料(SAP号:
${
this
.
form
.
allowedCategoryIds
}
)
`
)
},
/** 导入
组件
*/
/** 导入
库位数据
*/
handleImport
()
{
this
.
$refs
.
import
.
show
()
}
...
...
@@ -867,4 +938,17 @@ export default {
max-width
:
300px
;
white-space
:
normal
;
}
/* 优化SAP号显示样式 */
/
deep
/
.el-form-item__content
.el-input
{
margin-bottom
:
4px
;
}
.el-form-item__content
.el-button
{
margin-top
:
4px
;
}
.el-form-item__content
div
[
style
*=
"font-size: 12px"
]
{
color
:
#888
;
}
</
style
>
\ No newline at end of file
ruoyi-admin-vue/src/views/inventory/orders/OutboundOrderFormWithItems.vue
View file @
4551012a
...
...
@@ -12,7 +12,6 @@
<el-row
:gutter=
"20"
>
<el-col
:span=
"12"
>
<el-form-item
label=
"货物ID"
prop=
"materialId"
>
<!-- 核心:编辑状态禁用输入框和选择按钮 -->
<el-input
v-model=
"form.materialId"
placeholder=
"请选择或输入货物ID"
...
...
@@ -30,7 +29,6 @@
></el-button>
</
template
>
</el-input>
<!-- 编辑状态隐藏物料选择器弹窗 -->
<el-dialog
v-if=
"!isMaterialLocked"
title=
"选择物料"
...
...
@@ -59,7 +57,6 @@
</el-col>
</el-row>
<!-- 库存信息列表 - 添加库存ID列和单价列 -->
<el-row
v-if=
"form.materialId && form.materialId.trim()"
style=
"margin: 10px 0;"
>
<el-col
:span=
"24"
>
<div
style=
"margin-bottom: 8px; font-weight: 600; color: #1989fa;"
>
...
...
@@ -75,13 +72,13 @@
stripe
empty-text=
"暂无库存数据"
@
row-click=
"handleRowClick"
:row-key=
"item => item.id"
:row-key=
"item => item.i
nventoryI
d"
>
<el-table-column
prop=
"materialId"
label=
"货物ID"
width=
"1
2
0"
/>
<el-table-column
prop=
"batchId"
label=
"批次ID"
width=
"1
2
0"
/>
<el-table-column
prop=
"outboundOrderId"
label=
"出库单号"
width=
"1
2
0"
/>
<
el-table-column
prop=
"warehouseId"
label=
"仓库ID"
width=
"120"
/
>
<el-table-column
prop=
"locationId"
label=
"库位ID"
width=
"1
1
0"
/>
<el-table-column
prop=
"materialId"
label=
"货物ID"
width=
"1
5
0"
/>
<el-table-column
prop=
"batchId"
label=
"批次ID"
width=
"1
5
0"
/>
<el-table-column
prop=
"outboundOrderId"
label=
"出库单号"
width=
"1
5
0"
/>
<
!-- <el-table-column prop="warehouseId" label="仓库ID" width="120" /> --
>
<el-table-column
prop=
"locationId"
label=
"库位ID"
width=
"1
4
0"
/>
<el-table-column
prop=
"inventoryType"
label=
"库存类型"
...
...
@@ -98,7 +95,6 @@
{{
(
scope
.
row
.
quantity
||
0
)
-
(
scope
.
row
.
lockedQuantity
||
0
)
}}
</
template
>
</el-table-column>
<!-- 实际数量:填写即视为选中(原选择数量) -->
<el-table-column
label=
"实际数量"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<el-input
...
...
@@ -114,7 +110,6 @@
</el-table-column>
</el-table>
<!-- 选中行的扩展字段填写区域 -->
<div
v-if=
"currentSelectedRow"
style=
"margin-top: 10px; padding: 10px; border: 1px solid #e6e6e6; border-radius: 4px;"
...
...
@@ -122,7 +117,6 @@
<div
style=
"margin-bottom: 8px; font-weight: 600; color: #1989fa;"
>
库存明细信息
</div>
<!-- 扩展字段区域 -->
<el-row
:gutter=
"20"
>
<el-col
:span=
"8"
>
<el-form-item
label=
"约数"
prop=
"divisor"
>
...
...
@@ -197,7 +191,18 @@
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"margin-top: 10px;"
>
<el-col
:span=
"24"
>
<el-col
:span=
"8"
>
<el-form-item
label=
"发货时间"
prop=
"shippedAt"
>
<el-date-picker
v-model=
"currentSelectedRow.shippedAt"
type=
"date"
placeholder=
"选择发货时间"
style=
"width: 100%;"
@
input=
"syncDetails(false)"
/>
</el-form-item>
</el-col>
<el-col
:span=
"16"
>
<el-form-item
label=
"备注"
prop=
"remark"
>
<el-input
v-model=
"currentSelectedRow.remark"
...
...
@@ -213,7 +218,6 @@
</el-col>
</el-row>
<!-- 已生成的明细预览 - 添加库存ID列和单价列 -->
<el-row
v-if=
"details.length > 0"
style=
"margin: 10px 0;"
>
<el-col
:span=
"24"
>
<div
style=
"margin-bottom: 8px; font-weight: 600; color: #1989fa;"
>
...
...
@@ -241,6 +245,7 @@
</el-table-column>
<el-table-column
prop=
"voucherNumber"
label=
"凭证号"
/>
<el-table-column
prop=
"shippedBy"
label=
"发货方"
/>
<el-table-column
prop=
"shippedAt"
label=
"发货时间"
/>
<el-table-column
prop=
"remark"
label=
"备注"
/>
<el-table-column
label=
"操作"
width=
"80"
>
<
template
slot-scope=
"scope"
>
...
...
@@ -264,7 +269,7 @@
<
script
>
import
{
listInventoryByMaterialId
}
from
"@/api/inventory/inventory"
;
import
MaterialSelector
from
'
../../..
/components/materialsSeletor.vue'
;
import
MaterialSelector
from
'
@
/components/materialsSeletor.vue'
;
function
debounce
(
fn
,
delay
=
500
)
{
let
timer
=
null
;
...
...
@@ -278,7 +283,7 @@ function debounce(fn, delay = 500) {
export
default
{
name
:
'OutboundOrderFormWithItems'
,
dicts
:
[
'inbound_order_status'
,
'inbound_order_type'
,
'inbound_order_item_status'
,
'label_color'
],
dicts
:
[
'inbound_order_status'
,
'inbound_order_type'
,
'inbound_order_item_status'
,
'label_color'
],
components
:
{
MaterialSelector
},
...
...
@@ -335,9 +340,8 @@ export default {
},
computed
:
{
currentSelectedRow
()
{
return
this
.
inventoryList
.
find
(
row
=>
row
.
id
===
this
.
currentSelectedRowId
)
||
null
;
return
this
.
inventoryList
.
find
(
row
=>
row
.
i
nventoryI
d
===
this
.
currentSelectedRowId
)
||
null
;
},
// 核心计算属性:判断是否为编辑状态(有初始数据则锁死物料)
isMaterialLocked
()
{
return
this
.
initDetails
.
length
>
0
||
!!
this
.
initForm
.
materialId
;
}
...
...
@@ -356,9 +360,18 @@ export default {
this
.
selectedMaterialInfo
=
null
;
this
.
currentSelectedRowId
=
null
;
this
.
details
=
this
.
initDetails
.
length
>
0
?
JSON
.
parse
(
JSON
.
stringify
(
this
.
initDetails
))
:
[];
// 强制等待DOM更新后再查库存,避免数据未初始化
this
.
$nextTick
(
async
()
=>
{
if
(
this
.
form
.
materialId
&&
this
.
form
.
materialId
.
trim
())
{
this
.
handleMaterialIdChange
();
await
this
.
handleMaterialIdChange
();
// 二次确认:库存加载完成后手动触发回显
if
(
this
.
inventoryList
.
length
>
0
&&
!
this
.
isInitEcho
)
{
this
.
initEchoDetails
();
this
.
isInitEcho
=
true
;
this
.
currentSelectedRowId
=
this
.
inventoryList
[
0
].
inventoryId
;
}
}
});
}
else
{
this
.
$nextTick
(()
=>
{
this
.
closeLoading
();
...
...
@@ -381,10 +394,18 @@ export default {
const
oldMaterialId
=
this
.
selectedMaterialId
;
this
.
selectedMaterialId
=
this
.
form
.
materialId
||
''
;
this
.
currentSelectedRowId
=
null
;
// 强制等待DOM更新后再查库存
this
.
$nextTick
(
async
()
=>
{
if
(
this
.
form
.
materialId
&&
this
.
form
.
materialId
.
trim
()
&&
this
.
form
.
materialId
!==
oldMaterialId
)
{
this
.
handleMaterialIdChange
();
await
this
.
handleMaterialIdChange
();
if
(
this
.
inventoryList
.
length
>
0
&&
!
this
.
isInitEcho
)
{
this
.
initEchoDetails
();
this
.
isInitEcho
=
true
;
this
.
currentSelectedRowId
=
this
.
inventoryList
[
0
].
inventoryId
;
}
}
});
}
},
immediate
:
true
,
deep
:
true
...
...
@@ -394,9 +415,7 @@ export default {
if
(
this
.
open
&&
newVal
.
length
>
0
&&
!
this
.
isInitEcho
)
{
this
.
initEchoDetails
();
this
.
isInitEcho
=
true
;
if
(
!
this
.
currentSelectedRowId
)
{
this
.
currentSelectedRowId
=
newVal
[
0
].
id
;
}
this
.
currentSelectedRowId
=
newVal
[
0
].
inventoryId
;
}
},
immediate
:
true
,
...
...
@@ -441,12 +460,18 @@ export default {
materialId
:
materialId
,
outboundOrderId
:
this
.
form
.
outboundOrderId
};
console
.
log
(
'【查询库存参数】'
,
params
);
const
res
=
await
listInventoryByMaterialId
(
params
);
console
.
log
(
'【库存接口返回】'
,
res
);
console
.
log
(
'【库存接口原始行数据】'
,
res
.
rows
);
// 打印原始行数据
if
(
res
.
code
===
200
)
{
this
.
inventoryList
=
[];
(
res
.
rows
||
[]).
forEach
(
item
=>
{
console
.
log
(
'【单条库存数据】'
,
item
);
// 打印单条库存数据
const
newRow
=
{
id
:
item
.
id
,
// 核心修复:优先取item.inventoryId(匹配回显字段),兼容item.id
inventoryId
:
item
.
inventoryId
||
item
.
id
,
id
:
item
.
id
,
// 保留原id字段
materialId
:
item
.
materialId
||
materialId
,
batchId
:
item
.
batchId
||
''
,
outboundOrderId
:
item
.
outboundOrderId
||
this
.
form
.
outboundOrderId
,
...
...
@@ -468,6 +493,8 @@ export default {
};
this
.
inventoryList
.
push
(
newRow
);
});
console
.
log
(
'【组装后的库存列表】'
,
this
.
inventoryList
);
console
.
log
(
'【待回显的initDetails】'
,
this
.
initDetails
);
if
(
this
.
inventoryList
.
length
===
0
)
{
this
.
$message
.
warning
(
'未查询到该物料的库存信息'
);
...
...
@@ -485,11 +512,11 @@ export default {
});
}
},
// 修复:初始化回显逻辑 - 确保所有明细都正确赋值
initEchoDetails
()
{
if
(
this
.
initDetails
.
length
===
0
)
return
;
console
.
log
(
'【开始回显】inventoryList='
,
this
.
inventoryList
,
'initDetails='
,
this
.
initDetails
);
if
(
this
.
initDetails
.
length
===
0
||
this
.
inventoryList
.
length
===
0
)
return
;
// 清空原有数据
,避免残留
// 清空原有数据
this
.
inventoryList
.
forEach
(
row
=>
{
this
.
$set
(
row
,
'actualQuantity'
,
null
);
this
.
$set
(
row
,
'plannedQuantity'
,
null
);
...
...
@@ -502,27 +529,53 @@ export default {
this
.
$set
(
row
,
'remark'
,
''
);
});
// 重新赋值所有明细
this
.
initDetails
.
forEach
(
detail
=>
{
const
targetRow
=
this
.
inventoryList
.
find
(
row
=>
row
.
id
===
detail
.
inventoryId
);
// 方案1:优先用inventoryId匹配
let
targetRow
=
null
;
const
firstDetail
=
this
.
initDetails
[
0
];
targetRow
=
this
.
inventoryList
.
find
(
row
=>
row
.
inventoryId
===
firstDetail
.
inventoryId
);
// 方案2:兜底用batchId+warehouseId+locationId匹配
if
(
!
targetRow
)
{
console
.
log
(
'【兜底匹配】使用batchId+warehouseId+locationId匹配,明细='
,
firstDetail
);
targetRow
=
this
.
inventoryList
.
find
(
row
=>
row
.
batchId
===
firstDetail
.
batchId
&&
row
.
warehouseId
===
firstDetail
.
warehouseId
&&
row
.
locationId
===
firstDetail
.
locationId
);
}
// 方案3:终极兜底(强制赋值到第一行)
if
(
!
targetRow
)
{
console
.
log
(
'【强制回显】无匹配字段,直接赋值到第一条库存行'
);
targetRow
=
this
.
inventoryList
[
0
];
}
console
.
log
(
'【匹配明细】detail.inventoryId='
,
firstDetail
.
inventoryId
,
'匹配到的行='
,
targetRow
);
if
(
targetRow
)
{
this
.
$set
(
targetRow
,
'actualQuantity'
,
detail
.
actualQuantity
??
null
);
this
.
$set
(
targetRow
,
'plannedQuantity'
,
detail
.
plannedQuantity
??
null
);
this
.
$set
(
targetRow
,
'divisor'
,
detail
.
divisor
??
null
);
this
.
$set
(
targetRow
,
'labelColor'
,
detail
.
labelColor
??
''
);
this
.
$set
(
targetRow
,
'unitPrice'
,
detail
.
unitPrice
??
null
);
this
.
$set
(
targetRow
,
'shippedBy'
,
detail
.
shippedBy
??
''
);
this
.
$set
(
targetRow
,
'shippedAt'
,
detail
.
shippedAt
??
''
);
this
.
$set
(
targetRow
,
'voucherNumber'
,
detail
.
voucherNumber
??
''
);
this
.
$set
(
targetRow
,
'remark'
,
detail
.
remark
??
''
);
// 回显赋值(所有字段)
this
.
$set
(
targetRow
,
'actualQuantity'
,
firstDetail
.
actualQuantity
??
null
);
this
.
$set
(
targetRow
,
'plannedQuantity'
,
firstDetail
.
plannedQuantity
??
null
);
this
.
$set
(
targetRow
,
'divisor'
,
firstDetail
.
divisor
??
null
);
this
.
$set
(
targetRow
,
'labelColor'
,
firstDetail
.
labelColor
??
''
);
this
.
$set
(
targetRow
,
'unitPrice'
,
firstDetail
.
unitPrice
??
null
);
this
.
$set
(
targetRow
,
'shippedBy'
,
firstDetail
.
shippedBy
??
''
);
this
.
$set
(
targetRow
,
'shippedAt'
,
firstDetail
.
shippedAt
??
''
);
this
.
$set
(
targetRow
,
'voucherNumber'
,
firstDetail
.
voucherNumber
??
''
);
this
.
$set
(
targetRow
,
'remark'
,
firstDetail
.
remark
??
''
);
// 强制选中该行
this
.
currentSelectedRowId
=
targetRow
.
inventoryId
;
}
else
{
console
.
warn
(
'【匹配失败】无可用库存行进行回显'
);
}
});
// 同步明细数据
this
.
syncDetails
(
false
);
console
.
log
(
'【回显完成】inventoryList='
,
this
.
inventoryList
);
},
handleRowClick
(
row
)
{
if
(
!
row
)
return
;
this
.
currentSelectedRowId
=
row
.
id
;
this
.
currentSelectedRowId
=
row
.
i
nventoryI
d
;
},
handleRowActualQtyInput
(
row
)
{
if
(
isNaN
(
row
.
actualQuantity
)
||
row
.
actualQuantity
===
''
)
{
...
...
@@ -552,7 +605,6 @@ export default {
this
.
$set
(
row
,
'plannedQuantity'
,
1
);
}
},
// 修复:同步明细数据逻辑 - 确保严格模式下正确收集所有有效数据
syncDetails
(
strict
=
true
)
{
this
.
details
=
[];
...
...
@@ -560,7 +612,6 @@ export default {
if
(
strict
)
{
validRows
=
this
.
inventoryList
.
filter
(
row
=>
{
const
availableQty
=
(
row
.
quantity
||
0
)
-
(
row
.
lockedQuantity
||
0
);
// 修复:允许0值(但需大于0),同时确保必填字段不为空
return
row
.
actualQuantity
!==
null
&&
row
.
actualQuantity
!==
undefined
&&
row
.
actualQuantity
>=
1
&&
...
...
@@ -585,10 +636,9 @@ export default {
});
}
// 修复:确保每条明细都有唯一标识
validRows
.
forEach
(
row
=>
{
const
newDetail
=
{
inventoryId
:
row
.
id
,
inventoryId
:
row
.
i
nventoryI
d
,
materialId
:
row
.
materialId
||
this
.
form
.
materialId
,
batchId
:
row
.
batchId
||
row
.
batchCode
||
''
,
warehouseId
:
row
.
warehouseId
||
''
,
...
...
@@ -609,7 +659,7 @@ export default {
},
removeDetail
(
row
)
{
this
.
details
=
this
.
details
.
filter
(
d
=>
d
.
inventoryId
!==
row
.
inventoryId
);
const
inventoryRow
=
this
.
inventoryList
.
find
(
item
=>
item
.
id
===
row
.
inventoryId
);
const
inventoryRow
=
this
.
inventoryList
.
find
(
item
=>
item
.
i
nventoryI
d
===
row
.
inventoryId
);
if
(
inventoryRow
)
{
this
.
$set
(
inventoryRow
,
'actualQuantity'
,
null
);
this
.
$set
(
inventoryRow
,
'plannedQuantity'
,
null
);
...
...
@@ -621,12 +671,11 @@ export default {
this
.
$set
(
inventoryRow
,
'voucherNumber'
,
''
);
this
.
$set
(
inventoryRow
,
'remark'
,
''
);
if
(
this
.
currentSelectedRowId
===
row
.
inventoryId
)
{
this
.
currentSelectedRowId
=
this
.
inventoryList
.
length
>
0
?
this
.
inventoryList
[
0
].
id
:
null
;
this
.
currentSelectedRowId
=
this
.
inventoryList
.
length
>
0
?
this
.
inventoryList
[
0
].
i
nventoryI
d
:
null
;
}
}
this
.
syncDetails
(
this
.
initDetails
.
length
===
0
);
},
// 修复:提交逻辑 - 确保严格模式同步后再提交
handleSubmit
()
{
if
(
!
this
.
form
.
materialId
?.
trim
())
{
this
.
$message
.
error
(
'请先选择物料ID'
);
...
...
@@ -639,7 +688,6 @@ export default {
return
;
}
// 强制严格模式同步
this
.
syncDetails
(
true
);
if
(
this
.
details
.
length
===
0
)
{
...
...
@@ -647,14 +695,12 @@ export default {
return
;
}
// 移除重复的校验逻辑(已在syncDetails中处理)
const
submitDetails
=
this
.
details
.
map
(
detail
=>
({
...
detail
,
outboundOrderId
:
this
.
form
.
outboundOrderId
||
detail
.
outboundOrderId
,
materialId
:
this
.
form
.
materialId
||
detail
.
materialId
}));
// 调试:打印提交的数据
console
.
log
(
'提交的明细数据:'
,
submitDetails
);
this
.
$emit
(
'submit'
,
submitDetails
);
...
...
@@ -679,11 +725,10 @@ export default {
this
.
$emit
(
'update:open'
,
false
);
},
handleMaterialSelectionChange
()
{
// 核心修改:将物料选择器返回的sap_no作为物料ID
const
selectedData
=
this
.
$refs
.
materialsSeletor
?.
getSelectedMaterials
?.()
||
this
.
$refs
.
materialsSeletor
?.
selectedList
||
[];
if
(
selectedData
&&
selectedData
.
length
>
0
)
{
this
.
selectedMaterialInfo
=
selectedData
[
0
];
// 替换:使用sapNo作为物料ID
if
(
selectedData
)
{
this
.
selectedMaterialInfo
=
selectedData
;
this
.
selectedMaterialId
=
this
.
selectedMaterialInfo
.
sapNo
||
this
.
selectedMaterialInfo
.
materialId
||
''
;
console
.
log
(
"选中的SAP物料号:"
,
this
.
selectedMaterialId
);
}
else
{
...
...
@@ -691,7 +736,6 @@ export default {
this
.
selectedMaterialId
=
''
;
}
},
// 修复:物料选择后的数据赋值 - 核心替换为sap_no
confirmMaterialSelect
()
{
this
.
handleMaterialSelectionChange
();
if
(
!
this
.
selectedMaterialId
)
{
...
...
@@ -699,7 +743,6 @@ export default {
return
;
}
// 核心修改:将sapNo赋值给materialId和materialUuids
this
.
$set
(
this
.
form
,
'materialId'
,
this
.
selectedMaterialInfo
.
sapNo
||
this
.
selectedMaterialId
);
this
.
$set
(
this
.
form
,
'materialUuids'
,
this
.
selectedMaterialInfo
.
sapNo
||
this
.
selectedMaterialId
);
...
...
@@ -755,7 +798,6 @@ export default {
}
}
/* 优化禁用状态样式 */
/
deep
/
.el-input.is-disabled
{
background-color
:
#f5f7fa
;
cursor
:
not-allowed
;
...
...
ruoyi-admin-vue/src/views/inventory/orders/index.vue
View file @
4551012a
...
...
@@ -373,7 +373,7 @@
<
div
v
-
for
=
"(group, materialId) in outboundOrderItemsGroup"
:
key
=
"materialId"
class
=
"material-group mb10"
>
<
div
class
=
"group-header"
style
=
"background: #f5f7fa; padding: 8px 12px; border-radius: 4px; margin-bottom: 8px;"
>
<
span
style
=
"font-weight: 600; margin-right: 16px;"
>
物料
ID
:
{{
materialId
}}
<
/span
>
<
span
style
=
"font-weight: 600; margin-right: 16px;"
>
物料
:
{{
materialId
+
" "
+
getMaterialName
(
materialId
)
}}
<
/span
>
<
span
style
=
"color: #666;"
>
明细数量:
{{
group
.
items
.
length
}}
条
<
/span
>
<!--
仅编辑模式显示分组操作按钮
-->
<
el
-
button
...
...
@@ -391,7 +391,6 @@
:
row
-
class
-
name
=
"(params) => rowInboundOrderItemsIndex(params, group.items)"
@
selection
-
change
=
"handleInboundOrderItemsSelectionChange"
ref
=
"inboundOrderItems"
border
style
=
"width: 100%;"
:
row
-
key
=
"item => item.inventoryId"
:
disabled
=
"isViewDetail"
...
...
@@ -399,8 +398,8 @@
<!--
仅编辑模式显示选择列
-->
<
el
-
table
-
column
type
=
"selection"
width
=
"50"
align
=
"center"
v
-
if
=
"!isViewDetail"
/>
<
el
-
table
-
column
label
=
"序号"
align
=
"center"
prop
=
"index"
width
=
"50"
/>
<
el
-
table
-
column
label
=
"物料编号"
prop
=
"materialId"
width
=
"150"
/>
<
el
-
table
-
column
label
=
"仓库编号"
prop
=
"warehouseId"
width
=
"150"
/
>
<
el
-
table
-
column
label
=
"物料编号"
prop
=
"materialId"
width
=
"180"
/>
<
!--
<
el
-
table
-
column
label
=
"仓库编号"
prop
=
"warehouseId"
width
=
"150"
/>
--
>
<
el
-
table
-
column
label
=
"库位编号"
prop
=
"locationId"
width
=
"150"
/>
<
el
-
table
-
column
label
=
"批次编号"
prop
=
"batchCode"
width
=
"150"
/>
...
...
@@ -439,6 +438,7 @@
:
init
-
details
=
"getInitDetails()"
:
group
-
data
=
"currentGroupData"
:
outbound
-
order
-
id
=
"form.orderId || form.outboundOrderId"
:
materialdicts
=
"materialdicts"
@
submit
=
"handleDetailSubmit"
@
close
=
"detailDialogOpen = false"
@
update
:
open
=
"detailDialogOpen = $event"
...
...
@@ -466,6 +466,8 @@
<
script
>
import
{
listOrders
,
getOrders
,
delOrders
,
addOrders
,
updateOrders
,
ship
}
from
"@/api/inventory/orders"
import
{
getMaterialsdicts
}
from
"@/api/inventory/materials"
import
OutboundOrderFormWithItems
from
'./OutboundOrderFormWithItems.vue'
import
WarehouseSelector
from
"@/views/compononents/WarehouseSelector.vue"
import
LocationSelector
from
"@/views/compononents/LocationSelector.vue"
...
...
@@ -484,6 +486,7 @@ export default {
}
,
data
()
{
return
{
materialdicts
:[],
// 添加tableKey解决tableId渲染问题
tableKey
:
1
,
// 遮罩层
...
...
@@ -600,22 +603,33 @@ export default {
created
()
{
// 延迟加载避免初始化渲染问题
this
.
$nextTick
(()
=>
{
this
.
getdicts
(),
this
.
getList
()
}
)
}
,
methods
:
{
// 货主选择回调
handleOwnerSelected
(
owner
)
{
if
(
!
owner
)
return
if
(
this
.
ownerSelectTarget
===
'query'
)
{
this
.
queryParams
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
queryOwnerName
=
owner
.
ownerName
||
owner
.
name
this
.
handleQuery
()
}
else
{
this
.
form
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
form
.
ownerName
=
owner
.
ownerName
||
owner
.
name
}
this
.
ownerSelectorVisible
=
false
getMaterialName
(
materialId
)
{
if
(
!
materialId
||
!
this
.
materialdicts
.
length
)
return
'未知物料'
;
// 精准匹配(如果需要模糊匹配,把 === 改成 includes 即可)
const
matchItem
=
this
.
materialdicts
.
find
(
item
=>
String
(
item
.
value
)
===
String
(
materialId
)
);
return
matchItem
?
matchItem
.
label
:
'未知物料'
;
}
,
getdicts
(){
return
getMaterialsdicts
()
.
then
(
response
=>
{
this
.
materialdicts
=
(
response
.
data
||
response
).
map
(
item
=>
({
value
:
item
.
sap_no
,
label
:
item
.
material_name
,
}
));
console
.
log
(
"物料字典数据加载成功:"
,
this
.
materialdicts
);
}
)
.
catch
(
error
=>
{
console
.
error
(
"加载物料字典失败:"
,
error
);
this
.
$message
.
error
(
"物料字典加载失败,请刷新重试"
);
}
);
}
,
// 仓库选择回调
handleWarehouseSelected
(
warehouse
)
{
...
...
@@ -650,6 +664,25 @@ export default {
this
.
ownerSelectTarget
=
target
this
.
ownerSelectorVisible
=
true
}
,
// 货主选择回调(核心缺失方法)
handleOwnerSelected
(
owner
)
{
if
(
!
owner
)
return
if
(
this
.
ownerSelectTarget
===
'query'
)
{
this
.
queryParams
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
queryOwnerName
=
owner
.
ownerName
||
owner
.
name
this
.
handleQuery
()
}
else
{
this
.
form
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
form
.
ownerName
=
owner
.
ownerName
||
owner
.
name
// 更新明细中的默认货主(可选)
if
(
this
.
currentDetailItem
)
{
this
.
currentDetailItem
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
currentDetailItem
.
ownerName
=
owner
.
ownerName
||
owner
.
name
}
}
this
.
ownerSelectorVisible
=
false
}
,
// 打开仓库选择器
openWarehouseSelector
(
target
=
'form'
)
{
this
.
warehouseSelectTarget
=
target
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/MaterialsMapper.java
View file @
4551012a
...
...
@@ -30,7 +30,7 @@ public interface MaterialsMapper
* @param id 物料主键
* @return 物料
*/
public
List
<
Materials
>
selectMaterialsBy
MaterialsCode
(
String
id
);
public
List
<
Materials
>
selectMaterialsBy
SapNo
(
String
id
);
/**
* 查询物料列表
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/OutboundOrderItemsMapper.java
View file @
4551012a
...
...
@@ -65,5 +65,5 @@ public interface OutboundOrderItemsMapper
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public
int
deleteOutboundOrderItemsById
s
(
String
[]
ids
);
public
int
deleteOutboundOrderItemsById
(
String
[]
ids
);
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/ReturnOrderItemsMapper.java
View file @
4551012a
...
...
@@ -2,7 +2,6 @@ package com.ruoyi.inventory.mapper;
import
java.util.List
;
import
com.ruoyi.inventory.domain.ReturnOrderItems
;
import
com.ruoyi.inventory.domain.ReturnOrders
;
import
com.ruoyi.inventory.domain.vo.ReturnOrdersSummaryVO
;
/**
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IInventoryService.java
View file @
4551012a
...
...
@@ -106,4 +106,5 @@ public interface IInventoryService
* @return 库存明细集合
*/
public
List
<
Inventory
>
selectInventoryDetailList
(
Inventory
inventory
);
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InventoryServiceImpl.java
View file @
4551012a
...
...
@@ -4,11 +4,10 @@ import java.util.*;
import
java.util.stream.Collectors
;
import
com.ruoyi.common.annotation.SerialExecution
;
import
com.ruoyi.common.core.domain.entity.Materials
;
import
com.ruoyi.common.utils.DateUtils
;
import
com.ruoyi.inventory.domain.OutboundOrderItems
;
import
com.ruoyi.inventory.domain.OutboundOrderLog
;
import
com.ruoyi.inventory.domain.
StocktakeItems
;
import
com.ruoyi.inventory.domain.
TO.StocktakeItemsTo
;
import
com.ruoyi.inventory.domain.vo.InventorySummaryVO
;
import
com.ruoyi.inventory.mapper.OutboundOrderItemsMapper
;
import
com.ruoyi.inventory.mapper.OutboundOrderLogMapper
;
...
...
@@ -233,7 +232,7 @@ public class InventoryServiceImpl implements IInventoryService
* @date 2025/12/3
* @version 1.0
*/
public
List
<
StocktakeItems
>
selectstocktakeItemsList
(){
public
List
<
StocktakeItems
To
>
selectstocktakeItemsList
(){
return
inventoryMapper
.
selectstocktakeItemsList
();
}
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrderItemsServiceImpl.java
View file @
4551012a
...
...
@@ -81,7 +81,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
@Override
public
int
deleteOutboundOrderItemsByIds
(
String
[]
ids
)
{
return
outboundOrderItemsMapper
.
deleteOutboundOrderItemsById
s
(
ids
);
return
outboundOrderItemsMapper
.
deleteOutboundOrderItemsById
(
ids
);
}
/**
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrdersServiceImpl.java
View file @
4551012a
...
...
@@ -41,6 +41,11 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
private
OutboundOrderLogMapper
outboundOrderLogMapper
;
@Autowired
private
OwnersServiceImpl
ownersService
;
@Autowired
private
WarehousesServiceImpl
warehousesService
;
@Autowired
private
InventoryServiceImpl
inventoryService
;
/**
* 查询出库单主
...
...
@@ -64,7 +69,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
@Override
public
List
<
OutboundOrders
>
selectOutboundOrdersList
(
OutboundOrders
outboundOrders
)
{
return
outboundOrdersMapper
.
selectOutboundOrdersList
(
outboundOrders
);
List
<
OutboundOrders
>
outboundOrders1
=
outboundOrdersMapper
.
selectOutboundOrdersList
(
outboundOrders
);
return
outboundOrders1
;
}
/**
...
...
@@ -80,6 +86,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
outboundOrders
.
setCreateTime
(
DateUtils
.
getNowDate
());
outboundOrders
.
setCreateBy
(
SystemUtils
.
getUserName
());
outboundOrders
.
setId
(
UUID
.
randomUUID
().
toString
());
int
rows
=
outboundOrdersMapper
.
insertOutboundOrders
(
outboundOrders
);
insertOutboundOrderItems
(
outboundOrders
);
return
rows
;
...
...
@@ -95,9 +102,12 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
@Override
public
int
updateOutboundOrders
(
OutboundOrders
outboundOrders
)
{
outboundOrders
.
setUpdateTime
(
DateUtils
.
getNowDate
());
outboundOrdersMapper
.
deleteOutboundOrderItemsByOrderId
(
outboundOrders
.
getId
());
outboundOrderLogMapper
.
deleteOutboundOrderLogByOrdersId
(
outboundOrders
.
getId
());
outboundOrders
.
setUpdateBy
(
SystemUtils
.
getUserName
());
outboundOrders
.
setUpdateTime
(
DateUtils
.
getNowDate
());
insertOutboundOrderItems
(
outboundOrders
);
return
outboundOrdersMapper
.
updateOutboundOrders
(
outboundOrders
);
}
...
...
@@ -197,6 +207,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
for
(
OutboundOrderItems
items
:
outboundOrderItemsList
)
{
OutboundOrderLog
log
=
new
OutboundOrderLog
();
BeanUtils
.
copyProperties
(
items
,
log
);
// 单个对象属性拷贝
log
.
setOrderId
(
items
.
getId
());
outboundOrderLogs
.
add
(
log
);
inventoryIds
.
add
(
log
.
getInventoryId
());
deleteOutboundOrdersById
(
items
.
getId
());
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/StorageLocationsServiceImpl.java
View file @
4551012a
...
...
@@ -76,7 +76,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
String
[]
AllowedCategoryIds
=
storageLocations2
.
getAllowedCategoryIds
().
split
(
","
);
for
(
String
AllowedCategoryId
:
AllowedCategoryIds
)
{
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
MaterialsCode
(
AllowedCategoryId
);
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
SapNo
(
AllowedCategoryId
);
if
(
materials
!=
null
&&
!
materials
.
isEmpty
())
{
Materials
materials1
=
materials
.
get
(
0
);
...
...
@@ -120,7 +120,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory
.
setCategoryId
(
categoryId
);
storageLocationsCategory
.
setCreateTime
(
DateUtils
.
getNowDate
());
storageLocationsCategory
.
setCreateUserCode
(
String
.
valueOf
(
SecurityUtils
.
getUserId
()));
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
MaterialsCode
(
categoryId
);
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
SapNo
(
categoryId
);
if
(
materials
!=
null
&&
!
materials
.
isEmpty
())
{
Materials
materials1
=
materials
.
get
(
0
);
storageLocationsCategory
.
setCategoryName
(
materials1
.
getMaterialName
());
...
...
@@ -159,7 +159,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocationsCategory
.
setCategoryId
(
categoryId
);
storageLocationsCategory
.
setUpdateTime
(
DateUtils
.
getNowDate
());
storageLocationsCategory
.
setUpdateUserCode
(
String
.
valueOf
(
SecurityUtils
.
getUserId
()));
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
MaterialsCode
(
categoryId
);
List
<
Materials
>
materials
=
materialsMapper
.
selectMaterialsBy
SapNo
(
categoryId
);
if
(
materials
!=
null
&&
!
materials
.
isEmpty
())
{
Materials
materials1
=
materials
.
get
(
0
);
storageLocationsCategory
.
setCategoryName
(
materials1
.
getMaterialName
());
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/InboundOrderItemsMapper.xml
View file @
4551012a
...
...
@@ -4,7 +4,7 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.ruoyi.inventory.mapper.InboundOrderItemsMapper"
>
<resultMap
type=
"InboundOrderItems"
id=
"InboundOrderItemsResult"
>
<resultMap
type=
"
com.ruoyi.inventory.domain.
InboundOrderItems"
id=
"InboundOrderItemsResult"
>
<result
property=
"id"
column=
"id"
/>
<result
property=
"orderId"
column=
"order_id"
/>
<result
property=
"materialId"
column=
"material_id"
/>
...
...
@@ -38,7 +38,7 @@
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,inbound_order_id from inbound_order_items
</sql>
<select
id=
"selectInboundOrderItemsList"
parameterType=
"InboundOrderItems"
resultMap=
"InboundOrderItemsResult"
>
<select
id=
"selectInboundOrderItemsList"
parameterType=
"
com.ruoyi.inventory.domain.
InboundOrderItems"
resultMap=
"InboundOrderItemsResult"
>
<include
refid=
"selectInboundOrderItemsVo"
/>
<where>
<if
test=
"inboundOrderId != null and inboundOrderId != ''"
>
and inbound_order_id = #{inboundOrderId}
</if>
...
...
@@ -73,7 +73,7 @@
<select
id=
"selectInboundOrderItemsListAndMaterialName"
parameterType=
"InboundOrderItems"
parameterType=
"
com.ruoyi.inventory.domain.
InboundOrderItems"
resultMap=
"InboundOrderItemsAndMnameResult"
>
SELECT
ii.id,
...
...
@@ -110,7 +110,7 @@
and inbound_order_id = #{inboundOrderId}
</if>
<if
test=
"orderId != null and orderId != ''"
>
order_id = #{orderId}
and
order_id = #{orderId}
</if>
<if
test=
"materialId != null and materialId != ''"
>
and material_id = #{materialId}
...
...
@@ -173,7 +173,7 @@
</where>
</select>
<insert
id=
"insertInboundOrderItems"
parameterType=
"InboundOrderItems"
>
<insert
id=
"insertInboundOrderItems"
parameterType=
"
com.ruoyi.inventory.domain.
InboundOrderItems"
>
insert into inbound_order_items
<trim
prefix=
"("
suffix=
")"
suffixOverrides=
","
>
<if
test=
"id != null"
>
id,
</if>
...
...
@@ -231,7 +231,7 @@
</trim>
</insert>
<update
id=
"updateInboundOrderItems"
parameterType=
"InboundOrderItems"
>
<update
id=
"updateInboundOrderItems"
parameterType=
"
com.ruoyi.inventory.domain.
InboundOrderItems"
>
update inbound_order_items
<trim
prefix=
"SET"
suffixOverrides=
","
>
<if
test=
"orderId != null"
>
order_id = #{orderId},
</if>
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/MaterialsMapper.xml
View file @
4551012a
...
...
@@ -76,9 +76,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id}
order by sort_no asc
</select>
<select
id=
"selectMaterialsBy
MaterialsCode
"
parameterType=
"String"
resultMap=
"MaterialsResult"
>
<select
id=
"selectMaterialsBy
SapNo
"
parameterType=
"String"
resultMap=
"MaterialsResult"
>
<include
refid=
"selectMaterialsVo"
/>
where
material_code
= #{id}
where
sap_no
= #{id}
order by sort_no asc
</select>
<select
id=
"selectMaterialsByCategory"
parameterType=
"String"
resultMap=
"MaterialsResult"
>
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrderItemsMapper.xml
View file @
4551012a
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.ruoyi.inventory.mapper.OutboundOrderItemsMapper"
>
<resultMap
type=
"OutboundOrderItems"
id=
"OutboundOrderItemsResult"
>
...
...
@@ -58,6 +58,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result
property=
"updateTime"
column=
"update_time"
/>
<result
property=
"updateUserCode"
column=
"update_user_code"
/>
</resultMap>
<sql
id=
"selectOutboundOrderItemsVo"
>
select id, order_id, material_id, batch_code, warehouse_id, location_id, inventory_id, outbound_order_id, unit_price, 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
</sql>
...
...
@@ -65,6 +66,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select
id=
"selectOutboundOrderItemsList"
parameterType=
"OutboundOrderItems"
resultMap=
"OutboundOrderItemsResult"
>
<include
refid=
"selectOutboundOrderItemsVo"
/>
<where>
<if
test=
"isUsed == null"
>
is_used = 1
</if>
<if
test=
"isUsed != null"
>
is_used = #{isUsed}
</if>
<if
test=
"orderId != null and orderId != ''"
>
and order_id = #{orderId}
</if>
<if
test=
"materialId != null and materialId != ''"
>
and material_id = #{materialId}
</if>
<if
test=
"batchCode != null and batchCode != ''"
>
and batch_code = #{batchCode}
</if>
...
...
@@ -79,16 +86,23 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"itemStatus != null "
>
and item_status = #{itemStatus}
</if>
<if
test=
"shippedAt != null "
>
and shipped_at = #{shippedAt}
</if>
<if
test=
"shippedBy != null and shippedBy != ''"
>
and shipped_by = #{shippedBy}
</if>
<if
test=
"isUsed != null "
>
and is_used = #{isUsed}
</if>
<if
test=
"sortNo != null "
>
and sort_no = #{sortNo}
</if>
<if
test=
"createUserCode != null and createUserCode != ''"
>
and create_user_code = #{createUserCode}
</if>
<if
test=
"updateUserCode != null and updateUserCode != ''"
>
and update_user_code = #{updateUserCode}
</if>
</where>
</select>
<!-- 单条查询:默认查使用中,若手动传isUsed则覆盖 -->
<select
id=
"selectOutboundOrderItemsById"
parameterType=
"String"
resultMap=
"OutboundOrderItemsResult"
>
<include
refid=
"selectOutboundOrderItemsVo"
/>
where id = #{id}
<!-- 增加is_used过滤,避免查询已逻辑删除的数据 -->
<if
test=
"isUsed == null"
>
and is_used = 1
</if>
<if
test=
"isUsed != null"
>
and is_used = #{isUsed}
</if>
</select>
<insert
id=
"insertOutboundOrderItems"
parameterType=
"OutboundOrderItems"
>
...
...
@@ -112,6 +126,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"shippedAt != null"
>
shipped_at,
</if>
<if
test=
"shippedBy != null"
>
shipped_by,
</if>
<if
test=
"remark != null"
>
remark,
</if>
<if
test=
"isUsed == null"
>
is_used,
</if>
<if
test=
"isUsed != null"
>
is_used,
</if>
<if
test=
"sortNo != null"
>
sort_no,
</if>
<if
test=
"createTime != null"
>
create_time,
</if>
...
...
@@ -138,6 +153,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"shippedAt != null"
>
#{shippedAt},
</if>
<if
test=
"shippedBy != null"
>
#{shippedBy},
</if>
<if
test=
"remark != null"
>
#{remark},
</if>
<if
test=
"isUsed == null"
>
1,
</if>
<if
test=
"isUsed != null"
>
#{isUsed},
</if>
<if
test=
"sortNo != null"
>
#{sortNo},
</if>
<if
test=
"createTime != null"
>
#{createTime},
</if>
...
...
@@ -177,10 +193,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where id = #{id}
</update>
<delete
id=
"deleteOutboundOrderItemsById"
parameterType=
"String"
>
delete from outbound_order_items where id = #{id}
</delete>
<!-- 单条删除:逻辑删除 -->
<update
id=
"deleteOutboundOrderItemsById"
parameterType=
"String"
>
update outbound_order_items
set is_used = 0
where id = #{id}
</update>
<!-- 统计查询:默认查is_used=1,支持手动传isUsed覆盖 -->
<select
id=
"selectOutboundOrderItemsStatistics"
parameterType=
"OutboundOrderItemsStatisticsVO"
resultMap=
"OutboundOrderItemsStatisticsVoResult"
>
...
...
@@ -211,7 +231,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
oi.update_user_code
FROM outbound_order_items oi
LEFT JOIN outbound_orders o ON oi.outbound_order_id = o.id
WHERE oi.is_used = 1
<where>
<if
test=
"isUsed == null"
>
oi.is_used = 1
</if>
<if
test=
"isUsed != null"
>
oi.is_used = #{isUsed}
</if>
<if
test=
"orderId != null and orderId != ''"
>
AND o.order_id LIKE CONCAT('%', #{orderId}, '%')
</if>
...
...
@@ -233,14 +259,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"itemStatus != null and itemStatus != ''"
>
AND oi.item_status = #{itemStatus}
</if>
</where>
ORDER BY oi.create_time DESC
</select>
<delete
id=
"deleteOutboundOrderItemsByIds"
parameterType=
"String"
>
delete from outbound_order_items where id in
<!-- 批量删除:逻辑删除 -->
<update
id=
"deleteOutboundOrderItemsByIds"
parameterType=
"String"
>
update outbound_order_items
set is_used = 0
where id in
<foreach
item=
"id"
collection=
"array"
open=
"("
separator=
","
close=
")"
>
#{id}
</foreach>
</
dele
te>
</
upda
te>
</mapper>
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrderLogMapper.xml
View file @
4551012a
...
...
@@ -24,7 +24,7 @@
<select
id=
"selectOutboundOrderLogList"
parameterType=
"OutboundOrderLog"
resultMap=
"OutboundOrderLogResult"
>
<include
refid=
"selectOutboundOrderLogVo"
/>
<where>
where is_used=1
<if
test=
"orderId != null and orderId != ''"
>
and order_id = #{orderId}
</if>
<if
test=
"inventoryId != null and inventoryId != ''"
>
and inventory_id = #{inventoryId}
</if>
<if
test=
"materialId != null and materialId != ''"
>
and material_id = #{materialId}
</if>
...
...
@@ -32,34 +32,29 @@
<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>
<
select
id=
"deleteLog"
parameterType=
"OutboundOrderLog"
resultMap=
"OutboundOrderLogResult
"
>
delete from outbound_order_log
<
update
id=
"deleteLog"
parameterType=
"OutboundOrderLog
"
>
update outbound_order_log set is_used=0
<where>
<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=
"itemStatus != null "
>
and item_status = #{itemStatus}
</if>
<!-- 补充inventory_id条件 -->
<if
test=
"inventoryId != null and inventoryId != ''"
>
and inventory_id = #{inventoryId}
</if>
</where>
</
select
>
</
update
>
<!-- 修正参数错误:原#{id}改为#{inventoryId} -->
<select
id=
"selectLockedQuantityByInventory"
parameterType=
"OutboundOrderLog"
resultType=
"java.lang.Long"
>
select ifnull(sum(actual_quantity), 0)
from outbound_order_log
where item_status=1
where item_status=1
and is_used=1
<if
test=
"inventoryId != null and inventoryId != ''"
>
and inventory_id = #{inventoryId}
</if>
</select>
<select
id=
"selectOutboundOrderLogById"
parameterType=
"String"
resultMap=
"OutboundOrderLogResult"
>
<include
refid=
"selectOutboundOrderLogVo"
/>
where id = #{id}
where id = #{id}
and is_used=1
</select>
<!-- 插入语句补充inventory_id -->
...
...
@@ -105,20 +100,20 @@
where id = #{id}
</update>
<
dele
te
id=
"deleteOutboundOrderLogById"
parameterType=
"String"
>
delete from outbound_order_log
where id = #{id}
</
dele
te>
<
upda
te
id=
"deleteOutboundOrderLogById"
parameterType=
"String"
>
update outbound_order_log set is_used=0
where id = #{id}
</
upda
te>
<
dele
te
id=
"deleteOutboundOrderLogByOrdersId"
parameterType=
"String"
>
delete from outbound_order_log
where order_id = #{id}
</
dele
te>
<
upda
te
id=
"deleteOutboundOrderLogByOrdersId"
parameterType=
"String"
>
update outbound_order_log set is_used=0
where order_id = #{id}
</
upda
te>
<
dele
te
id=
"deleteOutboundOrderLogByOrdersIds"
parameterType=
"String"
>
delete from outbound_order_log
where order_id in
<
upda
te
id=
"deleteOutboundOrderLogByOrdersIds"
parameterType=
"String"
>
update outbound_order_log set is_used=0
where order_id in
<foreach
item=
"id"
collection=
"array"
open=
"("
separator=
","
close=
")"
>
#{id}
</foreach>
</
dele
te>
</
upda
te>
<!-- 批量插入补充inventory_id -->
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrdersMapper.xml
View file @
4551012a
...
...
@@ -4,7 +4,7 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper
namespace=
"com.ruoyi.inventory.mapper.OutboundOrdersMapper"
>
<resultMap
type=
"OutboundOrders"
id=
"OutboundOrdersResult"
>
<resultMap
type=
"
com.ruoyi.inventory.domain.
OutboundOrders"
id=
"OutboundOrdersResult"
>
<result
property=
"id"
column=
"id"
/>
<result
property=
"orderId"
column=
"order_id"
/>
<result
property=
"systemNo"
column=
"system_no"
/>
...
...
@@ -27,12 +27,17 @@
<result
property=
"updateUserCode"
column=
"update_user_code"
/>
</resultMap>
<resultMap
id=
"OutboundOrdersOutboundOrderItemsResult"
type=
"OutboundOrders"
extends=
"OutboundOrdersResult"
>
<collection
property=
"outboundOrderItemsList"
ofType=
"OutboundOrderItems"
column=
"id"
select=
"selectOutboundOrderItemsList"
/>
<!-- 核心修复:删除重复的collection,只保留一个正确的关联配置 -->
<resultMap
id=
"OutboundOrdersOutboundOrderItemsResult"
type=
"com.ruoyi.inventory.domain.OutboundOrders"
extends=
"OutboundOrdersResult"
>
<collection
property=
"outboundOrderItemsList"
ofType=
"com.ruoyi.inventory.domain.OutboundOrderItems"
column=
"id"
select=
"selectOutboundOrderItemsList"
/>
</resultMap>
<!--
修复:仅保留子表outbound_order_items的字段映射,删除错误的主表字段
-->
<resultMap
type=
"OutboundOrderItems"
id=
"OutboundOrderItemsResult"
>
<!--
原主表结果映射:仅修复InboundOrderId大小写,其余完全保留
-->
<resultMap
type=
"
com.ruoyi.inventory.domain.
OutboundOrderItems"
id=
"OutboundOrderItemsResult"
>
<result
property=
"id"
column=
"id"
/>
<result
property=
"orderId"
column=
"order_id"
/>
<result
property=
"materialId"
column=
"material_id"
/>
...
...
@@ -57,17 +62,17 @@
<result
property=
"createUserCode"
column=
"create_user_code"
/>
<result
property=
"updateTime"
column=
"update_time"
/>
<result
property=
"updateUserCode"
column=
"update_user_code"
/>
<result
property=
"
I
nboundOrderId"
column=
"inbound_order_id"
/>
<result
property=
"
i
nboundOrderId"
column=
"inbound_order_id"
/>
</resultMap>
<!-- 以下所有代码完全保留,不做任何修改 -->
<sql
id=
"selectOutboundOrdersVo"
>
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_orders
</sql>
<select
id=
"selectOutboundOrdersList"
parameterType=
"OutboundOrders"
resultMap=
"OutboundOrdersResult"
>
<include
refid=
"selectOutboundOrdersVo"
/>
<where>
where is_used = 1
<if
test=
"orderId != null and orderId != ''"
>
and order_id = #{orderId}
</if>
<if
test=
"systemNo != null and systemNo != ''"
>
and system_no = #{systemNo}
</if>
<if
test=
"orderTypeId != null and orderTypeId != ''"
>
and order_type_id = #{orderTypeId}
</if>
...
...
@@ -80,24 +85,21 @@
<if
test=
"totalPlannedQuantity != null "
>
and total_planned_quantity = #{totalPlannedQuantity}
</if>
<if
test=
"totalActualQuantity != null "
>
and total_actual_quantity = #{totalActualQuantity}
</if>
<if
test=
"totalPackages != null "
>
and total_packages = #{totalPackages}
</if>
<if
test=
"isUsed != null "
>
and is_used = #{isUsed}
</if>
<if
test=
"sortNo != null "
>
and sort_no = #{sortNo}
</if>
<if
test=
"createUserCode != null and createUserCode != ''"
>
and create_user_code = #{createUserCode}
</if>
<if
test=
"updateUserCode != null and updateUserCode != ''"
>
and update_user_code = #{updateUserCode}
</if>
</where>
</select>
<select
id=
"selectOutboundOrdersById"
parameterType=
"String"
resultMap=
"OutboundOrdersOutboundOrderItemsResult"
>
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code
from outbound_orders
where id = #{id}
where id = #{id}
and is_used=1
</select>
<!-- 仅保留子表查询逻辑,字段完整且映射正确 -->
<select
id=
"selectOutboundOrderItemsList"
parameterType=
"String"
resultMap=
"OutboundOrderItemsResult"
>
select id, order_id, material_id, batch_code, warehouse_id, location_id, inventory_id, outbound_order_id, unit_price, 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 o
rder_id = #{id}
where o
utbound_order_id = #{id} AND is_used=1
</select>
<insert
id=
"insertOutboundOrders"
parameterType=
"OutboundOrders"
>
...
...
@@ -174,26 +176,26 @@
where id = #{id}
</update>
<
dele
te
id=
"deleteOutboundOrdersById"
parameterType=
"String"
>
delete from outbound_orders
where id = #{id}
</
dele
te>
<
upda
te
id=
"deleteOutboundOrdersById"
parameterType=
"String"
>
update outbound_orders set is_used=0
where id = #{id}
</
upda
te>
<
dele
te
id=
"deleteOutboundOrdersByIds"
parameterType=
"String"
>
delete from outbound_orders
where id in
<
upda
te
id=
"deleteOutboundOrdersByIds"
parameterType=
"String"
>
update outbound_orders set is_used=0
where id in
<foreach
item=
"id"
collection=
"array"
open=
"("
separator=
","
close=
")"
>
#{id}
</foreach>
</
dele
te>
</
upda
te>
<
dele
te
id=
"deleteOutboundOrderItemsByOrderIds"
parameterType=
"String"
>
delete from outbound_order_items
where outbound_order_id in
<
upda
te
id=
"deleteOutboundOrderItemsByOrderIds"
parameterType=
"String"
>
update outbound_order_items set is_used=0
where outbound_order_id in
<foreach
item=
"orderId"
collection=
"array"
open=
"("
separator=
","
close=
")"
>
#{orderId}
</foreach>
</
dele
te>
</
upda
te>
<delete
id=
"deleteOutboundOrderItemsByOrderId"
parameterType=
"String"
>
delete from outbound_order_items
where outbound_order_id = #{orderId}
update outbound_order_items set is_used=0
where outbound_order_id = #{orderId}
</delete>
<insert
id=
"batchOutboundOrderItems"
>
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论