Browse Source

作品数据改成分页

Ethanfly 13 hours ago
parent
commit
61bcc729e2

+ 42 - 4
client/src/views/Analytics/Account/index.vue

@@ -278,7 +278,7 @@
           </el-tab-pane>
 
           <el-tab-pane label="作品" name="works">
-            <el-table :data="detailWorks" v-loading="detailLoading" stripe>
+            <el-table :data="pagedDetailWorks" v-loading="detailLoading" stripe>
               <el-table-column label="标题" min-width="260">
                 <template #default="{ row }">
                   <div class="work-title-cell">
@@ -317,6 +317,19 @@
                 </template>
               </el-table-column>
             </el-table>
+            <div
+              class="pagination-wrapper"
+              v-if="detailWorksTotal > detailWorksPageSize"
+            >
+              <el-pagination
+                v-model:current-page="detailWorksPage"
+                :page-size="detailWorksPageSize"
+                :total="detailWorksTotal"
+                layout="total, prev, pager, next"
+                small
+                @current-change="handleDetailWorksPageChange"
+              />
+            </div>
           </el-tab-pane>
         </el-tabs>
       </div>
@@ -510,6 +523,22 @@ const detailWorks = ref<Array<{
   likesCount: number;
 }>>([]);
 
+// 账号详情 - 作品列表分页
+const detailWorksPage = ref(1);
+const detailWorksPageSize = ref(15);
+
+const pagedDetailWorks = computed(() => {
+  const start = (detailWorksPage.value - 1) * detailWorksPageSize.value;
+  const end = start + detailWorksPageSize.value;
+  return detailWorks.value.slice(start, end);
+});
+
+const detailWorksTotal = computed(() => detailWorks.value.length);
+
+function handleDetailWorksPageChange(page: number) {
+  detailWorksPage.value = page;
+}
+
 function getPlatformName(platform: PlatformType) {
   return PLATFORMS[platform]?.name || platform;
 }
