Files
happy-life-star/docs/superpowers/plans/2026-05-25-call-log-add-user-plan.md

10 KiB
Raw Permalink Blame History

调用日志列表增加用户字段实现计划

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 在管理后台调用日志列表中增加"调用用户"列,显示格式为 昵称(ID),方便排查用户反馈问题。

Architecture: 后端 AiCallLog 实体新增 userName 字段,两处日志保存逻辑写入该字段;前端列表和详情弹窗统一展示 昵称(ID) 格式。

Tech Stack: Java (Spring Boot 2.7 + MyBatis-Plus), Vue 3 + TypeScript + Element Plus

Spec: docs/superpowers/specs/2026-05-25-call-log-add-user-design.md


文件清单

操作 文件 说明
Modify backend-single/src/main/java/com/emotion/entity/AiCallLog.java 实体新增 userName 字段
Create backend-single/src/main/resources/db/migration/V20260525__add_user_name_to_ai_call_log.sql 数据库迁移脚本
Modify backend-single/src/main/java/com/emotion/service/impl/AiRuntimeServiceImpl.java:68-73 invokeStream 写入 userName
Modify backend-single/src/main/java/com/emotion/service/impl/AiRuntimeServiceImpl.java:219-225 invokeEndpointStream 写入 userName
Modify web-admin/src/types/aiconfig.ts AiCallLog 接口新增 userName
Modify web-admin/src/views/aiconfig/AiRoutingList.vue 列表新增"调用用户"列 + userDisplay 函数
Modify web-admin/src/views/aiconfig/components/AiCallLogDetailDialog.vue 详情弹窗"用户 ID"改为"调用用户"

Task 1: 后端实体 + 数据库迁移

Files:

  • Modify: backend-single/src/main/java/com/emotion/entity/AiCallLog.java:29-31

  • Create: backend-single/src/main/resources/db/migration/V20260525__add_user_name_to_ai_call_log.sql

  • Test: backend-single/ 目录下执行编译验证

  • Step 1: 在 AiCallLog 实体中新增 userName 字段

userId 字段(第 29-30 行)下方新增:

// AiCallLog.java — 在 @TableField("user_id") private String userId; 之后新增

@TableField("user_name")
private String userName;
  • Step 2: 创建数据库迁移脚本

创建 backend-single/src/main/resources/db/migration/V20260525__add_user_name_to_ai_call_log.sql:

-- 调用日志表新增 user_name 字段
ALTER TABLE t_ai_call_log ADD COLUMN user_name VARCHAR(100) DEFAULT NULL COMMENT '用户昵称' AFTER user_id;
  • Step 3: 编译验证后端代码
cd backend-single
mvn clean compile -DskipTests

预期:BUILD SUCCESS

  • Step 4: 提交
git add backend-single/src/main/java/com/emotion/entity/AiCallLog.java
git add backend-single/src/main/resources/db/migration/V20260525__add_user_name_to_ai_call_log.sql
git commit -m "feat: 调用日志实体新增 userName 字段及数据库迁移脚本"

Task 2: 后端日志保存逻辑写入 userName

Files:

  • Modify: backend-single/src/main/java/com/emotion/service/impl/AiRuntimeServiceImpl.java

  • Test: backend-single/src/test/java/com/emotion/service/AiRuntimeServiceImplTest.java

  • Step 1: 在 invokeStream 方法中写入 userName

找到第 71 行 callLog.setUserId(resolveUserId(request)); 之后,第 72 行 callLog.setInputText(...) 之前,新增:

// 在 callLog.setUserId(resolveUserId(request)); 之后新增
callLog.setUserName(request.getUserName());

修改后的上下文(第 68-74 行)变为:

        AiCallLog callLog = new AiCallLog();
        callLog.setRequestId(requestId);
        callLog.setSceneCode(request.getSceneCode());
        callLog.setUserId(resolveUserId(request));
        callLog.setUserName(request.getUserName());
        callLog.setInputText(JSON.toJSONString(request.getInputs()));
        callLog.setStatus("running");
  • Step 2: 在 invokeEndpointStream 方法中写入 userName

找到第 223 行 callLog.setUserId(request.getUserId()); 之后,第 224 行 callLog.setInputText(...) 之前,新增:

// 在 callLog.setUserId(request.getUserId()); 之后新增
callLog.setUserName(request.getUserName());

修改后的上下文(第 219-226 行)变为:

        AiCallLog callLog = new AiCallLog();
        callLog.setRequestId(requestId);
        callLog.setEndpointCode(endpoint.getEndpointCode());
        callLog.setProviderCode(provider.getProviderCode());
        callLog.setUserId(request.getUserId());
        callLog.setUserName(request.getUserName());
        callLog.setInputText(JSON.toJSONString(request.getInputs()));
        callLog.setStatus("running");
  • Step 3: 更新单元测试,验证 userName 被正确写入

修改 backend-single/src/test/java/com/emotion/service/AiRuntimeServiceImplTest.java,在 invokeStreamRecoversWhenOutputExists 测试中:

在已有的 request.setRequestId("client-request-1"); 之后添加 request.setUserName("测试用户");,然后在断言部分新增 userName 的验证:

// 在 request.setRequestId("client-request-1"); 之后添加
request.setUserName("测试用户");

