-- 国内头程 PDA 操作员初始化(MySQL 8.0+,可重复执行) -- -- 初始化内容: -- 1. 平台角色 CN_FIRSTLEG_PDA_OPERATOR(国内头程 PDA 作业员) -- 2. 张三 / pda_zhangsan,绑定 CN-YIWU-01(义乌仓) -- 3. 李四 / pda_lisi,绑定 CN-YIWU-01(义乌仓) -- -- 目标库:同一 MySQL 实例中的 baiyue_auth、baiyue_iam、baiyue_warehouse。 -- 前置条件:IAM 已包含 iam_membership.domestic_warehouse_id,且义乌仓主数据已初始化。 -- 密码列只写 BCrypt 哈希;首次插入时要求首次登录修改密码。重复执行不会覆盖用户后来修改的密码。 SET NAMES utf8mb4; USE baiyue_iam; DROP PROCEDURE IF EXISTS assert_domestic_pda_operator_seed_ready; DELIMITER $$ CREATE PROCEDURE assert_domestic_pda_operator_seed_ready() BEGIN IF NOT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'baiyue_auth' AND table_name = 'auth_account' ) OR NOT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'baiyue_iam' AND table_name = 'iam_membership' ) OR NOT EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'baiyue_warehouse' AND table_name = 'wh_warehouse' ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:baiyue_auth、baiyue_iam 或 baiyue_warehouse 基础表未部署'; END IF; IF NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'baiyue_iam' AND table_name = 'iam_membership' AND column_name = 'domestic_warehouse_id' ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:请先部署 iam_membership.domestic_warehouse_id'; END IF; IF (SELECT COUNT(*) FROM baiyue_warehouse.wh_warehouse WHERE tenant_id = 0 AND warehouse_code = 'CN-YIWU-01' AND warehouse_type = 'DOMESTIC' AND status = 'ACTIVE' AND deleted = 0) <> 1 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:未找到唯一启用的国内仓 CN-YIWU-01'; END IF; IF EXISTS ( SELECT 1 FROM iam_role WHERE (id = 4000007 AND (tenant_id <> 0 OR app_code <> 'PLATFORM' OR role_code <> 'CN_FIRSTLEG_PDA_OPERATOR')) OR (tenant_id = 0 AND app_code = 'PLATFORM' AND role_code = 'CN_FIRSTLEG_PDA_OPERATOR' AND id <> 4000007) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:角色ID 4000007 或角色编码已被其他数据占用'; END IF; IF EXISTS ( SELECT 1 FROM iam_data_scope WHERE (id = 6000007 AND role_id <> 4000007) OR (role_id = 4000007 AND id <> 6000007) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:数据范围ID 6000007 已被占用'; END IF; IF (SELECT COUNT(*) FROM iam_permission WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND status = 'ACTIVE' AND deleted = 0 AND permission_code IN ('platform:firstleg:pda:view', 'platform:firstleg:pda:work')) <> 2 THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:PDA view/work 权限尚未完整部署'; END IF; END$$ DELIMITER ; CALL assert_domestic_pda_operator_seed_ready(); DROP PROCEDURE assert_domestic_pda_operator_seed_ready; SET @domestic_warehouse_id = ( SELECT id FROM baiyue_warehouse.wh_warehouse WHERE tenant_id = 0 AND warehouse_code = 'CN-YIWU-01' AND warehouse_type = 'DOMESTIC' AND status = 'ACTIVE' AND deleted = 0 LIMIT 1 ); -- 优先复用同名账号已有ID;首次执行使用下面的稳定ID。 SET @zhangsan_auth_id = COALESCE( (SELECT id FROM baiyue_auth.auth_account WHERE username = 'pda_zhangsan' AND deleted = 0 LIMIT 1), 194000000000000101 ); SET @lisi_auth_id = COALESCE( (SELECT id FROM baiyue_auth.auth_account WHERE username = 'pda_lisi' AND deleted = 0 LIMIT 1), 194000000000000102 ); SET @zhangsan_user_id = COALESCE( (SELECT id FROM iam_user WHERE auth_user_id = @zhangsan_auth_id AND deleted = 0 LIMIT 1), 194000000000000201 ); SET @lisi_user_id = COALESCE( (SELECT id FROM iam_user WHERE auth_user_id = @lisi_auth_id AND deleted = 0 LIMIT 1), 194000000000000202 ); SET @zhangsan_membership_id = COALESCE( (SELECT id FROM iam_membership WHERE tenant_id = 0 AND user_id = @zhangsan_user_id AND deleted = 0 LIMIT 1), 194000000000000301 ); SET @lisi_membership_id = COALESCE( (SELECT id FROM iam_membership WHERE tenant_id = 0 AND user_id = @lisi_user_id AND deleted = 0 LIMIT 1), 194000000000000302 ); DROP PROCEDURE IF EXISTS assert_domestic_pda_operator_ids_available; DELIMITER $$ CREATE PROCEDURE assert_domestic_pda_operator_ids_available() BEGIN IF EXISTS ( SELECT 1 FROM baiyue_auth.auth_account WHERE (id = @zhangsan_auth_id AND username <> 'pda_zhangsan') OR (id = @lisi_auth_id AND username <> 'pda_lisi') OR (username = 'pda_zhangsan' AND id <> @zhangsan_auth_id) OR (username = 'pda_lisi' AND id <> @lisi_auth_id) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:张三或李四的认证账号ID/用户名冲突'; END IF; IF EXISTS ( SELECT 1 FROM iam_user WHERE (id = @zhangsan_user_id AND auth_user_id <> @zhangsan_auth_id) OR (id = @lisi_user_id AND auth_user_id <> @lisi_auth_id) OR (auth_user_id = @zhangsan_auth_id AND id <> @zhangsan_user_id) OR (auth_user_id = @lisi_auth_id AND id <> @lisi_user_id) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:张三或李四的 IAM 用户ID冲突'; END IF; IF EXISTS ( SELECT 1 FROM iam_membership WHERE (id = @zhangsan_membership_id AND (tenant_id <> 0 OR user_id <> @zhangsan_user_id)) OR (id = @lisi_membership_id AND (tenant_id <> 0 OR user_id <> @lisi_user_id)) OR (tenant_id = 0 AND member_no = 'CN-PDA-YIWU-ZS' AND user_id <> @zhangsan_user_id) OR (tenant_id = 0 AND member_no = 'CN-PDA-YIWU-LS' AND user_id <> @lisi_user_id) ) THEN SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '国内 PDA 初始化失败:张三或李四的成员ID/工号冲突'; END IF; END$$ DELIMITER ; CALL assert_domestic_pda_operator_ids_available(); DROP PROCEDURE assert_domestic_pda_operator_ids_available; START TRANSACTION; INSERT INTO iam_role ( id, tenant_id, app_code, role_code, role_name, role_type, status, description, deleted, version ) VALUES ( 4000007, 0, 'PLATFORM', 'CN_FIRSTLEG_PDA_OPERATOR', '国内头程 PDA 作业员', 'SYSTEM', 'ACTIVE', '负责使用国内 PDA 执行柜次拣货、现场取证和装柜完成', 0, 0 ) ON DUPLICATE KEY UPDATE role_name = VALUES(role_name), role_type = 'SYSTEM', status = 'ACTIVE', description = VALUES(description), deleted = 0; -- 该角色只保留国内 PDA 查看、作业两项最小权限。 DELETE role_permission FROM iam_role_permission role_permission JOIN iam_permission permission ON permission.id = role_permission.permission_id WHERE role_permission.role_id = 4000007 AND permission.permission_code NOT IN ('platform:firstleg:pda:view', 'platform:firstleg:pda:work'); INSERT IGNORE INTO iam_role_permission (role_id, permission_id, tenant_id) SELECT 4000007, id, 0 FROM iam_permission WHERE tenant_id = 0 AND app_code = 'PLATFORM' AND status = 'ACTIVE' AND deleted = 0 AND permission_code IN ('platform:firstleg:pda:view', 'platform:firstleg:pda:work'); INSERT INTO iam_data_scope (id, role_id, tenant_id, scope_type, scope_expression) VALUES (6000007, 4000007, 0, 'TENANT', NULL) ON DUPLICATE KEY UPDATE tenant_id = 0, scope_type = 'TENANT', scope_expression = NULL; -- 首次插入使用既定临时密码的 BCrypt(12) 哈希;重复执行保留账号当前密码。 INSERT INTO baiyue_auth.auth_account ( id, username, phone, password_hash, display_name, account_status, failed_login_count, locked_until, token_version, password_change_required, default_tenant_id, operator_tenant_id, default_membership_id, default_app_code, deleted ) VALUES (@zhangsan_auth_id, 'pda_zhangsan', NULL, '$2a$12$/BdqRpdgVPAu6aoizfuTJ.UhtgpZYEAkwdvworS5GVirUBSwCcuKG', '张三', 'ACTIVE', 0, NULL, 1, 1, 0, 0, @zhangsan_membership_id, 'PLATFORM', 0), (@lisi_auth_id, 'pda_lisi', NULL, '$2a$12$Uv.KUNtVSAwT1R0Sk3Gb6uaytWitd7Hrda5xrZl0zKxLY1/SCUyXe', '李四', 'ACTIVE', 0, NULL, 1, 1, 0, 0, @lisi_membership_id, 'PLATFORM', 0) ON DUPLICATE KEY UPDATE display_name = VALUES(display_name), account_status = 'ACTIVE', failed_login_count = 0, locked_until = NULL, default_tenant_id = 0, operator_tenant_id = 0, default_membership_id = VALUES(default_membership_id), default_app_code = 'PLATFORM', deleted = 0; INSERT INTO iam_user ( id, auth_user_id, user_type, display_name, phone, email, status, deleted, version ) VALUES (@zhangsan_user_id, @zhangsan_auth_id, 'INTERNAL', '张三', NULL, NULL, 'ACTIVE', 0, 0), (@lisi_user_id, @lisi_auth_id, 'INTERNAL', '李四', NULL, NULL, 'ACTIVE', 0, 0) ON DUPLICATE KEY UPDATE user_type = 'INTERNAL', display_name = VALUES(display_name), status = 'ACTIVE', deleted = 0; INSERT INTO iam_membership ( id, tenant_id, user_id, member_type, member_no, overseas_warehouse_id, domestic_warehouse_id, status, joined_at, left_at, deleted, version ) VALUES (@zhangsan_membership_id, 0, @zhangsan_user_id, 'EMPLOYEE', 'CN-PDA-YIWU-ZS', NULL, @domestic_warehouse_id, 'ACTIVE', CURRENT_TIMESTAMP(3), NULL, 0, 0), (@lisi_membership_id, 0, @lisi_user_id, 'EMPLOYEE', 'CN-PDA-YIWU-LS', NULL, @domestic_warehouse_id, 'ACTIVE', CURRENT_TIMESTAMP(3), NULL, 0, 0) ON DUPLICATE KEY UPDATE member_type = 'EMPLOYEE', member_no = VALUES(member_no), overseas_warehouse_id = NULL, domestic_warehouse_id = VALUES(domestic_warehouse_id), status = 'ACTIVE', joined_at = COALESCE(joined_at, CURRENT_TIMESTAMP(3)), left_at = NULL, deleted = 0; -- 国内、海外 PDA 角色互斥;保留人员可能已有的其他非 PDA 角色。 DELETE membership_role FROM iam_membership_role membership_role JOIN iam_role role ON role.id = membership_role.role_id WHERE membership_role.membership_id IN (@zhangsan_membership_id, @lisi_membership_id) AND role.role_code = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR'; INSERT INTO iam_membership_role (membership_id, role_id, tenant_id) VALUES (@zhangsan_membership_id, 4000007, 0), (@lisi_membership_id, 4000007, 0) ON DUPLICATE KEY UPDATE tenant_id = 0; INSERT IGNORE INTO iam_security_subject_version (auth_user_id, permission_version) VALUES (@zhangsan_auth_id, 1), (@lisi_auth_id, 1); COMMIT; -- 验证结果:应返回两行,且 role_code、warehouse_code、account_status、member_status 均为有效值。 SELECT account.username, user_profile.display_name, role.role_code, warehouse.warehouse_code, warehouse.warehouse_name, account.account_status, membership.status AS member_status FROM baiyue_auth.auth_account account JOIN iam_user user_profile ON user_profile.auth_user_id = account.id AND user_profile.deleted = 0 JOIN iam_membership membership ON membership.user_id = user_profile.id AND membership.tenant_id = 0 AND membership.deleted = 0 JOIN iam_membership_role membership_role ON membership_role.membership_id = membership.id JOIN iam_role role ON role.id = membership_role.role_id AND role.role_code = 'CN_FIRSTLEG_PDA_OPERATOR' JOIN baiyue_warehouse.wh_warehouse warehouse ON warehouse.id = membership.domestic_warehouse_id WHERE account.username IN ('pda_zhangsan', 'pda_lisi') ORDER BY account.username;