- 新增双项目整合可行性评估 V0.1 rev.2:覆盖度矩阵、方案对比、目标架构、工作量/TCO、风险与决策清单 - 新增 dewu/sucaigongfang 两份调研报告(内部资料,平台敏感值已脱敏) - 新增技术栈与架构定稿 V1.0:Node 24.15.0 / pnpm 11.4.0 / Prisma 7.10.1 / PostgreSQL 18 / Redis 7 - 更新 README 文档索引与仓库结构
727 lines
83 KiB
Markdown
727 lines
83 KiB
Markdown
# dewu-material-Downloader 调研报告
|
||
|
||
> **调研对象**:`参考项目/dewu-material-Downloader/`(应用名「得物素材助手」,v2.7.0,git HEAD `fe7646b`)。
|
||
> **密级**:内部;文中平台接口/签名等敏感信息已脱敏,原文见受控知识库。
|
||
> **调研方式**:只读通读源码与文档,交叉核对 git 历史、CI 配置与构建脚本;**未安装依赖、未运行构建、未修改参考项目**。凡文档与代码冲突处,以代码为准,并在文中注明文档已过时的位置。
|
||
> **路径简写**:下文 `dw/` = `参考项目/dewu-material-Downloader/`;`dw:line` 均指该仓库内文件行号。
|
||
> **数字口径**:LOC 用 `find <dir> -name '*.ts' -o -name '*.tsx'`(scripts 为 `*.mjs`/`*.cjs`)+ `wc -l`,口径在 §7.1 写明;文件数不含 `node_modules/`、`dist/`、`dist-electron/`、`release/`、`.cache/`、`.probe-material-page/`、`review/` 等产物或本地取证目录。
|
||
> **调研时间**:2026-10-30。
|
||
|
||
---
|
||
|
||
## 0. 结论速览
|
||
|
||
- **一句话定位**:这不是一个简单的「下载器」,而是得物「星光平台」软广素材的**桌面端运营工作台**——已从 v1 的「登录→抓素材→下视频」演进为「素材下载 + 商品查询 + 素材审核查询 + 批量送审/混剪送审 + DPLink 一键复制」五段闭环。
|
||
- **端形态**:Electron 44 单窗口桌面应用(Windows 为主力历史平台、macOS 为当前开发/验证机;Linux 有配置但未验证);`contextIsolation: true` + preload 白名单;React 19 + Semi Design 2 + Tailwind 3 + Playwright(`dw/package.json:3`、`dw/electron/main.ts:1`)。
|
||
- **成熟度**:v2.7.0;git 记录 **228 个提交 / 21 个 tag / 2026-05-23 → 2026-10-22**(约 5 个月;最后 tag 为 v2.4.0,2.5.0–2.7.0 未打 tag,仅有 release 提交);功能覆盖深、但**真机验证不均**(送审非混剪已端到端成功,混剪「是」分支未真机;素材审核页仍挂 BETA)。
|
||
- **质量基线**:TypeScript `strict` 全开、`tsc --noEmit` 是 CI 第一道门禁;**无单一测框架**(无 vitest/jest),但有 **32 个验证脚本、15,411 行、CI 三个 job**(`verify:ui` v2.7.0 记录 480 条通过、`verify:platform` 260 条通过;脚本内 `ok()` 断言点分别为 472/255);无 ESLint/Prettier 配置。
|
||
- **体量**:`src/` 19,120 行(67 个 ts/tsx)、`electron/` 17,345 行(45 个 ts)、`scripts/` 27,828 行(73 个 mjs/cjs)、`release-scripts/` 875 行(mjs/cjs,不含 .sh/README 的 622 行),合计 **65,168 行**;另有 CSS 3,675 行、docs 30 篇 Markdown 14,633 行。
|
||
- **最大的整合事实**:它只覆盖 **得物/星光一个平台**(全仓检索不到唯品会/vipshop 代码),且只覆盖 PRD 的 **P-01/P-04 与 P-05 的一部分**;**P-02 图片模板、P-03 视频 AI、P-06 多平台、P-07 资产管理完全不含**。新平台这两条产线必须另起,不能指望从本项目迁移。
|
||
- **Web 化的核心结论**:**「读」链路可以做到无浏览器**(签名 + 只读接口已验证,纯 Node 可复现);**「写」链路(送审)必须保留服务端浏览器自动化**(平台上传走页面第一方 SDK + `duToken` 网关,重放成本高且易踩风控);**Electron 外壳能力(内嵌 webview、本地文件路径、FTP Cookie 同步、safeStorage、自动更新、代码签名)全部重写或废弃**。
|
||
|
||
### 0.1 结论表(能力域 → Web 化结论)
|
||
|
||
| 能力域 | Web 化结论 | 关键原因 | 粗估人日 |
|
||
|---|---|---|---|
|
||
| 登录态(接口验证码登录 / 浏览器兜底 / Cookie 同步) | **服务端重写** | 单账号单会话;凭据是本机 `safeStorage` 加密文件 + FTP 静态共享;服务端需多用户账号归属与 KMS 加密 | 8–12 |
|
||
| 素材读取(软广素材库列表/详情、审核列表、枚举) | **改造复用** | 只读接口 + MD5 签名 + 信封解析已跑通,纯 Node 可复现;去掉 Electron 直接作为服务端模块 | 5–8 |
|
||
| 原始物料下载(含任务工作台 UI + 视频 CDN 直连 + 商品图/主视频) | **服务端重写** | 浏览器只用于「登录/兜底」;下载、MD5 去重、分批冷却可保留策略,但文件落盘改为对象存储/下载中心;UI 需按新设计系统重做 | 25–38 |
|
||
| 商品查询(SPU 解析 + 商品详情 + 素材 9 项) | **改造复用** | 商品详情是 SSR HTML 直取,不需要浏览器;链接短链解析可服务端做 | 12–18(含 UI) |
|
||
| 内嵌商品 H5 画布 + 净化模式 | **废弃** | 依赖 Electron `<webview>` + 移动端 UA + 持久分区;Web 端受 iframe/X-Frame-Options 限制,且价值低于「数据直取」 | 0(可选 3–5) |
|
||
| 素材审核页(列表/筛选/驳回原因/上传记录/CSV) | **改造复用** | 纯只读接口 + 平台枚举,无 Electron 依赖;UI 需按新设计系统重做 | 8–12 |
|
||
| 送审判定 / 命名解析 / 预检规则 | **直接复用** | 已是应用与门禁共用的纯逻辑(`scripts/lib/submit-naming.mjs` 等),零 Electron 依赖 | 3–5 |
|
||
| 批量送审(页面自动化 + 上传 + 幂等 + 回查 + 账本/审计) | **服务端重写** | 浏览器填表 + `setInputFiles` + 观察响应;服务端需浏览器池、大文件上传通道、会话串行;策略层可复用 | 26–37 |
|
||
| 混剪送审(双栏配对 + 源检索 + N 组提交) | **服务端重写(UI 改造复用)** | 纯逻辑已抽到 `scripts/lib/mix-submit.mjs`;「混剪=是」写链路尚未真机验证 | 14–22 |
|
||
| DPLink 一键复制 | **改造复用** | 纯算法 4/4 样本逐字符复现;仅两个只读接口 + 硬广凭据 | 5–8 |
|
||
| 应用设置 / 远端配置 / 日志 | **改造复用** | 配置分层、档位预设、白名单和签名机制可迁移;用户配置改服务端 DB | 7–10 |
|
||
| 自动更新 / 关于页 / 旧版本清理 / 窗口状态 | **废弃** | 桌面应用专属(Squirrel/ShipIt、`legacy-bundle`、BrowserWindow maximize) | 0–1 |
|
||
| 验证门禁与纯逻辑资产 | **改造复用** | 21 个 `scripts/lib/*.mjs` + fixtures + 32 个 verify 脚本,可直接转服务端单测/契约测试 | 6–10 |
|
||
|
||
> 人日为「分析员粗估、供排期参考」,含联调与验收、不含图片/视频 AI 产线;合计约 **115–190 人日**(逐项见 §8)。
|
||
|
||
---
|
||
|
||
## 1. 项目定位与业务链路
|
||
|
||
### 1.1 解决什么问题、给谁用
|
||
|
||
**业务背景**:得物「星光平台」是软广/KOL 投放的素材后台,素材库、审核、送审都在内网/H5 体系里,**没有面向内部的开放 API**,也没有批量下载能力。运营与剪辑的日常是:
|
||
|
||
1. 在软广视频库里逐条点「预览」,复制视频地址,手工记录 `媒体任务ID / 视频ID / SPUID / 投放类目 / 授权时间`;
|
||
2. 手工改名落盘,反复登录网页版导致桌面工具掉线;
|
||
3. 剪辑后回到素材池「KOL原生二创素材上传」抽屉,逐条填投放渠道、媒体任务ID、视频ID、SPUID、挂 140–190MB 成片、点提交;
|
||
4. 被拒后去审核列表逐条看驳回原因;
|
||
5. 投放前再去星光「商品生成链接」页手工选落地页、商品,复制 iOS/Android 唤端链接。
|
||
|
||
**目标用户**:得物软广素材运营、剪辑、投放优化师(小团队、共享少数星光账号)。产品一直是**内部效率工具**,不是多租户 SaaS——这决定了它大量假设「一台机器、一个人、一个账号」。
|
||
|
||
### 1.2 主链路(端到端)
|
||
|
||
```
|
||
① 登录星光(接口验证码登录 / 浏览器登录兜底 / 云端 Cookie 同步)
|
||
↓
|
||
② 选品
|
||
A. 素材下载页:输入 SPUID(可多个)→ 软广视频库筛选 → 提取素材
|
||
B. 商品查询页:输入 SPUID / 商品链接 / App 分享文本 → 商品详情 + 9 项原始素材
|
||
↓
|
||
③ 原始物料获取
|
||
A. 视频:按「媒体任务ID-视频ID-SPUID-类目-授权起-授权止.mp4」命名 → CDN 直连下载 → MD5 去重
|
||
B. 商品图/主视频:按「<下载目录>/商品素材/<spuId>-<货号>-<标题前40字>/」落盘
|
||
↓
|
||
④ 本地剪辑 / 混剪(应用外,本仓库不覆盖)
|
||
↓
|
||
⑤ 提审:命名解析 → md5 本地查重 → 预检弹窗 → 页面自动化逐条提交 → 超时只回查不重试
|
||
→ 已送审 md5 账本 + JSONL 审计
|
||
↓
|
||
⑥ 审核查询:审核中/通过/不通过/全部 → 驳回原因、审核人、视频直链、上传记录 xlsx、CSV 导出
|
||
↓
|
||
⑦ 投放配置:商品查询页复制 iOS UniversalLink / 安卓 DeepLink(DPLink)
|
||
```
|
||
|
||
**与旧版下载器的关键差异**(git 历史可证):v1.x 只有 ①③(登录 + 下载)以及更新/设置;v2.0 加商品查询页;v2.1 收敛设置/远端配置/更新验签;v2.2 升 Electron 44 并落地 mac 签名公证;v2.3 把「读」接口化(P1);v2.4 加素材审核(P2);v2.5 加素材送审(P4)+ 改名 + mac 原生更新;v2.6 加 DPLink;v2.7 改为任务工作台、加混剪送审/素材预览/过滤开关。**它已经是一个流程闭环产品,而不是单点脚本**。
|
||
|
||
### 1.3 与 PRD 1.1 问题的对应关系
|
||
|
||
| PRD 编号 | PRD 问题 | 本项目覆盖度 | 证据 / 说明 |
|
||
|---|---|---|---|
|
||
| P-01 | 原始物料:详情页图片逐张人工下载、分散存放 | **部分覆盖** | 商品查询页支持主图/详情图/主视频一键下载并按商品目录归档(`dw/electron/shop/materials.ts:24-26`);视频素材库支持按 SPUID 批量下载(`dw/electron/platform/materials.ts`)。**只覆盖得物单平台**,且无「本次选品物料库」概念 |
|
||
| P-02 | 图片:三规格 × 四层信息人工排版 | **不覆盖** | 全仓无 PSD 解析、无模板合成、无 800×800/1280×720/1080×1920 产出代码 |
|
||
| P-03 | 视频:依赖实拍与个人脚本经验 | **不覆盖** | 无脚本生成、无 AI 视频、无 TTS/画面组合 |
|
||
| P-04 | 命名提审:手工改名与登记,进度散落 | **覆盖** | 命名规范 + 末三段解析 + 预检弹窗 + 批量送审 + 审核状态跟踪 + md5 幂等 + 审计(`dw/electron/submit/*`、`dw/docs/送审命名规范与预检规则.md`) |
|
||
| P-05 | 账户搭建:DP、承接页逐条复制 | **部分覆盖(仅 DPLink)** | 只做「商品 → 投放唤端链接」拼接与复制,**不做 DP 编写、不做承接页字段批量替换**(PRD 中 DP 的具体口径也待业务确认) |
|
||
| P-06 | 多平台:资源与口径不统一 | **不覆盖** | 全仓检索 `唯品会/vipshop/vip.com` 无命中;平台地址只有星光 + 得物商品站 |
|
||
| P-07 | 资产管理:模板/脚本散落 | **不覆盖** | 无模板/脚本/Logo 资产库;仅有「落地页列表」与「商品库」两个只读数据源 |
|
||
|
||
> **结论**:本项目是**新平台「选品→原始物料→提审→投放链接」段的现成参考实现**,但不是「图片/视频产线」的参考实现;新平台需要「得物作业端(迁移+增强) + 图片/视频产线(新建) + 多平台抽象(新建)」三块并行。
|
||
|
||
---
|
||
|
||
## 2. 功能模块清单(全量)
|
||
|
||
> 以 `dw/src/App.tsx:240-306` 的侧边栏 6 个入口 + 代码内实际存在的能力为准;「实现状态」按代码与文档的真实完成度标注(完整 / BETA / Phase 1 待真机 / 仅配置 / 未实现)。
|
||
|
||
| 模块 | 页面/入口 | 核心功能点 | 实现状态 | 关键文件:行 | 依赖 Electron 能力 |
|
||
|---|---|---|---|---|---|
|
||
| **素材下载** | 侧边栏「素材下载」`/` | SPUID 筛选(多值、中文分隔归一化、填写后显示各 SPUID 素材数);按页数/按数量两种范围;提取「拦截→接口→DOM 兜底」三级路径并显示读取方式;两个下载前过滤开关(30 天内到期 / 未授权快手);素材预览;分批+并发+随机延迟+指数退避+冷却;MD5 去重;任务详情/重试历史;打开下载目录/系统通知/日志导出;新建任务(保留前置条件) | **完整**(v2.7.0 真机可用) | `dw/src/pages/DownloadPage/index.tsx:250`、`dw/electron/browser/manager.ts`、`dw/electron/downloader/manager.ts`、`dw/electron/platform/materials.ts` | 是:Playwright、文件系统、dialog、通知、剪贴板、`shell.openPath` |
|
||
| **商品查询** | 侧边栏「商品查询」`/shop` | 输入 SPUID / 商品链接 / App 分享文本;左栏内嵌得物 H5 商品页(移动 UA + 独立持久分区 + 净化模式 + 导航白名单 + 右键菜单);右栏 SSR 直取商品卡片(标题/价格/货号/SKU/主图/详情图/主视频/来源链接);9 项素材格;下载范围「主图+视频 / 全部」;逐文件进度与取消;DPLink 两个复制按钮 | **完整**(2026-10-22 摘除 BETA) | `dw/src/pages/ShopPage/index.tsx:426`、`dw/src/components/SpuCanvas.tsx`、`dw/electron/shop/session.ts:32-66`、`dw/electron/shop/detail.ts:11-27` | 是:`<webview>`、partition、dialog、文件系统 |
|
||
| **素材审核** | 侧边栏「素材审核」`/review` | 审核中/通过/不通过/全部 4 Tab + 总数;按素材ID、审核时间、上传时间筛选;列表(32 条/页,与网页版一致);详情弹窗(视频、字段、审核人);驳回原因富文本(白名单 AST,不 `dangerouslySetInnerHTML`);上传/送审记录(含 xlsx 预签名下载);勾选行导出 CSV;权限前置「建议而非硬拦」 | **BETA**(数据来自平台接口,界面仍按反馈调整) | `dw/src/pages/ReviewPage/index.tsx:627`、`dw/src/pages/ReviewPage/ReviewTable.tsx`、`dw/electron/platform/reviews.ts:43-48`、`dw/scripts/lib/review-csv.mjs` | 否(只读 HTTP);CSV 落盘用 dialog |
|
||
| **批量送审** | 素材审核页「批量送审 / 选文件夹」→ 预检弹窗 → 进度浮层 | 命名两模式解析(文件夹名恰好三段 / 文件名末三段);SPUID 回显;md5 流式查重 + 已送审账本;批内去重;就地改 ID / 批量补 SPUID / 冲突二选一;逐条开抽屉→选混剪=否→投放渠道→填 3 字段→`setInputFiles`→等上传→提交→观察响应;超时只回查;掉线停批;审计 JSONL | **完整**(非混剪链路 2026-10-16 端到端成功 1 条;离线门禁全绿) | `dw/src/pages/ReviewPage/SubmitPrecheckModal.tsx`、`dw/electron/submit/page.ts:47-110`、`dw/electron/submit/batch.ts:1-40`、`dw/electron/submit/verify.ts` | 是:Playwright、dialog |
|
||
| **混剪送审** | 素材审核页「混剪送审」→ 双栏配对弹窗 | 成品文件名只取末段 SPUID;右栏按 SPUID 自动检索平台素材/本机下载库;授权状态(有效/≤30天/已过期/未生效/长期/未知);N 组 `{xtTaskId, videoId}` 配对;提交前校验配对/渠道/SPUID 一致性/组数;页面自动化选「混剪=是」并回读组数 | **Phase 1 已落地,待真机**(「混剪=是」写链路未验证) | `dw/src/pages/ReviewPage/MixSubmitModal.tsx`、`dw/electron/submit/mix.ts`、`dw/electron/platform/source-search.ts`、`dw/scripts/lib/mix-submit.mjs` | 是:Playwright、dialog |
|
||
| **送审进度** | 全局浮层 + 页面卡片 | 逐条阶段(填表/上传/提交/回查)、成功/跳过/失败/未知、可中断(当前条跑完即停)、切页不中断、可按 md5 看审计尾部 | **完整** | `dw/src/pages/ReviewPage/SubmitProgressPopover.tsx`、`dw/src/hooks/useSubmitProgress.ts` | 是(经 IPC) |
|
||
| **DPLink 一键复制** | 商品查询页「复制 iOS DPLink / 复制安卓 DPLink」+ 设置「投放落地页」 | 拉落地页列表(含 `flag/_gsign/navControl`)、按 SPU 反查商品库 `cSpuId`、拼两层链接(内层整段 encode)、复制到剪贴板;硬广账号独立凭据、云端 `accounts.dplink` 分区、错误分类(未配置/无权限/未选落地页/不在商品库/网络) | **完整**(2.6.0;4 条样本 4/4 逐字符复现;依赖客户共享硬广账号) | `dw/src/pages/ShopPage/index.tsx:695-703`、`dw/electron/dplink/link.ts:39-41`、`dw/electron/dplink/account.ts:1-40` | 剪贴板(主进程 `clipboard`);凭据 safeStorage |
|
||
| **登录态** | 侧边栏底部状态、登录弹窗、设置「账号与同步」 | 软广账号:接口发码/登录(不启浏览器)、浏览器登录兜底、无头/有头切换、登录预检(启动检测)、退出(只清本机+忽略云端);硬广账号:独立加密槽 + 独立登录;云端 Cookie 同步 v2(soft/dplink 分区、HTTP 拉、FTP 推、写后回读) | **完整**(接口登录 `verify:login` 9/9 实测;云端同步为遗留架构) | `dw/src/components/SidebarLoginStatus.tsx:32-74`、`dw/src/components/LoginDialog.tsx`、`dw/electron/platform/auth.ts:1-70`、`dw/electron/browser/cookieSync.ts:1-40` | 是:Playwright、safeStorage、FTP、文件系统 |
|
||
| **配置管理** | 侧边栏「应用设置」`/config` | 分区清单:账号与同步 / 下载(路径、完成后自动打开、三档速度)/ 外观与启动(主题、启动最大化)/ 更新(启动检查、自动下载、退出安装)/ 投放落地页 / 诊断与日志(版本、日志、远端配置来源、忽略远端配置);未保存改动导航守卫;恢复默认 | **完整** | `dw/src/pages/ConfigPage/index.tsx:716-1180`、`dw/electron/config/default.ts:52-72`、`dw/electron/config/presets.ts:59-102` | 是:dialog、safeStorage、BrowserWindow |
|
||
| **远端配置** | 设置「诊断与日志 → 远端配置」 | Ed25519 验签、JSONC 解析、白名单+区间校验、revision 单调、三级回退(远端→缓存→内置)、紧急 `disabled`、送审总开关 `enableSubmitReview` | **完整**(线上 revision 2) | `dw/electron/config/remote.ts:1-40`、`dw/scripts/lib/remote-config-schema.mjs:32-80`、`dw/remote-config/app-config.json:26,72` | 否(HTTP GET) |
|
||
| **运行日志** | 设置「诊断与日志」、下载/送审页 | 内存缓冲 + 按日文件(保留 7 个)+ 导出 + 打开目录 + 跨天切换 | **完整** | `dw/electron/logger.ts:41-101` | 是:文件系统、shell |
|
||
| **自动更新** | 侧边栏「软件更新」`/update` | 检查/下载/安装/跳过此版本/恢复提醒;更新元数据 `.sig` Ed25519 验签;强制更新、最低版本、更新说明 Markdown 渲染;mac 走 Squirrel 原生替换 `.app` | **完整**(CI 签名+公证+装订;本机 ad-hoc 包点更新会失败属预期) | `dw/src/pages/UpdatePage/index.tsx`、`dw/electron/updater/manager.ts:56-90,185,274-301` | 是:electron-updater、shell、app 生命周期 |
|
||
| **关于页** | 侧边栏「关于应用」`/about` | 版本徽标、复制版本信息、日志入口、第三方许可清单/完整文本、企微反馈;**无更新逻辑**(跳更新页) | **完整** | `dw/src/pages/AboutPage/index.tsx:23-59` | 是:clipboard、shell、许可文件路径 |
|
||
| **应用外壳** | `App.tsx` | HashRouter 6 页、侧边栏、主题(亮/暗/跟随系统)、4 页骨架屏、错误边界、退出二次确认、崩溃兜底、单实例锁、窗口最小尺寸/启动最大化、`Cmd/Ctrl+,` 打开设置 | **完整** | `dw/src/App.tsx:240-306,437-442`、`dw/src/contexts/*`、`dw/electron/window/state.ts` | 是:BrowserWindow、Menu、app 事件 |
|
||
| **浏览器组件分发** | 首次启动/设置提示 | 三级检测:`PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` → 系统 Chrome → 自建服务器 manifest 下载;manifest Ed25519 验签 + sha256 + revision 精确匹配;无 CDN 回退(防无校验下载) | **完整**(曾有版本错配事故,已修并加门禁) | `dw/electron/browser/playwrightInstaller.ts:1-125,436`、`dw/scripts/lib/browser-manifest-trust.mjs` | 是:Chromium 下载/解压、文件系统 |
|
||
| **旧版本应用清理** | macOS 启动弹窗 | 改名后新旧 `.app` 并存,检测旧包→移入废纸篓/访达显示/7 天稍后提醒;路径二次校验防后门 | **完整**(仅 macOS) | `dw/electron/legacy/bundle.ts:33-64,60` | 是:shell、应用枚举 |
|
||
| **素材预览 / 过滤偏好** | 素材下载页 | 素材卡片首帧预览、已过滤卡片隐藏与计数、两个开关记 localStorage、DOM 兜底路径同一规则 | **完整**(门禁 43 条;真实数据过滤比例待真机) | `dw/src/components/MaterialPreview.tsx`、`dw/scripts/lib/material-filter.mjs`、`dw/docs/素材下载过滤开关-实现说明.md` | 否(渲染层) |
|
||
| **SPUID 素材数量即时查询** | 素材下载页筛选区 | 填完 SPUID 后显示各 SPUID 达人素材条数;最多 20 个、超出显式截断;单条失败不拖垮整批 | **完整** | `dw/src/components/SpuMaterialCounts.tsx`、`dw/electron/platform/materials.ts:112-140` | 否(只读接口) |
|
||
| **混剪 Excel/CSV 导入(Phase 2)** | 方案文档 | 批量导入清单 | **未实现(仅文档 + 模板 xlsx)** | `dw/docs/混剪素材批量上传-开发方案.md`、`dw/docs/混剪素材批量上传模板.xlsx` | — |
|
||
|
||
> **核对说明**:侧边栏只有 6 个一级入口,但「素材审核」页内聚合了 4 个写/读子能力(批量送审、混剪送审、上传明细、CSV 导出),菜单文字易让人低估其分量;「素材下载」页也不只是下载,而是任务工作台(提取、预览、过滤、结果分级)。另:PRD 语境里的「混剪素材」在本项目中不是下载分类,而是**审核页的混剪送审**(源素材检索 + N 组配对提交);下载侧只有「软广视频库素材」与「商品原始素材」两条链路。
|
||
|
||
---
|
||
|
||
## 3. 技术栈与架构
|
||
|
||
### 3.1 栈与关键版本
|
||
|
||
| 层 | 选型 | 版本(声明 → 实测) | 说明 |
|
||
|---|---|---|---|
|
||
| 渲染层 | React / react-dom | `^19.3.0` → 19.3.0 | 无全局状态库;Theme/LoginStatus/UnsavedChanges 三个 Context |
|
||
| 路由 | react-router-dom | `^6.20.0` → 6.30.3 | `HashRouter`(Windows 打包后 BrowserRouter 失效的历史修复) |
|
||
| UI | @douyinfe/semi-ui | `^2.103.0` → 2.103.0 | 2026-10 全量从 Ant Design 迁到 Semi(commit `bf350ae`);`@douyinfe/semi-vite-plugin` |
|
||
| 样式 | Tailwind CSS / PostCSS | `^3.4.0` → 3.4.19 | 大量页面级 CSS + Semi token 变量(`--semi-color-*`) |
|
||
| 图标 | @remixicon/react | `^4.9.0` → 4.9.0 | 统一图标库(`src/icons.tsx` 173 行) |
|
||
| Markdown | marked | `^18.1.0` → 18.1.0 | 发版说明渲染(`Changelog.tsx`) |
|
||
| 桌面 | Electron | `^44.7.0` | contextIsolation + preload;主进程 ESM 打包为 `dist-electron/main.js` |
|
||
| 浏览器自动化 | playwright | **`^1.40.0` → 1.60.0(⚠️ 漂移)** | 核心能力:登录、DOM 兜底、送审抽屉自动化、上传 |
|
||
| 构建 | Vite + vite-plugin-electron | 5.4.21 / 0.28 | 三份构建配置(frontend 配置为死文件) |
|
||
| 打包 | electron-builder | `^26.15.3` | Win NSIS / mac dmg+zip / Linux;`extraResources` 分发许可文本 |
|
||
| 更新 | electron-updater | `^6.8.9` | generic provider + 自建签名元数据 |
|
||
| 其他 | basic-ftp、adm-zip、fs-extra | 6.2.3 / 0.6.1 / 11.3.5 | Cookie FTP 同步、Chromium zip 解压 |
|
||
| 类型 | TypeScript | `^5.3.0` → 5.9.3 | `strict` / `noUnusedLocals` / `noUnusedParameters` / `noFallthroughCasesInSwitch` 全开(`dw/tsconfig.json`) |
|
||
|
||
### 3.2 进程模型与数据流
|
||
|
||
```
|
||
Renderer(React,HashRouter,6 页)
|
||
└─ window.electronAPI(preload.ts contextBridge,唯一通道)
|
||
├─ invoke/handle:87 条(请求-响应)
|
||
└─ on/send:14 条单向事件(进度/登录态/更新)
|
||
Main(Electron)
|
||
├─ ipc/handlers.ts(1822 行,模块级单例协调层,唯一组装点)
|
||
│ ├─ BrowserManager(Playwright 会话、登录、提取、送审编排,1962 行)
|
||
│ ├─ DownloadManager(下载、MD5、分批/并发/重试,516 行)
|
||
│ ├─ PlaywrightInstaller(浏览器分发,864 行)
|
||
│ ├─ configManager(三层配置:用户/档位/开发者 + 远端覆盖)
|
||
│ ├─ platform/*(只读接口层:client/http/sign/auth/materials/reviews/cache/authorization)
|
||
│ ├─ submit/*(写链路:page 自动化 / batch 执行器 / plan 会话 / verify 回查 / idempotency 账本 / audit)
|
||
│ ├─ shop/*(商品查询:webview 承载 / SSR 直取 / 素材下载)
|
||
│ ├─ dplink/*(硬广凭据 + 只读商品库/落地页 + 拼链)
|
||
│ └─ updater / logger / legacy / task-state / window-state
|
||
```
|
||
|
||
**文件落盘**:主进程是唯一写文件的地方——`userData/config.json`、`cookies.json`、`dplink-*.json`、`platform-cache/*`、`submit-audit.jsonl`、`submit-payloads.jsonl`、`remote-config.cache.json`、`logs/`、下载目录(默认 `~/Downloads/得物素材` 或用户指定)。渲染层无文件系统权限,所有落盘必须经 IPC(CSV 导出、日志导出、下载目录选择)。
|
||
|
||
**关键约束(详见 `dw/docs/新功能开发计划.md:455-475`)**:
|
||
|
||
1. **业务写只走页面自动化**,绝不直接调用写接口;唯一豁免是登录(`electron/platform/auth.ts` 只含两条硬编码路径且不重试);
|
||
2. **不另开浏览器 context**(平台单账号单会话,另开会被判新会话并踢掉自己);
|
||
3. **提交超时只回查、不重试**;
|
||
4. **筛选/取数失败显式失败**,不静默降级为「下载全部」;
|
||
5. 选择器不绑哈希类名(`previewBtn___*` 集中到 `legacySelectors.ts`,仅 DOM 兜底可用)。
|
||
|
||
### 3.3 IPC 契约(按域汇总,不逐条贴参数)
|
||
|
||
| 域 | 通道数 | 主要用途 | 事件 | 定义位置 |
|
||
|---|---|---|---|---|
|
||
| `browser:*` | 24 | 启停、登录预检/登录/退出、发码/验证码登录、切换无头、导航/分页/提取、保存 Cookie、浏览器组件安装 | `browser:loginStateChanged`、`browser:download:progress` | `dw/electron/ipc/channels.ts`、`dw/electron/preload.ts:5-100` |
|
||
| `submit:*` | 16 | 可用性、选文件/解析、md5 计算、起批、混剪选成品/检索/计算/起批、中断、状态快照、审计尾部、忘记已送审 | `submit:md5Progress`、`submit:batchProgress` | `dw/electron/preload.ts:190-240` |
|
||
| `update:*` | 11 | 检查/下载/安装/跳过/恢复/状态 + 5 个事件 | 进度/可用/无更新/已下载/错误 | `dw/electron/preload.ts:300-380` |
|
||
| `platform:*` | 10 | 签名自检、取素材页/详情、SPUID 数量、预览、审核列表、上传记录、枚举、标签树、账号详情 | — | `dw/electron/platform/*` |
|
||
| `dplink:*` | 9 | 硬广账号状态/发码/登录/复核/退出、落地页列表/读取/保存、按 SPU 拼链 | — | `dw/electron/dplink/*` |
|
||
| `download:*` | 8 | 开始/停止/统计/打开目录 + 4 个事件 | 进度/完成/汇总/状态 | `dw/electron/downloader/*` |
|
||
| `shop:*` | 6 | 承载配置、链接解析、商品详情、素材下载、取消 + 进度事件 | `shop:downloadProgress` | `dw/electron/shop/*` |
|
||
| `config:*` | 4 | 读取/保存/恢复默认/刷新远端配置 | — | `dw/electron/config/*` |
|
||
| `legacy:*` | 4 | 检测/移入废纸篓/访达显示/7 天稍后 | — | `dw/electron/legacy/bundle.ts` |
|
||
| `log:*` | 3 | 日志目录/导出/打开 | — | `dw/electron/logger.ts` |
|
||
| 其他 | 6 | 通知、剪贴板、许可、dialog、shell.openExternal、review 导出 CSV | — | `dw/electron/ipc/channels.ts` |
|
||
| **合计** | **101** | 87 invoke + 14 event | — | `dw/scripts/verify-channels.mjs` 断言唯一来源 |
|
||
|
||
> 通道名收口到 `IpcChannel` 常量表(`dw/electron/ipc/channels.ts:1`),`verify:channels` 静态守「handlers/preload 不得出现字符串字面量」——这是 2026-10 修掉的历史债(旧版 channels.ts 曾是死代码且含拼写错误)。
|
||
|
||
### 3.4 构建与发布链路
|
||
|
||
- **开发**:`npm run dev`(Vite + vite-plugin-electron 热重载);`postinstall` 是 `playwright install chromium --dry-run`,**装依赖不会装浏览器**。
|
||
- **构建**:`build:web`(licenses + `tsc` + `vite build`)与 `build[:win|:mac|:linux]`(再跑 electron-builder)。
|
||
- **CI**:三个 workflow——`ci.yml`(每次 push/PR:gates 20+ 步、ui-verify 480 条通过、package-size)、`build-release.yml`(仅 `workflow_dispatch`,Win 构建 + mac 签名/公证 + 产物断言 + 更新元数据签名 + GitHub Release + FTP)、`build-chromium.yml`(手动构建 Chromium 包 + manifest)。
|
||
- **发版唯一入口**:`npm run release`(`scripts/release.mjs`,改版本号 + 预检 + 门禁 + 推送 + `gh workflow run`),已移除 tag 触发后门。
|
||
- **签名/信任根**:远端配置 Ed25519、更新元数据 Ed25519、浏览器 manifest Ed25519 三把独立密钥;macOS Developer ID + 公证 + 装订(`verify:mac-sign` 断言产物本身)。
|
||
|
||
---
|
||
|
||
## 4. 数据模型与持久化
|
||
|
||
### 4.1 存储位置与形态(`app.getPath('userData')`)
|
||
|
||
| 数据 | 路径 | 形态 | 加密 | 说明 |
|
||
|---|---|---|---|---|
|
||
| 用户配置 | `config.json` | JSON | 字段级 safeStorage(`ftpPassword`/`cookieSyncKey` 加 `encrypted:` 前缀) | 明文可读;解析失败**静默回退默认**,不备份坏文件(排查坑) |
|
||
| 软广 Cookie | `cookies.json` | safeStorage 整文件加密 | 是 | 跨机器复制**解不开且静默解析失败**(双刃剑) |
|
||
| 硬广账号 | `dplink-account.json` | safeStorage 整文件 | 是 | 与软广凭据**完全隔离**,绝不注入浏览器上下文 |
|
||
| 硬广落地页设置 | `dplink-settings.json` | safeStorage 整文件 | 是 | 只在本机、不同步云端;旧明文首次读取自动迁移 |
|
||
| 平台枚举/标签树缓存 | `platform-cache/enums.json`、`label-tree.json` | JSON + `fetchedAt` | 否 | TTL 24 小时;过期仍返回并标 `stale`(离线可用) |
|
||
| 已送审 md5 账本 | `platform-cache/submitted-md5.json` | JSON `{version, md5s[], updatedAt}` | 否 | 无 TTL(100 年);原子写;审核列表回灌自愈 |
|
||
| 送审审计 | `submit-audit.jsonl` | JSONL 追加 | 否 | 每条结果/阶段/md5/groups;写失败不阻断送审 |
|
||
| 送审请求体快照 | `submit-payloads.jsonl` | JSONL 追加 | 脱敏后否 | 与同事「人工提交」做字段级对账 |
|
||
| 远端配置缓存 | `remote-config.cache.json` | JSON + `.sig` 校验后缓存 | 否 | 读缓存**重新验签**,防本地投毒 |
|
||
| 旧版本清理状态 | `legacy-bundle.json` | JSON | 否 | 已处理/稍后提醒(7 天) |
|
||
| 云 Cookie 上传临时文件 | `_cloud_cookies_upload.json` | JSON 明文 | 否 | 遗留 P1 风险:上传临时文件明文落盘 |
|
||
| 日志 | `logs/YYYY-MM-DD.log` | 文本,保留 7 个 | 否 | 内存缓冲 + 按日 + 跨天切换 |
|
||
| 本地操作偏好 | `localStorage` | `download.skipExpiring`、`download.skipUnauthorizedChannel`、`submit.lastSpuId`、最近 SPU 等 | 否 | 渲染层,生产 `file://` 下可能不可用,读写全 try/catch |
|
||
|
||
> **无 sqlite、无数据库**:全部 JSON/JSONL;缓存写入一律「临时文件 + rename」原子写(`dw/electron/platform/cache.ts:11-24`)。
|
||
|
||
### 4.2 配置项全表
|
||
|
||
**A. 用户项(`PersistedUserConfig`,`dw/electron/config/default.ts:16-72`)**
|
||
|
||
| 键 | 默认 | 含义 | 远端可覆盖 |
|
||
|---|---|---|---|
|
||
| `theme` | `light` | 亮/暗/跟随系统 | 否 |
|
||
| `downloadPath` | `''` → `~/Downloads/得物素材` | 素材保存目录 | 否 |
|
||
| `downloadPreset` | `balanced` | 下载速度档位(保守/均衡/快速) | 档位数值可覆盖 |
|
||
| `autoOpenDownloadDir` | `true` | 完成后打开下载目录 | 否 |
|
||
| `cookieCloudSync` | `true` | 登录态云同步开关 | 否 |
|
||
| `checkUpdateOnStart` | `true` | 启动检查更新 | 否 |
|
||
| `autoDownloadUpdate` | `false` | 自动后台下载新版本 | 否 |
|
||
| `installOnQuit` | `true` | 退出时安装已下载更新 | 否 |
|
||
| `ignoreRemoteConfig` | `false` | 忽略远端配置(逃生口) | 否 |
|
||
| `maximizeOnStart` | `true` | 启动最大化(≠全屏) | 否 |
|
||
|
||
**B. 档位参数(`downloadPresets`,`dw/electron/config/presets.ts:59-102`)**
|
||
|
||
| 参数 | 保守 | 均衡(默认) | 快速 | 远端允许区间 |
|
||
|---|---|---|---|---|
|
||
| `maxConcurrent` | 2 | 3 | 5 | 1–10 |
|
||
| `retryTimes` | 5 | 3 | 3 | 0–10 |
|
||
| `downloadTimeout`(秒) | 180 | 120 | 90 | 30–600 |
|
||
| `downloadDelayMin/Max`(秒) | 3/8 | 1/3 | 0/1 | 0–30 / 0–60 |
|
||
| `batchSize` | 3 | 5 | 10 | 1–50 |
|
||
| `batchCooldownMin/Max`(秒) | 20/45 | 10/20 | 3/8 | 0–300 / 0–600 |
|
||
| `retryBaseDelay/MaxDelay`(秒) | 5/120 | 3/60 | 2/30 | 1–60 / 10–300 |
|
||
|
||
**C. 远端可下发字段(`dw/scripts/lib/remote-config-schema.mjs:32-53`)**
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---|---|
|
||
| `platform.baseUrl` | URL | 星光主站 |
|
||
| `platform.videoLibraryUrl` | URL | 软广视频库页面 |
|
||
| `platform.updateCheckUrl` | URL | 更新 feed |
|
||
| `platform.cookieCloudUrl` | URL | 云端 Cookie 读地址 |
|
||
| `platform.enableSubmitReview` | boolean(独立白名单) | **送审总开关**,内置默认 `true`,远端 `false` 一键止血 |
|
||
| `presets.{gentle,balanced,fast}.*` | number | 档位数值覆盖,超区间整份拒收 |
|
||
|
||
**D. 开发者项(`dw/electron/config/developer.ts:65-160`,不出现在 UI)**
|
||
|
||
| 键 | 值/默认 | 说明 |
|
||
|---|---|---|
|
||
| `baseUrl` / `videoLibraryUrl` / `spuDetailUrlTemplate` | 星光 + `fast.dewu.com/page/productDetail` | `spuDetailUrlTemplate` **不在远端白名单**(要改需同时改白名单并重签) |
|
||
| `updateCheckUrl` / `cookieCloudUrl` | `http://dw_update.xinsenidea.com/...` | **明文 HTTP**(历史债) |
|
||
| `cookieSyncKey` / `ftpHost` / `ftpPort` / `ftpUser` / `ftpPassword` / `ftpRemotePath` | **仓库内明文默认值**(`developer.ts:130,135`) | 🔴 严重:凭据仍在源码与 git 历史中,Web 化前必须轮换并改为服务端密钥管理 |
|
||
| `timeout` / `headless` | 30 秒 / `true` | 浏览器自动化内部参数,无 UI 开关 |
|
||
| `remoteConfigBootstrap.url/publicKey` | 远端配置地址 + Ed25519 公钥 | 信任根,**不可远端下发** |
|
||
| `updateMetadataPublicKey` | Ed25519 公钥 | 与远端配置是两把独立密钥 |
|
||
|
||
### 4.3 下载文件命名与路径规则
|
||
|
||
**视频素材(星光软广素材库)**:
|
||
|
||
```
|
||
{媒体任务ID}-{视频ID}-{SPUID}-{投放类目}-{授权开始日期}-{授权结束日期}.mp4
|
||
```
|
||
|
||
- 空值哨兵:SPUID → `无商品ID`;类目 → `未知类目`;开始 → `无开始日期`;结束 → `无限用日期`;
|
||
- `-`/`unknown`/空 均视为无值;长期授权 → `长期-长期`;
|
||
- 非法字符 `< > : " / \ | ? *` 替换为 `_`;
|
||
- 落盘:先写 `{name}.downloading{ext}` 临时文件 → 校验 MD5 → `rename` 原子转正。
|
||
- 证据:`dw/electron/downloader/utils.ts:11-20,24-37`、`dw/electron/downloader/manager.ts:430`(`-internal.aliyuncs.com` → `.aliyuncs.com` 内网转公网改写)。
|
||
|
||
**商品原始物料(商品查询页)**:
|
||
|
||
```
|
||
<下载目录>/商品素材/<spuId>-<货号>-<标题前40字>/
|
||
主图-01.jpg … 主图-06.jpg
|
||
详情图-<段落名>-01.jpg …
|
||
主视频.mp4
|
||
```
|
||
|
||
- 取的是 SSR 载荷里的**原图**(`cdn.poizon.com/pro-img/origin-img/...`),不是页面 `webimg.dewucdn.com` 的压缩衍生图;详情图在 `imageAndTextMap` 下;
|
||
- 证据:`dw/electron/shop/materials.ts:24-26`、`dw/electron/shop/detail.ts:11-27,242-280`。
|
||
|
||
**提审文件命名(与下载命名刻意不同)**:
|
||
|
||
- 模式 A(文件夹批量):文件夹名**恰好** `{媒体任务ID}-{视频ID}-{SPUID}`;
|
||
- 模式 B(单文件批量):文件名**末三段** = `{媒体任务ID}-{视频ID}-{SPUID}`,前缀(日期/版本/商品名/授权期/剪辑师)只展示不校验;
|
||
- **不兼容**应用自己下载的 `ID 在开头` 的命名 → 明确判识别失败并标红,不会误提交;
|
||
- 证据:`dw/docs/送审命名规范与预检规则.md:20-75`、`dw/scripts/lib/submit-naming.mjs`。
|
||
|
||
### 4.4 状态机
|
||
|
||
| 状态机 | 取值 | 说明/证据 |
|
||
|---|---|---|
|
||
| 登录态(渲染层) | `checking` / `logging_in` / `logged_in` / `not_logged_in` / `error` / `not_ready` | `dw/electron/browser/manager.ts:46-55` |
|
||
| 提取/下载任务 | `idle → extracting → downloading → done/stopped/failed`(渲染层 `currentStep 0..3`) | `dw/src/pages/DownloadPage/index.tsx:289,1562-1573` |
|
||
| 下载单文件结果 | `success / skipped / failed` + `retryHistory` | `dw/electron/downloader/manager.ts:288-339` |
|
||
| 送审行状态 | `pending / warning / conflict / invalid / duplicate / already_submitted / submitted / failed / unknown` | `dw/src/types/index.ts:511-520` |
|
||
| 送审批次结果 | `submitted / skipped / failed / unknown` | `dw/electron/submit/batch.ts:1-30`、`dw/src/types/index.ts:792-802` |
|
||
| 混剪授权状态 | `valid / soon / expired / not_started / longterm / unknown` | `dw/src/types/index.ts:629`、`dw/scripts/lib/mix-submit.mjs` |
|
||
| 审核状态(平台) | 数字:待审核=1 / 通过=2 / 拒绝=3;字符串 `toBeReviewed/reviewPassed/reviewFailed`;Tab 另加「全部=null」 | `dw/scripts/lib/platform-material-mapping.mjs:424-506`、`dw/docs/星光平台API接口文档.md:551` |
|
||
|
||
### 4.5 去重与校验
|
||
|
||
- **下载去重**:按内容 MD5(不是文件名)。下载前一次性扫描目录建 `md5 → path` 映射;命中则跳过并写明「经md5校验,本地已存在相同的文件」。已知性能债:**同步全量扫描 + 整文件读内存**(`dw/electron/downloader/manager.ts:174`、`dw/electron/downloader/utils.ts:78-100`;评估文档 §5.1 标 P0)。
|
||
- **送审去重**:只按 `md5`,双向同步——提交成功后立即记账;每次打开审核页/回查把平台审核行的 md5 并进账本(换机/清 userData 后能自愈)。平台侧同样按 md5 在「提交」步查重(`code:900` + msg 含 `md5/重复/已送审`),本地只是提前拦一次流量。
|
||
- **签名/完整性**:远端配置、更新元数据、浏览器 manifest 三处 Ed25519;安装包 sha512 由 electron-updater 校验;浏览器包 sha256 + revision 精确匹配。
|
||
- **上传预检**:原视频授权渠道(`authedMediaIds` 与投放渠道 `deliveryMediaIds` 求交集)、videoId↔xtTaskId 成对性、SPUID 回显、批内同名/同 md5、组数为 0 等。
|
||
|
||
---
|
||
|
||
## 5. 外部平台集成(重点)
|
||
|
||
### 5.1 星光平台(唯一外部平台)
|
||
|
||
**域名与鉴权**
|
||
|
||
| 项 | 值 | 证据 |
|
||
|---|---|---|
|
||
| 主站 | `https://material-manage.shizhuang-inc.com` | `dw/electron/config/developer.ts:119`(可由远端配置覆盖) |
|
||
| 商品站 | `https://fast.dewu.com/page/productDetail?spuId=…` | `dw/electron/config/developer.ts:124` |
|
||
| CDN | `h5cdn.dewu.com`、`delivery-platform.dewucdn.com`、`delivery-platform.oss-cn-shanghai.aliyuncs.com` | `dw/docs/星光平台API接口文档.md:19-24` |
|
||
| 凭据 | Cookie `materialAccessToken`(非 HttpOnly,会话 Cookie)→ 请求头 `authorization: <token>` | `dw/docs/星光平台API接口文档.md:54-62` |
|
||
| 未登录 | HTTP 401 + `{"code":700,"msg":"请先登录"}`;`hacking-kol` 族则是 HTTP 200 + `code:401` | 同上 §1.4 |
|
||
| 会话特性 | **单账号单会话**:网页版登录会顶掉应用 token;应用内所有操作复用同一个 Playwright context | `dw/docs/星光平台送审与审核查询-可行性评估.md:1-120` |
|
||
|
||
**登录方式(三条通道)**
|
||
|
||
1. **接口登录(主力,P1/P2 已上线)**:`POST /platform/user/send-code` → `POST /platform/user/login` → 响应体 `data.token`(实测长度 168);裸 Node 可完成,不启浏览器;`GET /platform/user/detail` 复核并取账号信息/权限菜单。实测 9/9(`dw/electron/platform/auth.ts:1-70`、`dw/docs/接口登录通道-实现说明.md:146-169`)。
|
||
2. **浏览器登录(兜底)**:有头 Chromium 打开登录页,轮询 120 秒 + 登录后 `detectLoginState()` 再确认;成功后切无头;换账号时先清本地 Cookie。
|
||
3. **云端 Cookie 同步(历史架构)**:HTTP GET `cookies.json`(带 `X-Sync-Key`)+ FTP 上传;v2 分区 `accounts.soft` / `accounts.dplink`,写时只替换自己的分区并回读校验;本地 `safeStorage` 加密。**明文 HTTP + FTP 无 TLS,且是「全体共享一个账号」的传输方式**(`dw/electron/browser/cookieSync.ts:1-40`)。
|
||
|
||
**Cookie 保活**:没有定时刷新/心跳。保活依赖三个检查点——① 启动时 `probeLoginState()` 无头校验;② 业务导航落到登录页时广播 `not_logged_in` 并抛错;③ 用户点侧边栏「重新登录」(清旧 Cookie 或以新 token 覆盖)。云端同步只发生在启动/登录/退出等节点,**不是持续保活机制**;平台无刷新 token 接口,token 失效只能重登。
|
||
|
||
**接口清单(实测/代码在用;完整 106 条静态枚举见 API 文档 §9.3)**
|
||
|
||
| 用途 | 方法 | 路径 | 证据 |
|
||
|---|---|---|---|
|
||
| 软广素材列表(含下载直链) | POST | `/api/v1/h5/delivery-platform/v1/platform/soft-material/material-library/list` | `dw/electron/platform/materials.ts:91`、API 文档 §2.1 |
|
||
| 素材全字段详情 | POST | `…/soft-material/material-library/detail` | `dw/electron/platform/materials.ts:177`、API 文档 §2.2 |
|
||
| 审核列表(状态/驳回原因/md5) | POST | `…/platform/self-material/list` | `dw/electron/platform/reviews.ts:43`、API 文档 §3.1 |
|
||
| 上传/送审记录(含明细 xlsx 预签名) | POST | `…/platform/self-material/publishRecord` | `dw/electron/platform/reviews.ts:44`、API 文档 §3.2 |
|
||
| 万能枚举(35 键:驳回原因/品牌/角色…) | GET | `…/platform/common/config-list` | `dw/electron/platform/reviews.ts:45`、API 文档 §5.1 |
|
||
| 标签树 | POST | `…/platform/material-label/label-tree` | `dw/electron/platform/reviews.ts:46`、API 文档 §3.3 |
|
||
| 账号信息 + 权限菜单 | GET | `…/platform/user/detail` | `dw/electron/platform/reviews.ts:48`、API 文档 §6 |
|
||
| 发短信验证码 | POST | `…/platform/user/send-code` | `dw/electron/platform/auth.ts:66` |
|
||
| 验证码登录 | POST | `…/platform/user/login` | `dw/electron/platform/auth.ts:68` |
|
||
| 媒体多清晰度详情 | POST | `/api/v1/h5/media-data-center/v1/media/query` | API 文档 §3.4(代码未接入) |
|
||
| SPUID 预检(标题/品牌/货号) | POST | `…/soft-material/kol-native/spuid-check` | API 文档 §4.1(送审预检数据源) |
|
||
| OSS 直传凭证 | POST | `/api/v2/h5/oss-platform/token/customize/stsToken/v2` | API 文档 §4.2(由页面 SDK 调用,应用不实现) |
|
||
| 登记 mediaId | POST | `/api/v1/h5/media-center/v1/media/create` | API 文档 §4.4(由页面 SDK 调用) |
|
||
| **提交审核(写)** | POST | `…/soft-material/kol-native/upload-derivative-material` | `dw/electron/submit/page.ts:47`、API 文档 §4.5 |
|
||
| DPLink 落地页列表 | GET | `…/platform/material-library/list-landing` | `dw/electron/dplink/link.ts:39`、DPLink 文档 §4.4 |
|
||
| DPLink 商品库反查 `cSpuId` | POST | `…/platform/material-library/list-commodities` | `dw/electron/dplink/link.ts:41`、DPLink 文档 §4.4 |
|
||
|
||
**签名/加密/remote-config**
|
||
|
||
- 每个请求带 `?sign=<32位hex>`:`md5(按 key 升序拼接的 "key" + serialize(value) + SALT)`,`SALT = <已脱敏;原值见受控文档>`;GET 覆盖 query、POST 覆盖 JSON body(`dw/scripts/lib/platform-sign.mjs:37,106`、`dw/electron/platform/sign.ts:18-36`)。
|
||
- **启动自校验**:`sign({})` 必须等于平台未登录时实际发出的签名(`fe26befc…`);盐变化时日志直接报「签名盐已变化」,避免把所有 401 误判成登录失效。
|
||
- 平台前端常量(`userId=1000000`、`bizSourceId=500041536`、上传 `appId=Jem7c…`、OSS bucket/prefix)来自前端硬编码,应用侧应配置化而非再硬编码(API 文档 §1.6)。
|
||
- 送审写链路**不重放接口**:用 `page.setInputFiles` 把文件交给平台自己的上传 SDK(含 md5/分片/OSS token/`duToken` 网关),应用只填表 + 点提交 + 观察响应。
|
||
- `remote-config` 是**应用自身**的运维配置(非星光),见 §4.2;三把 Ed25519 密钥分别守护远端配置、更新元数据、浏览器 manifest。
|
||
|
||
**CDN 直连下载与防限速**
|
||
|
||
- 下载不走浏览器:Node `http/https.get` 直连素材 `url`;把 `-internal.aliyuncs.com` 改写成 `.aliyuncs.com`(内网地址转公网);`downloadWithRetry` 指数退避 `min(base*2^n, max)`;随机延迟、分批、批间冷却、并发信号量;文件名/目录规则见 §4.3(`dw/electron/downloader/manager.ts:181-227,374-430`)。
|
||
- 商品图/视频下载同样直连 CDN,但只允许 `poizon.com / dewu.com / dewucdn.com` 三个域(IPC 入参防越权),带 `User-Agent` 与 Referer(`dw/electron/shop/materials.ts:82-95,212`)。
|
||
- 已识别的限速/风控线索:平台按账号会话统计;应用刻意把详情并发限制为 4、SPUID 数量查询串行、不并发轰炸(`dw/electron/platform/materials.ts:1-32,121-140`)。
|
||
|
||
**其他平台**
|
||
|
||
- **唯品会:无任何代码**(全仓检索 `唯品会/vipshop/vip.com` 零命中)。PRD 的 P-06 多平台能力在本项目完全没有参考实现;`sucaigongfang` 项目是否覆盖唯品会需由另一份调研确认(本报告不越界)。
|
||
|
||
### 5.2 服务端(无 Electron、多用户并发)复现评估
|
||
|
||
| 集成点 | 服务端复现可行性 | 改造点 | 结论 |
|
||
|---|---|---|---|
|
||
| 只读接口(素材/审核/枚举/标签) | **高**:纯 HTTPS + 签名 + 信封,Node 即可 | 把 `electron/platform/*` 抽成服务端 SDK;token 从「本机加密文件」改为「用户/账号凭据服务」;加缓存与限流 | **直接迁移(工作量小)** |
|
||
| 登录(发码/验证码) | **高**:不需要浏览器 | 服务端接收用户手机号/验证码;token 加密落库(KMS/信封加密);处理短信频控与失败码未知问题 | **可迁移,但账号归属需重设计** |
|
||
| 会话模型(单账号单会话) | **中**:技术可行,业务冲突 | 必须按「账号」串行化(同一账号同一时刻只允许一个任务),或为不同用户分配不同账号;Web 多用户共享一个 token 会互相顶号 | **最大架构约束之一** |
|
||
| 素材下载(CDN 直连) | **高** | 服务端可直接下载并转存对象存储;或下发签名 URL 让浏览器直下(省带宽);保留 MD5 去重与冷却策略,去重索引改 DB/Redis | **可迁移** |
|
||
| 商品详情 SSR 直取 | **高** | 服务端 HTTP GET + 解析 `__remixContext`,无需 UA/浏览器;短链解析放服务端(域名白名单) | **可迁移且更稳** |
|
||
| 内嵌商品 H5 / 净化 | **低** | Web 端 iframe 受 `X-Frame-Options/CSP` 限制;Electron `<webview>` 无对应物。替代:只保留数据卡片 / 服务端截图(成本高、收益低) | **建议废弃** |
|
||
| 送审写链路(页面自动化) | **中**:必须服务端浏览器 | 浏览器池 + 每账号一个 context + 上传通道(浏览器→服务端 140–190MB 或服务端代传 OSS)+ 队列/断点/回查/审计;风控暴露面从「单机」变成「机房 IP」 | **可做,但成本最高、风险最高** |
|
||
| DPLink | **高**:纯算法 + 两个只读接口 | 硬广账号凭据独立密钥槽;落地页配置存用户/项目级;错误分类保留 | **最划算的迁移项** |
|
||
| Cookie 云同步(HTTP+FTP) | **低**:架构应废弃 | 改为服务端凭据库(加密、审计、按用户/账号授权);FTP 与明文 HTTP 不应保留 | **废弃并重写** |
|
||
| 自动更新/浏览器分发/代码签名 | **不适用** | Web 无客户端分发;服务端浏览器镜像由部署流水线维护 | **废弃** |
|
||
| 本机文件/账本/审计 | **中** | 本地 JSON/JSONL → 数据库表;文件下载 → 对象存储 + 下载中心;路径语义(下载目录)改为「云端素材库/导出任务」 | **需数据模型重设计** |
|
||
|
||
**建议的 Web 目标形态(供后续架构评审)**:
|
||
|
||
1. **BFF + Worker 两层**:BFF 走只读接口与元数据;Worker 承担 Playwright 浏览器任务(送审、登录兜底),按账号加分布式锁,任务状态落 Redis/DB,前端用 SSE/WebSocket 订阅进度(替代 IPC 事件)。
|
||
2. **上传走「浏览器/客户端 → OSS 直传」**:服务端只发 STS 临时凭证并登记 mediaId,避免 140MB 文件绕行应用服务器;必要时再让服务端浏览器 `setInputFiles` 指向挂载的临时对象。
|
||
3. **凭据服务**:平台 token 与硬广 token 分别加密存储(KMS + 信封),按「用户/项目/账号」授权;禁止再出现仓库内硬编码密钥。
|
||
4. **账号串行化**:以 `accountId` 为粒度排队;同一账号的下载/送审/审核查询并发需互斥(沿用现在 `runExclusive` 的思路,但改为分布式锁)。
|
||
5. **只读优先**:把「读」全部走接口(无浏览器),仅「写」用浏览器,显著降低风控暴露面与资源成本。
|
||
|
||
---
|
||
|
||
## 6. 关键机制与难点
|
||
|
||
### 6.1 Playwright 浏览器自动化
|
||
|
||
- **登录/会话**:`smartStart` 状态机——有会话且有效→复用;云端/本地 Cookie→无头启动注入→校验→写回;失败则有头手动登录(120 秒轮询)→切无头。所有会动会话的操作走 `runExclusive` 串行队列(`dw/electron/browser/manager.ts:223,617-812`)。
|
||
- **读路径**:先挂 `page.on('response')` 拦截页面自身列表响应(第 1 页),后续页/详情走接口;失败整体降级 DOM(点预览弹窗 + 解析字段)。DOM 兜底只保留一期,哈希类名集中在 `legacySelectors.ts` 并加门禁。
|
||
- **写路径**:开送审抽屉 → 定位 `#deliveryMediaIds`/`#xtTaskId`/`#videoId`/`#spuIds`/`#url input[type=file]` → `setInputFiles` → 等上传完成(最长 15 分钟)→ 点提交 → `waitForResponse(SUBMIT_API_PATH)`(60 秒)。选择器必须「限定抽屉内 + 按 `label[title]` 精确匹配」,否则会命中页面上的「KOL投放渠道」筛选框(真机踩坑记录 `dw/electron/submit/page.ts:209-222`、`dw/docs/星光平台API接口文档.md:800-830`)。
|
||
- **难点**:平台改版即失效(最高频维护工作);上传完成没有可靠事件,只能轮询百分比/表单回显;抽屉复用必须显式清空上一条残值;「提交超时」不能重试。
|
||
|
||
### 6.2 登录态托管
|
||
|
||
- 本地 `safeStorage` 加密 + 云端 v2 分区共享;`loginInteractive(force)` 换账号;`logout` 只清本机并置 `ignoreCloudCookies`;启动预检 `probeLoginState` 用无头浏览器只校验、不弹窗。
|
||
- **已知边界**:单账号单会话(网页版登录会顶掉);接口登录失败码未实测;应用侧凭据落地(落盘/注入/云同步)仍需真人点一次才能验证;`verify:login` 刻意不进 CI(会发真短信、会让跑的人生效掉线)。
|
||
|
||
### 6.3 批量上传:并发/重试/断点
|
||
|
||
- **串行**而非并发(同一个浏览器会话,且上传本身占满上行);整批圈进 `runExclusive`,下载/送审互斥。
|
||
- **可中断**:中断请求在当前条跑完才停(避免半截抽屉 + 账本未落盘)。
|
||
- **可续跑**:账本按 md5 拦住已成功项;失败项不记账;「结果未知」只回查(3 次退避)不重试。
|
||
- **重试**:只有网络错误/5xx 才重试 1 次;提交响应超时绝不重试。
|
||
- **失败显式**:抽屉打不开、字段找不到、上传未完成 → 带 `reasonCode` 的 failed,并 dump 页面实况(抽屉数量、入口是否被遮、`elementFromPoint`)。
|
||
|
||
### 6.4 命名字段组合与预检规则
|
||
|
||
- 命名只承载三要素(媒体任务ID/视频ID/SPUID),前缀不校验;末三段解析 + 文件夹名恰好三段双候选,冲突不自动挑、要求人工确认;`无spuid` 五种写法大小写不敏感;位数 ≠ 19 只警告不阻断。
|
||
- 预检两段式:① 文件名解析(毫秒级,不读盘)先出结果;② md5 查重 + SPUID 商品标题回显(秒~几十秒,异步可取消)。只有 `pending/warning` 可勾选;失败可「就地修好」。
|
||
- 送审前额外预检:原视频授权渠道、videoId↔xtTaskId 配对、SPUID 一致性、组数;「unknown 不阻断」是刻意保守策略(宁可白传一次,不可误拦)。
|
||
|
||
### 6.5 混剪任务
|
||
|
||
- 成品只解析最后一个 SPUID;每条成品带 N 组 `{xtTaskId, videoId}`;右栏从平台素材库或本机下载目录检索源,授权状态六档;已过期/未生效/明确未授权默认不勾;平台检索目前只取第一页(最多 30 条)、无「加载更多」;Phase 2 Excel/CSV 导入未实现。
|
||
- **风险点**:「混剪=是」的写链路(选「是」、增删行、无 id 的视频ID输入框、组数回读)**尚未真机验证**,只做了离线门禁。
|
||
|
||
### 6.6 错误码与重试
|
||
|
||
| 平台回答 | 应用行为 | 说明 |
|
||
|---|---|---|
|
||
| `code:200` | 成功,记 md5 | 成功必须看 `code`,不能只看 HTTP 状态 |
|
||
| HTTP 401 + `code:700` | 未登录:停止批次、侧边栏变红、指向重登 | 与平台故障区分 |
|
||
| HTTP 200 + `code:401` | 平台族故障(`hacking-kol`),不当作未登录 | 平台自身页面也报错 |
|
||
| HTTP 200 + `code:900` | 业务校验失败:**必须看 msg**;只有含 `md5/重复/已送审` 才当重复记账,否则按 failed 显式展示 | 曾因「只看 900」把业务拒绝误记成已送审 |
|
||
| 提交超时/无响应 | unknown → 回查审核列表(3 次);命中记 submitted,未命中提示稍后刷新 | 绝不重试 |
|
||
| 网络错误/5xx | 只读请求重试 1 次;下载按档位指数退避;发短信不重试 | — |
|
||
|
||
### 6.7 更新与代码签名(Web 化后大概率废弃,但资产有价值)
|
||
|
||
- 桌面更新链路:electron-updater + 自建 feed;更新元数据 `.sig` Ed25519 验签 → 强制/最低版本/跳过版本;mac 走 Squirrel/ShipIt 原生替换 `.app` 并支持改名迁移;Win NSIS 静默安装。
|
||
- 代码签名:mac Developer ID 签名 + 公证 + 装订 + 产物门禁;Win 目前无签名(历史状态)。
|
||
- **Web 化后这些全部消失**,但可复用其**设计模式**:信任根不可远端下发、原始字节签名、灰度放行策略表、revision 单调、双密钥隔离。这些模式可直接用于新平台的「配置中心/发布系统」安全设计。
|
||
|
||
---
|
||
|
||
## 7. 代码规模与质量
|
||
|
||
### 7.1 规模(口径见页首)
|
||
|
||
| 目录 | 文件数 | 行数 | 主要内容 |
|
||
|---|---|---|---|
|
||
| `src/` | 67(ts/tsx) | **19,120** | 6 页 + 19 组件 + 3 Context + 1 Hook + 15 个 `.d.ts` + 1 个 `types/index.ts` |
|
||
| `electron/` | 45(ts) | **17,345** | IPC/浏览器/平台接口/送审/商品查询/DPLink/配置/更新/日志 |
|
||
| `scripts/` | 73(mjs/cjs) | **27,828** | 32 个 verify 脚本 + 21 个共享纯逻辑 + 探针/截图/发版/签名 |
|
||
| `release-scripts/` | 5 | **875**(mjs/cjs;含 .sh/README 共 1,497) | 本机发版、mac 签名/公证、Windows 构建 |
|
||
| **合计** | **190** | **65,168** | 不含 CSS(3,675 行)与 docs(30 篇、14,633 行) |
|
||
|
||
**单文件 Top(复杂度集中点)**:`DownloadPage/index.tsx` 2,241 行;`browser/manager.ts` 1,962;`ipc/handlers.ts` 1,822;`submit/page.ts` 1,824;`ConfigPage/index.tsx` 1,241;`SubmitPrecheckModal.tsx` 1,035;`ReviewPage/index.tsx` 1,004;`UpdatePage/index.tsx` 896;`playwrightInstaller.ts` 864;`ShopPage/index.tsx` 841。
|
||
|
||
### 7.2 类型与规范
|
||
|
||
- `tsconfig.json`:`strict: true`、`noUnusedLocals`、`noUnusedParameters`、`noFallthroughCasesInSwitch`;`include: ["src","electron"]`;无 `allowJs`,因此 `scripts/lib/*.mjs` 靠**手写 `.d.ts` 副本**+ `verify:type-declarations` 门禁保证一致。
|
||
- **无 ESLint / Prettier 配置**(仓库根目录无相关文件);格式靠约定与 review。
|
||
- `any` 仍有:`preload.ts` 51 处、`handlers.ts` 15 处、`src` 16 处(跨进程类型未共享,历史评估标 P1)。
|
||
- 无全局状态管理库:Context + 页面内 state;下载/送审状态主进程持有,渲染层用事件订阅。
|
||
|
||
### 7.3 测试与质量门禁
|
||
|
||
| 层 | 现状 |
|
||
|---|---|
|
||
| 单元测试框架 | **无**(无 vitest/jest,`src/App.test.tsx` 名不副实,是组件不是测试) |
|
||
| 离线验证 | **32 个 `verify:*` 脚本**,合计 15,411 行;`verify:ui` 5,283 行 / 472 个 `ok()` 断言点(v2.7.0 记录 480 通过;真实 Chromium 加载真实 `dist/`);`verify:platform` 2,352 行 / 255 个 `ok()` 断言点(v2.7.0 记录 260 通过;真实抓包 fixture + 静态边界);`verify:channels` 101 条通道唯一来源;`verify:type-declarations` 33 个导出;`verify:mix` 24;`verify:filter` 43 |
|
||
| 实机对比脚本 | `compare:extraction-paths`、`compare:review-list`、`compare:submit-payload`(人工登录后跑,结果落盘对账) |
|
||
| CI | `ci.yml` 三 job(gates / ui-verify / package-size);发版走 `release.mjs` + `build-release.yml`;历史教训「验证资产 10 个只有 1 个进 CI」已修 |
|
||
| 依赖审计 | `audit:prod` 强制官方 registry(防 npmmirror 不支持 audit 导致「无漏洞」假象);critical/high 失败 |
|
||
| 已知质量债 | 大文件上帝模块;`preload` 大量 `any`;`CSP` 宽松(允许 http/https/ws/`unsafe-eval` 已移除但范围仍宽);`scanDirectoryMd5` 同步读内存;日志/控制台噪音;无前端虚拟列表;无端到端自动化(写链路靠人工真机) |
|
||
|
||
### 7.4 文档与已知风险
|
||
|
||
- `docs/` 现有 **121 个文件、30 篇 Markdown(14,633 行)**,包括:星光 API 接口文档(807 行,含签名盐与 106 条接口)、送审/审核可行性评估(928 行)、P1/P2/P4 实现说明、送审命名规范、混剪方案、DPLink 评估、远端配置运维手册、签名/公证清单、项目评估 2.1.0(1,063 行)等。
|
||
- `DEVELOPMENT.md` 2,380 行,是**以代码为准**的交接文档,但其 §1-§14 基线停在 v1.0.6,**已明显滞后于 v2.7.0**;§17-§19 是后续补的登录态/商品查询/接口登录章节。**新平台调研应优先信任代码与 2.x 的实现说明文档**。
|
||
- **已知问题与风险(代码/文档交叉确认)**:
|
||
1. 🔴 **仓库内仍硬编码运维凭据**(`cookieSyncKey`、FTP 密码,`dw/electron/config/developer.ts:130,135`),且在 git 历史中;Web 化前必须轮换、改服务端密钥管理,不可沿用。
|
||
2. 🟠 **单账号单会话**是平台行为(网页版登录顶掉应用 token);多用户 Web 化必须按账号串行/分账号。
|
||
3. 🟠 **明文 HTTP + FTP 无 TLS** 用于更新/远端配置/Cookie 同步;新平台应拒绝此模式。
|
||
4. 🟠 平台接口/页面结构随时可能变更:签名盐、字段、选择器、权限菜单;维护成本高(`docs/` 多篇文档都在记录平台变更)。
|
||
5. 🟡 Playwright 依赖声明 `^1.40.0` 与实际 1.60.0 漂移(已有 `verify:playwright-version` 守版本→revision 映射,但锁文件仍应 pin)。
|
||
6. 🟡 浏览器分发/更新/签名/旧包清理的复杂度对 Web 化无意义,但占主进程相当比例代码与文档。
|
||
- `DEVELOPMENT.md §12` 列出「文档与实现的偏差」,`docs/项目评估与优化建议-2.1.0.md` 给健康度加权 **3.0/5**(产品完成度 4.5、安全信任链 2.0、测试质量 2.0、性能 3.0);其中 P0 缺陷多数已在 2.1.x-2.7.0 修复(重试退避、可重入、浏览器版本、验签),**硬编码凭据与 MD5 扫描仍是历史遗留**。
|
||
|
||
---
|
||
|
||
## 8. 逐模块 Web 化复用评估(核心交付)
|
||
|
||
**复用级别**:A=前端页面/组件几乎直接复用;B=改造成本可控;C=需服务端重写;D=废弃。人日为粗估(含联调,不含需求/设计评审)。
|
||
|
||
| 模块 | 现有实现 | 目标端形态 | 复用级别 | 改造要点 | 粗估人日 | 风险 |
|
||
|---|---|---|---|---|---|---|
|
||
| 应用外壳/导航/主题/骨架屏/错误边界 | React + Semi + Tailwind;`App.tsx` 558 行 | 新平台 Shell | **A(结构)/B(视觉)** | 保留信息架构(侧边栏、页头、分区、骨架屏、未保存守卫);重写导航与主题 token;Semi 组件替换(见 §8.1) | 3–5 | 低 |
|
||
| 素材下载 · 任务工作台 UI | `DownloadPage` 2,241 行;阶段化布局、双重过滤、素材预览、结果分级、重试历史 | 新平台「原始物料获取」页 | **B** | 保留交互模型与状态机;Semi→新 UI;`localStorage` 偏好改用户配置;「打开目录/通知」改「导出到素材库/下载中心」 | 8–12 | 中(页面巨大、需重排信息层级) |
|
||
| 素材提取(只读接口路径) | `platform/materials.ts`、`browser/manager.ts` 拦截路径 | 服务端取数服务 | **B** | 直接用签名客户端;去掉浏览器与 DOM 兜底;保留「读取方式/降级」可观测语义 | 5–8 | 中(签名盐/接口变更) |
|
||
| 下载引擎(CDN/MD5/限速/重试) | `downloader/manager.ts` + `utils.ts` | 服务端下载 Worker + 对象存储 | **C** | 文件系统→对象存储;MD5 扫描→DB/Redis 索引+流式 MD5;并发/冷却策略保留;临时文件/原子改名改为分片上传完成标记 | 12–18 | 中高(带宽/存储成本、平台限速) |
|
||
| 商品查询 · 工作台 UI | `ShopPage` 841 行 + `ActionBar`/`MaterialGrid`/`useShopDownload` | 新平台「选品」页 | **B** | 保留「命令条+画布+面板+底栏」布局与 9 项素材格;去掉 webview 画布或改为可选;Semi→新 UI | 8–12 | 中 |
|
||
| 商品详情 SSR 直取/短链解析 | `shop/detail.ts` 359 行 | 服务端选品服务 | **B** | 服务端 HTTP + `__remixContext` 解析;短链解析+域名白名单;图片原图 URL 规则保留 | 4–6 | 低中(站点结构变更) |
|
||
| 内嵌商品 H5 + 净化模式 | `SpuCanvas.tsx`、`shop/session.ts` | — | **D** | Web 端无法等价复现;最多保留「查看原页」外链或服务端截图 | 0(可选 3–5) | 中(做了也价值低) |
|
||
| 素材审核页 | `ReviewPage` 1,004 行 + 6 子组件 + `review-csv.mjs` | 新平台「提审/审核」页 | **B** | 只读接口直接迁移;表格/筛选/驳回富文本/CSV 逻辑保留;Semi→新 UI;权限提示保留「建议不硬拦」 | 8–12 | 中(平台字段/权限变化) |
|
||
| 只读接口层(签名/客户端/缓存/授权预检) | `electron/platform/*` 2,526 行 | 服务端 SDK | **B** | 抽包;凭据来源改注入;缓存改 Redis/DB;错误分类保留;`authorization.ts` 的「unknown 不阻断」策略保留 | 5–8 | 中(签名/接口契约) |
|
||
| 命名解析/预检/CSV/过滤/进度模型等纯逻辑 | 21 个 `scripts/lib/*.mjs` + `.d.ts` | 服务端/前端共用包 | **A** | 直接抽成 npm 包(保持「应用与门禁同一份实现」);补真单测 | 3–5 | 低 |
|
||
| 批量送审判定与编排 | `submit/plan.ts`、`idempotency.ts`、`audit.ts`、`verify.ts`、`batch.ts` | 服务端送审服务 | **B–C** | 策略层可复用(串行/中断/回查/记账/审计);存储改 DB;队列改任务系统;进度改 SSE | 8–12 | 中高(写操作) |
|
||
| 送审页面自动化(Playwright) | `submit/page.ts` 1,824 行 | 服务端浏览器 Worker | **C** | 浏览器池 + 账号锁;选择器集中配置化;上传改「客户端→OSS→服务端挂载」;日志/证据链保留 | 18–25 | **高(平台风控/改版/大文件)** |
|
||
| 混剪配对 UI | `MixSubmitModal.tsx` 683 行 | 新平台混剪送审页 | **B** | 双栏交互与授权状态保留;Semi→新 UI;补「加载更多」与 Excel Phase 2 | 8–12 | 中 |
|
||
| 混剪服务端编排 | `submit/mix.ts`、`source-search.ts`、`mix-submit.mjs` | 服务端 | **C** | 源检索(平台+本地下载库)改「平台素材库+云端素材库」;N 组配对校验保留;「混剪=是」需真机验证 | 6–10 | 高(未真机) |
|
||
| DPLink 拼装/复制 | `dplink/link.ts` 420 行 + `account.ts` + `dplink-link.mjs` | 服务端投放配置服务 | **B** | 纯算法与错误分类直接迁移;硬广凭据改 KMS;落地页配置改项目级;复制按钮保留(前端) | 5–8 | 中(硬广账号权限/共用凭据) |
|
||
| 登录态与账号体系 | `auth.ts`、`cookieSync.ts`、`SidebarLoginStatus`、`LoginDialog` | 平台账号中心 | **C** | 接口登录可迁移;浏览器兜底需 Worker;云端 FTP 同步废弃→凭据库;多用户账号归属/授权/审计重设计 | 8–12 | **高(单会话/账号归属/合规)** |
|
||
| 配置管理/远端配置 | `config/*`(1,261 行)+ `remote-config-schema.mjs` | 平台配置中心 | **B** | 用户项→用户级 DB;档位预设与白名单保留;远端配置改服务端配置中心(不必 Ed25519,除非仍需离线下发);`enableSubmitReview` 保留为运维开关 | 4–6 | 低中 |
|
||
| 日志/审计/诊断 | `logger.ts`、`submit/audit.ts` | 服务端日志/审计 | **B** | 本地文件→结构化日志/审计表;保留「审计只追加、写失败不阻断」的语义 | 3–4 | 低 |
|
||
| IPC 通道层 | 101 条通道 / preload | HTTP API + SSE/WebSocket | **C** | 契约可参考(通道名/入参/进度事件),实现全部重写;长任务改异步任务 + 订阅 | 5–8 | 中 |
|
||
| 自动更新/关于页/旧版清理/窗口状态 | updater 438 行 + legacy + window state | — | **D** | Web 无客户端;关于页可保留为「帮助/版本信息」薄页 | 0–1 | 低 |
|
||
| 验证门禁资产 | 32 个 verify 脚本 + fixtures | 新平台测试套件 | **B** | `.mjs` 纯逻辑断言可直接用;真实抓包 fixture 可做契约测试;UI 断言(472 条)大部分随新 UI 失效,需重写 | 6–10 | 低中 |
|
||
|
||
**合计粗估:约 115–190 人日**(低值=理想路径、无返工;高值=含平台改版适配/联调/真机验证)。其中「送审页面自动化 + 账号体系 + 下载引擎」三项占 **50% 以上**,是 Web 化成败关键。
|
||
|
||
### 8.1 Semi Design 2 与新平台 UI 选型的冲突处理
|
||
|
||
**冲突事实**:当前 UI 是 2026-10 从 Ant Design 全量迁到 **Semi Design 2.103**(React 19),组件 API/主题/图标/表单校验/表格/弹窗都深度绑定 Semi;页面级 CSS 3,675 行大量使用 `--semi-color-*` token、`@layer tailwind-utils` 与 `.semi-*` 类名。如果新平台 UI 选型是 Ant Design/Arco/自研,**组件层不能直接复用**。
|
||
|
||
**建议策略(按投入产出排序)**:
|
||
|
||
1. **分层复用,不整体搬迁**:把「纯逻辑 + 类型 + 接口封装 + 页面状态机」与「视觉组件」切开。前者(约 30–40% 代码量)跨 UI 库可复用;后者重写。
|
||
2. **先定设计 token,再谈组件**:把 Semi 的语义色/圆角/间距收敛成新平台 token(现在代码里已有集中化迹象:`icons.tsx`、`PageHeader`、`ProgressRow`、`SettingsRow`),避免把 `--semi-*` 变量原样搬进新平台。
|
||
3. **只对高价值组件做适配层**:表格(审核列表)、弹窗/抽屉(送审判定)、进度行、Toast 提示可写薄适配层;不要为每个组件做 Semi↔新库 shim(维护成本会超过重写)。
|
||
4. **样式资产可复用的部分**:布局类(`.shop-*`/`.dl-*`/`.review-*`)本质是 CSS Grid/Flex,可提取为设计系统布局原语;**依赖 `.semi-*` 内部 DOM 的样式必须丢弃**(`verify:css-layers` 也说明层叠顺序是精心维护的)。
|
||
5. **如果新平台也选 Semi**:可复用度显著提高(页面组件可近乎直搬),但仍需处理 React 版本、主题、路由与 Electron API 替换。**建议在 UI 选型评审时把「是否 Semi」作为明确决策项**,因为它直接决定 8–12 人日的差异。
|
||
|
||
---
|
||
|
||
## 9. 可复用资产清单
|
||
|
||
### 9.1 纯逻辑 / 协议层(最高价值,A 级)
|
||
|
||
| 资产 | 路径 | 价值 |
|
||
|---|---|---|
|
||
| 星光请求签名 + 序列化规则 + 自校验 | `dw/scripts/lib/platform-sign.mjs`(含 SALT,敏感值已脱敏)、`dw/electron/platform/sign.ts` | 服务端直连星光的关键;自校验能第一时间发现盐变更 |
|
||
| 平台字段映射 / 授权时间解析 / 审核状态映射 / 权限判定 | `dw/scripts/lib/platform-material-mapping.mjs`(719 行) | 与真实抓包逐字段对齐;P1/P2 的地基 |
|
||
| 送审命名解析 + 预检/载荷/审计记录形状 | `dw/scripts/lib/submit-naming.mjs`(1,013 行) | 新平台「命名规则 + 提审预检」可直接复用;有大量真实样本 |
|
||
| 混剪成品/源组/授权状态/结构校验 | `dw/scripts/lib/mix-submit.mjs`(约 500 行) | 混剪业务规则唯一实现 |
|
||
| 审核 CSV 构建 + 公式注入防护 | `dw/scripts/lib/review-csv.mjs` | 导出与界面列同源;安全细节可复用 |
|
||
| 驳回原因 HTML 白名单 AST | `dw/scripts/lib/reason-html.mjs`(1,028 行) | 平台自由文本渲染的安全方案(非 `dangerouslySetInnerHTML`) |
|
||
| 素材过滤规则(30 天/渠道) | `dw/scripts/lib/material-filter.mjs` | 与 PRD「授权/到期」相关的业务规则 |
|
||
| DPLink 拼装(双层/encode/常量) | `dw/scripts/lib/dplink-link.mjs` | 4 条样本 4/4 逐字符复现,可直接迁移 |
|
||
| 进度模型 / 送审进度模型 | `dw/scripts/lib/progress-model.mjs`、`submit-progress.mjs` | 统一进度语义与界面断言 |
|
||
| 远端配置 schema/白名单/区间 | `dw/scripts/lib/remote-config-schema.mjs` | 若新平台需要「运维不发版改配置」,可直接复用设计 |
|
||
| Cookie 分区 bundle(v1/v2 兼容) | `dw/scripts/lib/cookie-bundle.mjs` | 多账号凭据分区与迁移思路;**传输方式需重写** |
|
||
| Ed25519 原始字节签名/验签 | `dw/scripts/lib/ed25519-signature.mjs`、`update-metadata.mjs`、`browser-manifest-trust.mjs` | 信任链设计可迁移到配置中心/发布系统 |
|
||
|
||
### 9.2 服务端候选代码(B 级,抽包后可用)
|
||
|
||
| 资产 | 路径 | 说明 |
|
||
|---|---|---|
|
||
| 只读 HTTP 客户端 + 信封解析 + 失败分类 | `dw/electron/platform/http.ts`、`client.ts`、`types.ts` | 超时/重试/响应上限/`code` 分类;与登录层共用一份 |
|
||
| 素材列表/详情取数(并发 4、降级可见) | `dw/electron/platform/materials.ts` | 直接改造成服务端模块 |
|
||
| 审核列表/记录/枚举/标签树 + TTL 缓存 | `dw/electron/platform/reviews.ts`、`cache.ts` | 缓存/TTL/stale 语义清晰 |
|
||
| 授权渠道预检(unknown 不阻断) | `dw/electron/platform/authorization.ts` | 送审前风控策略可直接用 |
|
||
| 商品详情 SSR 解析 + 短链解析 | `dw/electron/shop/detail.ts` | 无浏览器取数的高价值实现 |
|
||
| 商品素材下载/命名/URL 白名单 | `dw/electron/shop/materials.ts` | 原始物料落盘结构参考 |
|
||
| 送审批次策略机(串行/中断/回查/记账/审计) | `dw/electron/submit/{batch,plan,verify,idempotency,audit}.ts` | 写链路业务策略层,独立于 Playwright |
|
||
| DPLink 拼装编排/错误分类 | `dw/electron/dplink/link.ts`、`account.ts` | 依赖硬广账号;接口参数已在文档中核实到「两个只读接口」 |
|
||
|
||
### 9.3 前端页面/组件(B 级,需去 Semi 化)
|
||
|
||
- 页面:`DownloadPage`(任务工作台与三阶段布局)、`ShopPage`+`ActionBar`+`MaterialGrid`(工作台布局)、`ReviewPage`+`ReviewTable`+`ReviewFilters`+`ReviewDetailModal`+`PublishRecordsModal`(审核表格与筛选)、`SubmitPrecheckModal`(预检/就地编辑/批量补字段)、`MixSubmitModal`(双栏配对)、`SubmitProgressPopover`/`SubmitProgressBody`(进度浮层)、`ConfigPage`(分区清单设置页)、`UpdatePage`/`AboutPage`(可参考信息架构)。
|
||
- 通用组件:`PageHeader`、`ProgressRow`、`SettingsRow`、`SettingsSection`、`MaterialPreview`、`SpuCanvas`(仅参考承载思路)、`CopyButton`(页面内)、`ErrorBoundary`、4 个骨架屏、`LoginDialog`、`SidebarLoginStatus`、`DplinkAccountDialog`、`DplinkLandingDialog`。
|
||
- 状态/工具:`src/contexts/{Theme,LoginStatus,UnsavedChanges}.tsx`(未保存守卫可直接复用思路)、`src/utils/spu.ts`(SPU 解析/价格/最近查询)、`spuIdList.ts`(多 SPUID 归一化/校验)、`updateLabels.ts`、`remote-config-label.ts`。
|
||
- 类型契约:`src/types/index.ts`(1,000+ 行,含 ElectronAPI、IPC 载荷、审核/送审/混剪/下载/更新类型)、13 个 `.d.ts` 纯逻辑类型声明——可作为**新平台 API DTO 草案**,但需与后端共同评审。
|
||
|
||
### 9.4 文档(可直接迁移,价值排序)
|
||
|
||
| 文档 | 行数 | 迁移价值 |
|
||
|---|---|---|
|
||
| `docs/星光平台API接口文档.md` | 807 | ⭐⭐⭐⭐⭐ 接口/签名/枚举/选择器/错误码全量,是服务端复现的**唯一权威**(注意含盐值,不可外发) |
|
||
| `docs/送审命名规范与预检规则.md` | 235 | ⭐⭐⭐⭐⭐ 命名/解析/预检/批量语义,直接对应 PRD P-04 |
|
||
| `docs/星光平台送审与审核查询-可行性评估.md` | 928 | ⭐⭐⭐⭐ 读写分离、页面自动化理由、单会话约束 |
|
||
| `docs/DPLink组成与一键复制-可行性评估.md` | 545 | ⭐⭐⭐⭐ 双层链接算法/字段/实测样本,对应 PRD P-05 |
|
||
| `docs/P1读数据接口化-实现说明.md` / `P2素材审核查询-实现说明.md` / `P4素材送审-实现说明.md` | 540/516/1,068 | ⭐⭐⭐⭐ 实现取舍、真机踩坑、门禁清单(P4 含 19 轮真机记录) |
|
||
| `docs/混剪素材批量上传-开发方案.md` / `混剪素材批量送审-实现说明.md` | 496/151 | ⭐⭐⭐ 混剪业务规则与 Phase 2 方向 |
|
||
| `docs/接口登录通道-实现说明.md` | 273 | ⭐⭐⭐ 登录接口化实测与红线 |
|
||
| `docs/远端配置运维手册.md` | 190 | ⭐⭐⭐ 白名单/签名/revision/应急停用;可迁移为配置中心 SOP |
|
||
| `docs/项目评估与优化建议-2.1.0.md` | 1,063 | ⭐⭐⭐ 架构/性能/安全/测试的系统性评估(部分已修,需按现状核对) |
|
||
| `DEVELOPMENT.md` | 2,380 | ⭐⭐⭐ 目录/主进程/IPC/配置/踩坑全量,但基线 v1.0.6,**只读 §3-§8 与 §17-§19,其余核对代码** |
|
||
| `docs/签名与公证落地清单.md`、`构建发布与版本更新指南.md` | 227/859 | ⭐⭐ 桌面端专用,Web 化后仅作历史参考 |
|
||
|
||
---
|
||
|
||
## 10. 风险与待确认问题
|
||
|
||
### 10.1 风险
|
||
|
||
**R1 平台合规/封禁(高)**
|
||
- 本项目是**未授权的页面自动化 + 接口逆向**:签名盐从平台前端产物取得,账号是客户共享账号;平台条款是否允许此类工具、是否会把团队账号风控,**没有任何书面确认**。
|
||
- Web 化后从「个人电脑 IP」变为「机房 IP + 多用户高频」,平台侧流量特征更显眼,封号/限流风险上升。
|
||
- 建议:法务/客户成功提前确认;保留「只读优先、写操作人工确认、可一键停用」的设计(现有 `enableSubmitReview` 就是范式)。
|
||
|
||
**R2 登录态与账号归属(高)**
|
||
- 平台**单账号单会话**:网页版登录会顶掉应用 token;多用户 Web 化若共享一个 token 会互踢。现有云端 Cookie 同步(HTTP+FTP 明文)是「团队共享一个账号」的临时方案,不适合作为平台级账号体系。
|
||
- 硬广账号是客户给团队的**共用账号**,DPLink 依赖它;多人同时使用/退出语义(退出只清本机)需要产品化定义。
|
||
- 账号归属、权限(platform 的 `user/detail` 权限菜单表)、数据可见范围(谁看谁的送审/审核)都需要新平台的权限模型。
|
||
|
||
**R3 接口/页面稳定性(高)**
|
||
- 签名盐、字段、枚举、选择器、权限菜单都可能随平台发版变化;本项目用 32 个验证脚本 + 真机对比脚本 + 抓包 fixture 对抗,但**没有 SLA/版本协商**。
|
||
- 混剪「混剪=是」写链路、登录失败码、素材审核部分字段尚未真机覆盖(文档已标注)。
|
||
- 新平台应把「平台适配层」隔离为可独立发版的服务,并提供「平台变更检测/健康检查」机制(签名自校验已有雏形)。
|
||
|
||
**R4 Electron 能力缺口(中)**
|
||
- 内嵌 webview、本地文件路径/对话框、剪贴板、系统通知、打开目录、safeStorage、FTP、自动更新、代码签名、窗口状态——Web 端均无等价物,需要替代方案(对象存储、浏览器下载、通知中心、KMS、部署流水线)。
|
||
- 特别是**送审大文件**(140–190MB)从「本地路径 `setInputFiles`」变为「浏览器→服务端→平台」,带宽与上传成功率是新增风险;建议优先设计「客户端→OSS 直传 + 服务端只发凭证」。
|
||
|
||
**R5 数据迁移(中)**
|
||
- 本地 `config.json`/`cookies.json`/`dplink-*`/`submitted-md5.json`/`submit-audit.jsonl`/下载目录命名规则都是「单机事实」;迁移到多用户平台需要:
|
||
- 账号与凭据迁移(safeStorage 加密跨机器不可解,必须重新登录);
|
||
- 已送审账本(避免重复送审)与审计日志的历史价值;
|
||
- 下载文件/命名规则兼容(历史文件如何进新素材库);
|
||
- 本地路径偏好(下载目录)在新平台无意义。
|
||
- 建议迁移策略:**不做客户端数据自动迁移**,只提供「md5 账本 + 审计日志导入」与「重新登录」;历史素材通过新平台重新拉取/上传。
|
||
|
||
**R6 凭据泄露(高,且为既成事实)**
|
||
- 星光/FTP 凭据曾在源码与 git 历史中;即使轮换,旧仓库/文档/随包产物仍可能流出。新平台**不得复用**这些凭据;上线前必须轮换并审计。
|
||
|
||
### 10.2 待确认清单
|
||
|
||
| 编号 | 问题 | 为什么影响整合 | 建议向谁确认 |
|
||
|---|---|---|---|
|
||
| Q-01 | 星光平台是否允许内部工具/服务端自动化?客户/平台方对此的书面态度? | 决定「服务端重写送审」是否合规,可能直接否决整个写链路 | 业务方 + 客户成功 + 法务 |
|
||
| Q-02 | 新平台的账号体系:一人一星光账号,还是团队共享账号池? | 决定会话串行化、权限、审计与凭据设计;现有单账号假设不成立 | 产品负责人 + 客户 |
|
||
| Q-03 | 新平台是否也要服务唯品会?其后台是否有可复用的接口/登录方式? | 决定 P-06 是否另起一套适配层;本项目零参考 | 产品 + 另一项目调研(sucaigongfang) |
|
||
| Q-04 | DP / 承接页的准确业务口径是什么?DPLink 是否就是 PRD 所指的「自动配置」? | 决定 P-05 的范围;本项目只做了得物 DPLink(iOS/安卓唤端链接),不含 DP 字段 | 业务方(PRD 1.1.3) |
|
||
| Q-05 | 新平台的 UI 选型是否包含 Semi?还是 Ant Design/Arco/自研? | 直接决定前端 8–12 人日差异与组件复用边界(§8.1) | 设计负责人 + 前端负责人 |
|
||
| Q-06 | 平台原始素材(图片/视频)在新平台的存储形态:对象存储?CDN?保留多久? | 决定下载引擎改造与成本;现有「本地目录 + 文件名」语义要替换 | 架构 + 运维 |
|
||
| Q-07 | 「图片/视频 AI 产线」是否已有供应商/模型选型? | 与 dewu 项目无关,但影响整体排期与数据流(原始物料→产线→提审) | 产品 + AI 负责人 |
|
||
| Q-08 | 混剪送审是否仍由人工配对,还是需要 Excel/CSV 导入(Phase 2)? | 决定 8–12 人日 UI 的范围;当前 Phase 2 未实现 | 业务方 |
|
||
| Q-09 | 历史数据(已送审 md5、审计日志、下载文件)是否需要迁移? | 决定迁移成本与「重复送审」风险 | 业务方 + 产品 |
|
||
| Q-10 | 写链路是否保留「人工确认 + 可中断 + 远端一键停用」的安全设计? | 若要求无人值守批量提交,风险与实现复杂度都会显著上升 | 业务方 + 风控 |
|
||
| Q-11 | 平台接口的 SLA/变更通知机制是否存在?谁负责平台改版后的适配? | 决定长期维护成本归属(≈1 人持续投入) | 客户/平台方 + 研发负责人 |
|
||
| Q-12 | 账号权限菜单(`user/detail.list`)是否可作为新平台的功能门禁依据? | 现有实现只做「建议不硬拦」;若要做硬权限需确认菜单稳定性 | 平台方 + 产品 |
|
||
|
||
---
|
||
|
||
## 11. 证据索引
|
||
|
||
> 路径前缀 `dw/` = `参考项目/dewu-material-Downloader/`。以下为关键结论的最小证据集(≥25 条)。
|
||
|
||
| # | 结论 | 证据 |
|
||
|---|---|---|
|
||
| 1 | 版本 2.7.0、应用标识 | `dw/package.json:3`、`dw/electron-builder.yml:1-2` |
|
||
| 2 | 技术栈(Electron 44 / React 19 / Semi 2 / Playwright) | `dw/package.json:70-96` |
|
||
| 3 | 6 个一级入口与 BETA 标记 | `dw/src/App.tsx:240-306` |
|
||
| 4 | 6 条路由 | `dw/src/App.tsx:437-442` |
|
||
| 5 | 101 条 IPC 通道、87 invoke + 14 event | `dw/electron/ipc/channels.ts:1`、`dw/electron/preload.ts:15,87,124,190,230,300` |
|
||
| 6 | 写链路红线(不直接调写接口) | `dw/electron/submit/page.ts:2-30` |
|
||
| 7 | 提交接口路径与上传超时 15 分钟 | `dw/electron/submit/page.ts:47,68` |
|
||
| 8 | 送审抽屉选择器(按 label 精确匹配、限定抽屉) | `dw/electron/submit/page.ts:77-110,209-222` |
|
||
| 9 | 批量送审策略表(成功/重复/失败/超时/掉线) | `dw/electron/submit/batch.ts:1-30` |
|
||
| 10 | 只按 md5 幂等 + 双向同步 | `dw/electron/submit/idempotency.ts:1-36` |
|
||
| 11 | 审计/请求体 JSONL 路径 | `dw/electron/submit/audit.ts:29-40,151` |
|
||
| 12 | 命名规范(模式 A/B、末三段、无 spuid) | `dw/docs/送审命名规范与预检规则.md:20-93` |
|
||
| 13 | 下载命名规则 | `dw/electron/downloader/utils.ts:11-20` |
|
||
| 14 | 下载分批/并发/冷却/重试 | `dw/electron/downloader/manager.ts:181-227,374-430` |
|
||
| 15 | MD5 全量同步扫描(性能债) | `dw/electron/downloader/manager.ts:174`、`dw/electron/downloader/utils.ts:78-100` |
|
||
| 16 | 星光签名盐与算法 | `dw/scripts/lib/platform-sign.mjs:20-37,73-106` |
|
||
| 17 | 素材列表/详情接口路径 | `dw/electron/platform/materials.ts:91,177` |
|
||
| 18 | 审核/记录/枚举/账号接口路径 | `dw/electron/platform/reviews.ts:43-48` |
|
||
| 19 | 登录接口路径与 token 事实 | `dw/electron/platform/auth.ts:1-70` |
|
||
| 20 | 接口登录实测 9/9 | `dw/docs/接口登录通道-实现说明.md:146-169` |
|
||
| 21 | 平台 API 全量文档(含签名/枚举/送审) | `dw/docs/星光平台API接口文档.md:130,197,229,277,326,342,366,379,522,594` |
|
||
| 22 | 读写分离与单会话红线 | `dw/docs/星光平台送审与审核查询-可行性评估.md:1-120`、`dw/docs/新功能开发计划.md:455-475` |
|
||
| 23 | 送审四步链路与 SPU 误报教训 | `dw/docs/星光平台API接口文档.md:340-520` |
|
||
| 24 | 远端配置三道防线/白名单 | `dw/electron/config/remote.ts:1-40`、`dw/scripts/lib/remote-config-schema.mjs:32-53` |
|
||
| 25 | 送审总开关/线上配置 revision 2 | `dw/remote-config/app-config.json:26,72` |
|
||
| 26 | 硬编码凭据仍在源码 | `dw/electron/config/developer.ts:130,135` |
|
||
| 27 | 三档下载参数与远端区间 | `dw/electron/config/presets.ts:59-102`、`dw/scripts/lib/remote-config-schema.mjs:60-80` |
|
||
| 28 | 商品详情 SSR 直取(无浏览器) | `dw/electron/shop/detail.ts:11-27,182-280` |
|
||
| 29 | 商品素材落盘结构/URL 白名单 | `dw/electron/shop/materials.ts:24-26,82-95` |
|
||
| 30 | 内嵌页 UA/分区/净化(Electron 依赖) | `dw/electron/shop/session.ts:32-66,198-200` |
|
||
| 31 | DPLink 双层算法与接口 | `dw/docs/DPLink组成与一键复制-可行性评估.md:12-35`、`dw/electron/dplink/link.ts:39-41` |
|
||
| 32 | DPLink 硬广凭据隔离 | `dw/electron/dplink/account.ts:1-40` |
|
||
| 33 | Cookie 同步 v2 分区(soft/dplink) | `dw/electron/browser/cookieSync.ts:1-40` |
|
||
| 34 | 登录态状态机与串行队列 | `dw/electron/browser/manager.ts:46-55,223` |
|
||
| 35 | 浏览器组件三级检测/验签 | `dw/electron/browser/playwrightInstaller.ts:1-125,436` |
|
||
| 36 | 更新元数据验签/强制/最低版本 | `dw/electron/updater/manager.ts:185,231,274-301` |
|
||
| 37 | CI 三 job 与门禁清单 | `dw/.github/workflows/ci.yml:53-217,257` |
|
||
| 38 | 验证脚本规模(verify:ui 480 通过 / verify:platform 260 通过) | `dw/scripts/verify-ui-behavior.mjs`(5,283 行)、`dw/scripts/verify-platform.mjs`(2,352 行) |
|
||
| 39 | TypeScript strict | `dw/tsconfig.json` |
|
||
| 40 | 项目评估健康度 3.0/5 与 P0 清单 | `dw/docs/项目评估与优化建议-2.1.0.md:27-43,314,455,705` |
|
||
| 41 | 素材过滤规则(30 天/未授权快手) | `dw/scripts/lib/material-filter.mjs`、`dw/docs/素材下载过滤开关-实现说明.md:1-40` |
|
||
| 42 | 混剪 Phase 1 未真机 | `dw/docs/混剪素材批量送审-实现说明.md:1-65` |
|
||
| 43 | 审核状态映射与 CSV 列 | `dw/scripts/lib/platform-material-mapping.mjs:424-506`、`dw/scripts/lib/review-csv.mjs:34-45` |
|
||
| 44 | DEVELOPMENT.md 基线过时(v1.0.6 vs 2.7.0) | `dw/DEVELOPMENT.md:1-13,1715-1830` |
|
||
| 45 | 无唯品会代码 | 全仓检索 `唯品会\|vipshop\|vip.com` 零命中 |
|