feat: BossAi v2.0 UI/UX 重构 + 看板断点续接 + 多轮上下文
CI / 后端测试 (push) Has been cancelled
CI / 前端构建 (push) Has been cancelled

- 新增 web2/ 前端:任务卡看板、风险雷达、决策日志、我的团队、快捷指令
- ChatPanel 增强:风险卡置顶、案卡接入、起诉状向导、语音输入
- 事项看板:点击查看详情弹窗、断点续接(恢复历史对话+matterId)
- 保密模式恢复:密码验证后重建内存 session,保留多轮上下文
- 多轮对话:ask/ask-stream/ask-analyze 注入 session 历史,AI 有上下文
- 追问优化:紧扣用户问题,不再偏离主题(社保问社保,工伤问工伤)
- 对话区可滚动,输入区固定可见
- 状态机放宽:允许从任意非终态转到 pending_expert
- session 存活检查端点,后端重启后自动重建 session
- DB migration:风险推送表、案卡表

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-31 08:38:33 +08:00
co-authored by Devin
parent 7a788bf8dc
commit 4de36547cd
88 changed files with 15237 additions and 62 deletions
+108
View File
@@ -0,0 +1,108 @@
-- BossAi 2.0 UIUX 重构 — 数据库迁移脚本
-- TASK-001: 案卡表 + sessions 扩展
-- TASK-002: 专家关系表
-- 幂等:可重复执行,已存在的对象跳过
-- 运行:psql -d mcp -f migrations/001_bossai_v2.sql
BEGIN;
-- ============================================================
-- TASK-001: 案卡(matters)表
-- ============================================================
CREATE TABLE IF NOT EXISTS matters (
id SERIAL PRIMARY KEY,
code TEXT NOT NULL UNIQUE, -- 唯一业务代码 MTR_{YYYYMMDD}_{seq}
user_phone TEXT NOT NULL, -- 所属老板(手机号,关联 users.phone)
scene TEXT NOT NULL, -- legal / decision / life / emotion
title TEXT NOT NULL, -- 案卡标题(AI 生成或用户命名)
status TEXT NOT NULL DEFAULT 'new', -- new / asking_facts / pending_confirm / analyzing / pending_expert / closed
session_id TEXT, -- 关联会话 sid(可空,旧会话无案卡)
risk_level TEXT, -- 可空: green / amber / orange / red
summary TEXT, -- 可空: AI 结论摘要
closed_at TIMESTAMPTZ, -- 闭环时间
execution_result TEXT, -- 可空: 顺利 / 受阻 / 未执行
execution_note TEXT, -- 可空: 执行情况备注
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_matters_user_phone ON matters(user_phone);
CREATE INDEX IF NOT EXISTS idx_matters_status ON matters(status);
CREATE INDEX IF NOT EXISTS idx_matters_user_status ON matters(user_phone, status);
CREATE INDEX IF NOT EXISTS idx_matters_created ON matters(created_at DESC);
-- 案卡状态流转合法性约束(通过 CHECK)
ALTER TABLE matters DROP CONSTRAINT IF EXISTS chk_matters_status;
ALTER TABLE matters ADD CONSTRAINT chk_matters_status CHECK (
status IN ('new', 'asking_facts', 'pending_confirm', 'analyzing', 'pending_expert', 'closed')
);
ALTER TABLE matters DROP CONSTRAINT IF EXISTS chk_matters_scene;
ALTER TABLE matters ADD CONSTRAINT chk_matters_scene CHECK (
scene IN ('legal', 'decision', 'life', 'emotion')
);
ALTER TABLE matters DROP CONSTRAINT IF EXISTS chk_matters_risk;
ALTER TABLE matters ADD CONSTRAINT chk_matters_risk CHECK (
risk_level IS NULL OR risk_level IN ('green', 'amber', 'orange', 'red')
);
-- sessions 表扩展:关联案卡(若 sessions 表存在)
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.tables WHERE table_name = 'sessions'
) AND NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'sessions' AND column_name = 'matter_id'
) THEN
ALTER TABLE sessions ADD COLUMN matter_id INTEGER REFERENCES matters(id);
CREATE INDEX IF NOT EXISTS idx_sessions_matter ON sessions(matter_id);
END IF;
END $$;
-- chat_messages 表扩展:关联案卡(用于无 sessions 表时通过消息关联)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'chat_messages' AND column_name = 'matter_id'
) THEN
ALTER TABLE chat_messages ADD COLUMN matter_id INTEGER REFERENCES matters(id);
CREATE INDEX IF NOT EXISTS idx_chat_messages_matter ON chat_messages(matter_id);
END IF;
END $$;
-- ============================================================
-- TASK-002: 专家关系(expert_relations)表
-- ============================================================
CREATE TABLE IF NOT EXISTS expert_relations (
id SERIAL PRIMARY KEY,
user_phone TEXT NOT NULL, -- 老板手机号
expert_id INTEGER NOT NULL REFERENCES experts(id),
consultation_count INTEGER NOT NULL DEFAULT 0, -- 咨询次数
last_consulted_at TIMESTAMPTZ, -- 最近咨询时间
last_topic TEXT, -- 最近咨询话题
tags TEXT, -- 擅长领域标签(逗号分隔)
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE(user_phone, expert_id)
);
CREATE INDEX IF NOT EXISTS idx_expert_relations_user ON expert_relations(user_phone);
CREATE INDEX IF NOT EXISTS idx_expert_relations_expert ON expert_relations(expert_id);
COMMIT;
-- ============================================================
-- 回滚脚本(手动执行,需谨慎)
-- 反向执行:psql -d mcp -f migrations/001_bossai_v2_rollback.sql
-- ============================================================
-- BEGIN;
-- ALTER TABLE chat_messages DROP COLUMN IF EXISTS matter_id;
-- ALTER TABLE sessions DROP COLUMN IF EXISTS matter_id;
-- DROP TABLE IF EXISTS expert_relations;
-- DROP TABLE IF EXISTS matters;
-- COMMIT;
+26
View File
@@ -0,0 +1,26 @@
-- BossAi 2.0 回滚脚本 — 慎用,会删除案卡和专家关系数据
-- 运行:psql -d mcp -f migrations/001_bossai_v2_rollback.sql
BEGIN;
-- 移除 chat_messages 的 matter_id 列
ALTER TABLE chat_messages DROP COLUMN IF EXISTS matter_id;
-- 移除 sessions 的 matter_id 列(若存在)
DO $$
BEGIN
IF EXISTS (
SELECT 1 FROM information_schema.columns
WHERE table_name = 'sessions' AND column_name = 'matter_id'
) THEN
ALTER TABLE sessions DROP COLUMN matter_id;
END IF;
END $$;
-- 删除专家关系表
DROP TABLE IF EXISTS expert_relations;
-- 删除案卡表
DROP TABLE IF EXISTS matters;
COMMIT;
+32
View File
@@ -0,0 +1,32 @@
-- BossAi 2.0 阶段三 — 风险推送表
-- TASK-021: risk_alerts 表
-- 幂等:可重复执行
-- 运行:psql -d mcp -f migrations/002_risk_alerts.sql
BEGIN;
CREATE TABLE IF NOT EXISTS risk_alerts (
id SERIAL PRIMARY KEY,
user_phone TEXT NOT NULL, -- 推送对象(手机号)
level TEXT NOT NULL, -- red / orange / blue
title TEXT NOT NULL, -- 标题
content TEXT NOT NULL, -- 详情
source TEXT NOT NULL DEFAULT 'knowledge', -- knowledge / doc_scan / system
related_matter_id INTEGER, -- 可空,关联案卡
read_at TIMESTAMPTZ, -- 可空,标记已读时间
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_risk_alerts_user ON risk_alerts(user_phone);
CREATE INDEX IF NOT EXISTS idx_risk_alerts_user_read ON risk_alerts(user_phone, read_at);
CREATE INDEX IF NOT EXISTS idx_risk_alerts_created ON risk_alerts(created_at DESC);
ALTER TABLE risk_alerts DROP CONSTRAINT IF EXISTS chk_risk_alerts_level;
ALTER TABLE risk_alerts ADD CONSTRAINT chk_risk_alerts_level CHECK (
level IN ('red', 'orange', 'blue')
);
COMMIT;
-- 回滚:
-- DROP TABLE IF EXISTS risk_alerts;