feat: 2026-04-15~05-02 累积变更基线 — AI 重构 + Runtime Context + DWS 修复

涵盖(每条对应已存的审计记录):
- AI 模块拆分:apps/backend/app/ai/apps -> prompts/(8 个 APP + app2a 派生)
  audit: 2026-04-20__ai-module-complete.md
- admin-web AI 管理套件:AIDashboard / AIOperations / AIRunLogs / AITriggers / TriggerManager
  audit: 2026-04-21__admin-web-ai-management-suite.md
- App2 财务洞察 prompt v3 -> v5.1 + 小程序 AI 接入(chat / board-finance)
  audit: 2026-04-22__app2_prompt_v5_1_and_miniprogram_ai_insight.md
- App2 prewarm 全过滤器 + AI 触发器 cron reschedule
  audit: 2026-04-21__app2-finance-prewarm-all-filters.md
  migration: 20260420_ai_trigger_jobs_and_app2_prewarm.sql / 20260421_app2_prewarm_cron_reschedule.sql
- AppType 联合类型对齐 + adminAiAppTypes.test.ts
  audit: 2026-04-30__admin_web_ai_app_type_alignment.md
- DashScope tokens_used 提取修复
  audit: 2026-04-30__backend_dashscope_tokens_used_extraction.md
- App3 线索完整详情 prompt
  audit: 2026-05-01__backend_app3_full_detail_prompt.md
- Runtime Context 沙箱(5-1~5-2 主线):
  - 后端 schema/service + admin_runtime_context / xcx_runtime_clock 两个 router
  - admin-web RuntimeContext.tsx + miniprogram runtime-clock.ts
  - migration: 20260501__runtime_context_sandbox.sql
  - tools/db/verify_admin_web_sandbox.py + verify_sandbox_end_to_end.py
  - database/changes: 7 份 sandbox_* 验证报告
- 飞球 DWS 修复:finance_area_daily 区域汇总 + task_engine 调整
  + RLS 视图业务日上界(migration 20260502 + scripts/ops/gen_rls_business_date_migration.py)

合规:
- .gitignore 启用 tmp/ 排除
- 不入仓:apps/etl/connectors/feiqiu/.env(API_TOKEN secret,本地修改保留)

待验证清单:
- docs/audit/changes/2026-05-04__cumulative_baseline_pending_verification.md
  每个主题的功能完整性 / 上线验证几乎都未收口,按优先级 P0~P3 逐一处理
This commit is contained in:
Neo
2026-05-04 02:30:19 +08:00
parent 2010034840
commit caf179a5da
130 changed files with 14543 additions and 2717 deletions

View File

@@ -198,6 +198,12 @@ Page({
/** 最后一次发送的用户消息内容(用于重试) */
_lastUserContent: '',
/** SSE 断线重试次数 */
_sseRetryCount: 0,
/** SSE 最大自动重试次数 */
_SSE_MAX_RETRY: 2,
onShow() {
// 权限守卫:检查登录状态、账号禁用、角色权限
checkPageAccess('pages/chat/chat')
@@ -227,10 +233,27 @@ Page({
this.loadMessagesByContext('coach', options.coachId)
} else if (options?.sourcePage) {
// 看板类入口:保存来源页面和筛选参数
const filterKeys = ['timeDimension', 'areaFilter', 'dimension', 'typeFilter', 'projectFilter']
// Phase 2.3:优先解析 options.pageFiltersai-float-button 传入的 JSON 字符串),
// 回退到单独键旧入口兼容timeDimension / areaFilter 等)
const pageFilters: Record<string, string> = {}
for (const key of filterKeys) {
if (options[key]) pageFilters[key] = options[key]
if (options.pageFilters) {
try {
const parsed = JSON.parse(decodeURIComponent(options.pageFilters))
if (parsed && typeof parsed === 'object') {
for (const k of Object.keys(parsed)) {
const v = parsed[k]
if (v != null) pageFilters[k] = String(v)
}
}
} catch {
// JSON 解析失败忽略,回退到单键读取
}
}
if (Object.keys(pageFilters).length === 0) {
const filterKeys = ['timeDimension', 'areaFilter', 'dimension', 'typeFilter', 'projectFilter']
for (const key of filterKeys) {
if (options[key]) pageFilters[key] = options[key]
}
}
this.setData({ sourcePage: options.sourcePage, pageFilters })
this.loadMessagesByContext(options.sourcePage, '')
@@ -418,6 +441,7 @@ Page({
},
// onDone: 流结束,更新消息 ID 和时间
(messageId: number, createdAt: string) => {
this._sseRetryCount = 0
this.setData({
[`messages[${aiIndex}].id`]: String(messageId),
[`messages[${aiIndex}].timestamp`]: createdAt,
@@ -477,8 +501,20 @@ Page({
}
},
fail: () => {
// 网络错误或连接中断
if (this.data.isStreaming) {
// 网络错误或连接中断:无内容时指数退避重连
this._sseTask = null
if (!this.data.isStreaming) return
if (fullContent === '' && this._sseRetryCount < this._SSE_MAX_RETRY) {
this._sseRetryCount++
const delay = (2 ** this._sseRetryCount) * 1000
wx.showToast({ title: `重连中 ${this._sseRetryCount}/${this._SSE_MAX_RETRY}...`, icon: 'loading', duration: delay })
this.setData({
messages: this.data.messages.slice(0, aiIndex),
isStreaming: false,
streamingContent: '',
})
setTimeout(() => { this.triggerAIReply(chatId, content) }, delay)
} else {
const errorContent = fullContent || '连接中断,请重试'
this.setData({
[`messages[${aiIndex}].content`]: errorContent,
@@ -487,7 +523,6 @@ Page({
})
wx.showToast({ title: '连接中断', icon: 'none', duration: 3000 })
}
this._sseTask = null
},
} as WechatMiniprogram.RequestOption)
@@ -509,4 +544,19 @@ Page({
}, 50)
}, 50)
},
/** 点击引用卡片跳转到对应详情页Phase 2.1 */
onRefCardTap(e: WechatMiniprogram.BaseEvent & { currentTarget: { dataset: { link?: string } } }) {
const link = e.currentTarget?.dataset?.link
if (!link || typeof link !== 'string') {
return
}
wx.navigateTo({
url: link,
fail: (err) => {
console.error('跳转引用详情失败', err)
wx.showToast({ title: '跳转失败', icon: 'none' })
},
})
},
})