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:
@@ -16,7 +16,6 @@ const CARD_SCENES: Array<[string, string, string]> = [
|
||||
|
||||
/** 弹窗截图:文件名、路由、触发按钮文本 */
|
||||
const MODAL_SCENES: Array<[string, string, string]> = [
|
||||
['add-record', '/transactions', '新增记录'],
|
||||
['batch-set', '/transactions', '一键设置'],
|
||||
['import-bill', '/transactions', '导入账单'],
|
||||
['ai-record', '/transactions', '智能记账'],
|
||||
@@ -58,9 +57,11 @@ export async function captureCards(page: Page): Promise<void> {
|
||||
* 截取各功能弹窗。
|
||||
*
|
||||
* @param page Page 实例
|
||||
* @param only 仅截取指定场景名(可选,缺省截取全部)
|
||||
*/
|
||||
export async function captureModals(page: Page): Promise<void> {
|
||||
for (const [name, path, button] of MODAL_SCENES) {
|
||||
export async function captureModals(page: Page, only?: string[]): Promise<void> {
|
||||
const scenes = only ? MODAL_SCENES.filter(([name]) => only.includes(name)) : MODAL_SCENES
|
||||
for (const [name, path, button] of scenes) {
|
||||
try {
|
||||
await page.setViewportSize({ width: 1440, height: 1000 })
|
||||
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 生成规则」的两步弹窗:步骤一选择记录、步骤二预览规则建议。
|
||||
*
|
||||
@@ -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> {
|
||||
const browser = await launchBrowser()
|
||||
try {
|
||||
@@ -478,8 +600,13 @@ async function main(): Promise<void> {
|
||||
const context = await newContext(browser)
|
||||
await injectSession(context, token)
|
||||
const page = await context.newPage()
|
||||
await captureCalendarMonth(page)
|
||||
await captureCalendarYear(page)
|
||||
await captureCalendarDetail(page)
|
||||
await captureAddRecord(page)
|
||||
await captureModals(page)
|
||||
await captureEditRecord(page)
|
||||
await captureInlineCreate(page)
|
||||
await captureAiRule(page)
|
||||
await captureAiRecordImage(page)
|
||||
await captureBillDetail(page)
|
||||
|
||||
Reference in New Issue
Block a user