From 1d95b134d85c3c60cf0e72739888c9741a0bb1ee Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期五, 10 四月 2026 13:20:39 +0800
Subject: [PATCH] #页面优化
---
rsf-design/src/locales/langs/en.json | 234 +++
rsf-design/src/locales/langs/zh.json | 234 +++
rsf-design/src/api/wh-mat.js | 147 ++
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-group-dialog.vue | 113 +
rsf-design/src/views/basic-info/bas-station-area/basStationAreaTable.columns.js | 42
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-dialog.vue | 380 ++++++
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-bind-loc-dialog.vue | 184 +++
rsf-design/src/views/basic-info/bas-station-area/basStationAreaPage.helpers.js | 89 +
rsf-design/src/views/basic-info/wh-mat/whMatPage.helpers.js | 446 ++++++-
rsf-design/src/hooks/core/useAuth.js | 1
rsf-design/src/views/basic-info/wh-mat/index.vue | 996 ++++++++++++++++
rsf-design/src/views/basic-info/wh-mat/whMatTable.columns.js | 118 +
rsf-design/src/views/basic-info/bas-station-area/modules/bas-station-area-dialog.vue | 215 +--
rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-dialog.vue | 232 ++++
14 files changed, 3,082 insertions(+), 349 deletions(-)
diff --git a/rsf-design/src/api/wh-mat.js b/rsf-design/src/api/wh-mat.js
index ed04047..2bc5a50 100644
--- a/rsf-design/src/api/wh-mat.js
+++ b/rsf-design/src/api/wh-mat.js
@@ -4,13 +4,53 @@
return String(value ?? '').trim()
}
+function normalizeIds(ids) {
+ if (Array.isArray(ids)) {
+ return ids
+ .map((item) => Number(item))
+ .filter((item) => Number.isFinite(item))
+ .join(',')
+ }
+ return String(ids ?? '')
+ .split(',')
+ .map((item) => Number(item))
+ .filter((item) => Number.isFinite(item))
+ .join(',')
+}
+
+function normalizeIdList(ids) {
+ if (Array.isArray(ids)) {
+ return ids.map((item) => Number(item)).filter((item) => Number.isFinite(item))
+ }
+ return String(ids ?? '')
+ .split(',')
+ .map((item) => Number(item))
+ .filter((item) => Number.isFinite(item))
+}
+
function normalizeQueryParams(params = {}) {
+ const allowKeys = new Set([
+ 'condition',
+ 'code',
+ 'name',
+ 'spec',
+ 'model',
+ 'color',
+ 'size',
+ 'barcode',
+ 'groupId',
+ 'unit',
+ 'status',
+ 'flagCheck',
+ 'validWarn'
+ ])
const result = {
current: params.current || 1,
- pageSize: params.pageSize || params.size || 20
+ pageSize: params.pageSize || params.size || 20,
+ orderBy: normalizeText(params.orderBy) || 'create_time desc'
}
- ;['condition', 'code', 'name', 'spec', 'model', 'color', 'size', 'barcode', 'groupId'].forEach((key) => {
+ Array.from(allowKeys).forEach((key) => {
const value = params[key]
if (value === undefined || value === null || value === '') {
return
@@ -19,6 +59,29 @@
const trimmed = normalizeText(value)
if (trimmed) {
result[key] = trimmed
+ }
+ return
+ }
+ result[key] = value
+ })
+
+ Object.entries(params).forEach(([key, value]) => {
+ if (['current', 'pageSize', 'size', 'orderBy'].includes(key) || allowKeys.has(key)) {
+ return
+ }
+ if (value === undefined || value === null || value === '') {
+ return
+ }
+ if (typeof value === 'string') {
+ const trimmed = normalizeText(value)
+ if (trimmed) {
+ result[key] = trimmed
+ }
+ return
+ }
+ if (Array.isArray(value)) {
+ if (value.length) {
+ result[key] = value
}
return
}
@@ -45,6 +108,53 @@
return request.get({ url: `/matnr/${id}` })
}
+export function fetchGetMatnrMany(ids) {
+ return request.post({ url: `/matnr/many/${normalizeIds(ids)}` })
+}
+
+export function fetchEnabledFields() {
+ return request.get({ url: '/fields/enable/list' })
+}
+
+export function fetchSaveMatnr(params = {}) {
+ return request.post({ url: '/matnr/save', params })
+}
+
+export function fetchUpdateMatnr(params = {}) {
+ return request.post({ url: '/matnr/update', params })
+}
+
+export function fetchDeleteMatnr(ids) {
+ return request.post({ url: `/matnr/remove/${normalizeIds(ids)}` })
+}
+
+export function fetchBindMatnrGroup(payload = {}) {
+ return request.post({
+ url: '/matnr/group/bind',
+ params: {
+ ids: normalizeIdList(payload.ids),
+ ...(payload.groupId !== undefined && payload.groupId !== null && payload.groupId !== ''
+ ? { groupId: Number(payload.groupId) }
+ : {})
+ }
+ })
+}
+
+export function fetchBatchUpdateMatnr(payload = {}) {
+ const matnr = payload.matnr && typeof payload.matnr === 'object' ? payload.matnr : {}
+ return request.post({
+ url: '/matnr/batch/update',
+ params: {
+ ids: normalizeIdList(payload.ids),
+ matnr: Object.fromEntries(
+ Object.entries(matnr).filter(
+ ([, value]) => value !== undefined && value !== null && value !== ''
+ )
+ )
+ }
+ })
+}
+
export function fetchMatnrGroupTree(params = {}) {
return request.post({
url: '/matnrGroup/tree',
@@ -52,3 +162,36 @@
})
}
+export async function fetchExportMatnrReport(payload = {}, options = {}) {
+ return fetch(`${import.meta.env.VITE_API_URL}/matnr/export`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(options.headers || {})
+ },
+ body: JSON.stringify(payload)
+ })
+}
+
+export async function fetchDownloadMatnrTemplate(payload = {}, options = {}) {
+ return fetch(`${import.meta.env.VITE_API_URL}/matnr/template/download`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ ...(options.headers || {})
+ },
+ body: JSON.stringify(payload)
+ })
+}
+
+export function fetchImportMatnr(file) {
+ const formData = new FormData()
+ formData.append('file', file)
+ return request.post({
+ url: '/matnr/import',
+ data: formData,
+ headers: {
+ 'Content-Type': 'multipart/form-data'
+ }
+ })
+}
diff --git a/rsf-design/src/hooks/core/useAuth.js b/rsf-design/src/hooks/core/useAuth.js
index b222810..e7ffe24 100644
--- a/rsf-design/src/hooks/core/useAuth.js
+++ b/rsf-design/src/hooks/core/useAuth.js
@@ -28,6 +28,7 @@
const BUTTON_ACTION_MAP = {
query: 'list',
add: 'save',
+ update: 'update',
edit: 'update',
delete: 'remove'
}
diff --git a/rsf-design/src/locales/langs/en.json b/rsf-design/src/locales/langs/en.json
index 1bbe119..f4ef9d8 100644
--- a/rsf-design/src/locales/langs/en.json
+++ b/rsf-design/src/locales/langs/en.json
@@ -182,20 +182,11 @@
"setting": {
"menuType": {
"title": "Menu Layout",
- "list": [
- "Vertical",
- "Horizontal",
- "Mixed",
- "Dual"
- ]
+ "list": ["Vertical", "Horizontal", "Mixed", "Dual"]
},
"theme": {
"title": "Theme Style",
- "list": [
- "Light",
- "Dark",
- "System"
- ]
+ "list": ["Light", "Dark", "System"]
},
"menu": {
"title": "Menu Style"
@@ -205,17 +196,11 @@
},
"box": {
"title": "Box Style",
- "list": [
- "Border",
- "Shadow"
- ]
+ "list": ["Border", "Shadow"]
},
"container": {
"title": "Container Width",
- "list": [
- "Full",
- "Boxed"
- ]
+ "list": ["Full", "Boxed"]
},
"basics": {
"title": "Basic Config",
@@ -659,21 +644,21 @@
"send": "Send",
"renameDialogTitle": "Rename Session",
"sessionTitleField": "Session Title",
- "requestMetric": "Req: {value}",
- "sessionMetric": "Session: {id}",
- "promptMetric": "Prompt: {value}",
- "modelMetric": "Model: {value}",
- "promptLabel": "Prompt",
- "modelLabel": "Model",
- "modelSelectorLabel": "Chat Model",
- "modelSelectorHint": "Switching only affects subsequent replies in this session and does not change the global default model.",
- "modelSwitchFailed": "Failed to switch the chat model",
- "defaultModelSuffix": "(Default)",
- "mcpMetric": "MCP: {value}",
- "historyMetric": "History: {value}",
- "mcpLabel": "MCP",
- "historyLabel": "History",
- "recentMetric": "Recent: {value}",
+ "requestMetric": "Req: {value}",
+ "sessionMetric": "Session: {id}",
+ "promptMetric": "Prompt: {value}",
+ "modelMetric": "Model: {value}",
+ "promptLabel": "Prompt",
+ "modelLabel": "Model",
+ "modelSelectorLabel": "Chat Model",
+ "modelSelectorHint": "Switching only affects subsequent replies in this session and does not change the global default model.",
+ "modelSwitchFailed": "Failed to switch the chat model",
+ "defaultModelSuffix": "(Default)",
+ "mcpMetric": "MCP: {value}",
+ "historyMetric": "History: {value}",
+ "mcpLabel": "MCP",
+ "historyLabel": "History",
+ "recentMetric": "Recent: {value}",
"elapsedMetric": "Elapsed: {value} ms",
"firstTokenMetric": "First token: {value} ms",
"tokenMetric": "Tokens: prompt {prompt} / completion {completion} / total {total}",
@@ -848,12 +833,12 @@
"systemPrompt": "System Prompt",
"userPromptTemplate": "User Prompt Template"
},
- "dialog": {
- "titleCreate": "Create Prompt",
- "titleEdit": "Edit Prompt",
- "titleDetail": "Prompt Detail",
- "defaultPreviewInput": "Please summarize the current input",
- "previewTitle": "Render Preview",
+ "dialog": {
+ "titleCreate": "Create Prompt",
+ "titleEdit": "Edit Prompt",
+ "titleDetail": "Prompt Detail",
+ "defaultPreviewInput": "Please summarize the current input",
+ "previewTitle": "Render Preview",
"previewDescription": "Input sample content and metadata to preview the final rendering.",
"previewAction": "Render Preview",
"previewResolvedVariables": "Resolved variables: {value}",
@@ -2465,8 +2450,20 @@
},
"whMat": {
"title": "Materials",
+ "entity": "Material",
"labels": {
"allMaterials": "All Materials"
+ },
+ "actions": {
+ "add": "Add Material",
+ "batchGroup": "Batch Group",
+ "batchWarn": "Batch Warning",
+ "batchFlagCheck": "Batch QC",
+ "batchStatus": "Batch Status",
+ "batchStockLevel": "Batch Stock Level",
+ "bindLoc": "Bind Location",
+ "import": "Import",
+ "downloadTemplate": "Download Template"
},
"search": {
"groupKeywordPlaceholder": "Search material groups",
@@ -2478,19 +2475,76 @@
"codePlaceholder": "Enter material code",
"name": "Material Name",
"namePlaceholder": "Enter material name",
+ "groupId": "Material Group",
+ "groupIdPlaceholder": "Select material group",
+ "platCode": "Platform Code",
+ "platCodePlaceholder": "Enter platform code",
"spec": "Specification",
"specPlaceholder": "Enter specification",
+ "model": "Model",
+ "modelPlaceholder": "Enter model",
+ "color": "Color",
+ "colorPlaceholder": "Enter color",
+ "size": "Size",
+ "sizePlaceholder": "Enter size",
+ "unit": "Unit",
+ "unitPlaceholder": "Enter unit",
+ "purUnit": "Purchase Unit",
+ "purUnitPlaceholder": "Enter purchase unit",
+ "stockUnit": "Stock Unit",
+ "stockUnitPlaceholder": "Enter stock unit",
"barcode": "Barcode",
- "barcodePlaceholder": "Enter barcode"
+ "barcodePlaceholder": "Enter barcode",
+ "describle": "Description",
+ "describlePlaceholder": "Enter description",
+ "rglarId": "Batch Rule",
+ "rglarIdPlaceholder": "Select batch rule",
+ "weight": "Weight",
+ "weightPlaceholder": "Enter weight",
+ "nromNum": "Standard Pack Qty",
+ "nromNumPlaceholder": "Enter standard pack qty",
+ "stockLevel": "Stock Level",
+ "stockLevelPlaceholder": "Select stock level",
+ "flagLabelMange": "Label Management",
+ "flagLabelMangePlaceholder": "Select label management",
+ "safeQty": "Safe Qty",
+ "safeQtyPlaceholder": "Enter safe qty",
+ "minQty": "Min Qty",
+ "minQtyPlaceholder": "Enter min qty",
+ "maxQty": "Max Qty",
+ "maxQtyPlaceholder": "Enter max qty",
+ "stagn": "Stagnant Days",
+ "stagnPlaceholder": "Enter stagnant days",
+ "valid": "Shelf Life Days",
+ "validPlaceholder": "Enter shelf life days",
+ "validWarn": "Expiry Warning",
+ "validWarnPlaceholder": "Enter expiry warning",
+ "flagCheck": "Exempt Inspection",
+ "flagCheckPlaceholder": "Select exempt inspection",
+ "status": "Status",
+ "statusPlaceholder": "Select status",
+ "memo": "Memo",
+ "memoPlaceholder": "Enter memo",
+ "dynamicPlaceholder": "Enter {field}"
},
"messages": {
"emptyGroups": "No material groups",
"groupTimeout": "Material groups loading timed out and waiting has stopped",
"groupLoadFailed": "Failed to load material groups",
+ "serialRuleTimeout": "Batch rules loading timed out and waiting has stopped",
+ "serialRuleLoadFailed": "Failed to load batch rules",
"listTimeout": "Material list loading timed out and waiting has stopped",
"listLoadFailed": "Failed to load material list",
"detailTimeout": "Material detail timed out and waiting has stopped",
- "detailLoadFailed": "Failed to load material detail"
+ "detailLoadFailed": "Failed to load material detail",
+ "importSuccess": "Material import succeeded",
+ "importFailed": "Material import failed",
+ "templateDownloadSuccess": "Template downloaded successfully",
+ "templateDownloadFailed": "Template download failed",
+ "enabledFieldsTimeout": "Dynamic fields loading timed out",
+ "bindLocTimeout": "Bind-location options loading timed out",
+ "bindLocLoadFailed": "Failed to load bind-location options",
+ "selectAtLeastOne": "Please select at least one material"
},
"table": {
"code": "Material Code",
@@ -2501,6 +2555,102 @@
"spec": "Specification",
"model": "Model"
},
+ "dialog": {
+ "titleCreate": "Add Material",
+ "titleEdit": "Edit Material",
+ "tabs": {
+ "basic": "Basic Information",
+ "control": "Control Information",
+ "batchRule": "Batch Rule"
+ },
+ "fields": {
+ "code": "Material Code",
+ "name": "Material Name",
+ "groupId": "Material Group",
+ "useOrgName": "Using Organization",
+ "spec": "Specification",
+ "model": "Model",
+ "color": "Color",
+ "size": "Size",
+ "weight": "Weight",
+ "unit": "Unit",
+ "purUnit": "Purchase Unit",
+ "describle": "Description",
+ "safeQty": "Safety Stock",
+ "minQty": "Minimum Stock",
+ "maxQty": "Maximum Stock",
+ "stagn": "Stagnation Days",
+ "valid": "Shelf Life Days",
+ "validWarn": "Validity Warning Threshold",
+ "flagCheck": "Exempt Inspection",
+ "rglarId": "Batch Rule"
+ },
+ "placeholders": {
+ "code": "Enter material code",
+ "name": "Enter material name",
+ "groupId": "Select material group",
+ "useOrgName": "Enter using organization",
+ "spec": "Enter specification",
+ "model": "Enter model",
+ "color": "Enter color",
+ "size": "Enter size",
+ "unit": "Enter unit",
+ "purUnit": "Enter purchase unit",
+ "describle": "Enter description",
+ "flagCheck": "Select exempt inspection",
+ "rglarId": "Select batch rule"
+ },
+ "validation": {
+ "code": "Please enter material code",
+ "name": "Please enter material name",
+ "groupId": "Please select material group"
+ }
+ },
+ "batchDialog": {
+ "titles": {
+ "status": "Batch Update Status",
+ "stockLevel": "Batch Update Stock Level",
+ "validWarn": "Batch Update Expiry Warning",
+ "flagCheck": "Batch Update QC Status"
+ },
+ "fields": {
+ "stockLevel": "Stock Level"
+ },
+ "placeholders": {
+ "stockLevel": "Select stock level",
+ "validWarn": "Enter expiry warning",
+ "valid": "Enter shelf life days",
+ "flagCheck": "Select exempt inspection"
+ },
+ "validation": {
+ "status": "Please select status",
+ "stockLevel": "Please select stock level",
+ "validWarn": "Please enter expiry warning",
+ "valid": "Please enter shelf life days",
+ "flagCheck": "Please select exempt inspection"
+ }
+ },
+ "batchGroupDialog": {
+ "title": "Batch Update Material Group"
+ },
+ "bindLocDialog": {
+ "title": "Bind Location",
+ "fields": {
+ "areaMatId": "Area Material",
+ "areaId": "Area",
+ "locId": "Location"
+ },
+ "placeholders": {
+ "areaMatId": "Select area material",
+ "areaId": "Select area",
+ "locId": "Select locations"
+ },
+ "validation": {
+ "areaMatId": "Please select area material",
+ "areaId": "Please select area",
+ "locId": "Please select locations"
+ }
+ },
"detail": {
"title": "Material Detail",
"sections": {
diff --git a/rsf-design/src/locales/langs/zh.json b/rsf-design/src/locales/langs/zh.json
index db85659..170cebe 100644
--- a/rsf-design/src/locales/langs/zh.json
+++ b/rsf-design/src/locales/langs/zh.json
@@ -182,20 +182,11 @@
"setting": {
"menuType": {
"title": "鑿滃崟甯冨眬",
- "list": [
- "鍨傜洿",
- "姘村钩",
- "娣峰悎",
- "鍙屽垪"
- ]
+ "list": ["鍨傜洿", "姘村钩", "娣峰悎", "鍙屽垪"]
},
"theme": {
"title": "涓婚椋庢牸",
- "list": [
- "娴呰壊",
- "娣辫壊",
- "绯荤粺"
- ]
+ "list": ["娴呰壊", "娣辫壊", "绯荤粺"]
},
"menu": {
"title": "鑿滃崟椋庢牸"
@@ -205,17 +196,11 @@
},
"box": {
"title": "鐩掑瓙鏍峰紡",
- "list": [
- "杈规",
- "闃村奖"
- ]
+ "list": ["杈规", "闃村奖"]
},
"container": {
"title": "瀹瑰櫒瀹藉害",
- "list": [
- "閾烘弧",
- "瀹氬"
- ]
+ "list": ["閾烘弧", "瀹氬"]
},
"basics": {
"title": "鍩虹閰嶇疆",
@@ -661,21 +646,21 @@
"send": "鍙戦��",
"renameDialogTitle": "閲嶅懡鍚嶄細璇�",
"sessionTitleField": "浼氳瘽鏍囬",
- "requestMetric": "Req: {value}",
- "sessionMetric": "Session: {id}",
- "promptMetric": "Prompt: {value}",
- "modelMetric": "Model: {value}",
- "promptLabel": "Prompt",
- "modelLabel": "Model",
- "modelSelectorLabel": "瀵硅瘽妯″瀷",
- "modelSelectorHint": "鍒囨崲鍚庝粎褰卞搷褰撳墠浼氳瘽鍚庣画鍥炲锛屼笉浼氭敼鍔ㄥ叏灞�榛樿妯″瀷銆�",
- "modelSwitchFailed": "鍒囨崲瀵硅瘽妯″瀷澶辫触",
- "defaultModelSuffix": "(榛樿)",
- "mcpMetric": "MCP: {value}",
- "historyMetric": "History: {value}",
- "mcpLabel": "MCP",
- "historyLabel": "History",
- "recentMetric": "Recent: {value}",
+ "requestMetric": "Req: {value}",
+ "sessionMetric": "Session: {id}",
+ "promptMetric": "Prompt: {value}",
+ "modelMetric": "Model: {value}",
+ "promptLabel": "Prompt",
+ "modelLabel": "Model",
+ "modelSelectorLabel": "瀵硅瘽妯″瀷",
+ "modelSelectorHint": "鍒囨崲鍚庝粎褰卞搷褰撳墠浼氳瘽鍚庣画鍥炲锛屼笉浼氭敼鍔ㄥ叏灞�榛樿妯″瀷銆�",
+ "modelSwitchFailed": "鍒囨崲瀵硅瘽妯″瀷澶辫触",
+ "defaultModelSuffix": "(榛樿)",
+ "mcpMetric": "MCP: {value}",
+ "historyMetric": "History: {value}",
+ "mcpLabel": "MCP",
+ "historyLabel": "History",
+ "recentMetric": "Recent: {value}",
"elapsedMetric": "鑰楁椂: {value} ms",
"firstTokenMetric": "棣栧寘: {value} ms",
"tokenMetric": "Tokens: prompt {prompt} / completion {completion} / total {total}",
@@ -850,12 +835,12 @@
"systemPrompt": "绯荤粺鎻愮ず璇�",
"userPromptTemplate": "鐢ㄦ埛鎻愮ず璇嶆ā鏉�"
},
- "dialog": {
- "titleCreate": "鏂板缓 Prompt",
- "titleEdit": "缂栬緫 Prompt",
- "titleDetail": "Prompt 璇︽儏",
- "defaultPreviewInput": "璇锋牴鎹綋鍓嶈緭鍏ョ粰鍑烘憳瑕�",
- "previewTitle": "娓叉煋棰勮",
+ "dialog": {
+ "titleCreate": "鏂板缓 Prompt",
+ "titleEdit": "缂栬緫 Prompt",
+ "titleDetail": "Prompt 璇︽儏",
+ "defaultPreviewInput": "璇锋牴鎹綋鍓嶈緭鍏ョ粰鍑烘憳瑕�",
+ "previewTitle": "娓叉煋棰勮",
"previewDescription": "杈撳叆绀轰緥鍐呭鍜� metadata锛岀洿鎺ラ瑙堟渶缁堟覆鏌撶粨鏋溿��",
"previewAction": "娓叉煋棰勮",
"previewResolvedVariables": "宸茶В鏋愬彉閲忥細{value}",
@@ -2473,8 +2458,20 @@
},
"whMat": {
"title": "鐗╂枡",
+ "entity": "鐗╂枡",
"labels": {
"allMaterials": "鍏ㄩ儴鐗╂枡"
+ },
+ "actions": {
+ "add": "鏂板鐗╂枡",
+ "batchGroup": "鎵归噺鏀瑰垎缁�",
+ "batchWarn": "鎵归噺鏀归璀�",
+ "batchFlagCheck": "鎵归噺璐ㄦ",
+ "batchStatus": "鎵归噺鐘舵��",
+ "batchStockLevel": "鎵归噺搴撳瓨绛夌骇",
+ "bindLoc": "缁戝畾搴撲綅",
+ "import": "瀵煎叆",
+ "downloadTemplate": "涓嬭浇妯℃澘"
},
"search": {
"groupKeywordPlaceholder": "鎼滅储鐗╂枡鍒嗙粍",
@@ -2486,19 +2483,76 @@
"codePlaceholder": "璇疯緭鍏ョ墿鏂欑紪鐮�",
"name": "鐗╂枡鍚嶇О",
"namePlaceholder": "璇疯緭鍏ョ墿鏂欏悕绉�",
+ "groupId": "鐗╂枡鍒嗙粍",
+ "groupIdPlaceholder": "璇烽�夋嫨鐗╂枡鍒嗙粍",
+ "platCode": "骞冲彴缂栫爜",
+ "platCodePlaceholder": "璇疯緭鍏ュ钩鍙扮紪鐮�",
"spec": "瑙勬牸",
"specPlaceholder": "璇疯緭鍏ヨ鏍�",
+ "model": "鍨嬪彿",
+ "modelPlaceholder": "璇疯緭鍏ュ瀷鍙�",
+ "color": "棰滆壊",
+ "colorPlaceholder": "璇疯緭鍏ラ鑹�",
+ "size": "灏哄",
+ "sizePlaceholder": "璇疯緭鍏ュ昂瀵�",
+ "unit": "鍗曚綅",
+ "unitPlaceholder": "璇疯緭鍏ュ崟浣�",
+ "purUnit": "閲囪喘鍗曚綅",
+ "purUnitPlaceholder": "璇疯緭鍏ラ噰璐崟浣�",
+ "stockUnit": "搴撲綅鍗曚綅",
+ "stockUnitPlaceholder": "璇疯緭鍏ュ簱浣嶅崟浣�",
"barcode": "鏉$爜",
- "barcodePlaceholder": "璇疯緭鍏ユ潯鐮�"
+ "barcodePlaceholder": "璇疯緭鍏ユ潯鐮�",
+ "describle": "鎻忚堪",
+ "describlePlaceholder": "璇疯緭鍏ユ弿杩�",
+ "rglarId": "鎵规瑙勫垯",
+ "rglarIdPlaceholder": "璇烽�夋嫨鎵规瑙勫垯",
+ "weight": "閲嶉噺",
+ "weightPlaceholder": "璇疯緭鍏ラ噸閲�",
+ "nromNum": "鏍囧寘鏁伴噺",
+ "nromNumPlaceholder": "璇疯緭鍏ユ爣鍖呮暟閲�",
+ "stockLevel": "搴撳瓨绛夌骇",
+ "stockLevelPlaceholder": "璇烽�夋嫨搴撳瓨绛夌骇",
+ "flagLabelMange": "鏍囩绠$悊",
+ "flagLabelMangePlaceholder": "璇烽�夋嫨鏍囩绠$悊",
+ "safeQty": "瀹夊叏搴撳瓨",
+ "safeQtyPlaceholder": "璇疯緭鍏ュ畨鍏ㄥ簱瀛�",
+ "minQty": "鏈�灏忓簱瀛�",
+ "minQtyPlaceholder": "璇疯緭鍏ユ渶灏忓簱瀛�",
+ "maxQty": "鏈�澶у簱瀛�",
+ "maxQtyPlaceholder": "璇疯緭鍏ユ渶澶у簱瀛�",
+ "stagn": "鍋滄粸澶╂暟",
+ "stagnPlaceholder": "璇疯緭鍏ュ仠婊炲ぉ鏁�",
+ "valid": "淇濊川鏈熷ぉ鏁�",
+ "validPlaceholder": "璇疯緭鍏ヤ繚璐ㄦ湡澶╂暟",
+ "validWarn": "鏁堟湡棰勮闃堝��",
+ "validWarnPlaceholder": "璇疯緭鍏ユ晥鏈熼璀﹂槇鍊�",
+ "flagCheck": "鏄惁鍏嶆",
+ "flagCheckPlaceholder": "璇烽�夋嫨鏄惁鍏嶆",
+ "status": "鐘舵��",
+ "statusPlaceholder": "璇烽�夋嫨鐘舵��",
+ "memo": "澶囨敞",
+ "memoPlaceholder": "璇疯緭鍏ュ娉�",
+ "dynamicPlaceholder": "璇疯緭鍏field}"
},
"messages": {
"emptyGroups": "鏆傛棤鐗╂枡鍒嗙粍",
"groupTimeout": "鐗╂枡鍒嗙粍鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
"groupLoadFailed": "鑾峰彇鐗╂枡鍒嗙粍澶辫触",
+ "serialRuleTimeout": "鎵规瑙勫垯鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
+ "serialRuleLoadFailed": "鑾峰彇鎵规瑙勫垯澶辫触",
"listTimeout": "鐗╂枡鍒楄〃鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
"listLoadFailed": "鑾峰彇鐗╂枡鍒楄〃澶辫触",
"detailTimeout": "鐗╂枡璇︽儏鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
- "detailLoadFailed": "鑾峰彇鐗╂枡璇︽儏澶辫触"
+ "detailLoadFailed": "鑾峰彇鐗╂枡璇︽儏澶辫触",
+ "importSuccess": "鐗╂枡瀵煎叆鎴愬姛",
+ "importFailed": "鐗╂枡瀵煎叆澶辫触",
+ "templateDownloadSuccess": "妯℃澘涓嬭浇鎴愬姛",
+ "templateDownloadFailed": "妯℃澘涓嬭浇澶辫触",
+ "enabledFieldsTimeout": "鎵╁睍瀛楁鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
+ "bindLocTimeout": "缁戝畾搴撲綅閫夐」鍔犺浇瓒呮椂锛屽凡鍋滄绛夊緟",
+ "bindLocLoadFailed": "鑾峰彇缁戝畾搴撲綅閫夐」澶辫触",
+ "selectAtLeastOne": "璇疯嚦灏戦�夋嫨涓�鏉$墿鏂欒褰�"
},
"table": {
"code": "鐗╂枡缂栫爜",
@@ -2509,6 +2563,102 @@
"spec": "瑙勬牸",
"model": "鍨嬪彿"
},
+ "dialog": {
+ "titleCreate": "鏂板鐗╂枡",
+ "titleEdit": "缂栬緫鐗╂枡",
+ "tabs": {
+ "basic": "鍩虹淇℃伅",
+ "control": "鎺у埗淇℃伅",
+ "batchRule": "鎵规瑙勫垯"
+ },
+ "fields": {
+ "code": "鐗╂枡缂栫爜",
+ "name": "鐗╂枡鍚嶇О",
+ "groupId": "鐗╂枡鍒嗙粍",
+ "useOrgName": "浣跨敤缁勭粐",
+ "spec": "瑙勬牸",
+ "model": "鍨嬪彿",
+ "color": "棰滆壊",
+ "size": "灏哄",
+ "weight": "閲嶉噺",
+ "unit": "鍗曚綅",
+ "purUnit": "閲囪喘鍗曚綅",
+ "describle": "鎻忚堪",
+ "safeQty": "瀹夊叏搴撳瓨",
+ "minQty": "鏈�灏忓簱瀛�",
+ "maxQty": "鏈�澶у簱瀛�",
+ "stagn": "鍋滄粸澶╂暟",
+ "valid": "淇濊川鏈熷ぉ鏁�",
+ "validWarn": "鏁堟湡棰勮闃堝��",
+ "flagCheck": "鏄惁鍏嶆",
+ "rglarId": "鎵规瑙勫垯"
+ },
+ "placeholders": {
+ "code": "璇疯緭鍏ョ墿鏂欑紪鐮�",
+ "name": "璇疯緭鍏ョ墿鏂欏悕绉�",
+ "groupId": "璇烽�夋嫨鐗╂枡鍒嗙粍",
+ "useOrgName": "璇疯緭鍏ヤ娇鐢ㄧ粍缁�",
+ "spec": "璇疯緭鍏ヨ鏍�",
+ "model": "璇疯緭鍏ュ瀷鍙�",
+ "color": "璇疯緭鍏ラ鑹�",
+ "size": "璇疯緭鍏ュ昂瀵�",
+ "unit": "璇疯緭鍏ュ崟浣�",
+ "purUnit": "璇疯緭鍏ラ噰璐崟浣�",
+ "describle": "璇疯緭鍏ユ弿杩�",
+ "flagCheck": "璇烽�夋嫨鏄惁鍏嶆",
+ "rglarId": "璇烽�夋嫨鎵规瑙勫垯"
+ },
+ "validation": {
+ "code": "璇疯緭鍏ョ墿鏂欑紪鐮�",
+ "name": "璇疯緭鍏ョ墿鏂欏悕绉�",
+ "groupId": "璇烽�夋嫨鐗╂枡鍒嗙粍"
+ }
+ },
+ "batchDialog": {
+ "titles": {
+ "status": "鎵归噺淇敼鐘舵��",
+ "stockLevel": "鎵归噺淇敼搴撳瓨绛夌骇",
+ "validWarn": "鎵归噺淇敼鏁堟湡棰勮",
+ "flagCheck": "鎵归噺淇敼璐ㄦ鐘舵��"
+ },
+ "fields": {
+ "stockLevel": "搴撳瓨绛夌骇"
+ },
+ "placeholders": {
+ "stockLevel": "璇烽�夋嫨搴撳瓨绛夌骇",
+ "validWarn": "璇疯緭鍏ユ晥鏈熼璀﹂槇鍊�",
+ "valid": "璇疯緭鍏ヤ繚璐ㄦ湡澶╂暟",
+ "flagCheck": "璇烽�夋嫨鏄惁鍏嶆"
+ },
+ "validation": {
+ "status": "璇烽�夋嫨鐘舵��",
+ "stockLevel": "璇烽�夋嫨搴撳瓨绛夌骇",
+ "validWarn": "璇疯緭鍏ユ晥鏈熼璀﹂槇鍊�",
+ "valid": "璇疯緭鍏ヤ繚璐ㄦ湡澶╂暟",
+ "flagCheck": "璇烽�夋嫨鏄惁鍏嶆"
+ }
+ },
+ "batchGroupDialog": {
+ "title": "鎵归噺淇敼鐗╂枡鍒嗙粍"
+ },
+ "bindLocDialog": {
+ "title": "缁戝畾搴撲綅",
+ "fields": {
+ "areaMatId": "搴撳尯鐗╂枡",
+ "areaId": "搴撳尯",
+ "locId": "搴撲綅"
+ },
+ "placeholders": {
+ "areaMatId": "璇烽�夋嫨搴撳尯鐗╂枡",
+ "areaId": "璇烽�夋嫨搴撳尯",
+ "locId": "璇烽�夋嫨搴撲綅"
+ },
+ "validation": {
+ "areaMatId": "璇烽�夋嫨搴撳尯鐗╂枡",
+ "areaId": "璇烽�夋嫨搴撳尯",
+ "locId": "璇烽�夋嫨搴撲綅"
+ }
+ },
"detail": {
"title": "鐗╂枡璇︽儏",
"sections": {
diff --git a/rsf-design/src/views/basic-info/bas-station-area/basStationAreaPage.helpers.js b/rsf-design/src/views/basic-info/bas-station-area/basStationAreaPage.helpers.js
index b3046db..c94a34a 100644
--- a/rsf-design/src/views/basic-info/bas-station-area/basStationAreaPage.helpers.js
+++ b/rsf-design/src/views/basic-info/bas-station-area/basStationAreaPage.helpers.js
@@ -181,7 +181,13 @@
}
return {
value: Number(value),
- label: normalizeText(item.name || item.areaName || item.code || item.areaCode || `${$t('menu.warehouseAreas')} ${value}`)
+ label: normalizeText(
+ item.name ||
+ item.areaName ||
+ item.code ||
+ item.areaCode ||
+ `${$t('menu.warehouseAreas')} ${value}`
+ )
}
})
.filter(Boolean)
@@ -203,7 +209,9 @@
}
return {
value: Number(value),
- label: normalizeText(item.stationName || item.stationId || item.name || `${$t('menu.basStation')} ${value}`)
+ label: normalizeText(
+ item.stationName || item.stationId || item.name || `${$t('menu.basStation')} ${value}`
+ )
}
})
.filter(Boolean)
@@ -290,7 +298,9 @@
containerType: normalizeText(params.containerType),
barcode: normalizeText(params.barcode),
autoTransfer:
- params.autoTransfer !== undefined && params.autoTransfer !== null && params.autoTransfer !== ''
+ params.autoTransfer !== undefined &&
+ params.autoTransfer !== null &&
+ params.autoTransfer !== ''
? Number(params.autoTransfer)
: void 0,
stationAlias: normalizeText(params.stationAlias),
@@ -302,7 +312,9 @@
}
return Object.fromEntries(
- Object.entries(searchParams).filter(([, value]) => value !== '' && value !== void 0 && value !== null)
+ Object.entries(searchParams).filter(
+ ([, value]) => value !== '' && value !== void 0 && value !== null
+ )
)
}
@@ -310,6 +322,7 @@
return {
current: params.current || 1,
pageSize: params.pageSize || params.size || 20,
+ orderBy: normalizeText(params.orderBy) || 'create_time desc',
...buildBasStationAreaSearchParams(params)
}
}
@@ -356,7 +369,9 @@
...(formData.area !== void 0 && formData.area !== null && formData.area !== ''
? { area: Number(formData.area) }
: {}),
- ...(formData.isCrossZone !== void 0 && formData.isCrossZone !== null && formData.isCrossZone !== ''
+ ...(formData.isCrossZone !== void 0 &&
+ formData.isCrossZone !== null &&
+ formData.isCrossZone !== ''
? { isCrossZone: Number(formData.isCrossZone) }
: {}),
...(Array.isArray(formData.crossZoneArea) && formData.crossZoneArea.length
@@ -370,7 +385,9 @@
? { containerType: normalizeIdArray(formData.containerType) }
: {}),
barcode: normalizeText(formData.barcode) || '',
- ...(formData.autoTransfer !== void 0 && formData.autoTransfer !== null && formData.autoTransfer !== ''
+ ...(formData.autoTransfer !== void 0 &&
+ formData.autoTransfer !== null &&
+ formData.autoTransfer !== ''
? { autoTransfer: Number(formData.autoTransfer) }
: {}),
...(Array.isArray(formData.stationAlias) && formData.stationAlias.length
@@ -384,10 +401,12 @@
}
}
-export function buildBasStationAreaDialogModel(record = {}, resolvers = {}) {
+export function buildBasStationAreaDialogModel(record = {}) {
return {
...createBasStationAreaFormState(),
- ...(record.id !== void 0 && record.id !== null && record.id !== '' ? { id: Number(record.id) } : {}),
+ ...(record.id !== void 0 && record.id !== null && record.id !== ''
+ ? { id: Number(record.id) }
+ : {}),
stationAreaName: normalizeText(record.stationAreaName || ''),
stationAreaId: normalizeText(record.stationAreaId || ''),
type: normalizeIdValue(record.type),
@@ -395,13 +414,17 @@
outAble: record.outAble !== void 0 && record.outAble !== null ? Number(record.outAble) : 0,
useStatus: normalizeText(record.useStatus || ''),
area: normalizeIdValue(record.area),
- isCrossZone: record.isCrossZone !== void 0 && record.isCrossZone !== null ? Number(record.isCrossZone) : 0,
+ isCrossZone:
+ record.isCrossZone !== void 0 && record.isCrossZone !== null ? Number(record.isCrossZone) : 0,
crossZoneArea: normalizeIdArray(record.crossZoneArea),
isWcs: record.isWcs !== void 0 && record.isWcs !== null ? Number(record.isWcs) : 0,
wcsData: normalizeText(record.wcsData || ''),
containerType: normalizeIdArray(record.containerType ?? record.containerTypes),
barcode: normalizeText(record.barcode || ''),
- autoTransfer: record.autoTransfer !== void 0 && record.autoTransfer !== null ? Number(record.autoTransfer) : 0,
+ autoTransfer:
+ record.autoTransfer !== void 0 && record.autoTransfer !== null
+ ? Number(record.autoTransfer)
+ : 0,
stationAlias: normalizeIdArray(record.stationAlias),
status: record.status !== void 0 && record.status !== null ? Number(record.status) : 1,
memo: normalizeText(record.memo || '')
@@ -424,32 +447,46 @@
stationAreaName: normalizeText(record.stationAreaName) || t('common.placeholder.empty'),
stationAreaId: normalizeText(record.stationAreaId) || t('common.placeholder.empty'),
type: normalizeIdValue(record.type),
- typeText: normalizeText(
- record.type$ || record.typeText || resolvers.resolveTypeLabel?.(typeValue) || typeValue
- ) || t('common.placeholder.empty'),
+ typeText:
+ normalizeText(
+ record.type$ || record.typeText || resolvers.resolveTypeLabel?.(typeValue) || typeValue
+ ) || t('common.placeholder.empty'),
inAble: normalizeIdValue(record.inAble),
inAbleText: normalizeBooleanText(record.inAble, t),
outAble: normalizeIdValue(record.outAble),
outAbleText: normalizeBooleanText(record.outAble, t),
useStatus: normalizeText(record.useStatus),
useStatusText:
- normalizeText(record.useStatus$ || record.useStatusText || resolvers.resolveUseStatusLabel?.(record.useStatus) || record.useStatus) ||
- t('common.placeholder.empty'),
+ normalizeText(
+ record.useStatus$ ||
+ record.useStatusText ||
+ resolvers.resolveUseStatusLabel?.(record.useStatus) ||
+ record.useStatus
+ ) || t('common.placeholder.empty'),
area: normalizeIdValue(areaId),
- areaText: normalizeText(record.area$ || record.areaText || resolvers.resolveAreaLabel?.(areaId) || '') || t('common.placeholder.empty'),
+ areaText:
+ normalizeText(
+ record.area$ || record.areaText || resolvers.resolveAreaLabel?.(areaId) || ''
+ ) || t('common.placeholder.empty'),
isCrossZone: normalizeIdValue(record.isCrossZone),
isCrossZoneText: normalizeBooleanText(record.isCrossZone, t),
crossZoneArea: crossZoneAreaIds,
crossZoneAreaText:
- resolveOptionText(crossZoneAreaIds, resolvers.resolveCrossZoneAreaLabel, record.crossZoneAreaText || []) ||
- t('common.placeholder.empty'),
+ resolveOptionText(
+ crossZoneAreaIds,
+ resolvers.resolveCrossZoneAreaLabel,
+ record.crossZoneAreaText || []
+ ) || t('common.placeholder.empty'),
isWcs: normalizeIdValue(record.isWcs),
isWcsText: normalizeBooleanText(record.isWcs, t),
wcsData: normalizeText(record.wcsData) || t('common.placeholder.empty'),
containerType: containerTypeIds,
containerTypeText:
- resolveOptionText(containerTypeIds, resolvers.resolveContainerTypeLabel, record.containerTypesText || []) ||
- t('common.placeholder.empty'),
+ resolveOptionText(
+ containerTypeIds,
+ resolvers.resolveContainerTypeLabel,
+ record.containerTypesText || []
+ ) || t('common.placeholder.empty'),
barcode: normalizeText(record.barcode) || t('common.placeholder.empty'),
autoTransfer: normalizeIdValue(record.autoTransfer),
autoTransferText: normalizeBooleanText(record.autoTransfer, t),
@@ -465,10 +502,14 @@
statusType: statusMeta.type,
statusBool: record.statusBool !== void 0 ? Boolean(record.statusBool) : statusMeta.bool,
memo: normalizeText(record.memo) || t('common.placeholder.empty'),
- createByText: normalizeText(record.createBy$ || record.createByText || '') || t('common.placeholder.empty'),
- createTimeText: normalizeText(record.createTime$ || record.createTime || '') || t('common.placeholder.empty'),
- updateByText: normalizeText(record.updateBy$ || record.updateByText || '') || t('common.placeholder.empty'),
- updateTimeText: normalizeText(record.updateTime$ || record.updateTime || '') || t('common.placeholder.empty')
+ createByText:
+ normalizeText(record.createBy$ || record.createByText || '') || t('common.placeholder.empty'),
+ createTimeText:
+ normalizeText(record.createTime$ || record.createTime || '') || t('common.placeholder.empty'),
+ updateByText:
+ normalizeText(record.updateBy$ || record.updateByText || '') || t('common.placeholder.empty'),
+ updateTimeText:
+ normalizeText(record.updateTime$ || record.updateTime || '') || t('common.placeholder.empty')
}
}
diff --git a/rsf-design/src/views/basic-info/bas-station-area/basStationAreaTable.columns.js b/rsf-design/src/views/basic-info/bas-station-area/basStationAreaTable.columns.js
index 476dfae..ec62b52 100644
--- a/rsf-design/src/views/basic-info/bas-station-area/basStationAreaTable.columns.js
+++ b/rsf-design/src/views/basic-info/bas-station-area/basStationAreaTable.columns.js
@@ -19,7 +19,12 @@
}
if (canDelete && handleDelete) {
- operations.push({ key: 'delete', label: t('common.actions.delete'), icon: 'ri:delete-bin-5-line', color: 'var(--art-error)' })
+ operations.push({
+ key: 'delete',
+ label: t('common.actions.delete'),
+ icon: 'ri:delete-bin-5-line',
+ color: 'var(--art-error)'
+ })
}
return [
@@ -33,6 +38,13 @@
label: t('table.index'),
width: 72,
align: 'center'
+ },
+ {
+ prop: 'id',
+ label: t('table.id'),
+ width: 90,
+ align: 'center',
+ formatter: (row) => row.id ?? '--'
},
{
prop: 'stationAreaId',
@@ -138,11 +150,21 @@
width: 96,
align: 'center',
formatter: (row) => {
- const status = getBasStationAreaStatusOptions(t).find((item) => Number(item.value) === Number(row.status))
+ const status = getBasStationAreaStatusOptions(t).find(
+ (item) => Number(item.value) === Number(row.status)
+ )
const text = status?.label || row.statusText || '--'
- const type = Number(row.status) === 1 ? 'success' : Number(row.status) === 0 ? 'danger' : 'info'
+ const type =
+ Number(row.status) === 1 ? 'success' : Number(row.status) === 0 ? 'danger' : 'info'
return h(ElTag, { type, effect: 'light' }, () => text)
}
+ },
+ {
+ prop: 'updateByText',
+ label: t('table.updateBy'),
+ minWidth: 120,
+ showOverflowTooltip: true,
+ formatter: (row) => row.updateByText || '--'
},
{
prop: 'updateTimeText',
@@ -152,6 +174,20 @@
formatter: (row) => row.updateTimeText || '--'
},
{
+ prop: 'createByText',
+ label: t('table.createBy'),
+ minWidth: 120,
+ showOverflowTooltip: true,
+ formatter: (row) => row.createByText || '--'
+ },
+ {
+ prop: 'createTimeText',
+ label: t('table.createTime'),
+ minWidth: 170,
+ showOverflowTooltip: true,
+ formatter: (row) => row.createTimeText || '--'
+ },
+ {
prop: 'memo',
label: t('pages.basicInfo.basStationArea.search.memo'),
minWidth: 180,
diff --git a/rsf-design/src/views/basic-info/bas-station-area/modules/bas-station-area-dialog.vue b/rsf-design/src/views/basic-info/bas-station-area/modules/bas-station-area-dialog.vue
index 32e068a..77c98c0 100644
--- a/rsf-design/src/views/basic-info/bas-station-area/modules/bas-station-area-dialog.vue
+++ b/rsf-design/src/views/basic-info/bas-station-area/modules/bas-station-area-dialog.vue
@@ -36,9 +36,7 @@
import {
buildBasStationAreaDialogModel,
createBasStationAreaFormState,
- getBasStationAreaBinaryOptions,
- getBasStationAreaStatusOptions,
- getBasStationAreaTypeOptions
+ getBasStationAreaStatusOptions
} from '../basStationAreaPage.helpers'
const props = defineProps({
@@ -48,7 +46,8 @@
areaOptions: { type: Array, default: () => [] },
crossZoneAreaOptions: { type: Array, default: () => [] },
containerTypeOptions: { type: Array, default: () => [] },
- stationOptions: { type: Array, default: () => [] }
+ stationOptions: { type: Array, default: () => [] },
+ useStatusOptions: { type: Array, default: () => [] }
})
const emit = defineEmits(['update:visible', 'submit'])
@@ -58,19 +57,47 @@
const isEdit = computed(() => props.dialogType === 'edit')
const dialogTitle = computed(() =>
- t(isEdit.value ? 'pages.basicInfo.basStationArea.dialog.titleEdit' : 'pages.basicInfo.basStationArea.dialog.titleAdd')
+ t(
+ isEdit.value
+ ? 'pages.basicInfo.basStationArea.dialog.titleEdit'
+ : 'pages.basicInfo.basStationArea.dialog.titleAdd'
+ )
)
const rules = computed(() => ({
- stationAreaName: [{ required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.stationAreaName'), trigger: 'blur' }],
- stationAreaId: [{ required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.stationAreaId'), trigger: 'blur' }],
- type: [{ required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.type'), trigger: 'change' }],
- area: [{ required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.area'), trigger: 'change' }],
- containerType: [{ type: 'array', required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.containerType'), trigger: 'change' }],
- stationAlias: [{ type: 'array', required: true, message: t('pages.basicInfo.basStationArea.dialog.validation.stationAlias'), trigger: 'change' }]
+ stationAreaName: [
+ {
+ required: true,
+ message: t('pages.basicInfo.basStationArea.dialog.validation.stationAreaName'),
+ trigger: 'blur'
+ }
+ ],
+ stationAreaId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.basStationArea.dialog.validation.stationAreaId'),
+ trigger: 'blur'
+ }
+ ],
+ containerType: [
+ {
+ type: 'array',
+ required: true,
+ message: t('pages.basicInfo.basStationArea.dialog.validation.containerType'),
+ trigger: 'change'
+ }
+ ],
+ stationAlias: [
+ {
+ type: 'array',
+ required: true,
+ message: t('pages.basicInfo.basStationArea.dialog.validation.stationAlias'),
+ trigger: 'change'
+ }
+ ]
}))
- const formItems = computed(() => [
+ const baseLegacyItems = computed(() => [
{
label: t('pages.basicInfo.basStationArea.dialog.stationAreaName'),
key: 'stationAreaName',
@@ -81,42 +108,12 @@
}
},
{
- label: t('pages.basicInfo.basStationArea.dialog.stationAreaId'),
- key: 'stationAreaId',
- type: 'input',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.placeholder.stationAreaId'),
- clearable: true
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.type'),
- key: 'type',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.type'),
- clearable: true,
- options: getBasStationAreaTypeOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.area'),
- key: 'area',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.area'),
- clearable: true,
- filterable: true,
- options: props.areaOptions || []
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.crossZoneArea'),
+ label: t('pages.basicInfo.basStation.table.crossZoneArea'),
key: 'crossZoneArea',
type: 'select',
span: 24,
props: {
- placeholder: t('pages.basicInfo.basStationArea.placeholder.crossZoneArea'),
+ placeholder: t('pages.basicInfo.basStation.table.crossZoneArea'),
clearable: true,
multiple: true,
collapseTags: true,
@@ -125,17 +122,26 @@
}
},
{
- label: t('pages.basicInfo.basStationArea.dialog.containerType'),
+ label: t('pages.basicInfo.basStation.table.containerTypes'),
key: 'containerType',
type: 'select',
span: 24,
props: {
- placeholder: t('pages.basicInfo.basStationArea.placeholder.containerType'),
+ placeholder: t('pages.basicInfo.basStation.table.containerTypes'),
clearable: true,
multiple: true,
collapseTags: true,
filterable: true,
options: props.containerTypeOptions || []
+ }
+ },
+ {
+ label: t('pages.basicInfo.basStationArea.dialog.stationAreaId'),
+ key: 'stationAreaId',
+ type: 'input',
+ props: {
+ placeholder: t('pages.basicInfo.basStationArea.placeholder.stationAreaId'),
+ clearable: true
}
},
{
@@ -151,101 +157,22 @@
filterable: true,
options: props.stationOptions || []
}
- },
+ }
+ ])
+
+ const createOnlyItems = computed(() => [
{
- label: t('pages.basicInfo.basStationArea.dialog.inAble'),
- key: 'inAble',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.inAble'),
- clearable: true,
- options: getBasStationAreaBinaryOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.outAble'),
- key: 'outAble',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.outAble'),
- clearable: true,
- options: getBasStationAreaBinaryOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.isCrossZone'),
- key: 'isCrossZone',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.isCrossZone'),
- clearable: true,
- options: getBasStationAreaBinaryOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.isWcs'),
- key: 'isWcs',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.isWcs'),
- clearable: true,
- options: getBasStationAreaBinaryOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.autoTransfer'),
- key: 'autoTransfer',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.autoTransfer'),
- clearable: true,
- options: getBasStationAreaBinaryOptions(t)
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.useStatus'),
- key: 'useStatus',
- type: 'select',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.search.useStatus'),
- clearable: true,
- filterable: true,
- options: props.useStatusOptions || []
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.wcsData'),
- key: 'wcsData',
- type: 'input',
- span: 24,
- props: {
- type: 'textarea',
- rows: 3,
- placeholder: t('pages.basicInfo.basStationArea.placeholder.wcsData'),
- clearable: true
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.barcode'),
- key: 'barcode',
- type: 'input',
- props: {
- placeholder: t('pages.basicInfo.basStationArea.placeholder.barcode'),
- clearable: true
- }
- },
- {
- label: t('pages.basicInfo.basStationArea.dialog.status'),
+ label: t('table.status'),
key: 'status',
type: 'select',
props: {
- placeholder: t('pages.basicInfo.basStationArea.search.status'),
+ placeholder: t('table.status'),
clearable: true,
options: getBasStationAreaStatusOptions(t)
}
},
{
- label: t('pages.basicInfo.basStationArea.dialog.memo'),
+ label: t('table.memo'),
key: 'memo',
type: 'input',
span: 24,
@@ -257,6 +184,10 @@
}
}
])
+
+ const formItems = computed(() =>
+ isEdit.value ? baseLegacyItems.value : [...baseLegacyItems.value, ...createOnlyItems.value]
+ )
const resetForm = () => {
Object.assign(form, createBasStationAreaFormState())
@@ -271,7 +202,25 @@
if (!formRef.value) return
try {
await formRef.value.validate()
- emit('submit', { ...form })
+ const payload = isEdit.value
+ ? {
+ id: form.id,
+ stationAreaName: form.stationAreaName,
+ crossZoneArea: Array.isArray(form.crossZoneArea) ? [...form.crossZoneArea] : [],
+ containerType: Array.isArray(form.containerType) ? [...form.containerType] : [],
+ stationAreaId: form.stationAreaId,
+ stationAlias: Array.isArray(form.stationAlias) ? [...form.stationAlias] : []
+ }
+ : {
+ stationAreaName: form.stationAreaName,
+ crossZoneArea: Array.isArray(form.crossZoneArea) ? [...form.crossZoneArea] : [],
+ containerType: Array.isArray(form.containerType) ? [...form.containerType] : [],
+ stationAreaId: form.stationAreaId,
+ stationAlias: Array.isArray(form.stationAlias) ? [...form.stationAlias] : [],
+ status: form.status,
+ memo: form.memo
+ }
+ emit('submit', payload)
} catch {
return
}
diff --git a/rsf-design/src/views/basic-info/wh-mat/index.vue b/rsf-design/src/views/basic-info/wh-mat/index.vue
index fb852a1..6d28ea1 100644
--- a/rsf-design/src/views/basic-info/wh-mat/index.vue
+++ b/rsf-design/src/views/basic-info/wh-mat/index.vue
@@ -5,7 +5,9 @@
<ElCard class="wh-mat-page__sidebar-card">
<div class="mb-3 flex items-center justify-between gap-3">
<div>
- <div class="text-base font-medium text-[var(--art-text-primary)]">{{ t('pages.basicInfo.whMat.title') }}</div>
+ <div class="text-base font-medium text-[var(--art-text-primary)]">{{
+ t('pages.basicInfo.whMat.title')
+ }}</div>
<div class="text-xs text-[var(--art-text-secondary)]">
{{ selectedGroupLabel }}
</div>
@@ -28,21 +30,26 @@
<div v-if="groupTreeLoading" class="py-6">
<ElSkeleton :rows="10" animated />
</div>
- <ElEmpty v-else-if="!groupTreeData.length" :description="t('pages.basicInfo.whMat.messages.emptyGroups')" />
+ <ElEmpty
+ v-else-if="!groupTreeData.length"
+ :description="t('pages.basicInfo.whMat.messages.emptyGroups')"
+ />
<ElTree
v-else
:data="groupTreeData"
:props="treeProps"
node-key="id"
highlight-current
- default-expand-all
+ :default-expanded-keys="defaultExpandedGroupKeys"
:current-node-key="selectedGroupId"
@node-click="handleGroupNodeClick"
>
<template #default="{ data }">
<div class="flex items-center gap-2">
<span class="font-medium">{{ data.name || t('common.placeholder.empty') }}</span>
- <span class="text-xs text-[var(--art-text-secondary)]">{{ data.code || t('common.placeholder.empty') }}</span>
+ <span class="text-xs text-[var(--art-text-secondary)]">{{
+ data.code || t('common.placeholder.empty')
+ }}</span>
</div>
</template>
</ElTree>
@@ -60,23 +67,155 @@
/>
<ElCard class="art-table-card">
- <ArtTableHeader :loading="loading" v-model:columns="columnChecks" @refresh="loadMatnrList" />
+ <ArtTableHeader
+ :loading="loading"
+ v-model:columns="columnChecks"
+ @refresh="handleRefresh"
+ >
+ <template #left>
+ <ElSpace wrap>
+ <ElButton v-auth="'add'" @click="handleShowDialog('add')" v-ripple>
+ {{ t('pages.basicInfo.whMat.actions.add') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBatchGroupDialog"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.batchGroup') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBatchDialog('validWarn')"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.batchWarn') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBatchDialog('flagCheck')"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.batchFlagCheck') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBatchDialog('status')"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.batchStatus') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBatchDialog('stockLevel')"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.batchStockLevel') }}
+ </ElButton>
+ <ElButton
+ v-if="showBatchActionButtons"
+ v-auth="'update'"
+ :disabled="selectedRows.length === 0"
+ @click="openBindLocDialog"
+ v-ripple
+ >
+ {{ t('pages.basicInfo.whMat.actions.bindLoc') }}
+ </ElButton>
+ <ElButton
+ v-auth="'delete'"
+ type="danger"
+ :disabled="selectedRows.length === 0"
+ @click="handleBatchDelete"
+ v-ripple
+ >
+ {{ t('common.actions.batchDelete') }}
+ </ElButton>
+ <div v-auth="'update'">
+ <ElUpload
+ :auto-upload="false"
+ :show-file-list="false"
+ accept=".xlsx,.xls"
+ @change="handleImportFileChange"
+ >
+ <ElButton :loading="importing" v-ripple>
+ {{ t('pages.basicInfo.whMat.actions.import') }}
+ </ElButton>
+ </ElUpload>
+ </div>
+ <ElButton :loading="templateDownloading" @click="handleDownloadTemplate" v-ripple>
+ {{ t('pages.basicInfo.whMat.actions.downloadTemplate') }}
+ </ElButton>
+ <ListExportPrint
+ class="inline-flex"
+ :preview-visible="previewVisible"
+ @update:previewVisible="handlePreviewVisibleChange"
+ :report-title="reportTitle"
+ :selected-rows="selectedRows"
+ :query-params="reportQueryParams"
+ :columns="columns"
+ :preview-rows="previewRows"
+ :preview-meta="resolvedPreviewMeta"
+ :total="pagination.total"
+ :disabled="loading"
+ @export="handleExport"
+ @print="handlePrint"
+ />
+ </ElSpace>
+ </template>
+ </ArtTableHeader>
<ArtTable
:loading="loading"
:data="tableData"
:columns="columns"
:pagination="pagination"
+ row-key="id"
+ @selection-change="handleSelectionChange"
@pagination:size-change="handleSizeChange"
@pagination:current-change="handleCurrentChange"
- >
- <template #action="{ row }">
- <ArtButtonTable icon="ri:eye-line" @click="openDetailDrawer(row)" />
- </template>
- </ArtTable>
+ />
</ElCard>
</div>
</div>
+
+ <WhMatDialog
+ v-model:visible="dialogVisible"
+ :dialog-type="dialogType"
+ :material-data="currentMaterialData"
+ :group-options="groupOptions"
+ :serial-rule-options="serialRuleOptions"
+ @submit="handleDialogSubmit"
+ />
+
+ <WhMatBatchDialog
+ v-model:visible="batchDialogVisible"
+ :action-type="batchDialogType"
+ @submit="handleBatchDialogSubmit"
+ />
+
+ <WhMatBatchGroupDialog
+ v-model:visible="batchGroupDialogVisible"
+ :group-options="groupOptions"
+ @submit="handleBatchGroupSubmit"
+ />
+
+ <WhMatBindLocDialog
+ v-model:visible="bindLocDialogVisible"
+ :area-mat-options="areaMatOptions"
+ :area-options="areaOptions"
+ :loc-options="locOptions"
+ @submit="handleBindLocSubmit"
+ />
<WhMatDetailDrawer
v-model:visible="detailDrawerVisible"
@@ -87,38 +226,97 @@
</template>
<script setup>
- import { ElMessage } from 'element-plus'
import { computed, onMounted, reactive, ref } from 'vue'
+ import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
- import ArtButtonTable from '@/components/core/forms/art-button-table/index.vue'
+ import ListExportPrint from '@/components/biz/list-export-print/index.vue'
+ import { useAuth } from '@/hooks/core/useAuth'
import { useTableColumns } from '@/hooks/core/useTableColumns'
+ import { useUserStore } from '@/store/modules/user'
+ import { fetchSerialRulePage } from '@/api/system-manage'
+ import { fetchWarehouseAreasList } from '@/api/warehouse-areas'
+ import { fetchLocPage } from '@/api/loc'
+ import { fetchLocAreaMatList } from '@/api/loc-area-mat'
+ import { fetchBindLocAreaMatRelaByMatnr } from '@/api/loc-area-mat-rela'
+ import { defaultResponseAdapter } from '@/utils/table/tableUtils'
import { guardRequestWithMessage } from '@/utils/sys/requestGuard'
- import { fetchMatnrDetail, fetchMatnrGroupTree, fetchMatnrPage } from '@/api/wh-mat'
+ import { useCrudPage } from '@/views/system/common/useCrudPage'
+ import { usePrintExportPage } from '@/views/system/common/usePrintExportPage'
+ import {
+ fetchBatchUpdateMatnr,
+ fetchBindMatnrGroup,
+ fetchDeleteMatnr,
+ fetchDownloadMatnrTemplate,
+ fetchEnabledFields,
+ fetchExportMatnrReport,
+ fetchGetMatnrMany,
+ fetchImportMatnr,
+ fetchMatnrDetail,
+ fetchMatnrGroupTree,
+ fetchMatnrPage,
+ fetchSaveMatnr,
+ fetchUpdateMatnr
+ } from '@/api/wh-mat'
+ import WhMatBatchDialog from './modules/wh-mat-batch-dialog.vue'
+ import WhMatBatchGroupDialog from './modules/wh-mat-batch-group-dialog.vue'
+ import WhMatBindLocDialog from './modules/wh-mat-bind-loc-dialog.vue'
+ import WhMatDialog from './modules/wh-mat-dialog.vue'
import WhMatDetailDrawer from './modules/wh-mat-detail-drawer.vue'
import { createWhMatTableColumns } from './whMatTable.columns'
import {
+ WH_MAT_REPORT_STYLE,
+ WH_MAT_REPORT_TITLE,
buildMatnrGroupTreeQueryParams,
buildMatnrPageQueryParams,
+ buildWhMatDialogModel,
+ buildWhMatPrintRows,
+ buildWhMatReportMeta,
+ buildWhMatSavePayload,
createWhMatSearchState,
+ getWhMatDynamicFieldKey,
+ getWhMatFlagLabelManageOptions,
+ getWhMatFlagCheckOptions,
+ getWhMatStockLevelOptions,
+ getWhMatStatusOptions,
getWhMatTreeNodeLabel,
normalizeMatnrDetail,
+ normalizeWhMatEnabledFields,
normalizeMatnrGroupTreeRows,
- normalizeMatnrRow
+ normalizeMatnrRow,
+ resolveWhMatGroupOptions,
+ resolveWhMatSerialRuleOptions
} from './whMatPage.helpers'
defineOptions({ name: 'WhMat' })
- const { t } = useI18n()
+ const { t } = useI18n()
+ const { hasAuth } = useAuth()
+ const userStore = useUserStore()
+
+ const showBatchActionButtons = false
const loading = ref(false)
const groupTreeLoading = ref(false)
const detailDrawerVisible = ref(false)
const detailLoading = ref(false)
+ const batchDialogVisible = ref(false)
+ const batchGroupDialogVisible = ref(false)
+ const bindLocDialogVisible = ref(false)
+ const bindLocOptionsLoading = ref(false)
+ const importing = ref(false)
+ const templateDownloading = ref(false)
const tableData = ref([])
const groupTreeData = ref([])
const detailData = ref({})
+ const enabledFields = ref([])
+ const serialRuleOptions = ref([])
+ const areaOptions = ref([])
+ const areaMatOptions = ref([])
+ const locOptions = ref([])
const selectedGroupId = ref(null)
const groupSearch = ref('')
+ const batchDialogType = ref('status')
const searchForm = ref(createWhMatSearchState())
+ let handleDeleteAction = null
const pagination = reactive({
current: 1,
@@ -130,6 +328,18 @@
label: 'name',
children: 'children'
}
+
+ const reportTitle = WH_MAT_REPORT_TITLE
+ const groupOptions = computed(() => resolveWhMatGroupOptions(groupTreeData.value))
+ const defaultExpandedGroupKeys = computed(() => collectExpandedGroupKeys(groupTreeData.value))
+ const reportQueryParams = computed(() =>
+ buildMatnrPageQueryParams({
+ ...searchForm.value,
+ groupId: searchForm.value?.groupId || selectedGroupId.value,
+ current: 1,
+ pageSize: pagination.size
+ })
+ )
const searchItems = computed(() => [
{
@@ -160,12 +370,65 @@
}
},
{
+ label: t('pages.basicInfo.whMat.search.groupId'),
+ key: 'groupId',
+ type: 'treeselect',
+ props: {
+ data: groupOptions.value,
+ props: {
+ label: 'displayLabel',
+ value: 'value',
+ children: 'children'
+ },
+ checkStrictly: true,
+ defaultExpandAll: true,
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.groupIdPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.platCode'),
+ key: 'platCode',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.platCodePlaceholder')
+ }
+ },
+ {
label: t('pages.basicInfo.whMat.search.spec'),
key: 'spec',
type: 'input',
props: {
clearable: true,
placeholder: t('pages.basicInfo.whMat.search.specPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.model'),
+ key: 'model',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.modelPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.color'),
+ key: 'color',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.colorPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.size'),
+ key: 'size',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.sizePlaceholder')
}
},
{
@@ -176,13 +439,214 @@
clearable: true,
placeholder: t('pages.basicInfo.whMat.search.barcodePlaceholder')
}
- }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.unit'),
+ key: 'unit',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.unitPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.purUnit'),
+ key: 'purUnit',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.purUnitPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.stockUnit'),
+ key: 'stockUnit',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.stockUnitPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.describle'),
+ key: 'describle',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.describlePlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.rglarId'),
+ key: 'rglarId',
+ type: 'select',
+ props: {
+ clearable: true,
+ filterable: true,
+ placeholder: t('pages.basicInfo.whMat.search.rglarIdPlaceholder'),
+ options: serialRuleOptions.value
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.weight'),
+ key: 'weight',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.weightPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.nromNum'),
+ key: 'nromNum',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.nromNumPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.stockLevel'),
+ key: 'stockLevel',
+ type: 'select',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.stockLevelPlaceholder'),
+ options: getWhMatStockLevelOptions()
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.flagLabelMange'),
+ key: 'flagLabelMange',
+ type: 'select',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.flagLabelMangePlaceholder'),
+ options: getWhMatFlagLabelManageOptions(t)
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.safeQty'),
+ key: 'safeQty',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.safeQtyPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.minQty'),
+ key: 'minQty',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.minQtyPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.maxQty'),
+ key: 'maxQty',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.maxQtyPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.stagn'),
+ key: 'stagn',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.stagnPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.valid'),
+ key: 'valid',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.validPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.validWarn'),
+ key: 'validWarn',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.search.validWarnPlaceholder')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.flagCheck'),
+ key: 'flagCheck',
+ type: 'select',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.flagCheckPlaceholder'),
+ options: getWhMatFlagCheckOptions(t)
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.status'),
+ key: 'status',
+ type: 'select',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.statusPlaceholder'),
+ options: getWhMatStatusOptions(t)
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.search.memo'),
+ key: 'memo',
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.memoPlaceholder')
+ }
+ },
+ ...enabledFields.value.map((field) => ({
+ label: field.fieldsAlise,
+ key: getWhMatDynamicFieldKey(field.fields),
+ type: 'input',
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.dynamicPlaceholder', {
+ field: field.fieldsAlise
+ })
+ }
+ }))
])
- const { columnChecks, columns } = useTableColumns(() =>
+ const { columnChecks, columns, resetColumns } = useTableColumns(() =>
createWhMatTableColumns({
- t,
- handleViewDetail: openDetailDrawer
+ enabledFields: enabledFields.value,
+ handleViewDetail: openDetailDrawer,
+ handleEdit: hasAuth('update') ? openEditDialog : null,
+ handleDelete: hasAuth('delete') ? (row) => handleDeleteAction?.(row) : null,
+ handlePrint: (row) => handlePrint({ ids: [row.id] }),
+ canEdit: hasAuth('update'),
+ canDelete: hasAuth('delete'),
+ t
})
)
@@ -208,6 +672,46 @@
}
}
return null
+ }
+
+ function collectExpandedGroupKeys(nodes, depth = 1, maxExpandedDepth = 1) {
+ if (!Array.isArray(nodes) || depth > maxExpandedDepth) {
+ return []
+ }
+
+ return nodes.flatMap((node) => {
+ const currentId = node?.id !== undefined && node?.id !== null ? [node.id] : []
+ return [
+ ...currentId,
+ ...collectExpandedGroupKeys(node?.children || [], depth + 1, maxExpandedDepth)
+ ]
+ })
+ }
+
+ function normalizeOptionText(value) {
+ return String(value ?? '').trim()
+ }
+
+ function buildOption(value, label, extra = {}) {
+ return {
+ value,
+ label,
+ ...extra
+ }
+ }
+
+ async function loadEnabledFieldDefinitions() {
+ const fields = await guardRequestWithMessage(fetchEnabledFields(), [], {
+ timeoutMessage: t('pages.basicInfo.whMat.messages.enabledFieldsTimeout')
+ })
+ enabledFields.value = normalizeWhMatEnabledFields(fields)
+ enabledFields.value.forEach((field) => {
+ const dynamicKey = getWhMatDynamicFieldKey(field.fields)
+ if (searchForm.value[dynamicKey] === undefined) {
+ searchForm.value[dynamicKey] = ''
+ }
+ })
+ resetColumns()
}
function updatePaginationState(target, response, fallbackCurrent, fallbackSize) {
@@ -237,6 +741,99 @@
}
}
+ async function loadSerialRuleOptions() {
+ try {
+ const response = await guardRequestWithMessage(
+ fetchSerialRulePage({ current: 1, pageSize: 200 }),
+ { records: [] },
+ { timeoutMessage: t('pages.basicInfo.whMat.messages.serialRuleTimeout') }
+ )
+ serialRuleOptions.value = resolveWhMatSerialRuleOptions(
+ defaultResponseAdapter(response).records
+ )
+ } catch (error) {
+ serialRuleOptions.value = []
+ ElMessage.error(error?.message || t('pages.basicInfo.whMat.messages.serialRuleLoadFailed'))
+ }
+ }
+
+ async function ensureBindLocOptionsLoaded(force = false) {
+ if (
+ !force &&
+ areaOptions.value.length &&
+ areaMatOptions.value.length &&
+ locOptions.value.length
+ ) {
+ return
+ }
+ if (bindLocOptionsLoading.value) {
+ return
+ }
+
+ bindLocOptionsLoading.value = true
+ try {
+ const [areasResponse, areaMatResponse, locResponse] = await Promise.all([
+ guardRequestWithMessage(fetchWarehouseAreasList(), [], {
+ timeoutMessage: t('pages.basicInfo.whMat.messages.bindLocTimeout')
+ }),
+ guardRequestWithMessage(fetchLocAreaMatList(), [], {
+ timeoutMessage: t('pages.basicInfo.whMat.messages.bindLocTimeout')
+ }),
+ guardRequestWithMessage(
+ fetchLocPage({ current: 1, pageSize: 1000 }),
+ { records: [] },
+ {
+ timeoutMessage: t('pages.basicInfo.whMat.messages.bindLocTimeout')
+ }
+ )
+ ])
+
+ areaOptions.value = defaultResponseAdapter(areasResponse)
+ .records.map((item) =>
+ buildOption(
+ Number(item.id),
+ [normalizeOptionText(item.name), normalizeOptionText(item.code)]
+ .filter(Boolean)
+ .join(' 路 ') || t('common.placeholder.empty'),
+ {
+ areaId: Number(item.id),
+ warehouseId: item.warehouseId !== undefined ? Number(item.warehouseId) : void 0
+ }
+ )
+ )
+ .filter((item) => Number.isFinite(item.value))
+
+ areaMatOptions.value = defaultResponseAdapter(areaMatResponse)
+ .records.map((item) =>
+ buildOption(
+ Number(item.id),
+ [normalizeOptionText(item.code), normalizeOptionText(item.depict || item.name)]
+ .filter(Boolean)
+ .join(' 路 ') || t('common.placeholder.empty'),
+ {
+ areaMatId: Number(item.id),
+ areaId: item.areaId !== undefined ? Number(item.areaId) : void 0
+ }
+ )
+ )
+ .filter((item) => Number.isFinite(item.value))
+
+ locOptions.value = defaultResponseAdapter(locResponse)
+ .records.map((item) =>
+ buildOption(
+ Number(item.id),
+ normalizeOptionText(item.code) || t('common.placeholder.empty'),
+ {
+ areaId: item.areaId !== undefined ? Number(item.areaId) : void 0
+ }
+ )
+ )
+ .filter((item) => Number.isFinite(item.value))
+ } finally {
+ bindLocOptionsLoading.value = false
+ }
+ }
+
async function loadMatnrList() {
loading.value = true
try {
@@ -244,7 +841,7 @@
fetchMatnrPage(
buildMatnrPageQueryParams({
...searchForm.value,
- groupId: selectedGroupId.value,
+ groupId: searchForm.value?.groupId || selectedGroupId.value,
current: pagination.current,
pageSize: pagination.size
})
@@ -258,7 +855,7 @@
{ timeoutMessage: t('pages.basicInfo.whMat.messages.listTimeout') }
)
tableData.value = Array.isArray(response?.records)
- ? response.records.map((record) => normalizeMatnrRow(record, t))
+ ? response.records.map((record) => normalizeMatnrRow(record, t, enabledFields.value))
: []
updatePaginationState(pagination, response, pagination.current, pagination.size)
} catch (error) {
@@ -269,16 +866,21 @@
}
}
+ async function loadMatnrDetail(id) {
+ return await guardRequestWithMessage(
+ fetchMatnrDetail(id),
+ {},
+ {
+ timeoutMessage: t('pages.basicInfo.whMat.messages.detailTimeout')
+ }
+ )
+ }
+
async function openDetailDrawer(row) {
detailDrawerVisible.value = true
detailLoading.value = true
try {
- detailData.value = normalizeMatnrDetail(
- await guardRequestWithMessage(fetchMatnrDetail(row.id), {}, {
- timeoutMessage: t('pages.basicInfo.whMat.messages.detailTimeout')
- }),
- t
- )
+ detailData.value = normalizeMatnrDetail(await loadMatnrDetail(row.id), t, enabledFields.value)
} catch (error) {
detailDrawerVisible.value = false
detailData.value = {}
@@ -288,21 +890,236 @@
}
}
+ async function openEditDialog(row) {
+ try {
+ const detail = await loadMatnrDetail(row.id)
+ showDialog('edit', detail)
+ } catch (error) {
+ ElMessage.error(error?.message || t('pages.basicInfo.whMat.messages.detailLoadFailed'))
+ }
+ }
+
+ const {
+ dialogVisible,
+ dialogType,
+ currentRecord: currentMaterialData,
+ selectedRows,
+ handleSelectionChange,
+ showDialog,
+ handleDialogSubmit,
+ handleDelete,
+ handleBatchDelete
+ } = useCrudPage({
+ createEmptyModel: () =>
+ buildWhMatDialogModel({ groupId: selectedGroupId.value || searchForm.value?.groupId || '' }),
+ buildEditModel: (record) => buildWhMatDialogModel(record),
+ buildSavePayload: (formData) => buildWhMatSavePayload(formData),
+ saveRequest: fetchSaveMatnr,
+ updateRequest: fetchUpdateMatnr,
+ deleteRequest: fetchDeleteMatnr,
+ entityName: t('pages.basicInfo.whMat.entity'),
+ resolveRecordLabel: (record) => record?.name || record?.code || record?.id,
+ refreshCreate: loadMatnrList,
+ refreshUpdate: loadMatnrList,
+ refreshRemove: loadMatnrList
+ })
+ handleDeleteAction = handleDelete
+
+ const getSelectedIds = () =>
+ selectedRows.value.map((item) => Number(item?.id)).filter((id) => Number.isFinite(id))
+
+ const ensureSelectedRows = () => {
+ const ids = getSelectedIds()
+ if (!ids.length) {
+ ElMessage.warning(t('pages.basicInfo.whMat.messages.selectAtLeastOne'))
+ return []
+ }
+ return ids
+ }
+
+ function openBatchDialog(type) {
+ if (!ensureSelectedRows().length) {
+ return
+ }
+ batchDialogType.value = type
+ batchDialogVisible.value = true
+ }
+
+ function openBatchGroupDialog() {
+ if (!ensureSelectedRows().length) {
+ return
+ }
+ batchGroupDialogVisible.value = true
+ }
+
+ async function openBindLocDialog() {
+ if (!ensureSelectedRows().length) {
+ return
+ }
+ try {
+ await ensureBindLocOptionsLoaded()
+ bindLocDialogVisible.value = true
+ } catch (error) {
+ ElMessage.error(error?.message || t('pages.basicInfo.whMat.messages.bindLocLoadFailed'))
+ }
+ }
+
+ async function handleBatchDialogSubmit(formData) {
+ const ids = ensureSelectedRows()
+ if (!ids.length) {
+ batchDialogVisible.value = false
+ return
+ }
+
+ try {
+ await fetchBatchUpdateMatnr({
+ ids,
+ matnr: formData
+ })
+ ElMessage.success(t('crud.messages.updateSuccess'))
+ batchDialogVisible.value = false
+ selectedRows.value = []
+ await loadMatnrList()
+ } catch (error) {
+ ElMessage.error(error?.message || t('crud.messages.submitFailed'))
+ }
+ }
+
+ async function handleBatchGroupSubmit(formData) {
+ const ids = ensureSelectedRows()
+ if (!ids.length) {
+ batchGroupDialogVisible.value = false
+ return
+ }
+
+ try {
+ await fetchBindMatnrGroup({
+ ids,
+ groupId: formData.groupId
+ })
+ ElMessage.success(t('crud.messages.updateSuccess'))
+ batchGroupDialogVisible.value = false
+ selectedRows.value = []
+ await loadMatnrList()
+ } catch (error) {
+ ElMessage.error(error?.message || t('crud.messages.submitFailed'))
+ }
+ }
+
+ async function handleBindLocSubmit(formData) {
+ const ids = ensureSelectedRows()
+ if (!ids.length) {
+ bindLocDialogVisible.value = false
+ return
+ }
+
+ try {
+ await fetchBindLocAreaMatRelaByMatnr({
+ ...formData,
+ matnrId: ids
+ })
+ ElMessage.success(t('crud.messages.updateSuccess'))
+ bindLocDialogVisible.value = false
+ selectedRows.value = []
+ await loadMatnrList()
+ } catch (error) {
+ ElMessage.error(error?.message || t('crud.messages.submitFailed'))
+ }
+ }
+
+ const buildPreviewMeta = (rows) => {
+ const now = new Date()
+ return {
+ reportDate: now.toLocaleDateString('zh-CN'),
+ printedAt: now.toLocaleString('zh-CN', { hour12: false }),
+ operator: userStore.getUserInfo?.name || userStore.getUserInfo?.username || '',
+ count: rows.length,
+ reportStyle: { ...WH_MAT_REPORT_STYLE }
+ }
+ }
+
+ const resolvePrintRecords = async (payload) => {
+ if (Array.isArray(payload?.ids) && payload.ids.length > 0) {
+ return defaultResponseAdapter(await fetchGetMatnrMany(payload.ids)).records
+ }
+ return tableData.value
+ }
+
+ const {
+ previewVisible,
+ previewRows,
+ previewMeta,
+ handlePreviewVisibleChange,
+ handleExport,
+ handlePrint
+ } = usePrintExportPage({
+ downloadFileName: 'matnr.xlsx',
+ requestExport: (payload) =>
+ fetchExportMatnrReport(payload, {
+ headers: {
+ Authorization: userStore.accessToken || ''
+ }
+ }),
+ resolvePrintRecords,
+ buildPreviewRows: (records) => buildWhMatPrintRows(records, t),
+ buildPreviewMeta
+ })
+
+ const resolvedPreviewMeta = computed(() =>
+ buildWhMatReportMeta({
+ previewMeta: previewMeta.value,
+ count: previewRows.value.length,
+ orientation: previewMeta.value?.reportStyle?.orientation || WH_MAT_REPORT_STYLE.orientation
+ })
+ )
+
+ async function downloadFile(response, fallbackName) {
+ if (!response?.ok) {
+ throw new Error(
+ t('crud.messages.exportFailedWithStatus', { status: response?.status || '-' })
+ )
+ }
+ const blob = await response.blob()
+ const downloadUrl = window.URL.createObjectURL(blob)
+ const link = document.createElement('a')
+ link.href = downloadUrl
+ link.download = fallbackName
+ document.body.appendChild(link)
+ link.click()
+ link.remove()
+ window.URL.revokeObjectURL(downloadUrl)
+ }
+
+ function handleShowDialog(type) {
+ showDialog(type)
+ }
+
function handleSearch(params) {
searchForm.value = {
...searchForm.value,
- ...params
+ ...params,
+ orderBy: searchForm.value?.orderBy || 'create_time desc'
}
pagination.current = 1
+ if (searchForm.value.groupId) {
+ selectedGroupId.value = null
+ }
loadMatnrList()
}
async function handleReset() {
searchForm.value = createWhMatSearchState()
+ enabledFields.value.forEach((field) => {
+ searchForm.value[getWhMatDynamicFieldKey(field.fields)] = ''
+ })
pagination.current = 1
selectedGroupId.value = null
groupSearch.value = ''
await Promise.all([loadGroupTree(), loadMatnrList()])
+ }
+
+ function handleRefresh() {
+ loadMatnrList()
}
function handleSizeChange(size) {
@@ -318,6 +1135,7 @@
function handleGroupNodeClick(data) {
selectedGroupId.value = data?.id ?? null
+ delete searchForm.value.groupId
pagination.current = 1
loadMatnrList()
}
@@ -335,46 +1153,154 @@
await Promise.all([loadGroupTree(), loadMatnrList()])
}
+ async function handleImportFileChange(uploadFile) {
+ if (!uploadFile?.raw) {
+ return
+ }
+ importing.value = true
+ try {
+ await fetchImportMatnr(uploadFile.raw)
+ ElMessage.success(t('pages.basicInfo.whMat.messages.importSuccess'))
+ await loadMatnrList()
+ } catch (error) {
+ ElMessage.error(error?.message || t('pages.basicInfo.whMat.messages.importFailed'))
+ } finally {
+ importing.value = false
+ }
+ }
+
+ async function handleDownloadTemplate() {
+ templateDownloading.value = true
+ try {
+ const response = await fetchDownloadMatnrTemplate(
+ {},
+ {
+ headers: {
+ Authorization: userStore.accessToken || ''
+ }
+ }
+ )
+ await downloadFile(response, 'matnr-template.xlsx')
+ ElMessage.success(t('pages.basicInfo.whMat.messages.templateDownloadSuccess'))
+ } catch (error) {
+ ElMessage.error(error?.message || t('pages.basicInfo.whMat.messages.templateDownloadFailed'))
+ } finally {
+ templateDownloading.value = false
+ }
+ }
+
onMounted(async () => {
- await Promise.all([loadGroupTree(), loadMatnrList()])
+ await Promise.allSettled([
+ loadEnabledFieldDefinitions(),
+ loadGroupTree(),
+ loadSerialRuleOptions()
+ ])
+ await loadMatnrList()
})
</script>
<style scoped>
+ .wh-mat-page-root {
+ height: 100%;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ }
+
.wh-mat-page {
display: flex;
flex-direction: row;
- align-items: flex-start;
+ align-items: stretch;
gap: 16px;
+ flex: 1 1 auto;
+ min-height: 0;
}
.wh-mat-page__sidebar {
width: 320px;
flex: 0 0 320px;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
}
.wh-mat-page__sidebar-card {
- position: sticky;
- top: 16px;
+ height: 100%;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .wh-mat-page__sidebar-card :deep(.el-card__body) {
+ height: 100%;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
}
.wh-mat-page__tree-scroll {
- height: calc(100vh - 320px);
- min-height: 420px;
+ flex: 1 1 auto;
+ min-height: 0;
}
.wh-mat-page__content {
+ height: 100%;
min-width: 0;
+ min-height: 0;
flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
}
.wh-mat-page__content > * + * {
margin-top: 16px;
}
+ .wh-mat-page__content > :deep(.art-search-bar) {
+ flex: 0 0 auto;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card) {
+ flex: 1 1 auto;
+ min-height: 0;
+ overflow: hidden;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card .el-card__body) {
+ display: flex;
+ min-height: 0;
+ flex-direction: column;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card #art-table-header) {
+ flex: 0 0 auto;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card .art-table) {
+ flex: 1 1 auto;
+ min-height: 0;
+ display: flex;
+ flex-direction: column;
+ overflow: hidden;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card .art-table .el-table) {
+ flex: 1 1 auto;
+ min-height: 0;
+ height: auto;
+ }
+
+ .wh-mat-page__content > :deep(.art-table-card .art-table .pagination) {
+ flex: 0 0 auto;
+ }
+
@media (max-width: 1024px) {
.wh-mat-page {
flex-direction: column;
+ flex: none;
}
.wh-mat-page__sidebar {
@@ -383,7 +1309,7 @@
}
.wh-mat-page__sidebar-card {
- position: static;
+ height: auto;
}
.wh-mat-page__tree-scroll {
diff --git a/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-dialog.vue b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-dialog.vue
new file mode 100644
index 0000000..c5aa0f5
--- /dev/null
+++ b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-dialog.vue
@@ -0,0 +1,232 @@
+<template>
+ <ElDialog
+ :title="dialogTitle"
+ :model-value="visible"
+ width="640px"
+ align-center
+ destroy-on-close
+ @update:model-value="handleCancel"
+ @closed="handleClosed"
+ >
+ <ArtForm
+ ref="formRef"
+ v-model="form"
+ :items="formItems"
+ :rules="rules"
+ :span="12"
+ :gutter="20"
+ label-width="120px"
+ :show-reset="false"
+ :show-submit="false"
+ />
+
+ <template #footer>
+ <span class="dialog-footer">
+ <ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton>
+ <ElButton type="primary" @click="handleSubmit">{{ t('common.confirm') }}</ElButton>
+ </span>
+ </template>
+ </ElDialog>
+</template>
+
+<script setup>
+ import { computed, nextTick, reactive, ref, watch } from 'vue'
+ import { useI18n } from 'vue-i18n'
+ import ArtForm from '@/components/core/forms/art-form/index.vue'
+ import {
+ getWhMatFlagCheckOptions,
+ getWhMatStatusOptions,
+ getWhMatStockLevelOptions
+ } from '../whMatPage.helpers'
+
+ const props = defineProps({
+ visible: { type: Boolean, default: false },
+ actionType: { type: String, default: 'status' }
+ })
+
+ const emit = defineEmits(['update:visible', 'submit'])
+ const { t } = useI18n()
+
+ const formRef = ref()
+ const form = reactive(createFormState())
+
+ function createFormState() {
+ return {
+ status: '',
+ stockLevel: '',
+ validWarn: null,
+ valid: null,
+ flagCheck: ''
+ }
+ }
+
+ const dialogTitle = computed(() =>
+ t(`pages.basicInfo.whMat.batchDialog.titles.${props.actionType}`)
+ )
+
+ const formItems = computed(() => {
+ if (props.actionType === 'status') {
+ return [
+ {
+ label: t('table.status'),
+ key: 'status',
+ type: 'select',
+ span: 24,
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.search.statusPlaceholder'),
+ options: getWhMatStatusOptions(t)
+ }
+ }
+ ]
+ }
+
+ if (props.actionType === 'stockLevel') {
+ return [
+ {
+ label: t('pages.basicInfo.whMat.batchDialog.fields.stockLevel'),
+ key: 'stockLevel',
+ type: 'select',
+ span: 24,
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.batchDialog.placeholders.stockLevel'),
+ options: getWhMatStockLevelOptions()
+ }
+ }
+ ]
+ }
+
+ if (props.actionType === 'validWarn') {
+ return [
+ {
+ label: t('pages.basicInfo.whMat.dialog.fields.validWarn'),
+ key: 'validWarn',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.batchDialog.placeholders.validWarn')
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.dialog.fields.valid'),
+ key: 'valid',
+ type: 'number',
+ props: {
+ min: 0,
+ controlsPosition: 'right',
+ valueOnClear: null,
+ placeholder: t('pages.basicInfo.whMat.batchDialog.placeholders.valid')
+ }
+ }
+ ]
+ }
+
+ return [
+ {
+ label: t('pages.basicInfo.whMat.dialog.fields.flagCheck'),
+ key: 'flagCheck',
+ type: 'select',
+ span: 24,
+ props: {
+ clearable: true,
+ placeholder: t('pages.basicInfo.whMat.batchDialog.placeholders.flagCheck'),
+ options: getWhMatFlagCheckOptions(t)
+ }
+ }
+ ]
+ })
+
+ const rules = computed(() => {
+ if (props.actionType === 'status') {
+ return {
+ status: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.batchDialog.validation.status'),
+ trigger: 'change'
+ }
+ ]
+ }
+ }
+
+ if (props.actionType === 'stockLevel') {
+ return {
+ stockLevel: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.batchDialog.validation.stockLevel'),
+ trigger: 'change'
+ }
+ ]
+ }
+ }
+
+ if (props.actionType === 'validWarn') {
+ return {
+ validWarn: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.batchDialog.validation.validWarn'),
+ trigger: 'blur'
+ }
+ ],
+ valid: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.batchDialog.validation.valid'),
+ trigger: 'blur'
+ }
+ ]
+ }
+ }
+
+ return {
+ flagCheck: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.batchDialog.validation.flagCheck'),
+ trigger: 'change'
+ }
+ ]
+ }
+ })
+
+ function resetForm() {
+ Object.assign(form, createFormState())
+ formRef.value?.clearValidate?.()
+ }
+
+ async function handleSubmit() {
+ if (!formRef.value) return
+ try {
+ await formRef.value.validate()
+ emit('submit', { ...form })
+ } catch {
+ return
+ }
+ }
+
+ function handleCancel() {
+ emit('update:visible', false)
+ }
+
+ function handleClosed() {
+ resetForm()
+ }
+
+ watch(
+ () => props.visible,
+ (visible) => {
+ if (visible) {
+ resetForm()
+ nextTick(() => {
+ formRef.value?.clearValidate?.()
+ })
+ }
+ },
+ { immediate: true }
+ )
+</script>
diff --git a/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-group-dialog.vue b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-group-dialog.vue
new file mode 100644
index 0000000..f75c105
--- /dev/null
+++ b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-batch-group-dialog.vue
@@ -0,0 +1,113 @@
+<template>
+ <ElDialog
+ :title="t('pages.basicInfo.whMat.batchGroupDialog.title')"
+ :model-value="visible"
+ width="640px"
+ align-center
+ destroy-on-close
+ @update:model-value="handleCancel"
+ @closed="handleClosed"
+ >
+ <ArtForm
+ ref="formRef"
+ v-model="form"
+ :items="formItems"
+ :rules="rules"
+ :span="24"
+ :gutter="20"
+ label-width="120px"
+ :show-reset="false"
+ :show-submit="false"
+ />
+
+ <template #footer>
+ <span class="dialog-footer">
+ <ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton>
+ <ElButton type="primary" @click="handleSubmit">{{ t('common.confirm') }}</ElButton>
+ </span>
+ </template>
+ </ElDialog>
+</template>
+
+<script setup>
+ import { computed, nextTick, reactive, ref, watch } from 'vue'
+ import { useI18n } from 'vue-i18n'
+ import ArtForm from '@/components/core/forms/art-form/index.vue'
+
+ const props = defineProps({
+ visible: { type: Boolean, default: false },
+ groupOptions: { type: Array, default: () => [] }
+ })
+
+ const emit = defineEmits(['update:visible', 'submit'])
+ const { t } = useI18n()
+
+ const formRef = ref()
+ const form = reactive({ groupId: '' })
+
+ const formItems = computed(() => [
+ {
+ label: t('pages.basicInfo.whMat.dialog.fields.groupId'),
+ key: 'groupId',
+ type: 'treeselect',
+ props: {
+ data: props.groupOptions,
+ props: {
+ label: 'displayLabel',
+ value: 'value',
+ children: 'children'
+ },
+ placeholder: t('pages.basicInfo.whMat.dialog.placeholders.groupId'),
+ clearable: false,
+ checkStrictly: true,
+ defaultExpandAll: true
+ }
+ }
+ ])
+
+ const rules = computed(() => ({
+ groupId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.dialog.validation.groupId'),
+ trigger: 'change'
+ }
+ ]
+ }))
+
+ function resetForm() {
+ form.groupId = ''
+ formRef.value?.clearValidate?.()
+ }
+
+ async function handleSubmit() {
+ if (!formRef.value) return
+ try {
+ await formRef.value.validate()
+ emit('submit', { ...form })
+ } catch {
+ return
+ }
+ }
+
+ function handleCancel() {
+ emit('update:visible', false)
+ }
+
+ function handleClosed() {
+ resetForm()
+ }
+
+ watch(
+ () => props.visible,
+ (visible) => {
+ if (visible) {
+ resetForm()
+ nextTick(() => {
+ formRef.value?.clearValidate?.()
+ })
+ }
+ },
+ { immediate: true }
+ )
+</script>
diff --git a/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-bind-loc-dialog.vue b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-bind-loc-dialog.vue
new file mode 100644
index 0000000..60f6862
--- /dev/null
+++ b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-bind-loc-dialog.vue
@@ -0,0 +1,184 @@
+<template>
+ <ElDialog
+ :title="t('pages.basicInfo.whMat.bindLocDialog.title')"
+ :model-value="visible"
+ width="960px"
+ align-center
+ destroy-on-close
+ @update:model-value="handleCancel"
+ @closed="handleClosed"
+ >
+ <ArtForm
+ ref="formRef"
+ v-model="form"
+ :items="formItems"
+ :rules="rules"
+ :span="12"
+ :gutter="20"
+ label-width="120px"
+ :show-reset="false"
+ :show-submit="false"
+ />
+
+ <template #footer>
+ <span class="dialog-footer">
+ <ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton>
+ <ElButton type="primary" @click="handleSubmit">{{ t('common.confirm') }}</ElButton>
+ </span>
+ </template>
+ </ElDialog>
+</template>
+
+<script setup>
+ import { computed, nextTick, reactive, ref, watch } from 'vue'
+ import { useI18n } from 'vue-i18n'
+ import ArtForm from '@/components/core/forms/art-form/index.vue'
+
+ const props = defineProps({
+ visible: { type: Boolean, default: false },
+ areaMatOptions: { type: Array, default: () => [] },
+ areaOptions: { type: Array, default: () => [] },
+ locOptions: { type: Array, default: () => [] }
+ })
+
+ const emit = defineEmits(['update:visible', 'submit'])
+ const { t } = useI18n()
+
+ const formRef = ref()
+ const form = reactive({
+ areaMatId: '',
+ areaId: '',
+ locId: []
+ })
+
+ const filteredAreaMatOptions = computed(() => {
+ const selectedAreaId =
+ form.areaId !== undefined && form.areaId !== null && form.areaId !== ''
+ ? Number(form.areaId)
+ : void 0
+ if (selectedAreaId === void 0) {
+ return props.areaMatOptions
+ }
+ return props.areaMatOptions.filter(
+ (item) => item.areaId === void 0 || Number(item.areaId) === selectedAreaId
+ )
+ })
+
+ const filteredLocOptions = computed(() => {
+ const selectedAreaId =
+ form.areaId !== undefined && form.areaId !== null && form.areaId !== ''
+ ? Number(form.areaId)
+ : void 0
+ if (selectedAreaId === void 0) {
+ return props.locOptions
+ }
+ return props.locOptions.filter(
+ (item) => item.areaId === void 0 || Number(item.areaId) === selectedAreaId
+ )
+ })
+
+ const formItems = computed(() => [
+ {
+ label: t('pages.basicInfo.whMat.bindLocDialog.fields.areaMatId'),
+ key: 'areaMatId',
+ type: 'select',
+ props: {
+ clearable: true,
+ filterable: true,
+ placeholder: t('pages.basicInfo.whMat.bindLocDialog.placeholders.areaMatId'),
+ options: filteredAreaMatOptions.value
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.bindLocDialog.fields.areaId'),
+ key: 'areaId',
+ type: 'select',
+ props: {
+ clearable: true,
+ filterable: true,
+ placeholder: t('pages.basicInfo.whMat.bindLocDialog.placeholders.areaId'),
+ options: props.areaOptions
+ }
+ },
+ {
+ label: t('pages.basicInfo.whMat.bindLocDialog.fields.locId'),
+ key: 'locId',
+ type: 'select',
+ span: 24,
+ props: {
+ clearable: true,
+ filterable: true,
+ multiple: true,
+ collapseTags: true,
+ placeholder: t('pages.basicInfo.whMat.bindLocDialog.placeholders.locId'),
+ options: filteredLocOptions.value
+ }
+ }
+ ])
+
+ const rules = computed(() => ({
+ areaMatId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.bindLocDialog.validation.areaMatId'),
+ trigger: 'change'
+ }
+ ],
+ areaId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.bindLocDialog.validation.areaId'),
+ trigger: 'change'
+ }
+ ],
+ locId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.bindLocDialog.validation.locId'),
+ trigger: 'change'
+ }
+ ]
+ }))
+
+ function resetForm() {
+ form.areaMatId = ''
+ form.areaId = ''
+ form.locId = []
+ formRef.value?.clearValidate?.()
+ }
+
+ async function handleSubmit() {
+ if (!formRef.value) return
+ try {
+ await formRef.value.validate()
+ emit('submit', {
+ areaMatId: form.areaMatId,
+ areaId: form.areaId,
+ locId: Array.isArray(form.locId) ? [...form.locId] : []
+ })
+ } catch {
+ return
+ }
+ }
+
+ function handleCancel() {
+ emit('update:visible', false)
+ }
+
+ function handleClosed() {
+ resetForm()
+ }
+
+ watch(
+ () => props.visible,
+ (visible) => {
+ if (visible) {
+ resetForm()
+ nextTick(() => {
+ formRef.value?.clearValidate?.()
+ })
+ }
+ },
+ { immediate: true }
+ )
+</script>
diff --git a/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-dialog.vue b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-dialog.vue
new file mode 100644
index 0000000..19b2489
--- /dev/null
+++ b/rsf-design/src/views/basic-info/wh-mat/modules/wh-mat-dialog.vue
@@ -0,0 +1,380 @@
+<template>
+ <ElDialog
+ :title="dialogTitle"
+ :model-value="visible"
+ width="960px"
+ align-center
+ destroy-on-close
+ @update:model-value="handleCancel"
+ @closed="handleClosed"
+ >
+ <ElForm
+ ref="formRef"
+ :model="form"
+ :rules="rules"
+ label-width="110px"
+ class="wh-mat-dialog-form"
+ >
+ <ElTabs v-model="activeTab">
+ <ElTabPane :label="t('pages.basicInfo.whMat.dialog.tabs.basic')" name="basic">
+ <ElRow :gutter="20">
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.code')" prop="code">
+ <ElInput
+ v-model.trim="form.code"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.code')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.name')" prop="name">
+ <ElInput
+ v-model.trim="form.name"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.name')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.groupId')" prop="groupId">
+ <ElTreeSelect
+ v-model="form.groupId"
+ :data="groupOptions"
+ :props="groupTreeProps"
+ check-strictly
+ default-expand-all
+ clearable
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.groupId')"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem
+ :label="t('pages.basicInfo.whMat.dialog.fields.useOrgName')"
+ prop="useOrgName"
+ >
+ <ElInput
+ v-model.trim="form.useOrgName"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.useOrgName')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.spec')" prop="spec">
+ <ElInput
+ v-model.trim="form.spec"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.spec')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.model')" prop="model">
+ <ElInput
+ v-model.trim="form.model"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.model')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.color')" prop="color">
+ <ElInput
+ v-model.trim="form.color"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.color')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.size')" prop="size">
+ <ElInput
+ v-model.trim="form.size"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.size')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.weight')" prop="weight">
+ <ElInputNumber
+ v-model="form.weight"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.unit')" prop="unit">
+ <ElInput
+ v-model.trim="form.unit"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.unit')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.purUnit')" prop="purUnit">
+ <ElInput
+ v-model.trim="form.purUnit"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.purUnit')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem
+ :label="t('pages.basicInfo.whMat.dialog.fields.describle')"
+ prop="describle"
+ >
+ <ElInput
+ v-model.trim="form.describle"
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.describle')"
+ clearable
+ />
+ </ElFormItem>
+ </ElCol>
+ </ElRow>
+ </ElTabPane>
+
+ <ElTabPane :label="t('pages.basicInfo.whMat.dialog.tabs.control')" name="control">
+ <ElRow :gutter="20">
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.safeQty')" prop="safeQty">
+ <ElInputNumber
+ v-model="form.safeQty"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.minQty')" prop="minQty">
+ <ElInputNumber
+ v-model="form.minQty"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.maxQty')" prop="maxQty">
+ <ElInputNumber
+ v-model="form.maxQty"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.stagn')" prop="stagn">
+ <ElInputNumber
+ v-model="form.stagn"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.valid')" prop="valid">
+ <ElInputNumber
+ v-model="form.valid"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem
+ :label="t('pages.basicInfo.whMat.dialog.fields.validWarn')"
+ prop="validWarn"
+ >
+ <ElInputNumber
+ v-model="form.validWarn"
+ :min="0"
+ controls-position="right"
+ class="w-full"
+ />
+ </ElFormItem>
+ </ElCol>
+ <ElCol :span="12">
+ <ElFormItem
+ :label="t('pages.basicInfo.whMat.dialog.fields.flagCheck')"
+ prop="flagCheck"
+ >
+ <ElSelect
+ v-model="form.flagCheck"
+ clearable
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.flagCheck')"
+ >
+ <ElOption
+ v-for="option in flagCheckOptions"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </ElSelect>
+ </ElFormItem>
+ </ElCol>
+ </ElRow>
+ </ElTabPane>
+
+ <ElTabPane :label="t('pages.basicInfo.whMat.dialog.tabs.batchRule')" name="batchRule">
+ <ElRow :gutter="20">
+ <ElCol :span="12">
+ <ElFormItem :label="t('pages.basicInfo.whMat.dialog.fields.rglarId')" prop="rglarId">
+ <ElSelect
+ v-model="form.rglarId"
+ clearable
+ filterable
+ :placeholder="t('pages.basicInfo.whMat.dialog.placeholders.rglarId')"
+ >
+ <ElOption
+ v-for="option in serialRuleOptions"
+ :key="option.value"
+ :label="option.label"
+ :value="option.value"
+ />
+ </ElSelect>
+ </ElFormItem>
+ </ElCol>
+ </ElRow>
+ </ElTabPane>
+ </ElTabs>
+ </ElForm>
+
+ <template #footer>
+ <span class="dialog-footer">
+ <ElButton @click="handleCancel">{{ t('common.cancel') }}</ElButton>
+ <ElButton type="primary" @click="handleSubmit">{{ t('common.confirm') }}</ElButton>
+ </span>
+ </template>
+ </ElDialog>
+</template>
+
+<script setup>
+ import { computed, nextTick, reactive, ref, watch } from 'vue'
+ import { useI18n } from 'vue-i18n'
+ import {
+ buildWhMatDialogModel,
+ createWhMatFormState,
+ getWhMatFlagCheckOptions
+ } from '../whMatPage.helpers'
+
+ const props = defineProps({
+ visible: { type: Boolean, default: false },
+ dialogType: { type: String, default: 'add' },
+ materialData: { type: Object, default: () => ({}) },
+ groupOptions: { type: Array, default: () => [] },
+ serialRuleOptions: { type: Array, default: () => [] }
+ })
+
+ const emit = defineEmits(['update:visible', 'submit'])
+ const { t } = useI18n()
+
+ const formRef = ref()
+ const activeTab = ref('basic')
+ const form = reactive(createWhMatFormState())
+
+ const dialogTitle = computed(() =>
+ props.dialogType === 'edit'
+ ? t('pages.basicInfo.whMat.dialog.titleEdit')
+ : t('pages.basicInfo.whMat.dialog.titleCreate')
+ )
+ const flagCheckOptions = computed(() => getWhMatFlagCheckOptions(t))
+ const groupTreeProps = {
+ label: 'displayLabel',
+ value: 'value',
+ children: 'children'
+ }
+
+ const rules = computed(() => ({
+ code: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.dialog.validation.code'),
+ trigger: 'blur'
+ }
+ ],
+ name: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.dialog.validation.name'),
+ trigger: 'blur'
+ }
+ ],
+ groupId: [
+ {
+ required: true,
+ message: t('pages.basicInfo.whMat.dialog.validation.groupId'),
+ trigger: 'change'
+ }
+ ]
+ }))
+
+ function loadFormData() {
+ Object.assign(form, buildWhMatDialogModel(props.materialData))
+ activeTab.value = 'basic'
+ }
+
+ function resetForm() {
+ Object.assign(form, createWhMatFormState())
+ formRef.value?.clearValidate?.()
+ activeTab.value = 'basic'
+ }
+
+ async function handleSubmit() {
+ try {
+ await formRef.value?.validate?.()
+ emit('submit', { ...form })
+ } catch {
+ return
+ }
+ }
+
+ function handleCancel() {
+ emit('update:visible', false)
+ }
+
+ function handleClosed() {
+ resetForm()
+ }
+
+ watch(
+ () => props.visible,
+ (visible) => {
+ if (visible) {
+ loadFormData()
+ nextTick(() => {
+ formRef.value?.clearValidate?.()
+ })
+ }
+ },
+ { immediate: true }
+ )
+
+ watch(
+ () => props.materialData,
+ () => {
+ if (props.visible) {
+ loadFormData()
+ }
+ },
+ { deep: true }
+ )
+</script>
+
+<style scoped>
+ .wh-mat-dialog-form :deep(.el-select),
+ .wh-mat-dialog-form :deep(.el-tree-select) {
+ width: 100%;
+ }
+</style>
diff --git a/rsf-design/src/views/basic-info/wh-mat/whMatPage.helpers.js b/rsf-design/src/views/basic-info/wh-mat/whMatPage.helpers.js
index 5930c2f..c433717 100644
--- a/rsf-design/src/views/basic-info/wh-mat/whMatPage.helpers.js
+++ b/rsf-design/src/views/basic-info/wh-mat/whMatPage.helpers.js
@@ -1,5 +1,13 @@
import { $t } from '@/locales'
+export const WH_MAT_REPORT_TITLE = '鐗╂枡鎶ヨ〃'
+export const WH_MAT_REPORT_STYLE = {
+ orientation: 'landscape',
+ titleAlign: 'center',
+ titleLevel: 'h2'
+}
+export const WH_MAT_DYNAMIC_FIELD_PREFIX = 'extendField__'
+
function normalizeText(value) {
return String(value ?? '').trim()
}
@@ -20,33 +28,137 @@
return Number.isFinite(numericValue) ? numericValue : null
}
+function normalizeNullableInteger(value) {
+ const numericValue = normalizeNullableNumber(value)
+ return numericValue === null ? null : Math.trunc(numericValue)
+}
+
+function normalizeBooleanLikeText(value, t = $t) {
+ if (value === 1 || value === '1') return t('common.status.yes')
+ if (value === 0 || value === '0') return t('common.status.no')
+ return t('common.placeholder.empty')
+}
+
export function createWhMatSearchState() {
return {
condition: '',
code: '',
name: '',
+ platCode: '',
spec: '',
model: '',
- barcode: ''
+ color: '',
+ size: '',
+ unit: '',
+ purUnit: '',
+ stockUnit: '',
+ barcode: '',
+ describle: '',
+ groupId: '',
+ rglarId: '',
+ weight: null,
+ nromNum: null,
+ stockLevel: '',
+ flagLabelMange: '',
+ safeQty: null,
+ minQty: null,
+ maxQty: null,
+ stagn: null,
+ valid: null,
+ status: '',
+ flagCheck: '',
+ validWarn: null,
+ memo: '',
+ orderBy: 'create_time desc'
+ }
+}
+
+export function createWhMatFormState() {
+ return {
+ id: void 0,
+ code: '',
+ name: '',
+ groupId: '',
+ useOrgName: '',
+ spec: '',
+ model: '',
+ color: '',
+ size: '',
+ weight: void 0,
+ unit: '',
+ purUnit: '',
+ describle: '',
+ safeQty: void 0,
+ minQty: void 0,
+ maxQty: void 0,
+ stagn: void 0,
+ valid: void 0,
+ validWarn: void 0,
+ flagCheck: 0,
+ rglarId: ''
}
}
export function buildWhMatPageQueryParams(params = {}) {
const result = {
current: params.current || 1,
- pageSize: params.pageSize || params.size || 20
+ pageSize: params.pageSize || params.size || 20,
+ orderBy: normalizeText(params.orderBy) || 'create_time desc'
}
- ;['condition', 'code', 'name', 'spec', 'model', 'barcode'].forEach((key) => {
+ ;[
+ 'condition',
+ 'code',
+ 'name',
+ 'platCode',
+ 'spec',
+ 'model',
+ 'color',
+ 'size',
+ 'unit',
+ 'purUnit',
+ 'stockUnit',
+ 'barcode',
+ 'describle',
+ 'memo'
+ ].forEach((key) => {
const value = normalizeText(params[key])
if (value) {
result[key] = value
}
})
+ ;[
+ 'groupId',
+ 'rglarId',
+ 'weight',
+ 'nromNum',
+ 'stockLevel',
+ 'flagLabelMange',
+ 'safeQty',
+ 'minQty',
+ 'maxQty',
+ 'stagn',
+ 'valid',
+ 'status',
+ 'flagCheck',
+ 'validWarn'
+ ].forEach((key) => {
+ const value = params[key]
+ if (value !== '' && value !== null && value !== undefined) {
+ const numericValue = Number(value)
+ result[key] = Number.isFinite(numericValue) ? numericValue : value
+ }
+ })
- if (params.groupId !== undefined && params.groupId !== null && params.groupId !== '') {
- result.groupId = String(params.groupId)
- }
+ Object.entries(params).forEach(([key, value]) => {
+ if (!key.startsWith(WH_MAT_DYNAMIC_FIELD_PREFIX)) {
+ return
+ }
+ const normalizedValue = normalizeText(value)
+ if (normalizedValue) {
+ result[key.slice(WH_MAT_DYNAMIC_FIELD_PREFIX.length)] = normalizedValue
+ }
+ })
return result
}
@@ -63,7 +175,7 @@
}
return records.map((item) => {
- const children = normalizeWhMatGroupTreeRows(item?.children || [])
+ const children = normalizeWhMatGroupTreeRows(item?.children || [], t)
const id = normalizeNullableNumber(item?.id)
const code = normalizeText(item?.code)
const name = normalizeText(item?.name)
@@ -77,8 +189,12 @@
name,
label,
displayLabel: label,
+ value: id,
status: normalizeNullableNumber(item?.status),
- statusText: normalizeNumber(item?.status, 1) === 1 ? t('common.status.normal') : t('common.status.frozen'),
+ statusText:
+ normalizeNumber(item?.status, 1) === 1
+ ? t('common.status.normal')
+ : t('common.status.frozen'),
statusType: normalizeNumber(item?.status, 1) === 1 ? 'success' : 'danger',
memo: normalizeText(item?.memo) || t('common.placeholder.empty'),
children
@@ -86,62 +202,241 @@
})
}
-export function normalizeWhMatRow(record = {}, t = $t) {
- const statusValue = normalizeNullableNumber(record?.status)
+export function resolveWhMatGroupOptions(treeRows = []) {
+ if (!Array.isArray(treeRows)) {
+ return []
+ }
+
+ return treeRows.map((item) => ({
+ id: item.id,
+ value: item.id,
+ label:
+ item.displayLabel || item.label || [item.name, item.code].filter(Boolean).join(' 路 ') || '-',
+ displayLabel:
+ item.displayLabel || item.label || [item.name, item.code].filter(Boolean).join(' 路 ') || '-',
+ children: resolveWhMatGroupOptions(item.children || [])
+ }))
+}
+
+export function resolveWhMatSerialRuleOptions(records = []) {
+ if (!Array.isArray(records)) {
+ return []
+ }
+ return records
+ .map((item) => ({
+ value: normalizeNullableNumber(item?.id),
+ label: normalizeText(item?.name || item?.code || item?.description)
+ }))
+ .filter((item) => item.value !== null && item.label)
+}
+
+export function getWhMatStatusOptions(t = $t) {
+ return [
+ { value: 1, label: t('common.status.normal') },
+ { value: 0, label: t('common.status.frozen') }
+ ]
+}
+
+export function getWhMatFlagCheckOptions(t = $t) {
+ return [
+ { value: 0, label: t('common.status.no') },
+ { value: 1, label: t('common.status.yes') }
+ ]
+}
+
+export function getWhMatStockLevelOptions() {
+ return [
+ { value: 0, label: 'A' },
+ { value: 1, label: 'B' },
+ { value: 2, label: 'C' }
+ ]
+}
+
+export function getWhMatFlagLabelManageOptions(t = $t) {
+ return [
+ { value: 0, label: t('common.status.no') },
+ { value: 1, label: t('common.status.yes') }
+ ]
+}
+
+export function getWhMatDynamicFieldKey(fieldName) {
+ return `${WH_MAT_DYNAMIC_FIELD_PREFIX}${fieldName}`
+}
+
+export function normalizeWhMatEnabledFields(fields = []) {
+ if (!Array.isArray(fields)) {
+ return []
+ }
+
+ return fields
+ .map((item) => ({
+ fields: normalizeText(item?.fields),
+ fieldsAlise: normalizeText(item?.fieldsAlise || item?.fieldsAlias || item?.fields)
+ }))
+ .filter((item) => item.fields)
+}
+
+export function attachWhMatDynamicFields(record = {}, enabledFields = []) {
+ const extendFields =
+ record?.extendFields &&
+ typeof record.extendFields === 'object' &&
+ !Array.isArray(record.extendFields)
+ ? record.extendFields
+ : {}
+ const dynamicValues = {}
+
+ enabledFields.forEach((field) => {
+ dynamicValues[getWhMatDynamicFieldKey(field.fields)] = extendFields[field.fields] || ''
+ })
+
return {
...record,
- code: normalizeText(record?.code) || t('common.placeholder.empty'),
- name: normalizeText(record?.name) || t('common.placeholder.empty'),
- groupName: normalizeText(record?.groupId$ || record?.groupCode) || t('common.placeholder.empty'),
- shipperName: normalizeText(record?.shipperId$ || record?.shipperName) || t('common.placeholder.empty'),
- barcode: normalizeText(record?.barcode) || t('common.placeholder.empty'),
- spec: normalizeText(record?.spec) || t('common.placeholder.empty'),
- model: normalizeText(record?.model) || t('common.placeholder.empty'),
- color: normalizeText(record?.color) || t('common.placeholder.empty'),
- size: normalizeText(record?.size) || t('common.placeholder.empty'),
- unit: normalizeText(record?.unit) || t('common.placeholder.empty'),
- purUnit: normalizeText(record?.purUnit) || t('common.placeholder.empty'),
- stockUnit: normalizeText(record?.stockUnit) || t('common.placeholder.empty'),
- stockLevelText: normalizeText(record?.stockLeval$) || t('common.placeholder.empty'),
- flagLabelManageText: normalizeText(record?.flagLabelMange$) || t('common.placeholder.empty'),
- flagCheckText:
- record?.flagCheck === 1 || record?.flagCheck === '1'
- ? t('common.status.yes')
- : record?.flagCheck === 0 || record?.flagCheck === '0'
- ? t('common.status.no')
- : t('common.placeholder.empty'),
- statusText:
- normalizeText(record?.status$) ||
- (statusValue === 1
- ? t('common.status.normal')
- : statusValue === 0
- ? t('common.status.frozen')
- : t('common.placeholder.empty')),
- statusType: statusValue === 1 ? 'success' : statusValue === 0 ? 'danger' : 'info',
- safeQty: record?.safeQty ?? t('common.placeholder.empty'),
- minQty: record?.minQty ?? t('common.placeholder.empty'),
- maxQty: record?.maxQty ?? t('common.placeholder.empty'),
- valid: record?.valid ?? t('common.placeholder.empty'),
- validWarn: record?.validWarn ?? t('common.placeholder.empty'),
- stagn: record?.stagn ?? t('common.placeholder.empty'),
- describle: normalizeText(record?.describle) || t('common.placeholder.empty'),
- baseUnit: normalizeText(record?.baseUnit) || t('common.placeholder.empty'),
- useOrgName: normalizeText(record?.useOrgName) || t('common.placeholder.empty'),
- erpClsId: normalizeText(record?.erpClsId) || t('common.placeholder.empty'),
- memo: normalizeText(record?.memo) || t('common.placeholder.empty'),
- updateByText: normalizeText(record?.updateBy$) || t('common.placeholder.empty'),
- createByText: normalizeText(record?.createBy$) || t('common.placeholder.empty'),
- updateTimeText: normalizeText(record?.updateTime$ || record?.updateTime) || t('common.placeholder.empty'),
- createTimeText: normalizeText(record?.createTime$ || record?.createTime) || t('common.placeholder.empty'),
- extendFields:
- record?.extendFields && typeof record.extendFields === 'object' && !Array.isArray(record.extendFields)
- ? record.extendFields
- : {}
+ ...dynamicValues,
+ extendFields
}
}
-export function normalizeWhMatDetail(record = {}, t = $t) {
- return normalizeWhMatRow(record, t)
+export function normalizeWhMatRow(record = {}, t = $t, enabledFields = []) {
+ const statusValue = normalizeNullableNumber(record?.status)
+ const validWarn = record?.validWarn ?? record?.valid_warn
+ const purUnit = record?.purUnit ?? record?.purchaseUnit
+ const stockLevelLabel =
+ getWhMatStockLevelOptions().find(
+ (item) => item.value === normalizeNullableNumber(record?.stockLevel)
+ )?.label || ''
+ const flagLabelManageLabel =
+ getWhMatFlagLabelManageOptions(t).find(
+ (item) => item.value === normalizeNullableNumber(record?.flagLabelMange)
+ )?.label || ''
+
+ return attachWhMatDynamicFields(
+ {
+ ...record,
+ id: normalizeNullableNumber(record?.id),
+ code: normalizeText(record?.code) || t('common.placeholder.empty'),
+ name: normalizeText(record?.name) || t('common.placeholder.empty'),
+ groupId: normalizeNullableNumber(record?.groupId),
+ groupName:
+ normalizeText(record?.groupId$ || record?.groupCode || record?.groupName) ||
+ t('common.placeholder.empty'),
+ shipperName:
+ normalizeText(record?.shipperId$ || record?.shipperName) || t('common.placeholder.empty'),
+ barcode: normalizeText(record?.barcode) || t('common.placeholder.empty'),
+ platCode: normalizeText(record?.platCode) || t('common.placeholder.empty'),
+ spec: normalizeText(record?.spec) || t('common.placeholder.empty'),
+ model: normalizeText(record?.model) || t('common.placeholder.empty'),
+ color: normalizeText(record?.color) || t('common.placeholder.empty'),
+ size: normalizeText(record?.size) || t('common.placeholder.empty'),
+ weight: record?.weight ?? t('common.placeholder.empty'),
+ nromNum: record?.nromNum ?? t('common.placeholder.empty'),
+ unit: normalizeText(record?.unit) || t('common.placeholder.empty'),
+ purUnit: normalizeText(purUnit) || t('common.placeholder.empty'),
+ stockUnit: normalizeText(record?.stockUnit) || t('common.placeholder.empty'),
+ stockLevelText:
+ normalizeText(record?.stockLeval$ || record?.stockLevel$ || stockLevelLabel) ||
+ t('common.placeholder.empty'),
+ flagLabelManageText:
+ normalizeText(record?.flagLabelMange$ || record?.isLabelMange$ || flagLabelManageLabel) ||
+ t('common.placeholder.empty'),
+ flagCheckText: normalizeBooleanLikeText(record?.flagCheck, t),
+ statusText:
+ normalizeText(record?.status$) ||
+ (statusValue === 1
+ ? t('common.status.normal')
+ : statusValue === 0
+ ? t('common.status.frozen')
+ : t('common.placeholder.empty')),
+ statusType: statusValue === 1 ? 'success' : statusValue === 0 ? 'danger' : 'info',
+ safeQty: record?.safeQty ?? t('common.placeholder.empty'),
+ minQty: record?.minQty ?? t('common.placeholder.empty'),
+ maxQty: record?.maxQty ?? t('common.placeholder.empty'),
+ valid: record?.valid ?? t('common.placeholder.empty'),
+ validWarn: validWarn ?? t('common.placeholder.empty'),
+ stagn: record?.stagn ?? t('common.placeholder.empty'),
+ describle: normalizeText(record?.describle) || t('common.placeholder.empty'),
+ baseUnit: normalizeText(record?.baseUnit) || t('common.placeholder.empty'),
+ useOrgName: normalizeText(record?.useOrgName) || t('common.placeholder.empty'),
+ erpClsId: normalizeText(record?.erpClsId) || t('common.placeholder.empty'),
+ rglarId: normalizeNullableNumber(record?.rglarId),
+ rglarName:
+ normalizeText(record?.rglarId$ || record?.rglarName || record?.rglarCode) ||
+ t('common.placeholder.empty'),
+ memo: normalizeText(record?.memo) || t('common.placeholder.empty'),
+ updateByText: normalizeText(record?.updateBy$) || t('common.placeholder.empty'),
+ createByText: normalizeText(record?.createBy$) || t('common.placeholder.empty'),
+ updateTimeText:
+ normalizeText(record?.updateTime$ || record?.updateTime) || t('common.placeholder.empty'),
+ createTimeText:
+ normalizeText(record?.createTime$ || record?.createTime) || t('common.placeholder.empty')
+ },
+ enabledFields
+ )
+}
+
+export function normalizeWhMatDetail(record = {}, t = $t, enabledFields = []) {
+ return normalizeWhMatRow(record, t, enabledFields)
+}
+
+export function buildWhMatDialogModel(record = {}) {
+ const source = normalizeWhMatRow(record)
+ return {
+ ...createWhMatFormState(),
+ id: source.id ?? void 0,
+ code: normalizeText(record?.code),
+ name: normalizeText(record?.name),
+ groupId: source.groupId ?? '',
+ useOrgName: normalizeText(record?.useOrgName),
+ spec: normalizeText(record?.spec),
+ model: normalizeText(record?.model),
+ color: normalizeText(record?.color),
+ size: normalizeText(record?.size),
+ weight: normalizeNullableNumber(record?.weight),
+ unit: normalizeText(record?.unit),
+ purUnit: normalizeText(record?.purUnit || record?.purchaseUnit),
+ describle: normalizeText(record?.describle),
+ safeQty: normalizeNullableNumber(record?.safeQty),
+ minQty: normalizeNullableNumber(record?.minQty),
+ maxQty: normalizeNullableNumber(record?.maxQty),
+ stagn: normalizeNullableInteger(record?.stagn),
+ valid: normalizeNullableInteger(record?.valid),
+ validWarn: normalizeNullableInteger(record?.validWarn),
+ flagCheck: normalizeNullableInteger(record?.flagCheck) ?? 0,
+ rglarId: normalizeNullableNumber(record?.rglarId) ?? ''
+ }
+}
+
+export function buildWhMatSavePayload(formData = {}) {
+ const payload = {
+ ...(formData.id !== undefined && formData.id !== null ? { id: Number(formData.id) } : {}),
+ code: normalizeText(formData.code),
+ name: normalizeText(formData.name),
+ groupId:
+ formData.groupId !== undefined && formData.groupId !== null && formData.groupId !== ''
+ ? Number(formData.groupId)
+ : void 0,
+ useOrgName: normalizeText(formData.useOrgName),
+ spec: normalizeText(formData.spec),
+ model: normalizeText(formData.model),
+ color: normalizeText(formData.color),
+ size: normalizeText(formData.size),
+ weight: normalizeNullableNumber(formData.weight),
+ unit: normalizeText(formData.unit),
+ purUnit: normalizeText(formData.purUnit),
+ describle: normalizeText(formData.describle),
+ safeQty: normalizeNullableNumber(formData.safeQty),
+ minQty: normalizeNullableNumber(formData.minQty),
+ maxQty: normalizeNullableNumber(formData.maxQty),
+ stagn: normalizeNullableInteger(formData.stagn),
+ valid: normalizeNullableInteger(formData.valid),
+ validWarn: normalizeNullableInteger(formData.validWarn),
+ flagCheck: normalizeNullableInteger(formData.flagCheck),
+ rglarId:
+ formData.rglarId !== undefined && formData.rglarId !== null && formData.rglarId !== ''
+ ? Number(formData.rglarId)
+ : void 0
+ }
+
+ return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== undefined))
}
export function getWhMatTreeNodeLabel(node = {}) {
@@ -150,6 +445,39 @@
return [name, code].filter(Boolean).join(' 路 ') || $t('common.placeholder.empty')
}
+export function buildWhMatPrintRows(records = [], t = $t) {
+ return records.map((record) => {
+ const normalizedRecord = normalizeWhMatRow(record, t)
+ return {
+ 鐗╂枡缂栫爜: normalizedRecord.code,
+ 鐗╂枡鍚嶇О: normalizedRecord.name,
+ 鐗╂枡鍒嗙粍: normalizedRecord.groupName,
+ 瑙勬牸: normalizedRecord.spec,
+ 鍨嬪彿: normalizedRecord.model,
+ 鍗曚綅: normalizedRecord.unit,
+ 鐘舵��: normalizedRecord.statusText,
+ 鏇存柊鏃堕棿: normalizedRecord.updateTimeText
+ }
+ })
+}
+
+export function buildWhMatReportMeta({
+ previewMeta = {},
+ count = 0,
+ orientation = WH_MAT_REPORT_STYLE.orientation
+} = {}) {
+ return {
+ reportTitle: WH_MAT_REPORT_TITLE,
+ count,
+ ...previewMeta,
+ reportStyle: {
+ ...WH_MAT_REPORT_STYLE,
+ ...(previewMeta.reportStyle || {}),
+ orientation
+ }
+ }
+}
+
export const buildMatnrPageQueryParams = buildWhMatPageQueryParams
export const buildMatnrGroupTreeQueryParams = buildWhMatGroupTreeQueryParams
export const normalizeMatnrGroupTreeRows = normalizeWhMatGroupTreeRows
diff --git a/rsf-design/src/views/basic-info/wh-mat/whMatTable.columns.js b/rsf-design/src/views/basic-info/wh-mat/whMatTable.columns.js
index 9d4b6d4..12aba26 100644
--- a/rsf-design/src/views/basic-info/wh-mat/whMatTable.columns.js
+++ b/rsf-design/src/views/basic-info/wh-mat/whMatTable.columns.js
@@ -1,9 +1,67 @@
import { h } from 'vue'
import { ElTag } from 'element-plus'
import { $t } from '@/locales'
+import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue'
+import { getWhMatDynamicFieldKey } from './whMatPage.helpers'
-export function createWhMatTableColumns({ handleViewDetail, t = $t }) {
+export function createWhMatTableColumns({
+ handleViewDetail,
+ handleEdit,
+ handleDelete,
+ handlePrint,
+ enabledFields = [],
+ canEdit = true,
+ canDelete = true,
+ t = $t
+} = {}) {
+ const operations = [{ key: 'view', label: t('common.actions.detail'), icon: 'ri:eye-line' }]
+
+ if (canEdit && handleEdit) {
+ operations.push({ key: 'edit', label: t('common.actions.edit'), icon: 'ri:pencil-line' })
+ }
+
+ if (handlePrint) {
+ operations.push({ key: 'print', label: t('common.actions.print'), icon: 'ri:printer-line' })
+ }
+
+ if (canDelete && handleDelete) {
+ operations.push({
+ key: 'delete',
+ label: t('common.actions.delete'),
+ icon: 'ri:delete-bin-5-line',
+ color: 'var(--art-error)'
+ })
+ }
+
+ const dynamicColumns = Array.isArray(enabledFields)
+ ? enabledFields.map((field) => ({
+ prop: getWhMatDynamicFieldKey(field.fields),
+ label: field.fieldsAlise,
+ minWidth: 140,
+ showOverflowTooltip: true,
+ formatter: (row) => row[getWhMatDynamicFieldKey(field.fields)] || '--'
+ }))
+ : []
+
return [
+ {
+ type: 'selection',
+ width: 48,
+ align: 'center'
+ },
+ {
+ type: 'globalIndex',
+ label: t('table.index'),
+ width: 72,
+ align: 'center'
+ },
+ {
+ prop: 'id',
+ label: t('table.id'),
+ width: 90,
+ align: 'center',
+ formatter: (row) => row.id ?? '--'
+ },
{
prop: 'code',
label: t('pages.basicInfo.whMat.table.code'),
@@ -19,7 +77,7 @@
{
prop: 'groupName',
label: t('pages.basicInfo.whMat.table.groupName'),
- minWidth: 160,
+ minWidth: 180,
showOverflowTooltip: true
},
{
@@ -31,15 +89,16 @@
{
prop: 'spec',
label: t('pages.basicInfo.whMat.table.spec'),
- minWidth: 150,
+ minWidth: 160,
showOverflowTooltip: true
},
{
prop: 'model',
label: t('pages.basicInfo.whMat.table.model'),
- minWidth: 150,
+ minWidth: 160,
showOverflowTooltip: true
},
+ ...dynamicColumns,
{
prop: 'unit',
label: t('table.unit'),
@@ -51,7 +110,17 @@
width: 100,
align: 'center',
formatter: (row) =>
- h(ElTag, { type: row.statusType || 'info', effect: 'light' }, () => row.statusText || t('common.placeholder.empty'))
+ h(
+ ElTag,
+ { type: row.statusType || 'info', effect: 'light' },
+ () => row.statusText || t('common.placeholder.empty')
+ )
+ },
+ {
+ prop: 'updateByText',
+ label: t('table.updateBy'),
+ minWidth: 120,
+ showOverflowTooltip: true
},
{
prop: 'updateTimeText',
@@ -60,12 +129,43 @@
showOverflowTooltip: true
},
{
- prop: 'action',
+ prop: 'createByText',
+ label: t('table.createBy'),
+ minWidth: 120,
+ showOverflowTooltip: true
+ },
+ {
+ prop: 'createTimeText',
+ label: t('table.createTime'),
+ minWidth: 180,
+ showOverflowTooltip: true
+ },
+ {
+ prop: 'memo',
+ label: t('table.memo'),
+ minWidth: 160,
+ showOverflowTooltip: true
+ },
+ {
+ prop: 'operation',
label: t('table.operation'),
- width: 100,
- fixed: 'right',
+ width: 120,
align: 'center',
- useSlot: true
+ fixed: 'right',
+ formatter: (row) =>
+ h(
+ 'div',
+ { class: 'flex justify-center' },
+ h(ArtButtonMore, {
+ list: operations,
+ onClick: (item) => {
+ if (item.key === 'view') handleViewDetail?.(row)
+ if (item.key === 'edit') handleEdit?.(row)
+ if (item.key === 'print') handlePrint?.(row)
+ if (item.key === 'delete') handleDelete?.(row)
+ }
+ })
+ )
}
]
}
--
Gitblit v1.9.1