task-273(验收反馈): 店铺数据卡片宫格排(一行3个/一页9张+卡片分页)
This commit is contained in:
@@ -30,6 +30,9 @@ const groups = ref<ShopDataTaskGroup[]>([])
|
|||||||
const totalShops = ref(0)
|
const totalShops = ref(0)
|
||||||
const page = ref(1)
|
const page = ref(1)
|
||||||
const pageSize = 20
|
const pageSize = 20
|
||||||
|
// 卡片宫格分页:一行 3 个、一页 9 张卡片(在店铺分页的结果文件内翻页)。
|
||||||
|
const cardPage = ref(1)
|
||||||
|
const cardPageSize = 9
|
||||||
|
|
||||||
const filter = reactive<ShopDataFilter & { dateRange: string[] }>({ ...createShopDataFilter(), dateRange: [] })
|
const filter = reactive<ShopDataFilter & { dateRange: string[] }>({ ...createShopDataFilter(), dateRange: [] })
|
||||||
const selection = ref<Set<string>>(new Set())
|
const selection = ref<Set<string>>(new Set())
|
||||||
@@ -90,8 +93,15 @@ function reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const allResultRows = computed(() => groups.value.flatMap((group) => group.results))
|
const allResultRows = computed(() => groups.value.flatMap((group) => group.results))
|
||||||
|
const pagedResultRows = computed(() =>
|
||||||
|
allResultRows.value.slice((cardPage.value - 1) * cardPageSize, cardPage.value * cardPageSize),
|
||||||
|
)
|
||||||
const selectionCount = computed(() => countShopDataSelection(selection.value))
|
const selectionCount = computed(() => countShopDataSelection(selection.value))
|
||||||
|
|
||||||
|
function changeCardPage(p: number) {
|
||||||
|
cardPage.value = p
|
||||||
|
}
|
||||||
|
|
||||||
function resultFileCount(): number {
|
function resultFileCount(): number {
|
||||||
return groups.value.reduce((sum, group) => sum + group.results.length, 0)
|
return groups.value.reduce((sum, group) => sum + group.results.length, 0)
|
||||||
}
|
}
|
||||||
@@ -274,12 +284,12 @@ onMounted(load)
|
|||||||
:total="totalShops"
|
:total="totalShops"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:current-page="page"
|
:current-page="page"
|
||||||
@current-change="(p: number) => { page = p; selection = new Set(); load() }"
|
@current-change="(p: number) => { page = p; cardPage = 1; selection = new Set(); load() }"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="allResultRows.length" class="shop-card-grid">
|
<div v-if="allResultRows.length" class="shop-card-grid">
|
||||||
<article v-for="row in allResultRows" :key="row.resultId || `${row.taskNo}-${row.filename}`" class="shop-card">
|
<article v-for="row in pagedResultRows" :key="row.resultId || `${row.taskNo}-${row.filename}`" class="shop-card">
|
||||||
<header class="shop-card-head">
|
<header class="shop-card-head">
|
||||||
<span class="shop-name" :title="row.shopName || '-'">{{ row.shopName || '-' }}</span>
|
<span class="shop-name" :title="row.shopName || '-'">{{ row.shopName || '-' }}</span>
|
||||||
</header>
|
</header>
|
||||||
@@ -335,6 +345,16 @@ onMounted(load)
|
|||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="allResultRows.length > cardPageSize" class="table-footer">
|
||||||
|
<el-pagination
|
||||||
|
background
|
||||||
|
layout="prev, pager, next"
|
||||||
|
:total="allResultRows.length"
|
||||||
|
:page-size="cardPageSize"
|
||||||
|
:current-page="cardPage"
|
||||||
|
@current-change="changeCardPage"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<el-empty v-else-if="!loading" description="暂无符合条件的店铺数据任务" />
|
<el-empty v-else-if="!loading" description="暂无符合条件的店铺数据任务" />
|
||||||
|
|
||||||
@@ -366,7 +386,7 @@ onMounted(load)
|
|||||||
.f-item.wide { width: 340px; }
|
.f-item.wide { width: 340px; }
|
||||||
.f-item.btn-row { flex-direction: row; align-items: flex-end; gap: 8px; width: auto; }
|
.f-item.btn-row { flex-direction: row; align-items: flex-end; gap: 8px; width: auto; }
|
||||||
.shop-summary-row { display: flex; justify-content: space-between; align-items: center; color: var(--el-text-color-secondary); font-size: 13px; }
|
.shop-summary-row { display: flex; justify-content: space-between; align-items: center; color: var(--el-text-color-secondary); font-size: 13px; }
|
||||||
.shop-card-grid { display: flex; flex-direction: column; gap: 14px; }
|
.shop-card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
|
||||||
.shop-card { border: 1px solid var(--el-border-color); border-radius: 12px; background: #fff; box-shadow: 0 1px 2px rgba(39, 67, 94, 0.04), 0 14px 30px -24px rgba(39, 67, 94, 0.28); overflow: hidden; }
|
.shop-card { border: 1px solid var(--el-border-color); border-radius: 12px; background: #fff; box-shadow: 0 1px 2px rgba(39, 67, 94, 0.04), 0 14px 30px -24px rgba(39, 67, 94, 0.28); overflow: hidden; }
|
||||||
.shop-card-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--el-border-color-lighter); }
|
.shop-card-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--el-border-color-lighter); }
|
||||||
.shop-name { font-weight: 600; color: var(--el-text-color-primary); }
|
.shop-name { font-weight: 600; color: var(--el-text-color-primary); }
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import { readSource } from './helpers.ts'
|
|||||||
|
|
||||||
test('align_shop_data_cards_per_task', () => {
|
test('align_shop_data_cards_per_task', () => {
|
||||||
const page = readSource('src/pages/tasks/ShopDataTasksPage.vue')
|
const page = readSource('src/pages/tasks/ShopDataTasksPage.vue')
|
||||||
// 每任务一张卡:以 resultRow 迭代渲染卡片,不再按店铺聚合。
|
// 每任务一张卡:以 resultRow 迭代渲染卡片(宫格分页后绑定 pagedResultRows),不再按店铺聚合。
|
||||||
assert.match(page, /v-for="row in allResultRows"/, '逐任务卡片渲染')
|
assert.match(page, /v-for="row in pagedResultRows"/, '逐任务卡片渲染')
|
||||||
assert.doesNotMatch(page, /v-for="group in groups"/, '去掉按店铺聚合卡片')
|
assert.doesNotMatch(page, /v-for="group in groups"/, '去掉按店铺聚合卡片')
|
||||||
// 卡片结构:店铺名头 + 任务号/状态 + 分组/最新/国家/文件 信息行 + 下载文件/删除。
|
// 卡片结构:店铺名头 + 任务号/状态 + 分组/最新/国家/文件 信息行 + 下载文件/删除。
|
||||||
assert.match(page, /任务 {{ row\.taskNo \|\| row\.resultId }}|任务 {{ row\.taskNo/, '卡片含任务号')
|
assert.match(page, /任务 {{ row\.taskNo \|\| row\.resultId }}|任务 {{ row\.taskNo/, '卡片含任务号')
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import test from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { readSource } from './helpers.ts'
|
||||||
|
|
||||||
|
// 验收反馈:店铺数据记录卡片用宫格排(一行 3 个、一页 9 张卡片)+ 分页组件翻页。
|
||||||
|
|
||||||
|
const PAGE = 'src/pages/tasks/ShopDataTasksPage.vue'
|
||||||
|
|
||||||
|
test('align_shop_data_grid_normal_primary_path', () => {
|
||||||
|
const src = readSource(PAGE)
|
||||||
|
assert.match(src, /grid-template-columns:\s*repeat\(3,\s*1fr\)/, '卡片容器应为 3 列宫格')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('align_shop_data_grid_normal_variant_input', () => {
|
||||||
|
const src = readSource(PAGE)
|
||||||
|
assert.match(src, /cardPageSize\s*=\s*9|pageSize\s*=\s*9/, '卡片分页每页 9 张')
|
||||||
|
assert.match(src, /cardPage\b/, '应有卡片页状态')
|
||||||
|
assert.match(src, /pagedResultRows|cardPageRows/, '卡片应绑定按 9 张切片的数据')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('align_shop_data_grid_boundary_empty_input', () => {
|
||||||
|
// 卡片区下方有翻页组件(prev/next),与店铺分页并存。
|
||||||
|
const src = readSource(PAGE)
|
||||||
|
const count = (src.match(/el-pagination/g) || []).length
|
||||||
|
assert.ok(count >= 2, '页面应含店铺分页 + 卡片分页两处 el-pagination')
|
||||||
|
assert.match(src, /layout="prev, pager, next"/, '卡片分页含上一页/下一页')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('align_shop_data_grid_boundary_single_item', () => {
|
||||||
|
// 卡片渲染绑定分页后的数组而非全量。
|
||||||
|
const src = readSource(PAGE)
|
||||||
|
assert.match(src, /v-for="row in pagedResultRows"/, '卡片 v-for 使用分页后数组')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('align_shop_data_grid_repeated_operation_is_idempotent', () => {
|
||||||
|
// 切店铺页时卡片页重置为第一页,避免空页。
|
||||||
|
const src = readSource(PAGE)
|
||||||
|
assert.match(src, /cardPage\s*(?:\.value)?\s*=\s*1/, '切页需重置卡片页到 1')
|
||||||
|
})
|
||||||
@@ -10,7 +10,7 @@ test('test_task_266_view_normal_primary_path', () => {
|
|||||||
// 视图已改为「每条任务一张卡」(对齐 admin.js renderShopDataRecordTable)。
|
// 视图已改为「每条任务一张卡」(对齐 admin.js renderShopDataRecordTable)。
|
||||||
const page = readSource('src/pages/tasks/ShopDataTasksPage.vue')
|
const page = readSource('src/pages/tasks/ShopDataTasksPage.vue')
|
||||||
assert.match(page, /shop-card-grid/, '需任务卡片网格')
|
assert.match(page, /shop-card-grid/, '需任务卡片网格')
|
||||||
assert.match(page, /v-for="row in allResultRows"/, '逐任务渲染卡片')
|
assert.match(page, /v-for="row in pagedResultRows"/, '逐任务渲染卡片')
|
||||||
assert.match(page, /shop-card-task-no/, '卡片含任务号')
|
assert.match(page, /shop-card-task-no/, '卡片含任务号')
|
||||||
assert.match(page, /暂无符合条件的店铺数据任务/, '空态文案')
|
assert.match(page, /暂无符合条件的店铺数据任务/, '空态文案')
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user