release: 0.2.0421.2
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
# Market Export Range Implementation Plan
|
||||
|
||||
> **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:** Add configurable CSV export ranges for the Xingtu market plugin, defaulting to the first 5 pages and supporting current page, preset ranges, all pages, and custom page counts.
|
||||
|
||||
**Architecture:** Keep filter and sort scoped to the current page, and introduce a dedicated batch-export path that only runs when exporting. Extend the toolbar with export-range controls, extract page-navigation/signature helpers, and add a focused controller that iterates pages, harvests lazy-loaded DOM fields, merges records by `authorId`, and returns a single record set for CSV generation.
|
||||
|
||||
**Tech Stack:** TypeScript, Vitest, jsdom, Chrome MV3 content script
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Extend Toolbar Controls For Export Range
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/content/market/plugin-toolbar.ts`
|
||||
- Test: `tests/market-content-entry.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add tests that assert:
|
||||
- the toolbar defaults to `前5页`
|
||||
- selecting `自定义` shows and uses a page-count input
|
||||
- invalid custom values prevent export
|
||||
- export mode disables toolbar controls during a running task
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts -t "export range"`
|
||||
Expected: FAIL because the toolbar has no range selector or custom input behavior.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Update `plugin-toolbar.ts` to:
|
||||
- add an export-range `<select>`
|
||||
- add a custom page-count `<input>`
|
||||
- add status text support
|
||||
- expose helpers for reading range state and toggling disabled/running UI
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts -t "export range"`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/content/market/plugin-toolbar.ts tests/market-content-entry.test.ts
|
||||
git commit -m "feat: add export range toolbar controls"
|
||||
```
|
||||
|
||||
### Task 2: Add Batch Export Coverage
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/market-content-entry.test.ts`
|
||||
- Modify: `tests/market-dom-sync.test.ts`
|
||||
- Test: `tests/market-content-entry.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add tests that assert:
|
||||
- `当前页` exports only the current page
|
||||
- `前5页` iterates through pages until it reaches page 5 or runs out of pages
|
||||
- `全部` stops when the next-page control is no longer usable
|
||||
- repeated authors across pages are merged by `authorId`
|
||||
- empty fields from later pages do not erase existing populated fields
|
||||
- page export waits for page signature change before harvesting the next page
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts`
|
||||
Expected: FAIL on the new batch-export expectations.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation scaffolding**
|
||||
|
||||
Only introduce the minimum new helpers/types needed to make the tests compile:
|
||||
- export range type(s)
|
||||
- page signature helpers
|
||||
- harness utilities in tests
|
||||
|
||||
- [ ] **Step 4: Run tests to verify the failures are now behavioral**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts`
|
||||
Expected: FAIL because batch export logic is still missing, not because types/selectors are missing.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/market-content-entry.test.ts tests/market-dom-sync.test.ts src/content/market/types.ts
|
||||
git commit -m "test: cover multi-page export behavior"
|
||||
```
|
||||
|
||||
### Task 3: Implement Batch Export Controller
|
||||
|
||||
**Files:**
|
||||
- Create: `src/content/market/export-range-controller.ts`
|
||||
- Modify: `src/content/market/types.ts`
|
||||
- Modify: `src/content/market/dom-sync.ts`
|
||||
- Modify: `src/content/market/result-store.ts`
|
||||
- Test: `tests/market-content-entry.test.ts`
|
||||
- Test: `tests/market-dom-sync.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add focused tests for:
|
||||
- reading a page signature from current DOM
|
||||
- detecting/using the next-page control
|
||||
- merging rows by `authorId` with non-empty-field preference
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `npm test -- tests/market-dom-sync.test.ts`
|
||||
Expected: FAIL because these helpers/controller do not exist yet.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Implement `export-range-controller.ts` to:
|
||||
- normalize export targets (`current`, `count`, `all`)
|
||||
- harvest current page rows with the existing lazy-load scroll path
|
||||
- read page signatures
|
||||
- click/advance pagination and wait for signature change
|
||||
- merge pages by `authorId` without overwriting non-empty fields
|
||||
- return a final `MarketRecord[]`
|
||||
|
||||
Keep `dom-sync.ts` focused on DOM reads:
|
||||
- page signature
|
||||
- next-page element lookup
|
||||
- next-page enabled check
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run:
|
||||
- `npm test -- tests/market-dom-sync.test.ts`
|
||||
- `npm test -- tests/market-content-entry.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/content/market/export-range-controller.ts src/content/market/dom-sync.ts src/content/market/result-store.ts src/content/market/types.ts tests/market-content-entry.test.ts tests/market-dom-sync.test.ts
|
||||
git commit -m "feat: add multi-page export controller"
|
||||
```
|
||||
|
||||
### Task 4: Wire Controller Into Market Entry
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/content/market/index.ts`
|
||||
- Modify: `src/content/market/plugin-toolbar.ts`
|
||||
- Test: `tests/market-content-entry.test.ts`
|
||||
|
||||
- [ ] **Step 1: Write the failing tests**
|
||||
|
||||
Add tests that assert:
|
||||
- `导出CSV` uses the selected range
|
||||
- progress text updates while exporting
|
||||
- controls are re-enabled on success and failure
|
||||
- invalid custom input blocks export without calling CSV builder
|
||||
|
||||
- [ ] **Step 2: Run tests to verify they fail**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts`
|
||||
Expected: FAIL because `market/index.ts` still always exports current-page records.
|
||||
|
||||
- [ ] **Step 3: Write the minimal implementation**
|
||||
|
||||
Update `market/index.ts` to:
|
||||
- parse toolbar export range
|
||||
- keep current-page export for `当前页`
|
||||
- delegate batch modes to `export-range-controller.ts`
|
||||
- update toolbar running/error/progress state
|
||||
- preserve existing current-page lazy-load harvest path
|
||||
|
||||
- [ ] **Step 4: Run tests to verify they pass**
|
||||
|
||||
Run: `npm test -- tests/market-content-entry.test.ts`
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add src/content/market/index.ts src/content/market/plugin-toolbar.ts tests/market-content-entry.test.ts
|
||||
git commit -m "feat: wire export range selection into market export"
|
||||
```
|
||||
|
||||
### Task 5: Verify End-To-End
|
||||
|
||||
**Files:**
|
||||
- Modify: `docs/superpowers/plans/2026-04-21-market-export-range.md`
|
||||
|
||||
- [ ] **Step 1: Run targeted regression tests**
|
||||
|
||||
Run:
|
||||
- `npm test -- tests/market-content-entry.test.ts`
|
||||
- `npm test -- tests/market-dom-sync.test.ts`
|
||||
|
||||
Expected: PASS
|
||||
|
||||
- [ ] **Step 2: Run the full suite**
|
||||
|
||||
Run: `npm test`
|
||||
Expected: PASS with all test files green.
|
||||
|
||||
- [ ] **Step 3: Run the build**
|
||||
|
||||
Run: `npm run build`
|
||||
Expected: PASS and emit updated `dist/` bundles.
|
||||
|
||||
- [ ] **Step 4: Mark the plan status**
|
||||
|
||||
Update this document’s checkboxes to reflect completed steps.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/superpowers/plans/2026-04-21-market-export-range.md
|
||||
git commit -m "docs: record export range implementation progress"
|
||||
```
|
||||
@@ -0,0 +1,257 @@
|
||||
# 星图市场导出范围设计
|
||||
|
||||
## 背景
|
||||
|
||||
当前插件的 `导出CSV` 只导出当前页数据,并在星图默认列后追加两列:
|
||||
|
||||
- `单视频看后搜率`
|
||||
- `个人视频看后搜率`
|
||||
|
||||
现阶段用户希望把导出范围扩展为可配置页数,而不是固定当前页。同时需要保留当前默认列导出逻辑,避免重新引入之前“全量扫描导致页面闪动、卡顿、排序异常”的问题。
|
||||
|
||||
## 目标
|
||||
|
||||
- 支持导出范围配置,默认导出前 `5` 页。
|
||||
- 支持以下范围选项:
|
||||
- `当前页`
|
||||
- `前5页`
|
||||
- `前10页`
|
||||
- `全部`
|
||||
- `自定义`
|
||||
- 保留当前 CSV 规则:
|
||||
- 先导出星图页面默认列
|
||||
- 末尾追加两列插件字段
|
||||
- 批量导出时真实翻页采集当前筛选结果页,不改变当前页面筛选条件来源。
|
||||
- 保持当前“筛选/排序只作用当前页”的行为,不重新绑定多页扫描逻辑。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不改为直接调用星图列表接口拉多页数据。
|
||||
- 不让插件筛选或排序自动跨页生效。
|
||||
- 不处理“导出后自动回到最初分页位置”的复杂恢复,首版只要求滚动位置恢复到单页采集前。
|
||||
|
||||
## 交互设计
|
||||
|
||||
在插件工具栏中保留一个 `导出CSV` 按钮,同时新增导出范围控件。
|
||||
|
||||
### 范围控件
|
||||
|
||||
- 默认值:`前5页`
|
||||
- 可选项:
|
||||
- `当前页`
|
||||
- `前5页`
|
||||
- `前10页`
|
||||
- `全部`
|
||||
- `自定义`
|
||||
- 选择 `自定义` 时,展示页数输入框
|
||||
- 仅接受正整数
|
||||
- 无效值时禁止导出并提示错误
|
||||
|
||||
### 任务状态
|
||||
|
||||
- 导出开始后:
|
||||
- `导出CSV` 按钮禁用
|
||||
- 筛选按钮、排序按钮、范围控件、自定义输入框一并禁用
|
||||
- 按钮文案根据任务模式更新:
|
||||
- 当前页:`导出中...`
|
||||
- 前 N 页:`导出中 3/5 页...`
|
||||
- 全部:`导出中 第3页...`
|
||||
- 全部导出时额外显示轻提示:
|
||||
- `全部导出可能耗时较长,页面会自动翻页。`
|
||||
|
||||
### 失败反馈
|
||||
|
||||
- 任一页采集失败时直接终止
|
||||
- 通过按钮附近状态文本或 `alert` 提示:
|
||||
- `第 N 页导出失败,请稍后重试`
|
||||
- 失败时不下载残缺 CSV
|
||||
|
||||
## 执行流程
|
||||
|
||||
### 当前页导出
|
||||
|
||||
当前页模式沿用现有逻辑:
|
||||
|
||||
1. 等待当前页表格可读取
|
||||
2. 自动滚动当前页一次,补齐懒加载字段
|
||||
3. 读取当前页星图默认列
|
||||
4. 合并插件两列
|
||||
5. 生成 CSV 并下载
|
||||
|
||||
### 多页导出
|
||||
|
||||
多页模式仅在导出任务中启用,不影响平时筛选和排序。
|
||||
|
||||
1. 读取导出范围配置
|
||||
2. 初始化批量任务状态与结果聚合器
|
||||
3. 对当前页执行:
|
||||
- 等待表格稳定
|
||||
- 自动滚动当前页以采全默认列
|
||||
- 读取当前页记录
|
||||
- 以 `authorId` 合并入结果集
|
||||
4. 判断是否达到目标页数
|
||||
5. 若未完成,则点击下一页
|
||||
6. 等待“页切换完成”信号
|
||||
7. 重复步骤 3 到 6
|
||||
8. 汇总所有记录,生成单个 CSV 下载
|
||||
|
||||
### 全部导出停止条件
|
||||
|
||||
`全部` 模式从当前页开始向后翻页,直到任一条件成立:
|
||||
|
||||
- 下一页按钮不可点击
|
||||
- 当前页签名不再变化
|
||||
- 页面无法继续翻页并达到超时阈值
|
||||
|
||||
## 页切换判定
|
||||
|
||||
批量导出不能只依赖固定 `setTimeout`。翻页完成需要同时满足至少一个强信号:
|
||||
|
||||
- 当前页作者 ID 集合发生变化
|
||||
- 当前页首行作者 ID 变化
|
||||
- 当前页活动分页按钮变化
|
||||
- 下一页按钮状态变化
|
||||
|
||||
为避免误判,翻页流程需要:
|
||||
|
||||
1. 记录翻页前页签名
|
||||
2. 点击下一页
|
||||
3. 轮询直到签名变化或超时
|
||||
4. 签名变化后再执行一次当前页表格稳定等待
|
||||
|
||||
## 当前页采集策略
|
||||
|
||||
当前页导出已知存在懒加载问题:页面初加载时后半段行的默认列为空,滚动后才补齐。
|
||||
|
||||
因此无论当前页导出还是多页导出,每一页都必须执行:
|
||||
|
||||
1. 初次读取当前页快照并写入 store
|
||||
2. 查找当前市场列表滚动容器
|
||||
3. 逐步向下滚动直到该页底部
|
||||
4. 每次滚动后等待 DOM 稳定,再采集一轮
|
||||
5. 恢复滚动位置并再采集一轮
|
||||
|
||||
这一步只针对“当前已打开的页”,不跨页扫描。
|
||||
|
||||
## 数据合并规则
|
||||
|
||||
### 去重键
|
||||
|
||||
- 使用 `authorId` 去重
|
||||
|
||||
### 字段合并
|
||||
|
||||
- 新页记录有值时,补充到已有记录
|
||||
- 新页记录为空时,不覆盖已有非空值
|
||||
- 插件两列沿用当前已有的合并规则
|
||||
|
||||
### CSV 表头
|
||||
|
||||
- 先保留星图默认列顺序
|
||||
- 再追加:
|
||||
- `单视频看后搜率`
|
||||
- `个人视频看后搜率`
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 单页失败
|
||||
|
||||
以下情况视为单页失败:
|
||||
|
||||
- 找不到表格根节点
|
||||
- 找不到下一页按钮但目标尚未完成
|
||||
- 翻页后页签名未变化且超时
|
||||
- 当前页采集过程中出现异常
|
||||
|
||||
处理方式:
|
||||
|
||||
- 立即终止任务
|
||||
- 恢复工具栏控件状态
|
||||
- 显示页级错误信息
|
||||
- 不触发下载
|
||||
|
||||
### 用户干预
|
||||
|
||||
首版不额外提供取消按钮,但应防御以下情况:
|
||||
|
||||
- 用户手动切换筛选
|
||||
- 用户手动翻页
|
||||
- 用户再次点击导出
|
||||
|
||||
处理方式:
|
||||
|
||||
- 导出期间禁用插件控件
|
||||
- 对关键节点重新校验表格和页签名
|
||||
- 如环境已被破坏,终止任务并报错
|
||||
|
||||
## 实现建议
|
||||
|
||||
建议按以下边界组织实现:
|
||||
|
||||
### `plugin-toolbar`
|
||||
|
||||
- 新增导出范围选择器
|
||||
- 新增自定义页数输入框
|
||||
- 新增导出过程中的状态展示
|
||||
|
||||
### `market/index`
|
||||
|
||||
- 保留当前页导出逻辑作为单页模式
|
||||
- 新增批量导出入口
|
||||
- 管理任务状态、按钮禁用、进度回写
|
||||
|
||||
### 新建批量导出控制器
|
||||
|
||||
建议新增类似 `export-range-controller.ts` 的模块,职责包括:
|
||||
|
||||
- 读取当前页记录
|
||||
- 控制翻页
|
||||
- 等待页切换
|
||||
- 聚合多页数据
|
||||
- 统一返回最终 `MarketRecord[]`
|
||||
|
||||
这样可以避免把 `market/index.ts` 继续堆大。
|
||||
|
||||
### `dom-sync` 或新辅助模块
|
||||
|
||||
- 提供读取当前页签名
|
||||
- 提供定位下一页按钮
|
||||
- 提供判断下一页是否可点击
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 单元测试
|
||||
|
||||
- 默认导出范围为前 5 页
|
||||
- 选择 `当前页` 时只导出一页
|
||||
- 选择 `前10页` 时最多导出 10 页
|
||||
- `自定义` 输入非法值时不启动导出
|
||||
- `全部` 模式在没有下一页时停止
|
||||
- 多页合并时按 `authorId` 去重
|
||||
- 空字段不会覆盖已有非空字段
|
||||
|
||||
### 集成测试
|
||||
|
||||
- 批量导出时会依次点击下一页
|
||||
- 翻页后等待新页签名再采集
|
||||
- 每一页在导出前都会执行滚动采集
|
||||
- 中途某页失败时不生成 CSV
|
||||
- 导出期间工具栏控件被禁用
|
||||
|
||||
## 风险
|
||||
|
||||
- 星图分页 DOM 结构可能不稳定,下一页按钮定位需要做降级兼容。
|
||||
- 全部导出在高页数场景下耗时会较长。
|
||||
- 页面中途刷新或筛选重算可能打断批量任务。
|
||||
|
||||
## 推荐实施顺序
|
||||
|
||||
1. 工具栏新增范围选择与自定义输入
|
||||
2. 抽出批量导出控制器
|
||||
3. 实现前 N 页导出
|
||||
4. 在前 N 页能力稳定后开放 `全部`
|
||||
5. 补齐全部相关失败与超时测试
|
||||
|
||||
## 决策结论
|
||||
|
||||
采用“一个导出按钮 + 范围选择器”的方案,默认导出前 `5` 页,支持 `全部` 和 `自定义`。批量模式通过真实翻页逐页采集当前筛选结果,不把多页扫描重新引入到筛选和排序链路中。
|
||||
Reference in New Issue
Block a user