From 83cee61476b31cbd44aa7a582a78ac25a7faf628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BB=9D=E5=B0=98?= <237809796@qq.com> Date: Mon, 22 Jun 2026 01:24:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E:=20=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E5=88=86=E9=A1=B5UI(Paginator=E7=BB=84=E4=BB=B6+=E4=B8=89?= =?UTF-8?q?=E8=A7=86=E5=9B=BE=E6=8E=A5=E5=85=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Paginator.vue复用组件(客户端切片,不发新IPC,数据量小前瞻基建) Tasks/Ideas/Projects.vue接store列表切片(pagedProjects/pagedIdeas) 向后兼容铁律:pageSize=0整组件v-if隐藏+切片返全量,等价改造前行为 旧调用方(store.loadTasks等签名)零改动,分页状态纯前端ref 筛选/排序变化page重置1防越界空页;i18n双语pagination键齐备 --- src/components/Paginator.vue | 168 +++++++++++++++++++++++++++++++++++ src/i18n/en/common.ts | 7 ++ src/i18n/zh-CN/common.ts | 7 ++ src/views/Ideas.vue | 26 +++++- src/views/Projects.vue | 21 ++++- src/views/Tasks.vue | 21 ++++- 6 files changed, 244 insertions(+), 6 deletions(-) create mode 100644 src/components/Paginator.vue diff --git a/src/components/Paginator.vue b/src/components/Paginator.vue new file mode 100644 index 0000000..de8aaf7 --- /dev/null +++ b/src/components/Paginator.vue @@ -0,0 +1,168 @@ + + + + + diff --git a/src/i18n/en/common.ts b/src/i18n/en/common.ts index d517b39..c53d03e 100644 --- a/src/i18n/en/common.ts +++ b/src/i18n/en/common.ts @@ -14,5 +14,12 @@ export default { close: 'Close', loading: 'Loading…', unknownError: 'Unknown error', + // Pagination UI (F-260621-02 P3 baseline; off by default, opt-in per-page) + pagination: { + prev: 'Prev', + next: 'Next', + perPage: 'Per page', + total: '{n} total', + }, }, } diff --git a/src/i18n/zh-CN/common.ts b/src/i18n/zh-CN/common.ts index 8abb61d..f91d864 100644 --- a/src/i18n/zh-CN/common.ts +++ b/src/i18n/zh-CN/common.ts @@ -14,5 +14,12 @@ export default { close: '关闭', loading: '加载中…', unknownError: '未知错误', + // 分页 UI(F-260621-02 P3 基建,默认不分页,用户选每页 N 条才触发) + pagination: { + prev: '上一页', + next: '下一页', + perPage: '每页', + total: '共 {n} 条', + }, }, } diff --git a/src/views/Ideas.vue b/src/views/Ideas.vue index 9d0905c..a4522d5 100644 --- a/src/views/Ideas.vue +++ b/src/views/Ideas.vue @@ -52,7 +52,7 @@
{{ $t('ideas.listEmpty') }}
+ + @@ -132,6 +138,7 @@ import { stripMd } from '../utils/markdown' import ConfirmDialog from '../components/ConfirmDialog.vue' import IdeaDetail from '../components/ideas/IdeaDetail.vue' import { useConfirm } from '../composables/useConfirm' +import Paginator from '../components/Paginator.vue' const { t } = useI18n() const router = useRouter() @@ -149,6 +156,10 @@ const searchQuery = ref('') // 列表排序:score 高分在前 / time 新在前(默认 score,避免高分灵感被淹没) const sortMode = ref<'score' | 'time'>('score') +// 分页(F-260621-02 P3):pageSize=0 → 全量(向后兼容,等价改造前);用户选 N → 客户端切片 +const page = ref(1) +const pageSize = ref(0) + // ── 新建灵感模态框 ── const showCaptureModal = ref(false) const newIdeaTitle = ref('') @@ -218,9 +229,9 @@ async function reloadIdeas(immediate = false) { } // 筛选/排序变化即时重载;keyword 输入防抖重载 -watch(activeFilter, () => void reloadIdeas(true)) -watch(sortMode, () => void reloadIdeas(true)) -watch(searchQuery, () => void reloadIdeas(false)) +watch(activeFilter, () => { page.value = 1; void reloadIdeas(true) }) +watch(sortMode, () => { page.value = 1; void reloadIdeas(true) }) +watch(searchQuery, () => { page.value = 1; void reloadIdeas(false) }) const filteredIdeas = computed(() => { let ideas = store.ideas @@ -237,6 +248,13 @@ const filteredIdeas = computed(() => { return ideas }) +// 分页视图(F-260621-02 P3):pageSize=0 → 全量(等价改造前);否则取当前页窗口。 +const pagedIdeas = computed(() => { + if (pageSize.value <= 0) return filteredIdeas.value + const start = (page.value - 1) * pageSize.value + return filteredIdeas.value.slice(start, start + pageSize.value) +}) + const currentIdea = computed(() => { if (!selectedId.value) return null return store.ideas.find(i => i.id === selectedId.value) ?? null diff --git a/src/views/Projects.vue b/src/views/Projects.vue index f748885..92fab5e 100644 --- a/src/views/Projects.vue +++ b/src/views/Projects.vue @@ -140,9 +140,16 @@
- +
+ + +
{{ $t('projects.empty') }} @@ -165,6 +172,7 @@ import { projectApi } from '@/api' import { formatDate } from '@/utils/time' import ConfirmDialog from '@/components/ConfirmDialog.vue' import ProjectCard from '@/components/project/ProjectCard.vue' +import Paginator from '@/components/Paginator.vue' import { useConfirm } from '@/composables/useConfirm' import type { ProjectRecord } from '@/api/types' import type { ScannedProjectItem } from '@/api/project' @@ -172,6 +180,17 @@ import type { ScannedProjectItem } from '@/api/project' const store = useProjectStore() const { t } = useI18n() +// 分页(F-260621-02 P3):pageSize=0 → 全量(向后兼容,等价改造前);用户选 N → 客户端切片 +const page = ref(1) +const pageSize = ref(0) + +// 分页视图:pageSize=0 → 全量;否则取当前页窗口 +const pagedProjects = computed(() => { + if (pageSize.value <= 0) return store.projects + const start = (page.value - 1) * pageSize.value + return store.projects.slice(start, start + pageSize.value) +}) + // 状态映射统一走 ../constants/project(与 ProjectDetail/Tasks/Dashboard 一致) // formatDate 由 ../utils/time 提供(统一毫秒字符串解析,根治 Invalid Date) diff --git a/src/views/Tasks.vue b/src/views/Tasks.vue index 0925f69..a798703 100644 --- a/src/views/Tasks.vue +++ b/src/views/Tasks.vue @@ -77,6 +77,13 @@
+ + +