docs: 新增日历页文档并补充记账直接新建分类/标签/渠道说明
补上此前已完成但未提交的文档更新:新增「日历」页面使用文档,并把登录后默认落地页由统计面板调整为日历,同步页面流程与偏好说明;同时补充记账弹窗内可直接新建分类/标签/渠道的说明,并登记相应截图场景。 变更内容: - 新增 guide/calendar.md,并在 .vitepress/config.mts 侧边栏与 guide/pages.md、guide/index.md 登记日历页 - index.md、guide/getting-started.md、guide/dashboard.md、guide/pages.md 同步日历为登录后默认落地页与页面流程 - dev/preferences.md 新增日历偏好 ledgerly.calendar.view/year/month/statsScope 说明 - guide/transactions.md 补充记账弹窗内直接新建分类/标签/渠道的说明,guide/ai.md、guide/categories-tags.md、guide/channels.md 同步相关描述 - scripts/ts/capture-all.ts、capture-pages.ts、capture-elements.ts 增加日历与新建分类等截图场景,captureModals 支持按场景过滤
This commit is contained in:
@@ -9,7 +9,7 @@ export default defineConfig({
|
|||||||
cleanUrls: true,
|
cleanUrls: true,
|
||||||
ignoreDeadLinks: true,
|
ignoreDeadLinks: true,
|
||||||
// 维护类文档不参与站点构建
|
// 维护类文档不参与站点构建
|
||||||
srcExclude: ['AGENTS.md'],
|
srcExclude: ['AGENTS.md', 'todo.md'],
|
||||||
// 文档站默认端口从 5173 调整为 5175,把 5173 让给 ledgerly 前端
|
// 文档站默认端口从 5173 调整为 5175,把 5173 让给 ledgerly 前端
|
||||||
vite: {
|
vite: {
|
||||||
server: {
|
server: {
|
||||||
@@ -31,6 +31,7 @@ export default defineConfig({
|
|||||||
{ text: '项目简介', link: '/guide/introduction' },
|
{ text: '项目简介', link: '/guide/introduction' },
|
||||||
{ text: '快速开始', link: '/guide/getting-started' },
|
{ text: '快速开始', link: '/guide/getting-started' },
|
||||||
{ text: '下载与安装', link: '/guide/download' },
|
{ text: '下载与安装', link: '/guide/download' },
|
||||||
|
{ text: '日历', link: '/guide/calendar' },
|
||||||
{ text: '统计面板', link: '/guide/dashboard' },
|
{ text: '统计面板', link: '/guide/dashboard' },
|
||||||
{ text: '页面总览', link: '/guide/pages' },
|
{ text: '页面总览', link: '/guide/pages' },
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -33,6 +33,10 @@
|
|||||||
| 键名 | 偏好内容 | 文件 | 保存时机 | 读取时机 |
|
| 键名 | 偏好内容 | 文件 | 保存时机 | 读取时机 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| `ledgerly.locale` | 界面语言 `zh-CN`/`en-US`/`ja-JP` | `locales/index.ts` | 切换语言 | 模块初始化 |
|
| `ledgerly.locale` | 界面语言 `zh-CN`/`en-US`/`ja-JP` | `locales/index.ts` | 切换语言 | 模块初始化 |
|
||||||
|
| `ledgerly.calendar.view` | 日历视图 `month`/`year` | `views/Calendar.vue` | `useStringPreference` 自动 | 组件初始化 |
|
||||||
|
| `ledgerly.calendar.year` | 日历最近浏览年份(四位数字符串) | `views/Calendar.vue` | 变量 `watch` 自动 | 组件初始化 |
|
||||||
|
| `ledgerly.calendar.month` | 日历月视图最近浏览月份(`1`-`12`) | `views/Calendar.vue` | 变量 `watch` 自动 | 组件初始化 |
|
||||||
|
| `ledgerly.calendar.statsScope` | 日历统计口径 `INCLUDED`/`ALL`/`EXCLUDED` | `views/Calendar.vue` | `useStringPreference` 自动 | 组件初始化 |
|
||||||
| `ledgerly.dashboard.prefs` | 统计面板时间范围、粒度与多项筛选 | `views/Dashboard.vue` | 变量 `watch` 自动 | `onMounted` |
|
| `ledgerly.dashboard.prefs` | 统计面板时间范围、粒度与多项筛选 | `views/Dashboard.vue` | 变量 `watch` 自动 | `onMounted` |
|
||||||
| `ledgerly.transaction.filterPrefs` | 收支列表筛选、分页、排序 | `views/TransactionList.vue` | 变量 `watch` 自动 | `onMounted` |
|
| `ledgerly.transaction.filterPrefs` | 收支列表筛选、分页、排序 | `views/TransactionList.vue` | 变量 `watch` 自动 | `onMounted` |
|
||||||
| `ledgerly.transaction.aiScope` | 批量 AI 建议范围 | `views/TransactionList.vue` | 变量 `watch` 自动 | ref 初始化 |
|
| `ledgerly.transaction.aiScope` | 批量 AI 建议范围 | `views/TransactionList.vue` | 变量 `watch` 自动 | ref 初始化 |
|
||||||
@@ -79,6 +83,18 @@
|
|||||||
- **目的**:记住用户语言选择,应用启动与切换即时生效。
|
- **目的**:记住用户语言选择,应用启动与切换即时生效。
|
||||||
- **入口**:`components/LocaleSwitch.vue`。
|
- **入口**:`components/LocaleSwitch.vue`。
|
||||||
|
|
||||||
|
### 日历偏好 `ledgerly.calendar.view` / `ledgerly.calendar.year` / `ledgerly.calendar.month` / `ledgerly.calendar.statsScope`
|
||||||
|
|
||||||
|
- **文件**:`frontend/src/views/Calendar.vue`
|
||||||
|
- **取值**:
|
||||||
|
- `ledgerly.calendar.view`:`month`(月视图,默认)/ `year`(年视图);非法值回退 `month`。
|
||||||
|
- `ledgerly.calendar.year`:最近浏览的年份(四位数字符串),月视图面板年份与年视图年份共用;非法值回退当前年。
|
||||||
|
- `ledgerly.calendar.month`:月视图最近浏览的月份(`1`-`12`);非法值回退当前月。
|
||||||
|
- `ledgerly.calendar.statsScope`:`INCLUDED`(仅计入统计,默认)/ `ALL`(全部记录)/ `EXCLUDED`(仅不计入);非法值回退 `INCLUDED`。
|
||||||
|
- **读取**:组件初始化时经 `useStringPreference` 读取;URL 中的 `view`/`y`/`m`(如 `?view=year&y=2026`)优先于偏好,无参数时按偏好恢复上次视图、年月与统计口径。
|
||||||
|
- **保存**:`view`/`statsScope` 由 `useStringPreference` 内部 `watch` 自动写入;`year`/`month` 由组件内 `watch(panelYear/panelMonth)`(月视图)与 `watch(yearViewYear)`(年视图)写入。
|
||||||
|
- **目的**:下次进入日历自动还原上次的月/年视图、年月与统计口径。
|
||||||
|
|
||||||
### 统计面板偏好 `ledgerly.dashboard.prefs`
|
### 统计面板偏好 `ledgerly.dashboard.prefs`
|
||||||
|
|
||||||
- **文件**:`frontend/src/views/Dashboard.vue`(键名第 470 行)
|
- **文件**:`frontend/src/views/Dashboard.vue`(键名第 470 行)
|
||||||
|
|||||||
+2
-1
@@ -55,6 +55,7 @@ API Key 仅保存在本地数据库中,仅用于向你配置的接口地址发
|
|||||||
| 统计搜索 | 统计面板 → AI 搜索 | 自然语言解析为统计筛选条件与维度 |
|
| 统计搜索 | 统计面板 → AI 搜索 | 自然语言解析为统计筛选条件与维度 |
|
||||||
| 生成关系名称 | 收支记录 → 账单关系 → AI 生成 | 依据关联账单的类型、渠道、分类与备注生成关系名称与备注 |
|
| 生成关系名称 | 收支记录 → 账单关系 → AI 生成 | 依据关联账单的类型、渠道、分类与备注生成关系名称与备注 |
|
||||||
| 智能查数 | 左侧菜单 → 智能查数 | 自然语言转只读 SQL 查询并展示结果 |
|
| 智能查数 | 左侧菜单 → 智能查数 | 自然语言转只读 SQL 查询并展示结果 |
|
||||||
|
| 手动新建分类/标签/渠道 | 新增/编辑记录 → 新建分类 / 新建标签 / 新建渠道 | 不依赖 AI,直接创建并选中(始终可用) |
|
||||||
|
|
||||||
## 分类与标签建议
|
## 分类与标签建议
|
||||||
|
|
||||||
@@ -128,5 +129,5 @@ API Key 仅保存在本地数据库中,仅用于向你配置的接口地址发
|
|||||||
## 说明
|
## 说明
|
||||||
|
|
||||||
- AI 建议结果仅供参考,应用前可逐条取消勾选。
|
- AI 建议结果仅供参考,应用前可逐条取消勾选。
|
||||||
- 关闭「启用 AI 建议」后,系统不会发起任何 AI 请求,相关入口也会隐藏。
|
- 关闭「启用 AI 建议」后,系统不会发起任何 AI 请求,相关入口也会隐藏(分类/标签/渠道的**手动新建**入口不受影响,始终可用)。
|
||||||
- 账单类型识别(邮箱账单)使用的是**发件人规则**而非 AI,结果更确定、可预期。
|
- 账单类型识别(邮箱账单)使用的是**发件人规则**而非 AI,结果更确定、可预期。
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# 日历
|
||||||
|
|
||||||
|
「日历」是登录后的默认首页,用月视图与年视图直观查看每天的收支情况。左侧菜单默认置于首项,访问 `/` 也会自动进入本页。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 月视图
|
||||||
|
|
||||||
|
- 每天展示当天**收入**(绿色,`+`)、**支出**(红色,`-`)与**结余**;同一天既有收入又有支出时显示三行,否则只显示对应的一侧。
|
||||||
|
- **今天**以高亮标记;点击网格中相邻月份的灰色日期会自动切换到该月。
|
||||||
|
- 顶部四张卡片显示**当月合计**:总收入、总支出、结余、交易笔数。
|
||||||
|
|
||||||
|
## 切换月份与视图
|
||||||
|
|
||||||
|
表头提供:
|
||||||
|
|
||||||
|
- 「‹」「›」:切换上一月 / 下一月(年视图下为上一年 / 下一年);
|
||||||
|
- **年份 / 月份下拉**:直接跳转到任意年月;
|
||||||
|
- **今天**:回到当前月并选中今天;
|
||||||
|
- **月视图 / 年视图**:切换视图。
|
||||||
|
|
||||||
|
## 年视图
|
||||||
|
|
||||||
|
年视图以 12 个月的卡片展示每月收入、支出与结余,无数据的月份显示「无数据」,当前月高亮。点击任意月份卡片即可进入该月的月视图。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
某一年完全没有数据时,会显示「本年暂无交易数据」的空状态提示。
|
||||||
|
|
||||||
|
## 统计口径
|
||||||
|
|
||||||
|
表头的「**统计口径**」下拉控制参与汇总的记录范围:
|
||||||
|
|
||||||
|
| 选项 | 含义 |
|
||||||
|
|---|---|
|
||||||
|
| 仅计入统计(默认) | 只统计「计入统计」的记录 |
|
||||||
|
| 全部记录 | 计入与不计入的记录都统计 |
|
||||||
|
| 仅不计入 | 只统计「不计入统计」的记录 |
|
||||||
|
|
||||||
|
切换后日历中的金额、顶部合计与点击日期弹出的**当日明细**都会随之变化:明细只列出符合当前口径的记录,与汇总口径保持一致。
|
||||||
|
|
||||||
|
## 查看某天的明细
|
||||||
|
|
||||||
|
点击日历中的某一天,会弹出当天的**交易明细浮窗**:
|
||||||
|
|
||||||
|
- 顶部显示**当日合计**(收入 / 支出 / 结余);
|
||||||
|
- 下方逐条列出当天交易,每条在主行显示时间、分类、渠道与**金额**(收绿支红);
|
||||||
|
- 点击任意条目可打开该笔账单的**完整详情**(标签、账单关系、来源图片、原始数据等,为只读);
|
||||||
|
- 底部「**在收支记录中查看**」会携带当天日期与当前统计口径跳转到[收支记录](/guide/transactions),便于继续编辑整理。
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> 当日明细(按当前统计口径)最多展示前 50 条,超出时浮窗内会提示总数,可点「在收支记录中查看」查看全部。
|
||||||
|
|
||||||
|
## 链接分享与偏好
|
||||||
|
|
||||||
|
- 当前视图与年月会同步到地址栏(形如 `?view=month&y=2026&m=9`),刷新页面或把链接分享给他人,都能还原到对应月份与视图。
|
||||||
|
- **视图**(月 / 年)、**统计口径**与**最近浏览的年月**会被记住,下次进入自动还原;地址栏带参数时以参数为准。
|
||||||
|
|
||||||
|
## 小技巧
|
||||||
|
|
||||||
|
- 想知道某一天具体花在哪,直接点该日期,先看当日合计,再逐条核对明细。
|
||||||
|
- 想看全年的分布,切到「年视图」浏览各月汇总,再点开支出最高的月份查看当天明细。
|
||||||
|
- 不计入统计的记录(如借款、账户间转账)默认不参与汇总,当日明细也不会列出;如需一并查看,把统计口径切换为「全部记录」。
|
||||||
|
|
||||||
|
> 想从更大的时间跨度看趋势与占比,可使用[统计面板](/guide/dashboard)的图表与筛选。
|
||||||
@@ -53,3 +53,4 @@
|
|||||||
- 建议为以下场景建立标签:报销/待报销、旅行、大额消费、订阅、礼物、家庭、工作等。
|
- 建议为以下场景建立标签:报销/待报销、旅行、大额消费、订阅、礼物、家庭、工作等。
|
||||||
- 需要按规则自动归类时,配合[规则管理](/guide/rules)使用:规则命中后会自动应用分类与标签。
|
- 需要按规则自动归类时,配合[规则管理](/guide/rules)使用:规则命中后会自动应用分类与标签。
|
||||||
- 分类与标签都支持在[账单导入](/guide/transactions)预览阶段批量指定为默认值。
|
- 分类与标签都支持在[账单导入](/guide/transactions)预览阶段批量指定为默认值。
|
||||||
|
- 在[新增/编辑记录](/guide/transactions#手动添加记录)弹窗中,可直接点分类/标签行右侧的「新建分类」「新建标签」创建并选用,无需先到本页维护。
|
||||||
|
|||||||
+1
-1
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
自定义渠道创建后,可在以下场景直接选用:
|
自定义渠道创建后,可在以下场景直接选用:
|
||||||
|
|
||||||
- **新增 / 编辑记录**:交易渠道下拉中出现在内置渠道之后。
|
- **新增 / 编辑记录**:交易渠道下拉中出现在内置渠道之后;也可点右侧「新建渠道」直接创建并选用(不受 AI 状态影响)。
|
||||||
- **筛选与统计**:收支记录页筛选、统计面板的渠道维度与筛选均可选择自定义渠道,图表与分组会展示其名称。
|
- **筛选与统计**:收支记录页筛选、统计面板的渠道维度与筛选均可选择自定义渠道,图表与分组会展示其名称。
|
||||||
- **AI 能力**:智能查询、统计搜索与智能记账会把当前账号的自定义渠道一并作为可选渠道;新增/编辑记录时还可用「渠道 · AI 推荐」选择已有渠道,或「渠道 · AI 新建」由描述生成并创建渠道。
|
- **AI 能力**:智能查询、统计搜索与智能记账会把当前账号的自定义渠道一并作为可选渠道;新增/编辑记录时还可用「渠道 · AI 推荐」选择已有渠道,或「渠道 · AI 新建」由描述生成并创建渠道。
|
||||||
- **导出**:Excel 导出时渠道列展示自定义渠道名称。
|
- **导出**:Excel 导出时渠道列展示自定义渠道名称。
|
||||||
|
|||||||
+3
-1
@@ -1,6 +1,6 @@
|
|||||||
# 统计面板
|
# 统计面板
|
||||||
|
|
||||||
「统计面板」是登录后的默认首页,用于查看指定时间范围内的收支汇总与图表。
|
「统计面板」用于查看指定时间范围内的收支汇总与图表,可从左侧菜单进入(登录后的默认首页为[日历](/guide/calendar))。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -77,6 +77,8 @@
|
|||||||
|
|
||||||
无论从哪张图下钻,都会同时保留面板当前的统计口径、标签、金额区间与备注关键字等筛选。
|
无论从哪张图下钻,都会同时保留面板当前的统计口径、标签、金额区间与备注关键字等筛选。
|
||||||
|
|
||||||
|
> 触屏设备上,点击趋势柱或饼图扇区会先弹出确认气泡(「查看明细」/「取消」),确认后才跳转,避免滑动或误触直接跳走;趋势图的**「整列可点」在触屏端禁用**,只能点击柱子本体。桌面端行为不变。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
页面底部的「**查看收支记录**」按钮则会携带**当前全部筛选条件**跳转,便于核对整体明细。
|
页面底部的「**查看收支记录**」按钮则会携带**当前全部筛选条件**跳转,便于核对整体明细。
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
## 首次使用建议
|
## 首次使用建议
|
||||||
|
|
||||||
1. 完成数据库配置并注册登录。
|
1. 完成数据库配置并注册登录。登录后默认进入[日历](/guide/calendar),可先熟悉按天查看收支的用法。
|
||||||
2. 进入「分类管理」「标签管理」按自己的习惯调整分类与标签。
|
2. 进入「分类管理」「标签管理」按自己的习惯调整分类与标签。
|
||||||
3. 在「规则管理」配置常用自动归类规则(如「星巴克 → 餐饮」)。
|
3. 在「规则管理」配置常用自动归类规则(如「星巴克 → 餐饮」)。
|
||||||
4. 导出并导入历史账单(见[账单类型与获取](/guide/bills/overview))。
|
4. 导出并导入历史账单(见[账单类型与获取](/guide/bills/overview))。
|
||||||
@@ -61,6 +61,7 @@
|
|||||||
|
|
||||||
## 下一步
|
## 下一步
|
||||||
|
|
||||||
|
- [日历](/guide/calendar):登录后的默认首页,按天查看每日收支
|
||||||
- [统计面板](/guide/dashboard)
|
- [统计面板](/guide/dashboard)
|
||||||
- [收支记录](/guide/transactions)
|
- [收支记录](/guide/transactions)
|
||||||
- [账单导入](/guide/transactions)
|
- [账单导入](/guide/transactions)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
- [项目简介](/guide/introduction):系统定位、核心功能与技术栈
|
- [项目简介](/guide/introduction):系统定位、核心功能与技术栈
|
||||||
- [快速开始](/guide/getting-started):数据库配置、注册登录、界面语言与首次使用建议
|
- [快速开始](/guide/getting-started):数据库配置、注册登录、界面语言与首次使用建议
|
||||||
- [下载与安装](/guide/download):Windows / Linux 安装包与可执行 jar 的下载、运行与校验
|
- [下载与安装](/guide/download):Windows / Linux 安装包与可执行 jar 的下载、运行与校验
|
||||||
|
- [日历](/guide/calendar):按天查看每日收支、月视图与年视图、当日明细
|
||||||
- [统计面板](/guide/dashboard):时间范围、筛选条件与图表说明
|
- [统计面板](/guide/dashboard):时间范围、筛选条件与图表说明
|
||||||
|
|
||||||
## 记账与整理
|
## 记账与整理
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
| 收支记录 | 增删改查、分页与多条件筛选、批量设置分类/标签、批量删除、计入统计开关、备注隐藏、导出 Excel |
|
| 收支记录 | 增删改查、分页与多条件筛选、批量设置分类/标签、批量删除、计入统计开关、备注隐藏、导出 Excel |
|
||||||
| 分类与标签 | 收入/支出分类与标签的增删改查,新用户自动获得默认数据,AI 推荐 Emoji 与颜色 |
|
| 分类与标签 | 收入/支出分类与标签的增删改查,新用户自动获得默认数据,AI 推荐 Emoji 与颜色 |
|
||||||
| 交易渠道 | 内置渠道 + 自定义渠道的新建/改名/删除,改名不影响历史账单 |
|
| 交易渠道 | 内置渠道 + 自定义渠道的新建/改名/删除,改名不影响历史账单 |
|
||||||
|
| 日历 | 默认首页,月视图按天展示每日收支与当月合计,年视图一览全年各月,支持统计口径过滤与当日明细下钻 |
|
||||||
| 统计图表 | 月度收支、分类占比、收支趋势、交易渠道占比,支持按日/周/月/季/年粒度,图表可点击下钻对应明细 |
|
| 统计图表 | 月度收支、分类占比、收支趋势、交易渠道占比,支持按日/周/月/季/年粒度,图表可点击下钻对应明细 |
|
||||||
| 账单关系 | 父子/同级多笔账单关联、自动绘制关系图,AI 生成关系名称与备注 |
|
| 账单关系 | 父子/同级多笔账单关联、自动绘制关系图,AI 生成关系名称与备注 |
|
||||||
| 账单导入 | 七类账单解析、zip 解密、解析预览、按交易号去重、规则建议 |
|
| 账单导入 | 七类账单解析、zip 解密、解析预览、按交易号去重、规则建议 |
|
||||||
|
|||||||
+6
-3
@@ -9,7 +9,8 @@
|
|||||||
| 登录 | `/login` | 用户名密码登录 | 未登录访问受保护页面时自动跳转 |
|
| 登录 | `/login` | 用户名密码登录 | 未登录访问受保护页面时自动跳转 |
|
||||||
| 注册 | `/register` | 创建账号 | 登录页「没有账号?去注册」(注册开启时) |
|
| 注册 | `/register` | 创建账号 | 登录页「没有账号?去注册」(注册开启时) |
|
||||||
| 数据库初始化 | `/database-setup` | 首次配置数据库 | 数据库未配置时自动引导 |
|
| 数据库初始化 | `/database-setup` | 首次配置数据库 | 数据库未配置时自动引导 |
|
||||||
| 统计面板 | `/dashboard` | 收支汇总与图表 | 登录后默认页;左侧菜单 |
|
| 日历 | `/calendar` | 每日收支日历、月/年视图与当日明细 | **登录后默认页**;左侧菜单(默认置顶) |
|
||||||
|
| 统计面板 | `/dashboard` | 收支汇总与图表 | 左侧菜单 |
|
||||||
| 智能查数 | `/smart-query` | 自然语言转只读 SQL 查询 | 左侧菜单(**AI 启用时**) |
|
| 智能查数 | `/smart-query` | 自然语言转只读 SQL 查询 | 左侧菜单(**AI 启用时**) |
|
||||||
| 收支记录 | `/transactions` | 记录管理与**账单导入** | 左侧菜单 |
|
| 收支记录 | `/transactions` | 记录管理与**账单导入** | 左侧菜单 |
|
||||||
| 分类管理 | `/categories` | 收入/支出分类维护 | 左侧菜单 |
|
| 分类管理 | `/categories` | 收入/支出分类维护 | 左侧菜单 |
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
|
|
||||||
### 左侧菜单
|
### 左侧菜单
|
||||||
|
|
||||||
统计面板 → 智能查数(AI 启用时)→ 收支记录 → 分类管理 → 标签管理 → 规则管理 → 邮箱账单
|
日历 → 统计面板 → 智能查数(AI 启用时)→ 收支记录 → 分类管理 → 标签管理 → 规则管理 → 邮箱账单
|
||||||
|
|
||||||
左侧菜单的**顺序与显隐可自定义**(设置 → 导航设置),并在下次进入时还原。
|
左侧菜单的**顺序与显隐可自定义**(设置 → 导航设置),并在下次进入时还原。
|
||||||
|
|
||||||
@@ -44,7 +45,8 @@
|
|||||||
|
|
||||||
## 典型跳转路径
|
## 典型跳转路径
|
||||||
|
|
||||||
- **首次使用**:`/database-setup` → `/register` → `/login` → `/dashboard`
|
- **首次使用**:`/database-setup` → `/register` → `/login` → `/calendar`
|
||||||
|
- **日历看某天**:日历 → 点击某天 → 当日明细浮窗(按当前统计口径)→ 点条目查看账单详情 / 点「在收支记录中查看」跳转收支记录(按当日筛选并沿用统计口径)
|
||||||
- **手动记账**:收支记录 → 点击「新增记录」→ 表单弹窗 → 保存
|
- **手动记账**:收支记录 → 点击「新增记录」→ 表单弹窗 → 保存
|
||||||
- **查看趋势明细**:统计面板 → 点击趋势柱、分类/渠道饼图或「查看收支记录」→ 收支记录(自动带入对应筛选条件)
|
- **查看趋势明细**:统计面板 → 点击趋势柱、分类/渠道饼图或「查看收支记录」→ 收支记录(自动带入对应筛选条件)
|
||||||
- **反向跳转**:收支记录 → 点击「查看统计」→ 统计面板(还原当前筛选条件)
|
- **反向跳转**:收支记录 → 点击「查看统计」→ 统计面板(还原当前筛选条件)
|
||||||
@@ -60,6 +62,7 @@
|
|||||||
|
|
||||||
## 页面关系说明
|
## 页面关系说明
|
||||||
|
|
||||||
|
- **日历**是登录后的默认落地页:按天查看每日收支、切换月/年视图与统计口径,并可点击某天下钻到当日明细与账单详情。
|
||||||
- **收支记录**是核心页面:手动记账、账单导入、批量操作、账单关系与 AI 能力都从这里进入,导入完成后也回到该页查看。
|
- **收支记录**是核心页面:手动记账、账单导入、批量操作、账单关系与 AI 能力都从这里进入,导入完成后也回到该页查看。
|
||||||
- **账单导入**有两条独立路径:
|
- **账单导入**有两条独立路径:
|
||||||
- 收支记录页的「导入账单」**弹窗**(桌面端常用);
|
- 收支记录页的「导入账单」**弹窗**(桌面端常用);
|
||||||
|
|||||||
+15
-3
@@ -178,18 +178,28 @@
|
|||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| 类型 | 支出 / 收入 |
|
| 类型 | 支出 / 收入 |
|
||||||
| 分类 | 新增时必填 |
|
| 分类 | 新增时必填;可点右侧「新建分类」直接创建 |
|
||||||
| 金额 | 大于 0 |
|
| 金额 | 大于 0 |
|
||||||
| 交易渠道 | 可选,含内置渠道与[自定义渠道](/guide/channels);启用 AI 时可一键推荐或新建 |
|
| 交易渠道 | 可选,含内置渠道与[自定义渠道](/guide/channels);可点右侧「新建渠道」直接创建;启用 AI 时可一键推荐或新建 |
|
||||||
| 交易时间 | 默认当前时间 |
|
| 交易时间 | 默认当前时间 |
|
||||||
| 备注 | 可选 |
|
| 备注 | 可选 |
|
||||||
| 标签 | 可选,可多选 |
|
| 标签 | 可选,可多选;可点右侧「新建标签」直接创建 |
|
||||||
| 计入统计 | 默认开启;关闭后不纳入统计 |
|
| 计入统计 | 默认开启;关闭后不纳入统计 |
|
||||||
|
|
||||||
3. 点击「确定」保存。
|
3. 点击「确定」保存。
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
::: tip 记账时直接新建分类 / 标签 / 渠道
|
||||||
|
新增与编辑弹窗中,**分类**、**标签**、**交易渠道** 三行在选择框右侧各有一个「**新建分类 / 新建标签 / 新建渠道**」按钮,**不受 AI 启用状态影响**,随时可用。点击后弹出精简表单,创建完成即自动填入当前账单:
|
||||||
|
|
||||||
|
- **新建分类**:填写名称、类型(默认跟随当前账单类型)与图标;创建后自动选中,并把账单类型同步为该分类的类型。
|
||||||
|
- **新建标签**:填写名称与颜色;创建后自动追加到已选标签。
|
||||||
|
- **新建渠道**:填写名称;创建后自动选中。
|
||||||
|
|
||||||
|

|
||||||
|
:::
|
||||||
|
|
||||||
## 编辑记录
|
## 编辑记录
|
||||||
|
|
||||||
在记录行点击「编辑」即可修改记录,弹窗字段与新增一致;编辑时允许不设置分类。
|
在记录行点击「编辑」即可修改记录,弹窗字段与新增一致;编辑时允许不设置分类。
|
||||||
@@ -212,6 +222,8 @@
|
|||||||

|

|
||||||
|
|
||||||
> 「AI 新建」需先填写备注或金额,便于模型理解;生成结果会显示确认条,点击「保存并选用」才真正创建。
|
> 「AI 新建」需先填写备注或金额,便于模型理解;生成结果会显示确认条,点击「保存并选用」才真正创建。
|
||||||
|
>
|
||||||
|
> 上述 AI 辅助按钮仅在[启用 AI](/guide/ai)后出现;**分类、标签、交易渠道三行始终各有一个手动「新建」按钮**(不受 AI 状态影响),可直接填写并创建,详见[手动添加记录](#手动添加记录)中的说明。
|
||||||
|
|
||||||
编辑完成后点击「确定」保存。其他 AI 能力(批量建议、智能记账、智能查询)见 [AI 能力](/guide/ai)。
|
编辑完成后点击「确定」保存。其他 AI 能力(批量建议、智能记账、智能查询)见 [AI 能力](/guide/ai)。
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ hero:
|
|||||||
text: 个人收支管理 · 多来源账单导入 · AI 智能记账
|
text: 个人收支管理 · 多来源账单导入 · AI 智能记账
|
||||||
tagline: 支持支付宝、微信、美团、淘宝、京东、招商银行、交通银行账单导入,提供分类标签与交易渠道管理、自定义规则、账单关系、AI 建议(含多图图片记账与智能查数)与定时提醒
|
tagline: 支持支付宝、微信、美团、淘宝、京东、招商银行、交通银行账单导入,提供分类标签与交易渠道管理、自定义规则、账单关系、AI 建议(含多图图片记账与智能查数)与定时提醒
|
||||||
image:
|
image:
|
||||||
src: https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/dashboard.png
|
src: https://adcarac.oss-cn-beijing.aliyuncs.com/finance-app-docs/screenshots/calendar.png
|
||||||
alt: 统计面板
|
alt: 日历
|
||||||
actions:
|
actions:
|
||||||
- theme: brand
|
- theme: brand
|
||||||
text: 使用文档
|
text: 使用文档
|
||||||
@@ -32,6 +32,8 @@ features:
|
|||||||
details: 按关键词、收支类型、金额区间组合条件,命中后自动应用分类与标签,导入预览即展示建议。
|
details: 按关键词、收支类型、金额区间组合条件,命中后自动应用分类与标签,导入预览即展示建议。
|
||||||
- title: AI 智能能力
|
- title: AI 智能能力
|
||||||
details: 基于 DeepSeek 的分类/标签/渠道建议、自然语言查询与查数(智能查数)、文字与多图图片记账(实时进度)、分类标签渠道生成、关系命名,并统计 token 用量。
|
details: 基于 DeepSeek 的分类/标签/渠道建议、自然语言查询与查数(智能查数)、文字与多图图片记账(实时进度)、分类标签渠道生成、关系命名,并统计 token 用量。
|
||||||
|
- title: 日历视图
|
||||||
|
details: 默认首页,月视图按天展示每日收支与当月合计,年视图一览全年各月;点击某天查看当日明细并直达账单详情,支持统计口径过滤。
|
||||||
- title: 统计与图表
|
- title: 统计与图表
|
||||||
details: 月度收支汇总、分类占比、收支趋势、交易渠道占比,支持多维度筛选与自定义时间范围,图表可点击下钻明细。
|
details: 月度收支汇总、分类占比、收支趋势、交易渠道占比,支持多维度筛选与自定义时间范围,图表可点击下钻明细。
|
||||||
- title: 定时提醒与通知
|
- title: 定时提醒与通知
|
||||||
@@ -59,7 +61,7 @@ features:
|
|||||||
|
|
||||||
- 想开始使用:[快速开始](/guide/getting-started)
|
- 想开始使用:[快速开始](/guide/getting-started)
|
||||||
- 想知道各类账单怎么导出:[账单类型与获取](/guide/bills/overview)
|
- 想知道各类账单怎么导出:[账单类型与获取](/guide/bills/overview)
|
||||||
- 想了解各功能怎么用:[统计面板](/guide/dashboard) 起逐页阅读
|
- 想了解各功能怎么用:[日历](/guide/calendar) 起逐页阅读
|
||||||
- 遇到问题:[常见问题](/guide/faq)
|
- 遇到问题:[常见问题](/guide/faq)
|
||||||
|
|
||||||
### 开发文档
|
### 开发文档
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// - scripts/samples/alipay_sample.zip 样例账单存在。
|
// - scripts/samples/alipay_sample.zip 样例账单存在。
|
||||||
import { mkdir } from 'node:fs/promises'
|
import { mkdir } from 'node:fs/promises'
|
||||||
import { injectSession, launchBrowser, login, newContext } from './browser.js'
|
import { injectSession, launchBrowser, login, newContext } from './browser.js'
|
||||||
import { captureAiRule, captureBillParse, captureCards, captureEditRecord, captureModals, captureSettingsPanels, captureTrendJump } from './capture-elements.js'
|
import { captureAddRecord, captureAiRule, captureBillParse, captureCalendarDetail, captureCalendarMonth, captureCalendarYear, captureCards, captureEditRecord, captureInlineCreate, captureModals, captureSettingsPanels, captureTrendJump } from './capture-elements.js'
|
||||||
import { capturePages } from './capture-pages.js'
|
import { capturePages } from './capture-pages.js'
|
||||||
import { ELEM_DIR } from './config.js'
|
import { ELEM_DIR } from './config.js'
|
||||||
|
|
||||||
@@ -25,8 +25,13 @@ async function main(): Promise<void> {
|
|||||||
await injectSession(context, token)
|
await injectSession(context, token)
|
||||||
const page = await context.newPage()
|
const page = await context.newPage()
|
||||||
await capturePages(page)
|
await capturePages(page)
|
||||||
|
await captureCalendarMonth(page)
|
||||||
|
await captureCalendarYear(page)
|
||||||
|
await captureCalendarDetail(page)
|
||||||
|
await captureAddRecord(page)
|
||||||
await captureModals(page)
|
await captureModals(page)
|
||||||
await captureEditRecord(page)
|
await captureEditRecord(page)
|
||||||
|
await captureInlineCreate(page)
|
||||||
await captureAiRule(page)
|
await captureAiRule(page)
|
||||||
await captureSettingsPanels(page)
|
await captureSettingsPanels(page)
|
||||||
await captureBillParse(page)
|
await captureBillParse(page)
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ const CARD_SCENES: Array<[string, string, string]> = [
|
|||||||
|
|
||||||
/** 弹窗截图:文件名、路由、触发按钮文本 */
|
/** 弹窗截图:文件名、路由、触发按钮文本 */
|
||||||
const MODAL_SCENES: Array<[string, string, string]> = [
|
const MODAL_SCENES: Array<[string, string, string]> = [
|
||||||
['add-record', '/transactions', '新增记录'],
|
|
||||||
['batch-set', '/transactions', '一键设置'],
|
['batch-set', '/transactions', '一键设置'],
|
||||||
['import-bill', '/transactions', '导入账单'],
|
['import-bill', '/transactions', '导入账单'],
|
||||||
['ai-record', '/transactions', '智能记账'],
|
['ai-record', '/transactions', '智能记账'],
|
||||||
@@ -58,9 +57,11 @@ export async function captureCards(page: Page): Promise<void> {
|
|||||||
* 截取各功能弹窗。
|
* 截取各功能弹窗。
|
||||||
*
|
*
|
||||||
* @param page Page 实例
|
* @param page Page 实例
|
||||||
|
* @param only 仅截取指定场景名(可选,缺省截取全部)
|
||||||
*/
|
*/
|
||||||
export async function captureModals(page: Page): Promise<void> {
|
export async function captureModals(page: Page, only?: string[]): Promise<void> {
|
||||||
for (const [name, path, button] of MODAL_SCENES) {
|
const scenes = only ? MODAL_SCENES.filter(([name]) => only.includes(name)) : MODAL_SCENES
|
||||||
|
for (const [name, path, button] of scenes) {
|
||||||
try {
|
try {
|
||||||
await page.setViewportSize({ width: 1440, height: 1000 })
|
await page.setViewportSize({ width: 1440, height: 1000 })
|
||||||
await page.goto(BASE_URL + path)
|
await page.goto(BASE_URL + path)
|
||||||
@@ -85,6 +86,32 @@ export async function captureModals(page: Page): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取新增记录弹窗(elements/add-record.png)。
|
||||||
|
*
|
||||||
|
* 先二次加载页面,确保模块级 AI 启用状态已就绪,使弹窗完整展示 AI 辅助按钮。
|
||||||
|
*
|
||||||
|
* @param page Page 实例
|
||||||
|
*/
|
||||||
|
export async function captureAddRecord(page: Page): Promise<void> {
|
||||||
|
try {
|
||||||
|
await page.setViewportSize({ width: 1440, height: 1000 })
|
||||||
|
await page.goto(BASE_URL + '/transactions')
|
||||||
|
await waitPage(page, { selector: PAGE_READY })
|
||||||
|
await page.reload()
|
||||||
|
await waitPage(page, { selector: PAGE_READY })
|
||||||
|
await page.waitForTimeout(1500)
|
||||||
|
if (!(await clickText(page, '新增记录'))) throw new Error('未找到「新增记录」按钮')
|
||||||
|
const modal = page.locator('.n-modal').first()
|
||||||
|
await modal.waitFor({ state: 'visible', timeout: 20000 })
|
||||||
|
await page.waitForTimeout(900)
|
||||||
|
await modal.screenshot({ path: resolve(ELEM_DIR, 'add-record.png') })
|
||||||
|
console.log('[OK] modal/add-record')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`[FAIL] modal/add-record: ${err}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取账单解析预览:上传样例账单后解析。
|
* 截取账单解析预览:上传样例账单后解析。
|
||||||
*
|
*
|
||||||
@@ -321,6 +348,31 @@ export async function captureEditRecord(page: Page): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取记账弹窗内「新建分类」子弹窗(体现新增/编辑记录时可直接新建分类)。
|
||||||
|
*
|
||||||
|
* @param page Page 实例
|
||||||
|
*/
|
||||||
|
export async function captureInlineCreate(page: Page): Promise<void> {
|
||||||
|
try {
|
||||||
|
await page.setViewportSize({ width: 1440, height: 1000 })
|
||||||
|
await page.goto(BASE_URL + '/transactions')
|
||||||
|
await waitPage(page, { selector: PAGE_READY })
|
||||||
|
if (!(await clickText(page, '新增记录'))) throw new Error('未找到「新增记录」按钮')
|
||||||
|
const modal = page.locator('.n-modal').first()
|
||||||
|
await modal.waitFor({ state: 'visible', timeout: 20000 })
|
||||||
|
if (!(await clickText(page, '新建分类'))) throw new Error('未找到「新建分类」按钮')
|
||||||
|
await page.waitForTimeout(800)
|
||||||
|
// 子弹窗为后打开的最后一层弹窗
|
||||||
|
const sub = page.locator('.n-modal').last()
|
||||||
|
await sub.waitFor({ state: 'visible', timeout: 8000 })
|
||||||
|
await sub.screenshot({ path: resolve(ELEM_DIR, 'record-new-category.png') })
|
||||||
|
console.log('[OK] modal/record-new-category')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`[FAIL] modal/record-new-category: ${err}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取「AI 生成规则」的两步弹窗:步骤一选择记录、步骤二预览规则建议。
|
* 截取「AI 生成规则」的两步弹窗:步骤一选择记录、步骤二预览规则建议。
|
||||||
*
|
*
|
||||||
@@ -466,6 +518,76 @@ export async function captureSqlQuery(page: Page): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取日历「月视图」整页:写入 screenshots/calendar.png。
|
||||||
|
*
|
||||||
|
* @param page Page 实例
|
||||||
|
*/
|
||||||
|
export async function captureCalendarMonth(page: Page): Promise<void> {
|
||||||
|
try {
|
||||||
|
await page.setViewportSize({ width: 1440, height: 1280 })
|
||||||
|
await page.goto(BASE_URL + '/calendar?view=month')
|
||||||
|
await waitPage(page, { selector: '.n-calendar' })
|
||||||
|
await page.locator('.day-cell__row').first().waitFor({ state: 'visible', timeout: 20000 }).catch(() => undefined)
|
||||||
|
await page.waitForTimeout(600)
|
||||||
|
await page.screenshot({ path: resolve(OUT_DIR, 'calendar.png') })
|
||||||
|
console.log('[OK] calendar')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`[FAIL] calendar: ${err}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取日历「年视图」:切换到年视图后截取。
|
||||||
|
*
|
||||||
|
* @param page Page 实例
|
||||||
|
*/
|
||||||
|
export async function captureCalendarYear(page: Page): Promise<void> {
|
||||||
|
try {
|
||||||
|
await page.setViewportSize({ width: 1440, height: 1000 })
|
||||||
|
await page.goto(BASE_URL + '/calendar?view=month')
|
||||||
|
await waitPage(page, { selector: '.n-calendar' })
|
||||||
|
const viewBtn = page.locator('.cal-toolbar__view').first()
|
||||||
|
await viewBtn.waitFor({ state: 'visible', timeout: 15000 })
|
||||||
|
await viewBtn.evaluate((el) => (el as HTMLElement).click())
|
||||||
|
await page.locator('.year-cell').first().waitFor({ state: 'visible', timeout: 15000 })
|
||||||
|
await page.waitForLoadState('networkidle', { timeout: 8000 }).catch(() => undefined)
|
||||||
|
await page.waitForTimeout(800)
|
||||||
|
await page.screenshot({ path: resolve(ELEM_DIR, 'calendar-year.png') })
|
||||||
|
console.log('[OK] calendar-year')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`[FAIL] calendar-year: ${err}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 截取日历「当日明细浮窗」:点击某天有数据的日期后截取浮窗。
|
||||||
|
*
|
||||||
|
* @param page Page 实例
|
||||||
|
*/
|
||||||
|
export async function captureCalendarDetail(page: Page): Promise<void> {
|
||||||
|
try {
|
||||||
|
await page.setViewportSize({ width: 1440, height: 1100 })
|
||||||
|
await page.goto(BASE_URL + '/calendar?view=month')
|
||||||
|
await waitPage(page, { selector: '.n-calendar' })
|
||||||
|
await page.locator('.day-cell__row').first().waitFor({ state: 'visible', timeout: 20000 })
|
||||||
|
const cell = page
|
||||||
|
.locator('.n-calendar-cell')
|
||||||
|
.filter({ has: page.locator('.day-cell__row') })
|
||||||
|
.first()
|
||||||
|
await cell.evaluate((el) => (el as HTMLElement).click())
|
||||||
|
const modal = page.locator('.n-modal', { hasText: '交易明细' }).first()
|
||||||
|
await modal.waitFor({ state: 'visible', timeout: 20000 })
|
||||||
|
// 等待明细列表加载完成(出现条目后再截图,避免截到加载中状态)
|
||||||
|
await modal.locator('.detail-item').first().waitFor({ state: 'visible', timeout: 20000 })
|
||||||
|
await page.waitForTimeout(600)
|
||||||
|
await modal.screenshot({ path: resolve(ELEM_DIR, 'calendar-day-detail.png') })
|
||||||
|
console.log('[OK] calendar-day-detail')
|
||||||
|
} catch (err) {
|
||||||
|
console.log(`[FAIL] calendar-day-detail: ${err}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function main(): Promise<void> {
|
async function main(): Promise<void> {
|
||||||
const browser = await launchBrowser()
|
const browser = await launchBrowser()
|
||||||
try {
|
try {
|
||||||
@@ -478,8 +600,13 @@ async function main(): Promise<void> {
|
|||||||
const context = await newContext(browser)
|
const context = await newContext(browser)
|
||||||
await injectSession(context, token)
|
await injectSession(context, token)
|
||||||
const page = await context.newPage()
|
const page = await context.newPage()
|
||||||
|
await captureCalendarMonth(page)
|
||||||
|
await captureCalendarYear(page)
|
||||||
|
await captureCalendarDetail(page)
|
||||||
|
await captureAddRecord(page)
|
||||||
await captureModals(page)
|
await captureModals(page)
|
||||||
await captureEditRecord(page)
|
await captureEditRecord(page)
|
||||||
|
await captureInlineCreate(page)
|
||||||
await captureAiRule(page)
|
await captureAiRule(page)
|
||||||
await captureAiRecordImage(page)
|
await captureAiRecordImage(page)
|
||||||
await captureBillDetail(page)
|
await captureBillDetail(page)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { BASE_URL, OUT_DIR } from './config.js'
|
|||||||
const PAGES: Array<[string, string, number, number, string]> = [
|
const PAGES: Array<[string, string, number, number, string]> = [
|
||||||
['login', '/login', 1440, 900, '.n-card'],
|
['login', '/login', 1440, 900, '.n-card'],
|
||||||
['register', '/register', 1440, 900, '.n-card'],
|
['register', '/register', 1440, 900, '.n-card'],
|
||||||
|
['calendar', '/calendar', 1440, 1280, '.n-calendar'],
|
||||||
['dashboard', '/dashboard', 1440, 1280, 'canvas'],
|
['dashboard', '/dashboard', 1440, 1280, 'canvas'],
|
||||||
['sql-query', '/smart-query', 1440, 1180, '.n-card'],
|
['sql-query', '/smart-query', 1440, 1180, '.n-card'],
|
||||||
['transactions', '/transactions', 1720, 1200, '.n-data-table-tbody tr'],
|
['transactions', '/transactions', 1720, 1200, '.n-data-table-tbody tr'],
|
||||||
@@ -28,12 +29,14 @@ const PAGES: Array<[string, string, number, number, string]> = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 截取全部整页。
|
* 截取整页。
|
||||||
*
|
*
|
||||||
* @param page Page 实例
|
* @param page Page 实例
|
||||||
|
* @param only 仅截取指定页面名(可选,缺省截取全部)
|
||||||
*/
|
*/
|
||||||
export async function capturePages(page: Page): Promise<void> {
|
export async function capturePages(page: Page, only?: string[]): Promise<void> {
|
||||||
for (const [name, path, width, height, selector] of PAGES) {
|
const pages = only ? PAGES.filter(([name]) => only.includes(name)) : PAGES
|
||||||
|
for (const [name, path, width, height, selector] of pages) {
|
||||||
try {
|
try {
|
||||||
await page.setViewportSize({ width, height })
|
await page.setViewportSize({ width, height })
|
||||||
await page.goto(BASE_URL + path)
|
await page.goto(BASE_URL + path)
|
||||||
|
|||||||
Reference in New Issue
Block a user