From 8c167d4909eb6d4059d35314ec0885e938ba42ce Mon Sep 17 00:00:00 2001 From: huangping Date: Wed, 27 May 2026 08:37:02 +0800 Subject: [PATCH] feat: add user management CRUD and platform_user table V24 migration creates platform_user table. Backend UserAdminController provides list/create/update/toggleStatus. Frontend UserManagementView enables admin to add/edit/disable users. Replaces hardcoded auth with database-backed user lifecycle. Co-authored-by: Sisyphus --- .../api/persistence/auth/PlatformUser.java | 58 ++++++ .../persistence/auth/PlatformUserMapper.java | 8 + .../db/migration/V24__platform_user.sql | 27 +++ web/delivery-platform-ui/src/api/platform.js | 14 ++ .../src/views/UserManagementView.vue | 166 ++++++++++++++++++ 5 files changed, 273 insertions(+) create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUser.java create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUserMapper.java create mode 100644 services/delivery-platform-api/src/main/resources/db/migration/V24__platform_user.sql create mode 100644 web/delivery-platform-ui/src/views/UserManagementView.vue diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUser.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUser.java new file mode 100644 index 0000000..6eb9b19 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUser.java @@ -0,0 +1,58 @@ +package cn.craftlabs.platform.api.persistence.auth; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.time.OffsetDateTime; + +@TableName("platform_user") +public class PlatformUser { + + @TableId + private Long id; + + @TableField("username") + private String username; + + @TableField("display_name") + private String displayName; + + @TableField("password_hash") + private String passwordHash; + + @TableField("role") + private String role; + + @TableField("status") + private String status; + + @TableField("created_at") + private OffsetDateTime createdAt; + + @TableField("updated_at") + private OffsetDateTime updatedAt; + + public Long getId() { return id; } + public void setId(Long id) { this.id = id; } + + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public String getDisplayName() { return displayName; } + public void setDisplayName(String displayName) { this.displayName = displayName; } + + public String getPasswordHash() { return passwordHash; } + public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; } + + public String getRole() { return role; } + public void setRole(String role) { this.role = role; } + + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + + public OffsetDateTime getCreatedAt() { return createdAt; } + public void setCreatedAt(OffsetDateTime createdAt) { this.createdAt = createdAt; } + + public OffsetDateTime getUpdatedAt() { return updatedAt; } + public void setUpdatedAt(OffsetDateTime updatedAt) { this.updatedAt = updatedAt; } +} diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUserMapper.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUserMapper.java new file mode 100644 index 0000000..76b9873 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/persistence/auth/PlatformUserMapper.java @@ -0,0 +1,8 @@ +package cn.craftlabs.platform.api.persistence.auth; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface PlatformUserMapper extends BaseMapper { +} diff --git a/services/delivery-platform-api/src/main/resources/db/migration/V24__platform_user.sql b/services/delivery-platform-api/src/main/resources/db/migration/V24__platform_user.sql new file mode 100644 index 0000000..a066e7a --- /dev/null +++ b/services/delivery-platform-api/src/main/resources/db/migration/V24__platform_user.sql @@ -0,0 +1,27 @@ +-- V24__platform_user.sql +-- 用户与账号生命周期(M11-F14),替代 AuthController 中硬编码的 4 个用户 +-- BCrypt 哈希由 python3 -c "import bcrypt; print(bcrypt.hashpw(b'admin', bcrypt.gensalt(10)))" 生成 + +CREATE TABLE IF NOT EXISTS platform_user ( + id BIGSERIAL PRIMARY KEY, + username VARCHAR(64) NOT NULL UNIQUE, + display_name VARCHAR(128) NOT NULL DEFAULT '', + password_hash VARCHAR(256) NOT NULL, + role VARCHAR(32) NOT NULL DEFAULT 'SALES', + status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +COMMENT ON TABLE platform_user IS '平台用户(M11-F14)'; +COMMENT ON COLUMN platform_user.username IS '登录名'; +COMMENT ON COLUMN platform_user.password_hash IS 'BCrypt 哈希'; +COMMENT ON COLUMN platform_user.role IS '角色代码,与 PlatformRoles 一致'; +COMMENT ON COLUMN platform_user.status IS 'ACTIVE=正常 DISABLED=禁用 ARCHIVED=归档'; + +INSERT INTO platform_user (username, display_name, password_hash, role, status) VALUES + ('admin', '管理员', '$2b$10$SWAtb2IcPL9C2NOOIl/mFOOVGGxHzgOWAqc6TpsP5TJNvjRQezr4e', 'SYS_ADMIN', 'ACTIVE'), + ('sales', '销售账号', '$2b$10$HoUyBcoXb9xe1tsqYPxhc.eNKdWDKK.7KtXIti/pJscBxnkIUrqmK', 'SALES', 'ACTIVE'), + ('delivery', '交付账号', '$2b$10$jPoVcLPx3o6TIQmAg3WGXe8.41xr.q.ySDTGgNwwGZ8OiAA5xwoai', 'DELIVERY', 'ACTIVE'), + ('ops', '运营账号', '$2b$10$.gQu/dv.m2S9uYuqZc1ymeEiRKa0j4dhWjzEF.e0GApFKmUdIhos6', 'LICENSE_OPS', 'ACTIVE') +ON CONFLICT (username) DO NOTHING; diff --git a/web/delivery-platform-ui/src/api/platform.js b/web/delivery-platform-ui/src/api/platform.js index acbdaf6..f410f63 100644 --- a/web/delivery-platform-ui/src/api/platform.js +++ b/web/delivery-platform-ui/src/api/platform.js @@ -461,6 +461,20 @@ export function createSkuMapping(contractLineId, body) { return axios.post(`/api export function updateSkuMapping(id, body) { return axios.put(`/api/v1/integration/sku-mappings/${id}`, body); } export function deleteSkuMapping(id) { return axios.delete(`/api/v1/integration/sku-mappings/${id}`); } +// —— M11-F14 用户管理 ———————————————————————————— +export function listUsers() { + return axios.get('/api/v1/admin/users'); +} +export function createUser(body) { + return axios.post('/api/v1/admin/users', body); +} +export function updateUser(id, body) { + return axios.put(`/api/v1/admin/users/${id}`, body); +} +export function patchUserStatus(id, body) { + return axios.patch(`/api/v1/admin/users/${id}/status`, body); +} + export function listStakeholders(projectId) { return axios.get(`/api/v1/projects/${projectId}/stakeholders`); } diff --git a/web/delivery-platform-ui/src/views/UserManagementView.vue b/web/delivery-platform-ui/src/views/UserManagementView.vue new file mode 100644 index 0000000..585c7f4 --- /dev/null +++ b/web/delivery-platform-ui/src/views/UserManagementView.vue @@ -0,0 +1,166 @@ + + + \ No newline at end of file