From 7c98af6ecbe51263d78ec18b9665de656b9bab83 Mon Sep 17 00:00:00 2001 From: maogeigei Date: Thu, 3 Sep 2026 16:01:50 +0800 Subject: [PATCH] =?UTF-8?q?R29:=20=E8=B4=A6=E5=8F=B7=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E5=88=97=E8=A1=A8=E3=80=8C=E6=97=B6=E9=95=BF?= =?UTF-8?q?=E3=80=8D=E5=89=8D=E6=96=B0=E5=A2=9E=E6=A0=87=E7=AD=BE=E5=88=97?= =?UTF-8?q?(40px=E5=9B=BA=E5=AE=9A+=E6=82=AC=E5=81=9C=E5=AE=8C=E6=95=B4?= =?UTF-8?q?=E6=A0=87=E7=AD=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - data-pages.js: renderAccountDetail 表头 收藏后加 th-tag;数据行加 td-tag(title=完整标签, CSS省略); colspan 8→9/batch 9→10 - style.css: th-tag/td-tag(40px min/max + ellipsis) - 冒烟 cdp-verify-r29.mjs 全 PASS; 版本 ?v=20260903l - MEMORY.md 二次压缩 11148→7213B(注入截断修复) --- .workbuddy/memory/2026-09-03.md | 8 +++ .workbuddy/memory/MEMORY.md | 56 ++++++++----------- .../V1.0/mcn-work-shop/cdp-verify-r29.mjs | 55 ++++++++++++++++++ .../V1.0/mcn-work-shop/public/data-pages.js | 3 +- .../V1.0/mcn-work-shop/public/index.html | 6 +- .../V1.0/mcn-work-shop/public/style.css | 3 + 6 files changed, 95 insertions(+), 36 deletions(-) create mode 100644 project/短视频脚本创作/V1.0/mcn-work-shop/cdp-verify-r29.mjs diff --git a/.workbuddy/memory/2026-09-03.md b/.workbuddy/memory/2026-09-03.md index 32c9be3..4668592 100644 --- a/.workbuddy/memory/2026-09-03.md +++ b/.workbuddy/memory/2026-09-03.md @@ -228,3 +228,11 @@ - style.css:.vd-tools(flex 右对齐,margin 2px 0 8px 20px 对齐 page-detail md-body 缩进) - 冒烟 cdp-verify-r28.mjs(9225):未解析58=2 tabs(无分析 tab)+双 tab 空态解析按钮+解析弹窗;已解析117=vd-tools 刷新按钮(icon);deconstruct 无 analysis→空态解析(符合分支)全 PASS - 版本 ?v=20260903k;待实测:解析完成后 account_video_source 更新链路(F5 产物在 视频对标/ 目录,import/account 只扫 视频分析/——需看技能侧 backfill 或 import 扩展) + +## R29 账号详情视频列表加「标签」列(09-03 收尾) +- 需求:视频列表中「时长」前增加标签列,宽度固定 40px,鼠标停留显示完整标签 +- data-pages.js renderAccountDetail(#/account/{id}/persona 视频列表 tab):①L869 数据行在 collect_count 后、duration 前插 ``(title=完整标签悬停);②L921 表头 收藏 后插 `标签`;③colspan 8→9/batch 9→10。数据源 account_videos.tags(listAccountVideos SELECT v.* 已带出;格式逗号分隔 # 话题) +- style.css:.table th.th-tag(40px/min-width 40/居中/收 padding)+ td.td-tag(max-width 40 + ellipsis 省略 + nowrap) +- 冒烟 cdp-verify-r29.mjs(9225 新 profile r29):表头 9 列序=…收藏|标签|时长…、th 实测宽 40px、首行 td-tag 视觉截断(scrollWidth>clientWidth)+title 完整含 #、无 num 类 全 PASS +- 版本 ?v=20260903k→l +- MEMORY.md 二次压缩 11148→7213 字节(注入截断修复) diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index 17ca1c6..bc0bc1a 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -1,41 +1,33 @@ -# MCNVideo AI 项目长期记忆(09-03 压缩整理) +# MCNVideo AI 项目长期记忆(09-03 二次压缩;详细规则权威源=SKILL.md+references,此处仅索引与红线) ## 环境判定两步模型 + 产出落盘(08-26 定稿) -- 两步判定:①本机无 `D:\AgentSkill`=③用户环境;有→②技能路径在 `D:\AgentSkill\` 下=①开发机(源技能)、含 `.dsh`=②dsh 环境。单一 `.dsh` 锚点会把用户环境误判为开发机(P0 已修) -- 产出落盘:①③=桌面 `MCNSkill项目/{账号名}/`;②dsh=`D:\dshworkspace\` 优先。三技能共用账号文件夹。权威=`references-add/路径配置.md`(运行时优先于 SKILL.md) +- 两步:①本机无 `D:\AgentSkill`=③用户环境;有→②技能路径在 `D:\AgentSkill\` 下=①开发机、含 `.dsh`=②dsh。单一 `.dsh` 锚点会把用户环境误判为开发机(P0 已修) +- 产出:①③=桌面 `MCNSkill项目/{账号名}/`;②dsh=`D:\dshworkspace\`。权威=`references-add/路径配置.md`(运行时优先于 SKILL.md) ## 核心技能 -- **短视频脚本创作** `project/短视频脚本创作/{V1.0,Lite1.0}`:11 步流程+知识库;V1.0 含接口、Lite1.0 去接口模型自带 WebSearch。**★软链事实(09-03 实测)**:`C:\Users\maidou\.workbuddy\skills\短视频脚本创作` → 软链 `/d/AgentSkill/mcn-video-script/project/短视频脚本创作/V1.0`(同一文件)——改源即改 WorkBuddy 技能**无需单独同步**;dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\` 是唯一需手动同步的独立副本。同步策略(08-26 用户定):只改 V1.0 源+dsh 副本;Lite1.0 默认不动(用户刻意 divergence)。**🧹后台任务清理**:触发「后台执行什么/清空没用的任务」→ 按 `references/接口调用/自动化任务清理规范.md` 执行;红线=只清过期/错误失败 once(ACCEPTED 或 PENDING_REVIEW/result_success=0/last_error/从未运行),禁清 recurring/未来/running/QUEUED;删除走宿主 automation_update 软删置 deleted_at,**禁 SQL 直改库** -- **MCN工作台**(仅 V1.0)`V1.0/mcn-work-shop/`(server.js+public,零依赖 Node,**端口 8900**,argv 可指定;8899 为错误旧值勿引用)。触发「打开工作台」→启动服务+内置浏览器。**AI 任务触发**:`POST /api/run` 写 `~/.workbuddy/workbuddy.db` automations(once+now,cwds=`D:\AgentSkill\mcn-workshop`)→客户端调度器建会话;轮询 `GET /api/run/status?id=`。**★调度机制实测定稿**(详见工作台 `自动化任务调度机制.md`):显式写 next_run_at(+5s)、scheduled_at 须留 +60s 余量(+17s 失败)、并发上限≈3 超出 QUEUED、runs 状态机 QUEUED→IN_PROGRESS→ACCEPTED、改 server.js 必须重启进程才生效。**★创作任务 prompt 必须带 SKILL_HINT_CREATE 前缀**(data-pages.js L386 弹窗/L711/L920 详情页改写;根因=漏前缀致模型跳步一步直出成品)——**新增创作/改写入口必须检查**。AI脚本选题 `/api/ai/topics`(Dify recall ~50s;key 内置 `scripts/MCN_CYLG_API.py` DEFAULT_CYLG_KEY,env `DIFY_MCN_CYLG_KEY` 优先;curl 中文被 CDN 拦用 Python;search 易超时用 recall)。AI脚本诊断=#/reviews 复盘页(prompt 明确「按 mcn-script-review 执行」) -- **mcn-dou-analysis** 源=`V1.0/subskills/mcn-dou-analysis/`,dsh=`C:\Users\maidou\.dsh\skills\mcn-dou-analysis/`。F1账号信息/F2视频列表/F3账号设定(人设卡)/F4分析数据/F5解析单视频/F6账号设定卡片(SVG 长图)。红线:达人表15列、TOP6筛选(点赞+分享降序)、≥60条停止、29赛道枚举、浏览器 9223 调试实例+标签页复用、**账号表禁从 DB 回填**(工作台 `hot_accounts`=MCP 内部库副本;身份标识留空待浏览器回填)、源技能只读单向同步、脚本必须切脚本创作技能。F6 配色两系(深色系深沉调性/浅色系明快甜美,如玫瑰金 #D6A3A9→#9A5563),**调性优先于赛道标签**,「治愈」双义须回读情绪锚点(俊希=浅色系暖橙非深焦糖);模块名统一「叙事结构」「内容标签」「内容基因·TOPn(n=实际条数)」;F3→F6 自动联动(删 06 文件禁用;md↔SVG 双向维护,交付前 grep 校验)。browser-harness:功能一/二执行前必检,未装→`uv tool install --python 3.12 --upgrade --force browser-harness`+doctor 三要素。**★产物入库(09-01)**:技能产出只落盘不入库(dsh 插件导入未接通=俊希全0根因)→工作台 `POST /api/import/account` 直写 mcn-plugin.db(analysis.json→account_video_analysis、content.json→account_video_source、设定md→account_persona、分析md→account_analysis、xlsx→account_videos;映射=`scripts/export_video_map.py`);**aweme_id 匹配必删全角标点+下划线转空格**,幂等删旧保新+清 null。选题 `/api/ai/topics` 读最新 3 条视频解析 JOIN account_videos 拼 prompt -- **mcn-data-insight(抖音数据获取技能集,09-03 定稿)**:源=`V1.0/subskills/mcn-data-insight/`+dsh=`C:\Users\maidou\.dsh\skills\mcn-data-insight/`(09-03 部署 diff=0)。**纯 11 个红狐系数据获取子技能**(account-diagnosis/daily-hot/hot-trend/works-crawler/ai-feed/prohibited-word/content-surge/weekly-surge/search/top-account/playlet-douyin-feed),**非数据获取技能不再放此包**(nuwa-skill 已删、multi-copywrite-alchemy 移至桌面);无 `.workbuddy`。注意 `mcn-dou-analysis/subskills/nuwa-skill-main/` 是**另一份**账号分析方法论组件(保留勿混)。原 `D:\AgentSkill\mcn-data-insight` 源已剩 SKILL.md+references 壳。**★榜单查询「即查即缓存」落盘(09-03 定稿,commit 4c18e7e)**:红狐 API 按调用计费+榜单=同日期固定快照→强制落盘免重复花钱;桌面 `MCNSkill项目\` 顶层分**业务账号/三方数据**,三方数据统一 `三方数据\{数据源}\`(当前=红狐数据 → `三方数据\红狐数据\抖音榜单\`,后续每数据源一文件夹),文件名**不加数据源前缀**(保 `抖音周榜_` 开头兼容 dsh RANKING_DIR 正则);②dsh=`D:\dshworkspace\抖音榜单\`;查询前先 ls 命中免 API(同榜名+赛道+数据日期全机器仅 1 次 API 调用);固化于主 SKILL.md「榜单数据落盘规范」+抖音数据规则 §2.1/2.2/2.4+三榜单子技能 -- **短视频分镜脚本** `project/短视频提示词生成/`(去 V1.0 层):F1反推图/F2反推视频/F3生图/F4生成分镜;三层引用 references→references-add(运行时优先);F4 输出=主题+导演阐述+代码块(>5s 时间戳分段/≤5s 单段);模板分档 A剧情/B Vlog/C旁白/D产品/E氛围 +4层×5类型;dsh 副本无独有内容需回流 +- **短视频脚本创作** `project/短视频脚本创作/{V1.0,Lite1.0}`:11 步 S1-S11;V1.0 含 MCP/Dify、Lite1.0 去接口模型自带 WebSearch。**★软链事实(09-03)**:`C:\Users\maidou\.workbuddy\skills\短视频脚本创作` 软链到源技能 V1.0(同一文件)→改源即自动同步 WorkBuddy,无需单独同步;dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\` 是唯一需手动同步的副本。同步策略(08-26 用户定):只改 V1.0 源+dsh 副本;Lite1.0 默认不动(刻意 divergence)。🧹后台任务清理按 `references/接口调用/自动化任务清理规范.md`:只清过期/失败 once(禁 recurring/未来/running/QUEUED),走宿主 automation_update 软删,禁 SQL 直改库 +- **MCN工作台**(仅 V1.0)`V1.0/mcn-work-shop/`(零依赖 Node,**端口 8900**,argv 可指定;8899 是错误旧值)。**AI 任务触发**:`POST /api/run` 写 automations(once,显式 next_run_at+5s)→轮询 `GET /api/run/status`;调度机制实测定稿见工作台 `自动化任务调度机制.md`(scheduled_at 须 +60s 余量、并发≈3 QUEUED、改 server.js 须重启进程)。**★创作类 prompt 必须带 SKILL_HINT_CREATE 前缀**(漏前缀=模型跳步一步直出成品;新增创作/改写入口必查)。AI选题 `/api/ai/topics`(Dify recall ~50s,key 内置 `scripts/MCN_CYLG_API.py`,curl 中文被 CDN 拦用 Python);复盘页 prompt 按 mcn-script-review。UI 改完**必重开页面带 `?v=`**(内置浏览器同 URL 复用旧标签,重开是唯一刷新方式) +- **mcn-dou-analysis** 源=`V1.0/subskills/mcn-dou-analysis/`、dsh=`C:\Users\maidou\.dsh\skills\mcn-dou-analysis/`。F1信息/F2视频表(13列xlsx)/F3账号设定/F4数据分析/F5解析单视频/F6设定卡片SVG。红线:达人表15列、TOP6(点赞+分享降序)、≥60条停止、29赛道枚举、浏览器 9223 调试实例+标签页复用、**账号身份标识禁从 DB 回填**(工作台 hot_accounts=MCP 内部库副本;留空待浏览器回填)、源技能只读单向同步。F6 配色按调性分深/浅两系(深=深沉催泪系;浅=明快甜美系如玫瑰金 #D6A3A9→#9A5563;「治愈」须回读情绪锚点)。browser-harness 执行功能一/二前必检。**★产物入库(09-01)**:产出落盘后须 `POST /api/import/account` 直写 mcn-plugin.db(analysis.json→account_video_analysis、content.json→account_video_source、设定/分析 md→account_persona/account_analysis、xlsx→account_videos);aweme_id 匹配必删全角标点+下划线转空格、幂等删旧保新。选题读最新 3 条视频解析拼 prompt +- **mcn-data-insight(09-03 定稿)**:源=`V1.0/subskills/mcn-data-insight/`+dsh 副本(deployed diff=0)。**纯 11 个红狐系数据获取子技能**,非数据获取技能不放此包;`mcn-dou-analysis/subskills/nuwa-skill-main/` 是另一份账号方法论组件勿混。**★榜单即查即缓存落盘(09-03)**:红狐 API 计费+同日期固定快照→先 ls 命中免 API;桌面 `MCNSkill项目\三方数据\{数据源}\`(当前 红狐数据\抖音榜单\),文件名不加数据源前缀(保 `抖音周榜_` 开头兼容 dsh RANKING_DIR);dsh=`D:\dshworkspace\抖音榜单\`。固化于主 SKILL.md「榜单数据落盘规范」 +- **短视频分镜脚本** `project/短视频提示词生成/`:F1反推图/F2反推视频/F3生图/F4生成分镜;F4 输出=主题+导演阐述+代码块(>5s 时间戳分段);模板分档 A剧情/B Vlog/C旁白/D产品/E氛围 -## AI创作弹窗 v2-v4(09-02 定稿;实现=data-pages.js + server.js + tmp/cdp-req-dialog-smoke.mjs) -- 单弹窗 confirmAiScript:REQ_FIELDS 10 项(idea/form/dur/mood/aud/plot/end/sym/ad/note)需求框常显+对话流+胶囊输入行;后端 `/api/ai/clarify`(同步 Dify chat-messages 100s;{accountName,turn,reqMd,history}→{answer};强制「对话+==REQ==+10行需求」;query=人设摘要+reqMd+最近2轮+本轮);AI 禁生成脚本正文 -- v4 附件:`/api/req/parse-attachment` + `scripts/attachment-parser.js`(零依赖 node:zlib 解 .docx/.pdf,.doc 400);提交拼【附件素材】段 -- CDP 冒烟坑(9224):同 URL navigate 不 reload→`?v=Date.now()` 强制;DOM 句柄跨连接失效→Runtime.evaluate+requestNode;setFileInputFiles 抛错→Uint8Array+DataTransfer 注入;**单条持久 WebSocket 必需**(新连接=新 session 句柄全失效) +## 创作技能关键红线(权威=SKILL.md+references/创作流程规范.md) +- 三态创作:⚡自动(默认静默只落最终交付物)/🤝共创(+确认门)/🛠开发(+全落盘);产物链 05选题→06框架→07大纲 顺序禁跳步、「产出与传递」永不省略;硬编码禁止(P0);references-add 增量优先 +- **技能边界**:凡生成/改写脚本必须切脚本创作技能走 S1-S11(含 S11 数字账取证/开场钩子=绝对时长 3-7s 硬上限 10s/编导终审),禁会话内直写脚本;交付物验收口径=执行约束非输出内容,铁律禁在 S9/S10 正文自证 +- MCP:myai-mcp-production(正式)/test;首次提问检测提醒;飞书登录每天检查 -## 创作技能关键规则(权威源=SKILL.md+references/创作流程规范.md) -- 三态创作:⚡自动(默认静默只落最终交付物)/🤝共创(+确认门)/🛠开发(+全落盘);产物链铁律 05选题→06框架→07大纲 顺序禁跳步、「产出与传递」永不省略;硬编码禁止(P0);references-add 增量优先;技能边界=凡生成/改写脚本必须切脚本创作技能走 S1-S11(含 S11 数字账取证/开场钩子铁律=绝对时长3-7s硬上限10s不看占比/编导终审),禁会话内直写脚本 -- 交付物输出边界:验收口径=执行约束非输出内容,铁律/时长占比禁在 S9/S10 正文自证 -- MCP:myai-mcp-production(正式)/myai-mcp-test;首次提问检测提醒安装;飞书登录每天检查 - -## 工作方式约定(红线) -- **治本原则**(09-01 用户明确):解决问题从根因入手→修机制→重新执行验证;禁补数据/临时绕过 -- **改完必重开页面**:网页改动完成最后一步必须 present_files 重开,**URL 必带 `?v=` 版本参数**(内置浏览器同 URL 复用旧标签不真加载;重开是唯一刷新方式)。排查顺序=先重开(?v=)排除旧缓存再改代码 -- 逐条修复:读一条→改一条→验证一条,禁批量读全部文件(上下文压缩丢质量);复查式修复:批量后多次「再检查之前要求」 -- git:**2 小时 push 一次**,本地随时 commit;push 前 fetch 查分叉;代理 socks5://127.0.0.1:10800 破坏连接需清空(local http/https proxy "");杀 node 用 PowerShell `Stop-Process -Id X -Force`(Git Bash taskkill //PID 无效);push 后 origin 跟踪引用可能被沙箱吞需重建 refs/remotes -- 同步时清 tmp(mcn-work-shop/tmp/ + 仓库根 tmp/,已 gitignore;**禁清 .workbuddy/tmp/**);先杀自己启动的测试 Chrome(netstat+taskkill /T /F)再删 -- 沙箱代理:HTTP(S)_PROXY=127.0.0.1:7505(沙箱注入非用户配置)——curl localhost 必须 `--noproxy '*'`;服务用 run_in_background 起,禁 (cmd &) 子 shell -- **Chrome 不主动关闭**(9223 调试实例/用户 Chrome/daemon 连接一律保留,除非用户明确要求;只回收自己启动的临时实例)——固化于 mcn-dou-analysis `references/浏览器搜索抖音账号操作规范.md` 5.7 -- .dsh 单向只读:副本只能读取→回流源技能,禁反向写回(除非用户明确授权) +## 工作方式红线(09-03 全量保留) +- **治本原则**:解决问题从根因入手→修机制→重新执行验证;禁补数据/临时绕过 +- **改完必重开**:网页改动完成最后一步 present_files 重开,URL 必带 `?v=YYYYMMDDx`;排查顺序=先重开排除旧缓存再改代码 +- 逐条修复:读一条→改一条→验证一条,禁批量读全部文件;复查式修复:批量后多次复查 +- git:**2 小时 push 一次**,本地随时 commit;push 前 fetch 查分叉;代理 socks5://127.0.0.1:10800 破坏连接需清 local proxy;杀 node 用 PowerShell `Stop-Process`(Git Bash taskkill 无效);push 后 origin 跟踪引用可能被沙箱吞需重建 refs/remotes +- 同步时清 tmp(mcn-work-shop/tmp/+仓库根 tmp/,gitignore;**禁清 .workbuddy/tmp/**);先杀自启测试 Chrome 再删 +- 沙箱代理 HTTP(S)_PROXY=127.0.0.1:7505——curl localhost 必须 `--noproxy '*'`;服务 run_in_background 起 +- **Chrome 不主动关闭**(9223 实例/用户 Chrome/daemon 连接保留;只回收自启临时实例) +- .dsh 单向只读:副本只读→回流源技能,禁反向写回(除非用户明确授权) +- **★git rm 沙箱坑(09-03,2 次踩)**:`git rm -r` 删大范围被 SIGTERM 中断=只删磁盘不写索引+留 index.lock+半删除。修法:删 index.lock → `git checkout HEAD -- <路径>` 恢复 → **纯 `rm -rf` + `git add -A -- <精确路径>`**(不经 git rm) +- 三层化沉淀:治本(改技能文件)→失误(append 日志)→记忆(MEMORY.md);日志 append-only 不改写历史;技能版本标签 frontmatter updated_at/last_change - 生成网页必先读 taste-skill 与 impeccable(08-27 强约束) -- 技能版本标签:frontmatter updated_at/last_change;dsh 副本 deployed_at<源 updated_at=滞后 -- **★git rm 沙箱坑(09-03,2 次踩)**:`git rm -r` 删大范围文件被 SIGTERM 中断=只删磁盘不写索引(全变 ` D` 未暂存)+留 index.lock+**范围失控半删除**。修法:`rm -f .git/index.lock` → `git checkout HEAD -- <路径>` 恢复 → **纯 `rm -rf` 删磁盘 + `git add -A -- <精确路径>` 暂存**(不经 git rm) -- 三层化沉淀:治本(改技能文件固化)→失误(append 日志)→记忆(MEMORY.md);偏好 append-only 日志不改写历史 ## 历史事件(摘要) -- 07-17 大炮创作方法;07-20 知识库重组;07-29 短剧知识库 V5.0;07-30 短视频知识库 V2.0 -- 08-11/12 素材库扁平化(8类型)+去硬编码+产物链铁律;08-16 赛道 8→27;08-17 三态创作定稿;08-20 分镜落库+seedance25;08-21 Lite1.0;08-22 .dsh 只读确立;08-25 更名 mcn-video-script -- 08-26 路径重构+环境判定两步模型;08-27 dou-analysis 主版+分镜技能解耦+工作台;08-31 数据预览条/AI脚本诊断/调度器根因(scheduledAt 须未来);09-01 产物入库机制+自动化清理规范;09-02 工作台 AI创作弹窗 v2-v4+Chrome 不关红线;09-03 全树相对路径审计+`路径引用规范.md` 固化、mcn-data-insight 瘦身定稿(纯 11 数据技能)+dsh 部署、符号链接事实实测 +07-17 大炮方法;07-20 知识库重组;07-29 短剧库 V5.0;07-30 短视频库 V2.0;08-11/12 素材库扁平化+产物链铁律;08-16 赛道 8→27;08-17 三态创作;08-20 分镜落库;08-21 Lite1.0;08-22 .dsh 只读;08-25 更名 mcn-video-script;08-26 路径重构+两步模型;08-27 dou-analysis+分镜解耦+工作台;08-31 数据预览条/AI脚本诊断/调度器 scheduledAt 须未来;09-01 产物入库+清理规范;09-02 AI创作弹窗 v2-v4+Chrome 不关红线;09-03 路径引用规范固化、data-insight 瘦身+部署、软链事实、git rm 坑 diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/cdp-verify-r29.mjs b/project/短视频脚本创作/V1.0/mcn-work-shop/cdp-verify-r29.mjs new file mode 100644 index 0000000..c36830d --- /dev/null +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/cdp-verify-r29.mjs @@ -0,0 +1,55 @@ +// R29 冒烟:账号详情「视频列表」tab——「时长」前新增「标签」列(固定 40px,超长省略,悬停 title 显示完整) +const list = await fetch('http://localhost:9225/json').then((r) => r.json()); +const page = list.find((t) => t.type === 'page'); +if (!page) { console.log('ERR: no page'); process.exit(1); } +const ws = new WebSocket(page.webSocketDebuggerUrl); +let id = 0; const pending = new Map(); +const send = (method, params = {}) => new Promise((res, rej) => { const i = ++id; pending.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, method, params })); }); +ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && pending.has(m.id)) { const p = pending.get(m.id); pending.delete(m.id); m.error ? p.rej(new Error(m.error.message)) : p.res(m.result); } }; +await new Promise((r) => (ws.onopen = r)); +const ev = async (expr) => { const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) return { __err: (r.exceptionDetails.exception?.description || r.exceptionDetails.text).slice(0, 200) }; return r.result.value; }; +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); +await send('Page.enable'); await send('Runtime.enable'); +const waitFor = async (expr, ms = 15000) => { const t0 = Date.now(); while (Date.now() - t0 < ms) { if (await ev(expr)) return true; await sleep(300); } return false; }; +const fail = (m) => { console.log('FAIL@' + m); process.exit(1); }; +const goto = async (hash) => { await ev(`location.hash = ${JSON.stringify(hash)}`); await sleep(800); }; + +await send('Page.navigate', { url: 'http://localhost:8900/#/' }); +if (!(await waitFor(`!!document.querySelector('#view')`))) fail('app boot'); +await ev(`document.querySelectorAll('.modal-mask').forEach((m) => m.remove())`); // 清 root 设置弹窗 + +/* ============ 账号 1629 视频列表 tab(persona) ============ */ +await goto('#/account/1629/persona'); +if (!(await waitFor(`document.querySelector('#view .table tbody tr')`))) fail('video table rows'); +const out = await ev(`(() => { + const ths = [...document.querySelectorAll('#view .table thead th')].map((t) => t.textContent.trim()); + const thTag = document.querySelector('#view .table thead th.th-tag'); + const firstTr = document.querySelector('#view .table tbody tr'); + const cells = [...firstTr.children]; + const tagTd = firstTr.querySelector('td.td-tag'); + return { + ths, // 完整表头文本序列 + thTagIdx: ths.indexOf('标签'), + durIdx: ths.indexOf('时长'), + thTagW: thTag ? Math.round(thTag.getBoundingClientRect().width) : null, + tagBeforeDur: ths.indexOf('标签') === ths.indexOf('时长') - 1, + // 数据行 + rowCells: cells.map((c) => ({ cls: c.className, txt: (c.textContent || '').trim().slice(0, 24) })), + tagTdText: tagTd ? (tagTd.textContent || '').trim() : null, + tagTdTitle: tagTd ? (tagTd.getAttribute('title') || '') : null, + tagTdClips: tagTd ? tagTd.scrollWidth > tagTd.clientWidth : null, // 是否发生省略截断 + tagTdW: tagTd ? Math.round(tagTd.getBoundingClientRect().width) : null, + hasNumClass: tagTd ? tagTd.classList.contains('num') : null, + }; +})()`); +console.log(JSON.stringify(out, null, 1)); +const ok = out && !out.__err + && out.ths.length === 9 && out.thTagIdx === 6 && out.durIdx === 7 && out.tagBeforeDur === true + && out.thTagW === 40 + && out.rowCells.length === 9 && out.rowCells[6].cls.includes('td-tag') + && !!out.tagTdText && out.tagTdText.length > 0 + && !!out.tagTdTitle && out.tagTdTitle.includes('#') && out.tagTdTitle.length >= out.tagTdText.length + && out.tagTdClips === true && out.tagTdW === 40 && out.hasNumClass === false; +console.log(ok ? '\n=== PASS ===' : '\n=== CHECK ==='); +ws.close(); +process.exit(ok ? 0 : 1); diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js index 69f52ff..cc45e1f 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/public/data-pages.js @@ -866,6 +866,7 @@ async function renderAccountDetail(view, id) { ${fmtWan(v.comment_count)} ${fmtWan(v.share_count)} ${fmtWan(v.collect_count)} + ${v.tags ? esc(v.tags) : ''} ${fmtDuration(v.duration)} `).join(''); @@ -917,7 +918,7 @@ async function renderAccountDetail(view, id) { ${personaPanel()}`; } else if (tab === 'persona') { panel = `
-
${bstate.batch ? '' : ''}${rows || ``}
发布时间视频标题点赞评论分享收藏时长操作
暂无视频数据
+
${bstate.batch ? '' : ''}${rows || ``}
发布时间视频标题点赞评论分享收藏标签时长操作
暂无视频数据
- - + + diff --git a/project/短视频脚本创作/V1.0/mcn-work-shop/public/style.css b/project/短视频脚本创作/V1.0/mcn-work-shop/public/style.css index 26a0951..65cf87c 100644 --- a/project/短视频脚本创作/V1.0/mcn-work-shop/public/style.css +++ b/project/短视频脚本创作/V1.0/mcn-work-shop/public/style.css @@ -488,6 +488,9 @@ main#view { height: calc(100vh - 55px); overflow: auto; } /* 55px=topbar 实际 th.th-pub { width: 135px; } td.td-pub { font-variant-numeric: tabular-nums; } td.td-title { max-width: 240px; } +/* 账号详情视频列表标签列:固定 40px,超长省略,悬停 title 显示完整标签 */ +.table th.th-tag { width: 40px; min-width: 40px; padding: 8px 2px; text-align: center; } +.table td.td-tag { max-width: 40px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 7px 2px; } /* ================= 账号设定 卡片版/文字版 切换(右上角图标按钮组) ================= */ .persona-wrap { position: relative; } /* 账号设定内容左右无间隔(09-02 用户要求去掉 20px) */