feat(admin): standard pagination + synced profile columns on users list

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-22 18:10:53 +08:00
parent 2f6b6afc92
commit eebf3b3334
12 changed files with 495 additions and 59 deletions
+67 -1
View File
@@ -12,8 +12,10 @@ test.use({ testIdAttribute: 'data-test' })
const SUFFIX = Date.now().toString(36) + Math.random().toString(36).slice(2, 6)
const SLOT_NAME = `E2E展示位 ${SUFFIX}`
const V2_SLOT_NAME = `E2E展示位v2 ${SUFFIX}`
const ALBUM_A_TITLE = `E2E嵌入相册A ${SUFFIX}`
const ALBUM_B_TITLE = `E2E嵌入相册B ${SUFFIX}`
const ALBUM_C_TITLE = `E2E嵌入相册C ${SUFFIX}`
interface SeededAlbum {
id: string
@@ -55,10 +57,11 @@ function slotRow(page: Page, name: string) {
return page.getByTestId('embed-slots-table').locator('tr', { hasText: name })
}
/** ov 公开嵌入 feed 形状(断言关心的子集) */
/** ov 公开嵌入 feed 形状(断言关心的子集;settings 为 UI-04 v2 投影断言) */
interface FeedBody {
album: { publicToken: string; title: string }
photos: Array<{ photoId: string }>
settings: { displayMode: string; scrollSpeed: number; reactionsEnabled: boolean }
}
/** ov 公开嵌入 feed(观众侧权威断言;断言侧直接读 ov 副本端点) */
@@ -82,6 +85,8 @@ test.describe.serial('embed slot management (P4b Task 5)', () => {
await page.getByTestId('slot-create-btn').click()
await expect(page.getByTestId('slot-form-dialog')).toBeVisible()
await page.getByTestId('slot-form-name').fill(SLOT_NAME)
// UI-04:新建默认「照片上滚」(v2)——本用例回归旧版轮播路径,先显式切换
await page.getByTestId('slot-form-mode-carousel').click()
// 设置表单:位置/间隔(其余取缺省值;编辑载荷映射由 vitest 覆盖)
await page.getByTestId('slot-form-position').click()
await page.getByTestId('slot-form-position-left').click()
@@ -198,4 +203,65 @@ test.describe.serial('embed slot management (P4b Task 5)', () => {
seedFixture('sync-flush')
expect((await ovFeed(page, slotToken)).status).toBe(404)
})
test('UI-04 v2 新建:照片上滚表单/真实组件预览/模拟按钮 → v2 代码卡 → ov settings 投影', async ({
page
}) => {
const albumC = await seedOvVisibleAlbum(page, ALBUM_C_TITLE, 2)
await loginAsAdmin(page)
await page.goto('/#/system/embed-slots')
await expect(page.getByTestId('embed-slots-table')).toBeVisible()
await page.getByTestId('slot-create-btn').click()
await expect(page.getByTestId('slot-form-dialog')).toBeVisible()
await page.getByTestId('slot-form-name').fill(V2_SLOT_NAME)
// 默认即「照片上滚」:v2 字段组可见、v1 布局字段隐藏(§7.2 不偷偷生效)。
await expect(page.getByTestId('slot-form-mode-stream')).toBeVisible()
await expect(page.getByTestId('slot-form-fixed-size')).toContainText('195')
await expect(page.getByTestId('slot-form-speed')).toBeVisible()
await expect(page.getByTestId('slot-form-reactions')).toBeVisible()
await expect(page.getByTestId('slot-form-interval')).toHaveCount(0)
await expect(page.getByTestId('slot-form-size')).toHaveCount(0)
// 真实组件预览(§8.2):iframe 挂载 + 模拟点赞按钮在工具区。
await expect(page.getByTestId('embed-preview-v2-iframe')).toBeVisible()
await expect(page.getByTestId('embed-preview-sim-like')).toBeVisible()
// 速度调整(24 px/s):滑轨点击定位((24-8)/(32-8)*180px ≈ 120)后断言值。
await page.getByTestId('slot-form-speed').click({ position: { x: 120, y: 10 } })
await expect(page.getByTestId('slot-form-speed-value')).toContainText('24')
await page.getByTestId('slot-form-submit').click()
await expect(page.getByTestId('slot-form-dialog')).toBeHidden()
const row = slotRow(page, V2_SLOT_NAME)
await expect(row).toBeVisible()
// 嵌入代码卡:v2 入口(§8.2 生成的接入代码使用 v2)。
await row.getByTestId('slot-code-btn').click()
await expect(page.getByTestId('embed-code-dialog')).toBeVisible()
const v2Token = ((await page.getByTestId('embed-code-token').textContent()) ?? '').trim()
expect(v2Token).toMatch(/^[0-9a-z]{20,32}$/)
await expect(page.getByTestId('embed-code-snippet')).toContainText(
`http://127.0.0.1:5175/embed/v2/loader.js`
)
await expect(page.getByTestId('embed-code-snippet')).toContainText(`data-slot="${v2Token}"`)
await page.getByTestId('embed-code-close').click()
// 绑定相册 + 排空 → ov 公开 feed settings 携带 v2 投影(保存与真实效果一致)。
await row.getByTestId('slot-bind-btn').click()
await page.getByTestId('slot-bind-select').click()
await page.getByTestId('slot-bind-select').locator('input').fill(SUFFIX)
await page.getByTestId(`slot-bind-option-${albumC.id}`).click()
await page.getByTestId('slot-bind-submit').click()
await page.locator('.el-message-box').getByRole('button', { name: '确定' }).click()
await expect(page.getByTestId('slot-bind-dialog')).toBeHidden()
seedFixture('sync-flush')
const feed = await ovFeed(page, v2Token)
expect(feed.status).toBe(200)
expect(feed.body.settings.displayMode).toBe('vertical-stream')
expect(feed.body.settings.scrollSpeed).toBe(24)
expect(feed.body.settings.reactionsEnabled).toBe(true)
})
})