Commit 4551012a by yubin

出库

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