fix: unify all aihr collations, stop silent logout on biz 403, enable knowledge apps
线上现象:「问」页语音提问报 401(请求不带 token),用户观察为
「点了几个页面后登录状态失效」。
根因链(逐环生产验证):
1. 问师傅 /api/knowledge/query 对真实登录返回业务 403
「当前登录端未启用知识问答应用」——生产 aihr_knowledge_app 为空表,
多租户知识平台的应用注册/空间绑定/角色授权从未在生产配置(P1 遗留)。
2. 前端 readPayload 把 403 也视为认证失败并 clearAuth() —— 业务 403
触发静默登出,localStorage token 被清。
3. 之后语音 ASR 请求裸奔 -> 401「未能读取到有效 token」。
同期回归:凌晨对 aihr_practice_assignment.ext_party_id 的单列 collation
热修复,使其与 aihr_practice_session(仍 0900_ai_ci)的 JOIN 反向失配,
/practice/mistakes 500。
修复:
- backend/script/sql/update/aihr_20260718_unify_all_collations_mysql8.sql:
47 张 aihr 表全部 CONVERT 到运行时基准 collation(生产=general_ci),
终结 collation 打地鼠;本地验证后已在生产执行
(schema 备份 /opt/wygj/backups/aihr-schema-before-unify-20260718041407.sql),
13 项移动端接口回归全 200(含 mistakes)。
- api.ts/auth.ts:本地登录态仅在真正 401(HTTP 或业务码)时清除,并经
redirectToLoginForAuthLoss 记住当前页自动回登录(2s 防抖,登录页内不跳);
业务 403(权限拒绝,如录音归属/知识空间)只报错不登出;
authenticatedFileUrl 同步收紧(403 不再清登录态)。
- 生产数据配置(幂等 INSERT,业务范围保守):
· aihr_knowledge_app 注册 yc_admin(pc)/yc_mobile(app) SESSION 应用
· yc_mobile 绑定 SOP 域 5 库(1001/1002/1003/1201/1202),
employee/supervisor ROLE READ;yc_admin 绑定全部 13 库,
hr_operator/superadmin MANAGE
· 财务/销售/行政等大库(1004-1010)暂仅管理端,待业务确认再放开
生产验证:
- 问师傅 query 200,真实回答+引用「投诉处理 SOP v1.0」
- E2E:登录后全 tab 浏览+语音+文字提问,token 全程稳定(storage 打桩零触发)
- 无效 token 点语音提问 -> 自动回登录页(原为死胡同 toast)
- H5 已发布(备份 h5-before-20260718042238)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
-- Unify the collation of EVERY aihr table (tables and all string columns).
|
||||
--
|
||||
-- History: the 2026-07-18 release aligned the 18 newly added tables to the
|
||||
-- collation of aihr_knowledge_info.tenant_id, and a same-day hotfix aligned
|
||||
-- aihr_practice_assignment.ext_party_id. Both were partial: older tables kept
|
||||
-- utf8mb4_0900_ai_ci columns (e.g. aihr_practice_session.ext_party_id), so any
|
||||
-- join between the two families still raises error 1267
|
||||
-- (Illegal mix of collations). Seen in production on
|
||||
-- /api/aihr/mobile/practice/assignments and /api/aihr/mobile/practice/mistakes.
|
||||
--
|
||||
-- This migration converts ALL aihr tables to the canonical collation derived
|
||||
-- at run time, ending the per-join whack-a-mole. CONVERT TO rewrites the table
|
||||
-- default plus every character column, and is idempotent.
|
||||
|
||||
SET @aihr_uni_collation := (
|
||||
SELECT collation_name
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = DATABASE()
|
||||
AND table_name = 'aihr_knowledge_info'
|
||||
AND column_name = 'tenant_id'
|
||||
LIMIT 1
|
||||
);
|
||||
SET @aihr_uni_collation := COALESCE(@aihr_uni_collation, 'utf8mb4_0900_ai_ci');
|
||||
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_candidate_employee_link` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_candidate_material` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_case_record` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_interview_result` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_answer_feedback` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_attach` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_fragment` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_gap` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_import_task` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_info` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_upload_item` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_model_config` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_model_provider` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_task` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_org_snapshot` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_position_responsibility` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_annotation` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_assignment` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_audio` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_audio_upload` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_calibration` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_rubric` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_rubric_dimension` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_scenario` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_session` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_prompt_template` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_qualification_gate` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_sop_answer_review` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_sop_applicability` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_community_answer` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_community_question` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_incentive_rule` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_admin_audit` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_app` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_app_space` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_query_log` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_knowledge_space_grant` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_learning_question` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_exam` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_exam_answer` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_exam_attempt` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_exam_question` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_onboard_exam_target` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_points_ledger` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_practice_question_feedback` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_web_ai_query_audit` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
SET @aihr_uni_ddl := CONCAT('ALTER TABLE `aihr_web_search_provider` CONVERT TO CHARACTER SET utf8mb4 COLLATE ', @aihr_uni_collation);
|
||||
PREPARE aihr_uni_stmt FROM @aihr_uni_ddl; EXECUTE aihr_uni_stmt; DEALLOCATE PREPARE aihr_uni_stmt;
|
||||
|
||||
SET @aihr_uni_ddl := NULL;
|
||||
SET @aihr_uni_collation := NULL;
|
||||
Reference in New Issue
Block a user