// 在已有的 assertEquals("完整输出", savedLog.getOutputText()); 之后添加
assertEquals("测试用户", savedLog.getUserName());
  • Step 4: 运行测试验证
cd backend-single
mvn test -Dtest=AiRuntimeServiceImplTest

预期:Tests run: 1, Failures: 0, Errors: 0

  • Step 5: 编译验证 + 提交
cd backend-single
mvn clean compile -DskipTests
git add backend-single/src/main/java/com/emotion/service/impl/AiRuntimeServiceImpl.java
git add backend-single/src/test/java/com/emotion/service/AiRuntimeServiceImplTest.java
git commit -m "feat: 日志保存时写入 userName 字段"

Task 3: 前端类型定义 + 列表新增列

Files:

  • Modify: web-admin/src/types/aiconfig.ts:249-250 (AiCallLog 接口)

  • Modify: web-admin/src/views/aiconfig/AiRoutingList.vue (调用日志表格区域)

  • Step 1: AiCallLog 接口新增 userName

web-admin/src/types/aiconfig.tsAiCallLog 接口中,找到 userId?: string 行(约第 249 行),在其下方新增:

// 在 userId?: string 之后新增
userName?: string
  • Step 2: AiRoutingList.vue 新增"调用用户"列

在调用日志表格中,找到 调用时间 列(<el-table-column prop="createTime" label="调用时间" width="175" />)之后,场景 列之前,新增:

<el-table-column label="调用用户" width="180" show-overflow-tooltip>
  <template #default="{ row }">
    {{ userDisplay(row) }}
  </template>
</el-table-column>
  • Step 3: AiRoutingList.vue 新增 userDisplay 辅助函数

<script setup> 中,找到 function formatMs(ms?: number) 函数之后(约第 640 行),新增:

function userDisplay(row: AiCallLog): string {
  const name = row.userName
  const id = row.userId
  if (name && id) return `${name}(${id})`
  if (name) return name
  if (id) return `-(ID: ${id})`
  return '-'
}
  • Step 4: 前端类型检查
cd web-admin
npm run type-check

预期:无错误

  • Step 5: 提交
git add web-admin/src/types/aiconfig.ts
git add web-admin/src/views/aiconfig/AiRoutingList.vue
git commit -m "feat: 调用日志列表新增调用用户列"

Task 4: 前端详情弹窗格式统一

Files:

  • Modify: web-admin/src/views/aiconfig/components/AiCallLogDetailDialog.vue

  • Step 1: 替换"用户 ID"行为"调用用户"

AiCallLogDetailDialog.vue 中,找到基本信息区域中的"用户 ID"行(约第 50-53 行):

          <div class="info-item">
            <span class="info-label">用户 ID</span>
            <span class="info-value">{{ log.userId || '-' }}</span>
          </div>

替换为:

          <div class="info-item">
            <span class="info-label">调用用户</span>
            <span class="info-value">{{ userDisplay(log) }}</span>
          </div>
  • Step 2: 添加 userDisplay 辅助函数

<script setup> 中,找到 function formatMs(ms?: number) 函数(约第 111 行)之后,新增:

function userDisplay(log: AiCallLog): string {
  const name = log.userName
  const id = log.userId
  if (name && id) return `${name}(${id})`
  if (name) return name
  if (id) return `-(ID: ${id})`
  return '-'
}
  • Step 3: 前端类型检查
cd web-admin
npm run type-check

预期:无错误

  • Step 4: 提交
git add web-admin/src/views/aiconfig/components/AiCallLogDetailDialog.vue
git commit -m "feat: 详情弹窗用户信息改为昵称+ID格式"

Task 5: 浏览器验证

  • Step 1: 启动管理后台
cd web-admin
npm run dev
  • Step 2: 浏览器验证
  1. 打开管理后台页面(通常 http://localhost:5174
  2. 导航至 AI 配置管理页面 (/aiconfig/list)
  3. 切换到"调用日志" tab
  4. 验证:列表中出现"调用用户"列,显示格式为 昵称(ID)-(ID: xxx)-
  5. 点击任意日志的"详情"按钮,验证弹窗中"调用用户"行显示格式与列表一致
  6. 打开浏览器 DevTools Console,确认无报错
  • Step 3: 最终提交(如有必要的小修复)
git add -A
git commit -m "fix: 调用日志用户列浏览器验证修复"

Self-Review: Spec Coverage Check

Spec 要求 对应 Task
AiCallLog 实体新增 userName Task 1 Step 1
数据库新增 user_name 列 Task 1 Step 2
invokeStream 写入 userName Task 2 Step 1
invokeEndpointStream 写入 userName Task 2 Step 2
前端类型定义新增 userName Task 3 Step 1
列表新增"调用用户"列 Task 3 Step 2-3
详情弹窗改为调用用户格式 Task 4 Step 1-2
兜底策略(历史数据 NULL userDisplay 函数已处理
不改 AiCallLogQueryRequest 确认未改

Placeholder Scan

计划中无 "TBD"、"TODO"、"fill in"、"add appropriate error handling" 等占位符。所有步骤包含完整代码和命令。

Type Consistency Check

  • AiCallLog.userName → Java String,前端 userName?: string 一致
  • userDisplay 函数在 AiRoutingList.vue 和 AiCallLogDetailDialog.vue 中实现相同逻辑 一致
  • 显示格式统一为 昵称(ID) / -(ID: xxx) / - 一致