@@ -572,9 +601,10 @@ function handleQuery() {
 async function loadGroups() {
   try {
     const res = await request.get('/api/accounts/groups');
-    if ((res as any).success && (res as any).data) {
-      accountGroups.value = (res as any).data || [];
-    } else if ((res as any).data?.success) {
+    // 新接口:request 已经解包,res 就是分组数组
+    if (Array.isArray(res)) {
+      accountGroups.value = res as AccountGroup[];
+    } else if ((res as any)?.data?.data) {
       // 兼容旧返回格式 { data: { success, data } }
       accountGroups.value = (res as any).data.data || [];
     }
@@ -734,6 +764,8 @@ async function loadAccountDetailData() {
 
       detailDailyData.value = Array.isArray(data.dailyData) ? data.dailyData : [];
       detailWorks.value = Array.isArray(data.works) ? data.works : [];
+      // 重新加载详情数据时,重置作品分页
+      detailWorksPage.value = 1;
     }
   } catch (error) {
     console.error('加载账号详情失败:', error);
@@ -1042,6 +1074,12 @@ onMounted(() => {
       color: $text-primary;
     }
   }
+
+  .pagination-wrapper {
+    padding-top: 12px;
+    display: flex;
+    justify-content: flex-end;
+  }
 }
 
 @media (max-width: 1400px) {

+ 6 - 2
client/src/views/Analytics/Overview/index.vue

@@ -300,8 +300,12 @@ function formatTime(time: string) {
 async function loadGroups() {
   try {
     const res = await request.get('/api/accounts/groups');
-    if (res.data.success) {
-      accountGroups.value = res.data.data || [];
+    // 新接口:request 已经解包,res 就是分组数组
+    if (Array.isArray(res)) {
+      accountGroups.value = res as AccountGroup[];
+    } else if ((res as any)?.data?.data) {
+      // 兼容旧格式 { data: { data: [] } }
+      accountGroups.value = (res as any).data.data || [];
     }
   } catch (error) {
     console.error('加载分组失败:', error);

+ 10 - 7
client/src/views/Analytics/Work/index.vue

@@ -174,11 +174,9 @@
       <div class="pagination-wrapper">
         <el-pagination
           v-model:current-page="currentPage"
-          v-model:page-size="pageSize"
+          :page-size="pageSize"
           :total="totalWorks"
-          :page-sizes="[10, 20, 50, 100]"
-          layout="total, sizes, prev, pager, next, jumper"
-          @size-change="handleQuery"
+          layout="total, prev, pager, next"
           @current-change="handleQuery"
         />
       </div>
@@ -295,7 +293,8 @@ const availablePlatforms = computed(() => {
 
 // 分页
 const currentPage = ref(1);
-const pageSize = ref(20);
+// 默认每页 15 条
+const pageSize = ref(15);
 const totalWorks = ref(0);
 
 // 汇总统计
@@ -440,8 +439,12 @@ async function loadAccountList() {
 async function loadGroups() {
   try {
     const res = await request.get('/api/accounts/groups');
-    if (res.data.success) {
-      accountGroups.value = res.data.data || [];
+    // 新接口:request 已经解包,res 就是分组数组
+    if (Array.isArray(res)) {
+      accountGroups.value = res as AccountGroup[];
+    } else if ((res as any)?.data?.data) {
+      // 兼容旧格式 { data: { data: [] } }
+      accountGroups.value = (res as any).data.data || [];
     }
   } catch (error) {
     console.error('加载分组失败:', error);

+ 5 - 6
client/src/views/Works/index.vue

@@ -105,12 +105,11 @@
       <el-pagination
         v-if="pagination.total > 0"
         v-model:current-page="pagination.page"
-        v-model:page-size="pagination.pageSize"
+        :page-size="pagination.pageSize"
         :total="pagination.total"
-        :page-sizes="[12, 24, 48]"
-        layout="total, sizes, prev, pager, next"
+        layout="total, prev, pager, next"
         style="margin-top: 20px"
-        @change="loadWorks"
+        @current-change="loadWorks"
       />
     </div>
     
@@ -421,7 +420,7 @@ const stats = ref<WorkStats>({
 
 const commentsPagination = reactive({
   page: 1,
-  pageSize: 20,
+  pageSize: 15,
   total: 0,
 });
 
@@ -439,7 +438,7 @@ const filter = reactive({
 
 const pagination = reactive({
   page: 1,
-  pageSize: 12,
+  pageSize: 15,
   total: 0,
 });
 

+ 16 - 27
server/src/services/WorkDayStatisticsService.ts

@@ -1232,7 +1232,7 @@ export class WorkDayStatisticsService {
     const startDateStr = startDate;
     const endDateStr = endDate;
 
-    // 基础查询:当前用户的作品
+    // 基础查询:当前用户的作品(先不分页,后面在内存中做分页,避免部分数据库在 GROUP BY + JOIN 场景下忽略 skip/take)
     const qb = this.workRepository
       .createQueryBuilder('w')
       .leftJoin(WorkDayStatistics, 'wds', 'wds.work_id = w.id AND wds.record_date >= :wStart AND wds.record_date <= :wEnd', {
@@ -1275,33 +1275,12 @@ export class WorkDayStatisticsService {
     // 排序:统一按发布时间倒序(最新的在前)
     qb.orderBy('w.publish_time', 'DESC');
 
-    // 统计总数(作品数)
-    const countQb = this.workRepository
-      .createQueryBuilder('w')
-      .innerJoin(PlatformAccount, 'pa', 'pa.id = w.accountId')
-      .where('w.userId = :userId', { userId });
-
-    if (platform) {
-      countQb.andWhere('w.platform = :platform', { platform });
-    }
-    if (accountIds && accountIds.length > 0) {
-      countQb.andWhere('w.accountId IN (:...accountIds)', { accountIds });
-    }
-    if (groupId) {
-      countQb.andWhere('pa.groupId = :groupId', { groupId });
-    }
-    if (keyword && keyword.trim()) {
-      const kw = `%${keyword.trim()}%`;
-      countQb.andWhere('(w.title LIKE :kw OR pa.accountName LIKE :kw)', { kw });
-    }
-
-    const total = await countQb.getCount();
+    // 先获取全部满足条件的作品聚合行,再在内存中做分页和汇总
+    const allRows = await qb.getRawMany();
 
-    // 分页
+    const total = allRows.length;
     const offset = (page - 1) * pageSize;
-    qb.skip(offset).take(pageSize);
-
-    const rows = await qb.getRawMany();
+    const pagedRows = allRows.slice(offset, offset + pageSize);
 
     let totalViews = 0;
     let totalComments = 0;
@@ -1309,7 +1288,8 @@ export class WorkDayStatisticsService {
     let totalCollects = 0;
     let totalLikes = 0;
 
-    const works = rows.map((row) => {
+    // 汇总统计使用所有作品(而不是当前页),确保顶部统计口径统一
+    for (const row of allRows) {
       const views = Number(row.viewsCount) || 0;
       const comments = Number(row.commentsCount) || 0;
       const shares = Number(row.sharesCount) || 0;
@@ -1321,6 +1301,15 @@ export class WorkDayStatisticsService {
       totalShares += shares;
       totalCollects += collects;
       totalLikes += likes;
+    }
+
+    // 当前页作品列表只返回分页后的数据
+    const works = pagedRows.map((row) => {
+      const views = Number(row.viewsCount) || 0;
+      const comments = Number(row.commentsCount) || 0;
+      const shares = Number(row.sharesCount) || 0;
+      const collects = Number(row.collectsCount) || 0;
+      const likes = Number(row.likesCount) || 0;
 
       const publishTime =
         row.publishTime instanceof Date