增加ai办公,考勤管理
This commit is contained in:
1 parent
eb9b7beff5
commit
31ae07175d
46 files changed
+9250
-296
No files matched your search
@@ -0,0 +1,223 @@
|
||||
-- =============================================================================
|
||||
-- 人员管理(yz_backend_employee) 与 用户管理(yz_system_tenant_user) 老数据对齐
|
||||
--
|
||||
-- 背景:员工表早期建的是「账号全局唯一」索引 uk_account(account),多租户后同一账号
|
||||
-- 在不同企业只能存在一份员工档案;再叠加历史手工录入的人员(如 hero001 这类旧账号),
|
||||
-- 导致「OA 设置 → 人员管理」与「基本设置 → 用户管理」两边数据对不上。
|
||||
--
|
||||
-- 处理内容:
|
||||
-- 1. 索引调整为 (tid, account) 唯一 ← 必须最先执行,否则第 3 步会撞全局唯一键
|
||||
-- 2. 员工 tid 为空/0:按唯一账号补 tid
|
||||
-- 3. 同一企业内「用户缺员工 + 存在同名无账号老员工」:把老员工账号改成用户账号
|
||||
-- (保留员工 ID,排班 / 日报 / 人事档案的历史引用不受影响)
|
||||
-- 4. 用户仍然没有员工:按用户资料补建员工记录(与「用户管理 → 同步员工」同规则)
|
||||
-- 5. 复核查询 + 仍需人工确认的清单
|
||||
--
|
||||
-- 反向缺口(「人员管理有、用户管理没有」)不在这里处理:补账号要先在统一认证建身份
|
||||
-- 并生成 argon2id 密码哈希,SQL 做不到,用 Go 工具:
|
||||
-- go run scripts/syncemployeeusers/main.go -tid <企业ID> -apply
|
||||
--
|
||||
-- 特性:可重复执行(幂等),第 2 次执行不会产生任何变更。
|
||||
-- 执行前请务必备份:mysqldump -u root -p go-platform > backup_$(date +%F).sql
|
||||
-- 执行后请重启 backend 服务:services/employee_sync.go 已改为按 (tid, account) 匹配员工。
|
||||
-- =============================================================================
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 0. 执行前预检(只看不改)
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT '执行前:用户/员工数量' AS section;
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM yz_system_tenant_user WHERE delete_time IS NULL) AS user_rows,
|
||||
(SELECT COUNT(*) FROM yz_backend_employee WHERE delete_time IS NULL) AS employee_rows,
|
||||
(SELECT COUNT(*) FROM yz_backend_employee WHERE delete_time IS NULL AND (tid IS NULL OR tid = 0)) AS employee_tid_empty,
|
||||
(SELECT COUNT(*) FROM yz_system_tenant_user u
|
||||
WHERE u.delete_time IS NULL AND u.account IS NOT NULL AND TRIM(u.account) <> ''
|
||||
AND NOT EXISTS (SELECT 1 FROM yz_backend_employee e
|
||||
WHERE e.delete_time IS NULL AND e.tid = u.tid AND TRIM(e.account) = TRIM(u.account))
|
||||
) AS user_without_employee;
|
||||
|
||||
-- 若下面这条 > 0,需要先人工处理重复的 (tid, account),否则第 1 步加唯一索引会失败
|
||||
SELECT '重复的 (tid, account)' AS section;
|
||||
SELECT tid, TRIM(account) AS account, COUNT(*) AS cnt
|
||||
FROM yz_backend_employee
|
||||
WHERE delete_time IS NULL
|
||||
GROUP BY tid, TRIM(account)
|
||||
HAVING COUNT(*) > 1;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 1. 索引:账号全局唯一 → 企业内唯一
|
||||
-- 关键:不先放开全局唯一,第 3 步把 hero001 改成 hero920103 会因另一企业已占用而失败
|
||||
-- -----------------------------------------------------------------------------
|
||||
SET @has_old := (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_backend_employee'
|
||||
AND INDEX_NAME = 'uk_account');
|
||||
SET @sql := IF(@has_old > 0, 'ALTER TABLE yz_backend_employee DROP INDEX uk_account', 'DO 0');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @has_plain := (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_backend_employee'
|
||||
AND INDEX_NAME = 'idx_tid_account');
|
||||
SET @sql := IF(@has_plain > 0, 'ALTER TABLE yz_backend_employee DROP INDEX idx_tid_account', 'DO 0');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @has_uk := (SELECT COUNT(*) FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'yz_backend_employee'
|
||||
AND INDEX_NAME = 'uk_tid_account' AND NON_UNIQUE = 0);
|
||||
SET @sql := IF(@has_uk = 0,
|
||||
'ALTER TABLE yz_backend_employee ADD UNIQUE KEY uk_tid_account (tid, account)',
|
||||
'DO 0');
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 2. 员工 tid 为空/0:按账号唯一匹配到企业用户后补 tid
|
||||
-- -----------------------------------------------------------------------------
|
||||
UPDATE yz_backend_employee e
|
||||
JOIN (
|
||||
SELECT TRIM(account) AS account, MIN(tid) AS tid
|
||||
FROM yz_system_tenant_user
|
||||
WHERE delete_time IS NULL AND account IS NOT NULL AND TRIM(account) <> ''
|
||||
GROUP BY TRIM(account)
|
||||
HAVING COUNT(DISTINCT tid) = 1
|
||||
) u ON u.account = TRIM(e.account)
|
||||
SET e.tid = u.tid,
|
||||
e.update_time = NOW()
|
||||
WHERE e.delete_time IS NULL
|
||||
AND (e.tid IS NULL OR e.tid = 0);
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 3. 同企业内同名老员工账号对齐
|
||||
-- 条件:① 员工账号在本企业没有对应用户(历史手工人员)
|
||||
-- ② 该用户在本企业还没有员工
|
||||
-- ③ 按姓名能唯一匹配到一个用户
|
||||
-- 只改 account,不动 id,历史引用全部保留
|
||||
-- -----------------------------------------------------------------------------
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_emp_align;
|
||||
CREATE TEMPORARY TABLE tmp_emp_align (
|
||||
emp_id BIGINT UNSIGNED NOT NULL PRIMARY KEY,
|
||||
tid BIGINT NOT NULL,
|
||||
old_account VARCHAR(64) NOT NULL,
|
||||
new_account VARCHAR(64) NOT NULL
|
||||
) ENGINE = InnoDB;
|
||||
|
||||
INSERT INTO tmp_emp_align (emp_id, tid, old_account, new_account)
|
||||
SELECT e.id, e.tid, TRIM(e.account), MIN(TRIM(u.account))
|
||||
FROM yz_backend_employee e
|
||||
JOIN yz_system_tenant_user u
|
||||
ON u.tid = e.tid
|
||||
AND u.delete_time IS NULL
|
||||
AND u.account IS NOT NULL
|
||||
AND TRIM(u.account) <> ''
|
||||
AND TRIM(u.name) = TRIM(e.name)
|
||||
LEFT JOIN yz_system_tenant_user ux
|
||||
ON ux.tid = e.tid
|
||||
AND ux.delete_time IS NULL
|
||||
AND TRIM(ux.account) = TRIM(e.account)
|
||||
LEFT JOIN yz_backend_employee ex
|
||||
ON ex.tid = e.tid
|
||||
AND ex.delete_time IS NULL
|
||||
AND TRIM(ex.account) = TRIM(u.account)
|
||||
WHERE e.delete_time IS NULL
|
||||
AND e.tid IS NOT NULL
|
||||
AND e.tid > 0
|
||||
AND ux.id IS NULL -- 员工账号在本企业没有用户
|
||||
AND ex.id IS NULL -- 用户在本企业还没有员工
|
||||
GROUP BY e.id, e.tid, TRIM(e.account)
|
||||
HAVING COUNT(DISTINCT TRIM(u.account)) = 1; -- 同名用户不唯一时不动,留待人工
|
||||
|
||||
UPDATE yz_backend_employee e
|
||||
JOIN tmp_emp_align t ON t.emp_id = e.id
|
||||
SET e.account = t.new_account,
|
||||
e.update_time = NOW();
|
||||
|
||||
SELECT '第 3 步:对齐的老员工账号' AS section, emp_id, tid, old_account, new_account
|
||||
FROM tmp_emp_align;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS tmp_emp_align;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 4. 用户仍然没有员工:按用户资料补建员工记录
|
||||
-- 与 services/EnsureEmployeeForTenantUser 的规则一致(账号、姓名、性别、生日、
|
||||
-- 部门、手机、邮箱、启用状态),密码留空(登录走统一认证,不校验员工密码)
|
||||
-- -----------------------------------------------------------------------------
|
||||
INSERT INTO yz_backend_employee
|
||||
(tid, account, password, name, gender, birthday, department, phone, email,
|
||||
account_status, create_time, update_time)
|
||||
SELECT
|
||||
u.tid,
|
||||
TRIM(u.account),
|
||||
'',
|
||||
COALESCE(NULLIF(TRIM(u.name), ''), TRIM(u.account)),
|
||||
IFNULL(u.sex, 0),
|
||||
STR_TO_DATE(LEFT(TRIM(IFNULL(u.birth, '')), 10), '%Y-%m-%d'),
|
||||
CASE WHEN IFNULL(u.org_id, 0) > 0 THEN CAST(u.org_id AS CHAR) ELSE NULL END,
|
||||
NULLIF(TRIM(IFNULL(u.phone, '')), ''),
|
||||
NULLIF(TRIM(IFNULL(u.email, '')), ''),
|
||||
IF(IFNULL(u.status, 1) = 0, 0, 1),
|
||||
NOW(), NOW()
|
||||
FROM yz_system_tenant_user u
|
||||
LEFT JOIN yz_backend_employee e
|
||||
ON e.delete_time IS NULL
|
||||
AND e.tid = u.tid
|
||||
AND TRIM(e.account) = TRIM(u.account)
|
||||
WHERE u.delete_time IS NULL
|
||||
AND u.account IS NOT NULL
|
||||
AND TRIM(u.account) <> ''
|
||||
AND e.id IS NULL;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 5. 复核
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT '执行后:用户/员工数量' AS section;
|
||||
SELECT
|
||||
(SELECT COUNT(*) FROM yz_system_tenant_user WHERE delete_time IS NULL) AS user_rows,
|
||||
(SELECT COUNT(*) FROM yz_backend_employee WHERE delete_time IS NULL) AS employee_rows,
|
||||
(SELECT COUNT(*) FROM yz_backend_employee WHERE delete_time IS NULL AND (tid IS NULL OR tid = 0)) AS employee_tid_empty,
|
||||
(SELECT COUNT(*) FROM yz_system_tenant_user u
|
||||
WHERE u.delete_time IS NULL AND u.account IS NOT NULL AND TRIM(u.account) <> ''
|
||||
AND NOT EXISTS (SELECT 1 FROM yz_backend_employee e
|
||||
WHERE e.delete_time IS NULL AND e.tid = u.tid AND TRIM(e.account) = TRIM(u.account))
|
||||
) AS user_without_employee;
|
||||
|
||||
-- 按企业对比:用户数 / 员工数 / 本企业无账号的员工数
|
||||
SELECT
|
||||
u.tid,
|
||||
u.user_cnt,
|
||||
e.emp_cnt,
|
||||
e.emp_without_user
|
||||
FROM (
|
||||
SELECT tid, COUNT(*) AS user_cnt
|
||||
FROM yz_system_tenant_user
|
||||
WHERE delete_time IS NULL
|
||||
GROUP BY tid
|
||||
) u
|
||||
LEFT JOIN (
|
||||
SELECT x.tid,
|
||||
COUNT(*) AS emp_cnt,
|
||||
SUM(CASE WHEN ux.id IS NULL THEN 1 ELSE 0 END) AS emp_without_user
|
||||
FROM yz_backend_employee x
|
||||
LEFT JOIN yz_system_tenant_user ux
|
||||
ON ux.tid = x.tid
|
||||
AND ux.delete_time IS NULL
|
||||
AND TRIM(ux.account) = TRIM(x.account)
|
||||
WHERE x.delete_time IS NULL
|
||||
GROUP BY x.tid
|
||||
) e ON e.tid = u.tid
|
||||
ORDER BY u.tid;
|
||||
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- 6. 仍需人工确认:员工在本企业没有登录账号(老数据,脚本不删除也不改)
|
||||
-- 处理方式二选一:
|
||||
-- a) 在「用户管理」用相同账号添加用户 → 会自动关联到已有员工档案,不会重复建档
|
||||
-- b) 在「人员管理」把这些人员设为离职(account_status = 2)
|
||||
-- -----------------------------------------------------------------------------
|
||||
SELECT '仍无登录账号的员工' AS section,
|
||||
e.tid, e.id, TRIM(e.account) AS account, TRIM(e.name) AS name,
|
||||
TRIM(IFNULL(e.department, '')) AS department
|
||||
FROM yz_backend_employee e
|
||||
LEFT JOIN yz_system_tenant_user u
|
||||
ON u.tid = e.tid
|
||||
AND u.delete_time IS NULL
|
||||
AND TRIM(u.account) = TRIM(e.account)
|
||||
WHERE e.delete_time IS NULL
|
||||
AND u.id IS NULL
|
||||
ORDER BY e.tid, e.id;
|
||||
Reference in new issue
Block a user