From 1cc3584f1a69bdaca458be7b81012af40ddf72b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=96=87=E7=9D=BF=20=E5=BC=A0?= Date: Wed, 16 Sep 2026 23:30:25 +0800 Subject: [PATCH] restore lost frontend and backend changes --- ...ms-v2.3-three-stage-implementation-plan.md | 34 +- frontend/src/api/index.js | 20 + frontend/src/api/materials.js | 7 +- frontend/src/api/organizations.js | 6 - frontend/src/api/stock.js | 6 + .../src/components/business/DeleteConfirm.vue | 12 +- frontend/src/components/layout/AppSidebar.vue | 34 +- frontend/src/router/index.js | 32 +- frontend/src/stores/auth.js | 7 +- frontend/src/stores/inbound.js | 7 +- frontend/src/stores/materials.js | 12 +- frontend/src/stores/outbound.js | 2 +- frontend/src/stores/stock.js | 11 +- frontend/src/test/setup.js | 1 + frontend/src/views/Inbound.vue | 22 +- frontend/src/views/Materials.vue | 188 +++++---- frontend/src/views/Outbound.vue | 25 +- frontend/src/views/Stock.vue | 210 +++++++--- frontend/src/views/Users.vue | 50 ++- frontend/src/views/materialForm.js | 11 +- frontend/src/views/materialForm.test.js | 21 - internal/handler/api.go | 226 ++++++++--- internal/middleware/auth.go | 46 ++- internal/model/model.go | 232 ++++++----- internal/repository/application.go | 28 +- internal/repository/material.go | 127 +++--- internal/repository/material_test.go | 8 +- internal/repository/stock.go | 184 +++++++-- internal/repository/stock_test.go | 75 +++- internal/repository/user.go | 371 ++++++++++++------ internal/repository/user_test.go | 61 +++ internal/service/application.go | 36 +- internal/service/auth.go | 31 +- internal/service/inbound.go | 19 +- internal/service/material.go | 82 ++-- internal/service/outbound.go | 31 +- internal/service/stock.go | 35 +- scripts/migrations/002_phase1_master_data.sql | 30 +- 38 files changed, 1554 insertions(+), 786 deletions(-) diff --git a/docs/superpowers/plans/2026-09-14-mms-v2.3-three-stage-implementation-plan.md b/docs/superpowers/plans/2026-09-14-mms-v2.3-three-stage-implementation-plan.md index 4304bd81..f391d37c 100644 --- a/docs/superpowers/plans/2026-09-14-mms-v2.3-three-stage-implementation-plan.md +++ b/docs/superpowers/plans/2026-09-14-mms-v2.3-three-stage-implementation-plan.md @@ -33,27 +33,27 @@ 当前系统具备物料、简单入库、简单出库、库存查询、物料申请、用户登录和日志页面,但与 v2.3 存在以下结构性差距: -| 当前实现 | v2.3 目标 | 处理阶段 | -| --------------------------------- | --------------------- | --------- | -| 用户只有一个 `admin/user` 枚举角色 | 用户与角色多对多,权限和数据范围分别控制 | 第一阶段 | -| 自制固定密钥 Token,权限依赖 Token 中的单角色 | 标准 JWT,按请求加载最新角色和数据范围 | 第一阶段 | -| 物料编码全局唯一 | 同一经营组织内唯一 | 第一阶段 | -| 分类和单位为自由文本 | 分类、物料类型、单位及换算为受控主数据 | 第一阶段 | -| 没有业务伙伴、组织、仓库和库位实体 | 完整主数据及停用规则 | 第一阶段 | -| 库存直接保存在 `materials.current_stock` | 第一阶段拆分独立库存余额,第二阶段启用不可变库存流水和过账内核 | 第一、二阶段 | -| 创建或删除入出库单直接增减库存 | 草稿、提交、过账、撤销过账状态机 | 第二阶段 | -| 没有调拨、盘点、预留和通知闭环 | 完整仓储执行闭环 | 第二阶段 | -| 没有 BOM 和制造订单 | BOM 版本、展开、校验和制造执行 | 第三阶段 | -| 没有 Excel 任务和 SSO | 受控批量任务及 OIDC SSO | 第三阶段 | -| 没有自动化测试 | 后端单元/集成测试与前端组件测试 | 第一阶段起持续建设 | +| 当前实现 | v2.3 目标 | 处理阶段 | +| --------------------------------- | ------------------------------- | --------- | +| 用户只有一个 `admin/user` 枚举角色 | 用户与角色多对多,权限和数据范围分别控制 | 第一阶段 | +| 自制固定密钥 Token,权限依赖 Token 中的单角色 | 标准 JWT,按请求加载最新角色和数据范围 | 第一阶段 | +| 物料编码全局唯一 | 同一经营组织内唯一 | 第一阶段 | +| 分类和单位为自由文本 | 分类、物料类型、单位及换算为受控主数据 | 第一阶段 | +| 没有业务伙伴、组织、仓库和库位实体 | 完整主数据及停用规则 | 第一阶段 | +| 库存直接保存在 `materials.current_stock` | 第一阶段拆分独立库存余额,第二阶段启用不可变库存流水和过账内核 | 第一、二阶段 | +| 创建或删除入出库单直接增减库存 | 草稿、提交、过账、撤销过账状态机 | 第二阶段 | +| 没有调拨、盘点、预留和通知闭环 | 完整仓储执行闭环 | 第二阶段 | +| 没有 BOM 和制造订单 | BOM 版本、展开、校验和制造执行 | 第三阶段 | +| 没有 Excel 任务和 SSO | 受控批量任务及 OIDC SSO | 第三阶段 | +| 没有自动化测试 | 后端单元/集成测试与前端组件测试 | 第一阶段起持续建设 | ## 二、三次交付边界 -| 阶段 | 交付主题 | 覆盖故事 | 可独立上线的业务结果 | -| ---- | -------------- | ------------------------------------------------------------------------------------ | ------------------------------------------ | +| 阶段 | 交付主题 | 覆盖故事 | 可独立上线的业务结果 | +| ---- | -------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------ | | 第一阶段 | 组织、权限和主数据底座 | ORG-001、CODE-001~004、MD-001~008、COM-001~005、WH-001~003、STOCK-003、AUTH-001、AUTH-003~006、AUD-001 | 用户可按多角色登录,只能访问授权组织/仓库;物料主数据与库存余额分表;可维护编码、物料、业务伙伴、仓库和库位 | -| 第二阶段 | 仓储业务闭环 | STOCK-001~002、STOCK-004~009、NOTIFY-001 | 入库、出库、调拨、盘点、预留、撤销过账、库存流水和预警形成完整闭环 | -| 第三阶段 | BOM、制造、批量和 SSO | BOM-001~010、BAT-001~004、AUTH-002 | 可维护受控 BOM,分批领料和完工;支持受控 Excel 任务和 OIDC 单点登录 | +| 第二阶段 | 仓储业务闭环 | STOCK-001~002、STOCK-004~009、NOTIFY-001 | 入库、出库、调拨、盘点、预留、撤销过账、库存流水和预警形成完整闭环 | +| 第三阶段 | BOM、制造、批量和 SSO | BOM-001~010、BAT-001~004、AUTH-002 | 可维护受控 BOM,分批领料和完工;支持受控 Excel 任务和 OIDC 单点登录 | ### 阶段依赖 diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index f53d4593..bdb7394f 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -17,6 +17,7 @@ request.interceptors.request.use( if (token) { config.headers.Authorization = `Bearer ${token}` } + console.log('API请求:', config.method?.toUpperCase(), config.url) return config }, (error) => Promise.reject(error) @@ -38,6 +39,25 @@ request.interceptors.response.use( localStorage.removeItem('wmms_user') router.push('/login') ElMessage.error('登录已过期,请重新登录') + } else if (error.response?.status === 422) { + // Validation errors - parse and show friendly message + const data = error.response?.data + let msg = data?.message || '' + if (data?.error && typeof data.error === 'string') { + // Go validator errors format: "Key: 'Field' Error:Field validation ..." + const matches = data.error.match(/Error: (Field validation.*?)(\n|$)/gi) + if (matches) { + const fields = matches.map(m => { + const fieldMatch = m.match(/Key: '([^']+)'/) + return fieldMatch ? fieldMatch[1] : m + }) + const labels = { Handler: '经手人', Supplier: '供应商', Receiver: '接收方' } + msg = fields.map(f => labels[f] || f).join('、') + '不能为空' + } + } + ElMessage.error(msg || '请检查必填字段') + } else if (error.response?.data?.message) { + ElMessage.error(error.response.data.message) } else { ElMessage.error(error.message || '网络错误') } diff --git a/frontend/src/api/materials.js b/frontend/src/api/materials.js index f84251b3..c3d9ebf6 100644 --- a/frontend/src/api/materials.js +++ b/frontend/src/api/materials.js @@ -13,8 +13,11 @@ export const materialsApi = { update(id, data) { return request.put(`/materials/${id}`, data) }, - delete(id) { - return request.delete(`/materials/${id}`) + obsolete(id) { + return request.post(`/materials/${id}/obsolete`) + }, + restore(id) { + return request.post(`/materials/${id}/restore`) }, uploadImage(formData) { return request.post('/upload', formData, { diff --git a/frontend/src/api/organizations.js b/frontend/src/api/organizations.js index 63aa0a56..ec01073b 100644 --- a/frontend/src/api/organizations.js +++ b/frontend/src/api/organizations.js @@ -12,11 +12,5 @@ export const organizationsApi = { }, listRoles() { return request.get('/roles') - }, - listPermissions() { - return request.get('/permissions') - }, - updateRole(id, data) { - return request.put(`/roles/${id}`, data) } } diff --git a/frontend/src/api/stock.js b/frontend/src/api/stock.js index 121bf4f8..90d09d7e 100644 --- a/frontend/src/api/stock.js +++ b/frontend/src/api/stock.js @@ -15,5 +15,11 @@ export const stockApi = { }, getLogs(materialId, params = {}) { return request.get(`/stock/logs/${materialId}`, { params }) + }, + getInventoryBalanceDetails(materialId) { + return request.get(`/stock/${materialId}/details`) + }, + updateWarning(materialId, warningStock) { + return request.put(`/stock/${materialId}/warning`, { warning_stock: warningStock }) } } diff --git a/frontend/src/components/business/DeleteConfirm.vue b/frontend/src/components/business/DeleteConfirm.vue index 931d1eac..830f38e4 100644 --- a/frontend/src/components/business/DeleteConfirm.vue +++ b/frontend/src/components/business/DeleteConfirm.vue @@ -1,9 +1,9 @@ @@ -13,6 +13,14 @@ import { ref, watch } from 'vue' const props = defineProps({ modelValue: Boolean, + title: { + type: String, + default: '确认删除' + }, + confirmText: { + type: String, + default: '确认删除' + }, content: { type: String, default: '确定要删除此数据吗?此操作不可恢复。' diff --git a/frontend/src/components/layout/AppSidebar.vue b/frontend/src/components/layout/AppSidebar.vue index 5a3db0a2..4bda20dd 100644 --- a/frontend/src/components/layout/AppSidebar.vue +++ b/frontend/src/components/layout/AppSidebar.vue @@ -4,12 +4,14 @@ class="app-sidebar" @select="handleSelect" > - - {{ item.label }} + + + + {{ item.label }} + + + + {{ item.label }} @@ -17,6 +19,7 @@