Merged
Merge Request #3 · created by 朱子纯


feat(user): wire frontend + backend — REQ-USR-001/002

本 MR 完成内容

  • 搭建 Vite + React + AntD 前端,接入后端 API
  • 大导航 / 侧边栏与原型对齐
  • 用户列表页、用户详情页(权限网格 + 作用域 Tab)实现
  • Staff 搜索接口 + UserDetail 员工选择器 typeahead
  • REQ-USR-002:权限保存竞态 / 越权 / 软删兼容修复
  • boolean 列从 TINYINT(1) 改为 BIT(1)
  • 开发种子数据脚本
  • 原型文件归档

测试

全量 149 单元 + 集成测试 GREEN(pre-push hook 验证)


From feature/wire-frontend-backend into master

Merged by 朱子纯

1 participants

  • 源自 Codex 对 wire-frontend-backend 分支的对抗性评审 (2× high / 1× medium),三条 finding 均已复核属实。
    
    - [HIGH] 详情未加载就保存会把 permissionCategoryIds 当成 [] → 静默清空:
      - 前端 ids 三态化 (number[] | null),列表态 snapshot 不带 ids 时保持 null
      - 编辑模式下 ids 仍为 null 时 disable 修改/保存按钮,DTO 中省略该字段
      - 后端 update() 把 delete+reinsert 包到 if (ids != null),null 视为"不动权限"
    - [HIGH] 过滤态下表头全选越权授权:allChecked 与 onChange 改为基于 visibleCategories
    - [MEDIUM] selectCategoryIdsByUserId 加 INNER JOIN tPermissionCategory 过滤 bDeleted=0,
      避免软删分类导致 40023 阻塞无关字段编辑
    zichun authored
     
    Browse Dir »
  • - Backend: add GET /usr/users/{id} detail endpoint that returns the user row plus its permissionCategoryIds
    - Backend: add GET /usr/permission-categories listing for the permission grid (active categories only)
    - Frontend: UserDetail consumes both endpoints to populate edit form and the permission grid
    zichun authored
     
    Browse Dir »

  • V2 ALTERs all 6 b* columns across tUser/tStaff/tPermissionCategory/
    tModule from TINYINT(1) to BIT(1). MySQL preserves data on the type
    change (0 → b'0', 1 → b'1') and indexes survive the modify.
    
    MyBatis-Plus entity Boolean fields and existing 'WHERE bDeleted = 0'
    queries continue to work — MySQL Connector/J 8.x maps BIT(1) ↔ Boolean
    automatically and accepts integer literals via implicit conversion.
    
    Verified: setup-test-db + mvn test → 149/149 pass with V2 applied.
    
    Also updates docs/03-数据库设计文档.md (schema SSoT) so the table
    descriptors say bit(1) instead of tinyint(1).
    zichun authored
     
    Browse Code »
  • 部门 (sDepartment) lives on tStaff, not tUser. Showing/editing it on
    the user form was misleading — it implied the value would be saved
    against the user, but the backend has no such column on tUser. The
    user list still surfaces 部门 via the LEFT JOIN on tStaff, which
    remains correct for display.
    
    Removes:
    - 部门 form field on UserDetail
    - DEPARTMENTS constant (now unused)
    zichun authored
     
    Browse Code »
  • - Remove the green '已绑定' badge from StaffPicker; the prototype
      doesn't show one and it's confusing in create mode (nothing has
      been saved yet).
    - On staff selection, auto-fill 用户号 (sUserNo) and 用户名 (sUserName)
      with the staff's Chinese name to match prototype behavior; user
      can still override either field after selection.
    zichun authored
     
    Browse Code »
  • Backend:
    - StaffSearchVO (iIncrement / sStaffNo / sStaffName / sDepartment)
    - StaffMapper.searchActive(keyword, limit) — LIKE on name + staff no
    - StaffController GET /api/usr/staffs?keyword=&limit=
    - UserListVO + UserMapper.xml: expose iStaffId so edit mode preserves
      the binding when user doesn't change 员工名
    
    Frontend:
    - api/staff.ts → searchStaff()
    - StaffPicker.tsx: input + dropdown with debounced search, '已绑定'
      badge when an iStaffId is bound, click outside to close, search icon
    - UserDetail: replace 员工名 PrimInput with StaffPicker; track iStaffId
      in form state; send to backend on save (no longer omitted)
    zichun authored
     
    Browse Dir »
  • Idempotent (INSERT IGNORE on unique keys) script that populates:
    - tStaff: 20 print-industry employees with realistic Chinese names,
      staff numbers (S0001..S0020), and varied departments
    - tUser: admin + 18 business users, all BCrypt(666666), linked to
      staff rows; mix of 超级管理员 / 普通用户, languages zh/en/zh-TW,
      with one bDeleted=1 to demo the 作废 column
    - tPermissionCategory: 30 groups matching prototype's permission grid
    - tUserPermission: department-correlated permission grants
      (e.g. 财务部 users get PERM_FINANCE + PERM_VIEW_ORDER_PRICE)
    - tModule: 5 KPI flow trees (估价/订单/拼版/送货/采购) + 系统设置,
      ~30 nodes with proper parent/child relationships
    
    Final SELECT prints row counts for verification.
    zichun authored
     
    Browse Code »
  • Reverses the earlier 'hide unsupported fields' decision per user request
    to strictly follow the prototype look. Brings back:
    
    - Full dark sub-toolbar: 新增 / 修改 / 删除 / 保存 / 取消 (separator)
      功能 / 作废 / 重置密码 / 取消作废, with status chip + settings gear
      on the right and 已选权限 counter
    - 9-field 3x3 form with prototype's required-field cyan tint, 制单人
      showing 保存后自动生成 placeholder in new mode
    - 6 perm tabs (权限组 / 客户 / 供应商 / 人员 / 工序 / 司机)
    - 30-row permission grid with hover, accent-soft selected row, filter
    - Scope tabs with master enable + 4-col grid of items
    - Floating vertical 帮助 button on right edge
    
    Permissions and the no-op buttons are visual-only — they don't round-trip
    to backend. Save still sends only sUserNo/sUserName/sUserType/sLanguage/
    bCanModifyDocs (iStaffId and permissionCategoryIds intentionally omitted).
    
    Adds bespoke Primitives.tsx (Field/PrimInput/PrimSelect/PrimCheckbox/
    ToolbarBtnDark/ToolbarBtnLight) so this screen renders pixel-faithful
    to prototype rather than picking up AntD chrome.
    zichun authored
     
    Browse Code »
  • - Sidebar 系统管理 now contains only 角色管理 / 菜单配置 / 操作日志
      (用户列表 and 系统模块配置 are accessed via mega-nav, not duplicated
      in the tree).
    - MegaNav rebuilt as full-viewport dark layout per prototype: dark
      topbar with highlighted 全部导航 chip, 150px left rail of categories
      (active = accent + white left border), right grid of category columns
      with bordered titles and muted/featured items.
    - MEGA_COLUMNS expanded to 8 columns matching prototype 系统设置
      (期初设置 / 用户管理 / 系统参数 / 计算方案 / 日志 / 开发平台 /
      API对接管理 / 系统模块).
    zichun authored
     
    Browse Code »
  • Previously the script used hardcoded defaults (127.0.0.1:3306 / xly_erp)
    and ignored the user's remote test DB. Now sources .env.local like
    setup-test-db.sh does. Documents the prereq that Spring Boot must have
    started at least once (Flyway applies V1) before seeding.
    zichun authored
     
    Browse Code »
  • Per docs/04 production stack: Vite + React 18 + TypeScript + AntD 5 +
    Redux Toolkit + React Router v6 + Axios. Theme tokens copied from
    prototype/XLY-ERP.html so density, colors, and layout match. Pages:
    Login, Home, UserList, UserDetail, ModuleConfig — wired to existing
    endpoints (/api/usr/auth/login, /api/usr/users, /api/mod/modules).
    Backend-unsupported fields (user permission grid, 18 module fields,
    iStaffId picker) hidden per scope. Sidebar/MegaNav remain static
    reference data; dashboard stats hardcoded (no endpoint).
    zichun authored
     
    Browse Code »
  • Enables the new frontend/ Vite app (localhost:5173) to call the backend
    across origins. Adds OPTIONS preflight permitAll. Seed script provisions
    an admin user (sUserName=admin / password=666666) for first-run login.
    zichun authored
     
    Browse Dir »