|
@@ -284,6 +284,10 @@ export default {
|
|
|
*/
|
|
|
selectedStockId: null,
|
|
|
|
|
|
+ // 选择状态:存储已选中的行唯一键(跨分页)
|
|
|
+ /** @type {Array<string|number>} */
|
|
|
+ selectedRowKeys: [],
|
|
|
+
|
|
|
/** 当前库存 */
|
|
|
currentInventory: null,
|
|
|
|
|
@@ -332,6 +336,12 @@ export default {
|
|
|
const start = (page - 1) * size
|
|
|
const end = start + size
|
|
|
return list.slice(start, end)
|
|
|
+ },
|
|
|
+
|
|
|
+ // 是否有选中项(用于禁用批量删除按钮)
|
|
|
+ /** @returns {boolean} */
|
|
|
+ hasSelection() {
|
|
|
+ return Array.isArray(this.selectedRowKeys) && this.selectedRowKeys.length > 0
|
|
|
}
|
|
|
},
|
|
|
|
|
@@ -1200,6 +1210,8 @@ export default {
|
|
|
this.stockDescList = []
|
|
|
this.stockSelectOptions = []
|
|
|
this.selectedStockId = null
|
|
|
+ // 重置选择状态
|
|
|
+ this.selectedRowKeys = []
|
|
|
const res = await getUserLinkGoods()
|
|
|
const payload = res && res.data && res.data.data ? res.data.data : null
|
|
|
const brandList = (payload && payload.pjpfBrandDescList) || []
|
|
@@ -1207,13 +1219,10 @@ export default {
|
|
|
this.brandDescList = brandList
|
|
|
// 存储库存列表供选择用,不直接展示到表格
|
|
|
this.stockDescList = stockList
|
|
|
- // 构造下拉选项,label 使用 cname,value 使用 id
|
|
|
- this.stockSelectOptions = stockList.map(item => ({
|
|
|
- label: item.cname,
|
|
|
- value: item.id
|
|
|
- }))
|
|
|
// 默认显示全部物料至下方表格,预测数量默认 0,用户可手动删除不需要的物料
|
|
|
this.stockTableData = stockList.map(item => ({ ...item, forecastQuantity: 0 }))
|
|
|
+ // 根据表格中已有的物料,过滤下拉选项
|
|
|
+ this.updateStockSelectOptions()
|
|
|
} catch (e) {
|
|
|
console.error('加载用户关联商品失败:', e)
|
|
|
this.$message.error(e.message || '加载用户关联商品失败')
|
|
@@ -1235,7 +1244,7 @@ export default {
|
|
|
return
|
|
|
}
|
|
|
// 查找明细
|
|
|
- const stock = this.stockDescList.find(s => s.id === this.selectedStockId)
|
|
|
+ const stock = this.stockDescList.find(s => String(s.id) === this.selectedStockId)
|
|
|
if (!stock) {
|
|
|
this.$message.error('未找到所选物料数据,请重新选择')
|
|
|
return
|
|
@@ -1244,15 +1253,15 @@ export default {
|
|
|
// 防止重复导入 - 使用多个字段进行更全面的重复检查
|
|
|
const exists = this.stockTableData.some(row => {
|
|
|
// 优先使用 id 进行匹配
|
|
|
- if (row.id && stock.id && row.id === stock.id) {
|
|
|
+ if (row.id !== undefined && row.id !== null && stock.id !== undefined && stock.id !== null && String(row.id) === String(stock.id)) {
|
|
|
return true
|
|
|
}
|
|
|
// 使用 goodsId 进行匹配
|
|
|
- if (row.goodsId && stock.goodsId && row.goodsId === stock.goodsId) {
|
|
|
+ if (row.goodsId !== undefined && row.goodsId !== null && stock.goodsId !== undefined && stock.goodsId !== null && String(row.goodsId) === String(stock.goodsId)) {
|
|
|
return true
|
|
|
}
|
|
|
// 使用 code 进行匹配
|
|
|
- if (row.code && stock.code && row.code === stock.code) {
|
|
|
+ if (row.code && stock.code && String(row.code) === String(stock.code)) {
|
|
|
return true
|
|
|
}
|
|
|
return false
|
|
@@ -1268,6 +1277,8 @@ export default {
|
|
|
this.stockTableData.push({ ...stock, forecastQuantity: 0 })
|
|
|
// 清空已选
|
|
|
this.selectedStockId = null
|
|
|
+ // 导入后更新下拉选项(过滤掉已在表格中的物料)
|
|
|
+ this.updateStockSelectOptions()
|
|
|
|
|
|
// 导入后保持当前页不变;无需校正页码(不会超过最大页)
|
|
|
},
|
|
@@ -1304,11 +1315,22 @@ export default {
|
|
|
cancelButtonText: '取消'
|
|
|
})
|
|
|
|
|
|
+ // 记录待删除行的唯一键,用于同步选择状态
|
|
|
+ const removedKey = this.getRowUniqueKey(row)
|
|
|
+
|
|
|
this.$delete(this.stockTableData, removeIndex)
|
|
|
|
|
|
+ // 同步移除选择状态中的该行
|
|
|
+ if (removedKey != null) {
|
|
|
+ this.selectedRowKeys = (Array.isArray(this.selectedRowKeys) ? this.selectedRowKeys : []).filter(k => k !== removedKey)
|
|
|
+ }
|
|
|
+
|
|
|
// 删除后校正页码:若当前页无数据则回退到上一页
|
|
|
this.normalizePageAfterMutations()
|
|
|
|
|
|
+ // 删除后更新下拉选项(被删除的物料重新回到可选择项)
|
|
|
+ this.updateStockSelectOptions()
|
|
|
+
|
|
|
this.$message && this.$message.success('已删除')
|
|
|
} catch (e) {
|
|
|
// 用户取消不提示为错误,其他情况做日志记录
|
|
@@ -1320,6 +1342,139 @@ export default {
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
+ * 表格选择变更(el-table @selection-change)
|
|
|
+ * @param {Array<import('./types').ForecastFormMixinData['stockTableData'][number]>} selection
|
|
|
+ * @returns {void}
|
|
|
+ */
|
|
|
+ handleSelectionChange(selection) {
|
|
|
+ // 基于当前页数据与新选择集,维护跨页 selection 的“并集 - 当前页未选差集”
|
|
|
+ const currentPageRows = Array.isArray(this.pagedStockTableData) ? this.pagedStockTableData : []
|
|
|
+ const currentPageKeys = new Set(
|
|
|
+ currentPageRows
|
|
|
+ .map(r => this.getRowUniqueKey(r))
|
|
|
+ .filter(k => k !== undefined && k !== null && k !== '')
|
|
|
+ )
|
|
|
+
|
|
|
+ const nextSelectedOnPage = new Set(
|
|
|
+ Array.isArray(selection)
|
|
|
+ ? selection
|
|
|
+ .map(r => this.getRowUniqueKey(r))
|
|
|
+ .filter(k => k !== undefined && k !== null && k !== '')
|
|
|
+ : []
|
|
|
+ )
|
|
|
+
|
|
|
+ const prev = Array.isArray(this.selectedRowKeys) ? this.selectedRowKeys : []
|
|
|
+ const union = new Set(prev)
|
|
|
+
|
|
|
+ // 1) 移除当前页中被取消勾选的键
|
|
|
+ currentPageKeys.forEach(k => {
|
|
|
+ if (!nextSelectedOnPage.has(k)) {
|
|
|
+ union.delete(k)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ // 2) 加入当前页新勾选的键
|
|
|
+ nextSelectedOnPage.forEach(k => {
|
|
|
+ union.add(k)
|
|
|
+ })
|
|
|
+
|
|
|
+ this.selectedRowKeys = Array.from(union)
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 行唯一键生成函数(绑定给 :row-key)
|
|
|
+ * @param {import('./types').ForecastFormMixinData['stockTableData'][number]} row
|
|
|
+ * @returns {string | number}
|
|
|
+ */
|
|
|
+ getRowUniqueKey(row) {
|
|
|
+ if (!row || typeof row !== 'object') return ''
|
|
|
+ // 优先使用后端提供的 id
|
|
|
+ if (row.id !== undefined && row.id !== null) return /** @type {any} */ (row.id)
|
|
|
+ // 其次使用 goodsId
|
|
|
+ if (row.goodsId !== undefined && row.goodsId !== null) return /** @type {any} */ (row.goodsId)
|
|
|
+ // 再次使用 code
|
|
|
+ if (row.code) return String(row.code)
|
|
|
+ // 兜底:用可读信息组合
|
|
|
+ const name = /** @type {any} */ (row.cname || '')
|
|
|
+ const code = /** @type {any} */ (row.code || '')
|
|
|
+ return `${String(name)}-${String(code)}`
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新物料下拉选项(过滤已在表格中的物料)
|
|
|
+ * @returns {void}
|
|
|
+ */
|
|
|
+ updateStockSelectOptions() {
|
|
|
+ try {
|
|
|
+ const table = Array.isArray(this.stockTableData) ? this.stockTableData : []
|
|
|
+ const source = Array.isArray(this.stockDescList) ? this.stockDescList : []
|
|
|
+
|
|
|
+ const idSet = new Set(table.filter(r => r && r.id !== undefined && r.id !== null).map(r => String(r.id)))
|
|
|
+ const goodsIdSet = new Set(table.filter(r => r && r.goodsId !== undefined && r.goodsId !== null).map(r => String(r.goodsId)))
|
|
|
+ const codeSet = new Set(table.filter(r => r && r.code).map(r => String(r.code)))
|
|
|
+
|
|
|
+ const options = source
|
|
|
+ .filter(item => {
|
|
|
+ const byId = item && item.id !== undefined && item.id !== null && idSet.has(String(item.id))
|
|
|
+ const byGoods = item && item.goodsId !== undefined && item.goodsId !== null && goodsIdSet.has(String(item.goodsId))
|
|
|
+ const byCode = item && item.code && codeSet.has(String(item.code))
|
|
|
+ return !(byId || byGoods || byCode)
|
|
|
+ })
|
|
|
+ .map(item => ({
|
|
|
+ label: /** @type {any} */ (item.cname || item.code || ''),
|
|
|
+ value: /** @type {any} */ (String(item.id))
|
|
|
+ }))
|
|
|
+
|
|
|
+ this.stockSelectOptions = options
|
|
|
+ // 如果当前选中不在可选项中,则清空
|
|
|
+ const hasSelected = options.some(opt => opt && opt.value === this.selectedStockId)
|
|
|
+ if (!hasSelected) {
|
|
|
+ this.selectedStockId = null
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ console.warn('更新物料下拉选项失败:', e)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量删除已选中的物料
|
|
|
+ * @returns {Promise<void>}
|
|
|
+ */
|
|
|
+ async handleBatchDelete() {
|
|
|
+ try {
|
|
|
+ const keys = new Set(Array.isArray(this.selectedRowKeys) ? this.selectedRowKeys : [])
|
|
|
+ if (keys.size === 0) {
|
|
|
+ this.$message && this.$message.warning('请先在下方表格选择要删除的物料')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ await this.$confirm('确认删除已选中的物料吗?删除后可重新通过上方选择器导入。', '提示', {
|
|
|
+ type: 'warning',
|
|
|
+ confirmButtonText: '删除',
|
|
|
+ cancelButtonText: '取消'
|
|
|
+ })
|
|
|
+
|
|
|
+ const filtered = (Array.isArray(this.stockTableData) ? this.stockTableData : []).filter(row => {
|
|
|
+ const key = this.getRowUniqueKey(row)
|
|
|
+ return !keys.has(key)
|
|
|
+ })
|
|
|
+ this.stockTableData = filtered
|
|
|
+
|
|
|
+ // 清空选择并校正页码
|
|
|
+ this.selectedRowKeys = []
|
|
|
+ this.normalizePageAfterMutations()
|
|
|
+ // 刷新下拉选项
|
|
|
+ this.updateStockSelectOptions()
|
|
|
+
|
|
|
+ this.$message && this.$message.success('已删除所选物料')
|
|
|
+ } catch (e) {
|
|
|
+ if (e && e !== 'cancel') {
|
|
|
+ console.error('批量删除失败:', e)
|
|
|
+ this.$message && this.$message.error('批量删除失败,请稍后重试')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
* 页容量变更(el-pagination: size-change)
|
|
|
* @param {number} size
|
|
|
* @returns {void}
|