Explorar el Código

feat(chat): 企业微信二维码上方加一句引导语(用户指定文案)

用户给出文案:如果您还有其他疑问,欢迎随时向我咨询,也可以联系CIPA海外服务平台获取支持。

- buildCipaQrcodeContent 改为「上文下码」:引导语(普通文本)+ 空行 + <image-scope> 图片块;
  渲染层按空行切成「文本行 + 图片行」,无需新增组件
- 文案做成导出的常量 CIPA_QRCODE_TIP(改文案只动一处)
- 断言新增 2 项(引导语存在、且排在图片之前)——适配层脚本 25 → 27/27

同步:api-chat.md 的 cipa 节与 feature_list 的 cipa-qrcode 条目。

验证:三个相关脚本全绿(27/87/33);build 与 validate-harness 通过。

Co-Authored-By: Claude Code <noreply@anthropic.com>
gongtianxiao hace 3 horas
padre
commit
4f17bdce12

+ 1 - 1
harness/docs/reference/api-chat.md

@@ -192,7 +192,7 @@ data: {"thread_id":"window-20260914-001","request_id":"a78b17a3b38241fa83c8ee91f
 
 | 取值 | 含义 | 前端行为 |
 |---|---|---|
-| `true` | 问的是 **CIPA / 海外服务平台 / 出海服务** | 在**参考资料之前**追加一张企业微信二维码(`<image-scope>` 块,点击可放大) |
+| `true` | 问的是 **CIPA / 海外服务平台 / 出海服务** | 在**参考资料之前**追加「一句引导语 + 一张企业微信二维码引导语:如果您还有其他疑问,欢迎随时向我咨询,也可以联系CIPA海外服务平台获取支持。;图片走 `<image-scope>` 块,点击可放大) |
 | `false` / 缺失 | 其他情况 | 不展示 |
 | `true` + **本轮有 `interrupt`** | 补问轮(等用户补充公司信息 / 确认候选) | **不展示**:那一轮界面上是补问卡片、还没有正文回答(2026-09-20 实测踩到) |
 

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2 - 3
harness/feature_list.json


+ 10 - 0
harness/progress.md

@@ -3021,3 +3021,13 @@ F073 把整篇综合说明当正文流式铺满后,卡片照旧排在正文之
 
 文档同步:`api-chat.md` 的 F073 实测补充加「版式」一句、`exec-plans/active/answer-streaming.md`
 加「修正」小节、`feature_list.json` 的 `answer-streaming` 更新。
+
+### 续 2:二维码上方加一句引导语(用户指定)
+
+用户给出文案:「如果您还有其他疑问,欢迎随时向我咨询,也可以联系CIPA海外服务平台获取支持。」
+
+- `buildCipaQrcodeContent()` 改为**上文下码**:引导语(普通文本)+ 空行 + `<image-scope>` 图片块
+  —— 渲染层按空行切成「文本行 + 图片行」,无需新增组件
+- 断言新增 2 项(引导语存在、且排在图片之前)——适配层脚本 25 → **27/27 通过**
+- 文案做成导出的常量 `CIPA_QRCODE_TIP`(要改文案只动一处)
+- 同步:`api-chat.md` 的 cipa 节、`feature_list.json` 的 `cipa-qrcode`

+ 7 - 0
harness/tools/verify-company-info-passthrough.mjs

@@ -163,6 +163,13 @@ console.log('\n【5】result.cipa → 企业微信二维码块(<image-scope>
   check('cipa=true → 追加 <image-scope> 块', /<image-scope>[\s\S]*?<\/image-scope>/.test(text), text.slice(-120));
   check('块里有非空的图片地址', /<image-scope>\s*\S[^\n]*\s*<\/image-scope>/.test(text));
   check('正文本身没被污染(正文仍在最前面)', text.trimStart().startsWith('这是回答正文。'), text.slice(0, 40));
+  // 二维码上方的一句引导语(用户 2026-09-20 指定文案),必须在图片**之前**
+  const TIP = '如果您还有其他疑问,欢迎随时向我咨询,也可以联系CIPA海外服务平台获取支持。';
+  check('二维码上方有引导语', text.includes(TIP), text.slice(-160));
+  check('引导语排在图片之前', text.indexOf(TIP) > -1 && text.indexOf(TIP) < text.indexOf('<image-scope>'), {
+    tip: text.indexOf(TIP),
+    img: text.indexOf('<image-scope>'),
+  });
 
   // 位置:正文 → 二维码 → 参考资料(用户 2026-09-20 指定「二维码放在参考资料之前」)
   const withSources = await runTurn([

+ 7 - 2
src/components/api-chat-coordinator.ts

@@ -237,14 +237,19 @@ export function mapChatErrorText(code?: string, message?: string): string {
   return CHAT_ERROR_TEXT[code || ''] || '服务异常,请稍后再试';
 }
 
+/** 二维码上方的一句引导语(文案由用户 2026-09-20 指定) */
+export const CIPA_QRCODE_TIP =
+  '如果您还有其他疑问,欢迎随时向我咨询,也可以联系CIPA海外服务平台获取支持。';
+
 /**
- * 企业微信二维码的内容标记。
+ * 企业微信二维码的内容标记(**上文下码**)
  *
  * 渲染层本来就认 `<image-scope>` 块(→ `ImageContent` 行类型,支持点击放大),
  * 所以这里不需要新增组件,只要按它的约定把图片地址放进去。
+ * 引导语是普通文本,与图片标记之间空一行 —— 渲染层按空行切成「文本行 + 图片行」。
  */
 export function buildCipaQrcodeContent(): string {
-  return `<image-scope>\n${cipaQrcodeUrl}\n</image-scope>`;
+  return `${CIPA_QRCODE_TIP}\n\n<image-scope>\n${cipaQrcodeUrl}\n</image-scope>`;
 }
 
 export const CHAT_ENDPOINT_PATH = '/api/chat';

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio