Pārlūkot izejas kodu

分页bug修改

jiapu 3 mēneši atpakaļ
vecāks
revīzija
d8733efc29

+ 1 - 1
code/backend/src/main/resources/application.yml

@@ -1,6 +1,6 @@
 spring:
   profiles:
-    active: liyu
+    active: dev
 
   # Jackson 日期时间格式配置
   jackson:

+ 36 - 0
code/frontend/src/utils/pagination.js

@@ -0,0 +1,36 @@
+const RECORD_KEYS = ['records', 'list', 'rows', 'items', 'data']
+const TOTAL_KEYS = ['total', 'count', 'totalCount', 'recordsTotal']
+
+function pickArray(source) {
+  if (Array.isArray(source)) {
+    return source
+  }
+  if (!source || typeof source !== 'object') {
+    return []
+  }
+  for (const key of RECORD_KEYS) {
+    if (Array.isArray(source[key])) {
+      return source[key]
+    }
+  }
+  return []
+}
+
+function pickTotal(source, fallback) {
+  if (!source || typeof source !== 'object' || Array.isArray(source)) {
+    return fallback
+  }
+  for (const key of TOTAL_KEYS) {
+    if (source[key] !== undefined && source[key] !== null) {
+      const value = Number(source[key])
+      return Number.isFinite(value) ? value : fallback
+    }
+  }
+  return fallback
+}
+
+export function parsePageData(pageData) {
+  const records = pickArray(pageData)
+  const total = pickTotal(pageData, records.length)
+  return { records, total }
+}

+ 5 - 2
code/frontend/src/views/acupoint/index.vue

@@ -135,7 +135,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -308,6 +310,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue'
 import ExcelImport from '@/components/ExcelImport.vue'
 import ExcelExport from '@/components/ExcelExport.vue'
+import { parsePageData } from '@/utils/pagination'
 import {
   getAcupointPage,
   exportAcupoint,
@@ -414,10 +417,10 @@ async function loadData() {
   loading.value = true
   try {
     const res = await getAcupointPage(queryForm)
-    const records = res.data?.records || []
+    const { records, total: pageTotal } = parsePageData(res.data)
     // 添加辅助显示字段
     tableData.value = records.map(formatAcupointRow)
-    total.value = res.data?.total || 0
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 4 - 2
code/frontend/src/views/admin/index.vue

@@ -220,6 +220,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import { Search, Refresh, Plus, Delete } from '@element-plus/icons-vue'
 import { adminApi } from '@/api'
 import { formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 // ======================== 可配置的菜单路由列表 ========================
 const allMenuRoutes = [
@@ -262,8 +263,9 @@ async function loadData() {
       pageSize: query.pageSize
     }
     const res = await adminApi.getAdminPage(params)
-    tableData.value = res.data.records || []
-    total.value = Number(res.data.total) || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 6 - 2
code/frontend/src/views/content/index.vue

@@ -151,7 +151,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -276,6 +278,7 @@ import { Search, Refresh, Plus, CopyDocument, View } from '@element-plus/icons-v
 import RichEditor from '@/components/RichEditor.vue'
 import { useUserStore } from '@/store/user'
 import { formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 import {
   getArticlePage,
   getArticleById,
@@ -373,8 +376,9 @@ async function loadData() {
   try {
     queryForm.createBy = onlyMine.value ? (userStore.userInfo?.userId || null) : null
     const res = await getArticlePage(queryForm)
-    tableData.value = res.data.records || []
-    total.value = res.data.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 5 - 2
code/frontend/src/views/device/index.vue

@@ -141,7 +141,9 @@
         v-model:page-size="pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -278,6 +280,7 @@ import { regionData, codeToText } from 'element-china-area-data'
 import ExcelImport from '@/components/ExcelImport.vue'
 import ExcelExport from '@/components/ExcelExport.vue'
 import { formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 import {
   getDevicePageList,
   addDevice,
@@ -448,14 +451,14 @@ async function loadData() {
       pageNum: pageNum.value,
       pageSize: pageSize.value
     })
-    const records = res.data?.records || []
+    const { records, total: pageTotal } = parsePageData(res.data)
     // 为导出添加状态标签字段和地区文本
     tableData.value = records.map(r => ({
       ...r,
       onlineStatusLabel: r.onlineStatus === 1 ? '在线' : '离线',
       regionText: formatRegion(r)
     }))
-    total.value = res.data?.total || 0
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 50 - 2
code/frontend/src/views/device/users.vue

@@ -74,6 +74,19 @@
           </template>
         </el-table-column>
       </el-table>
+
+      <el-pagination
+        v-model:current-page="pageNum"
+        v-model:page-size="pageSize"
+        :page-sizes="[10, 20, 50]"
+        :total="total"
+        :hide-on-single-page="false"
+        layout="total, sizes, prev, pager, next, jumper"
+        background
+        class="pagination"
+        @size-change="handlePageSizeChange"
+        @current-change="handleCurrentChange"
+      />
     </el-card>
 
     <!-- 添加用户弹窗 -->
@@ -141,7 +154,14 @@ const deviceCode = computed(() => route.query.deviceCode || '')
 const deviceName = computed(() => route.query.deviceName || '')
 
 // 列表数据
-const tableData = ref([])
+const allUsers = ref([])
+const pageNum = ref(1)
+const pageSize = ref(10)
+const total = computed(() => allUsers.value.length)
+const tableData = computed(() => {
+  const start = (pageNum.value - 1) * pageSize.value
+  return allUsers.value.slice(start, start + pageSize.value)
+})
 const loading = ref(false)
 const selectedBindIds = ref([])
 
@@ -153,12 +173,34 @@ async function loadData() {
   loading.value = true
   try {
     const res = await getDeviceUsers(deviceId.value)
-    tableData.value = res.data || []
+    allUsers.value = Array.isArray(res.data) ? res.data : []
+    normalizePageNum()
+    clearSelection()
   } finally {
     loading.value = false
   }
 }
 
+function normalizePageNum() {
+  const maxPage = Math.max(1, Math.ceil(total.value / pageSize.value))
+  if (pageNum.value > maxPage) {
+    pageNum.value = maxPage
+  }
+}
+
+function clearSelection() {
+  selectedBindIds.value = []
+}
+
+function handlePageSizeChange() {
+  pageNum.value = 1
+  clearSelection()
+}
+
+function handleCurrentChange() {
+  clearSelection()
+}
+
 /**
  * 多选变化(选择的是 bindId,即 user_device.id)
  */
@@ -327,6 +369,12 @@ onMounted(loadData)
   flex: 1;
 }
 
+.pagination {
+  margin-top: 16px;
+  display: flex;
+  justify-content: flex-end;
+}
+
 .add-user-tip {
   color: #909399;
   font-size: 13px;

+ 6 - 2
code/frontend/src/views/log/index.vue

@@ -138,7 +138,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50, 100]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -170,6 +172,7 @@ import { Search, Refresh } from '@element-plus/icons-vue'
 import { getLogPage, exportLog, getSysUserOptions } from '@/api/log'
 import ExcelExport from '@/components/ExcelExport.vue'
 import { dateTimeFormatter, formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 // ==================== 查询表单 ====================
 const queryForm = reactive({
@@ -214,8 +217,9 @@ async function loadData() {
   loading.value = true
   try {
     const res = await getLogPage(queryForm)
-    tableData.value = res.data?.records || []
-    total.value = res.data?.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 6 - 2
code/frontend/src/views/moxibustion/index.vue

@@ -103,7 +103,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -242,6 +244,7 @@ import {
   deleteTechnique,
   batchDeleteTechnique
 } from '@/api/moxibustion'
+import { parsePageData } from '@/utils/pagination'
 
 /** 运动模式中文映射 */
 const MOTION_MODE_MAP = {
@@ -364,8 +367,9 @@ async function loadData() {
   loading.value = true
   try {
     const res = await getTechniquePage(queryForm)
-    tableData.value = res.data?.records || []
-    total.value = res.data?.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 6 - 2
code/frontend/src/views/plan/index.vue

@@ -123,7 +123,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -417,6 +419,7 @@ import { getAcupointList } from '@/api/acupoint'
 import { getTechniqueList } from '@/api/moxibustion'
 import { useUserStore } from '@/store/user'
 import { formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 // ============ 枚举常量 ============
 const effectOptions = ['驱寒', '祛湿', '祛风', '化瘀', '活血', '化痰', '养颜', '扶阳']
 const modeTypeOptions = [
@@ -537,8 +540,9 @@ async function loadData() {
   queryForm.createTimeEnd = dateRange.value?.[1] || ''
   try {
     const res = await getPlanPage(queryForm)
-    tableData.value = res.data?.records || []
-    total.value = res.data?.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 5 - 2
code/frontend/src/views/system/user-category/index.vue

@@ -45,6 +45,7 @@
           v-model:page-size="query.pageSize"
           :page-sizes="[10, 20, 50]"
           :total="total"
+          :hide-on-single-page="false"
           layout="total, sizes, prev, pager, next, jumper"
           background
           @size-change="loadData"
@@ -89,6 +90,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 import { Search, Refresh, Plus } from '@element-plus/icons-vue'
 import { userCategoryApi } from '@/api'
 import { dateTimeFormatter } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 const loading = ref(false)
 const tableData = ref([])
@@ -108,8 +110,9 @@ async function loadData() {
       pageNum: query.pageNum,
       pageSize: query.pageSize
     })
-    tableData.value = res.data?.records || []
-    total.value = Number(res.data?.total) || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 5 - 2
code/frontend/src/views/user/app-user/index.vue

@@ -112,6 +112,7 @@
         :total="total"
         :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -181,6 +182,7 @@ import {
 } from '@/api/user'
 import { getUserCategoryList } from '@/api/userCategory'
 import { dateTimeFormatter } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 const router = useRouter()
 
@@ -256,8 +258,9 @@ async function loadData() {
   loading.value = true
   try {
     const res = await getAppUserPage(queryForm)
-    tableData.value = res.data?.records || []
-    total.value = Number(res.data?.total) || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 7 - 3
code/frontend/src/views/user/device/index.vue

@@ -84,7 +84,9 @@
         v-model:page-size="pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -144,6 +146,7 @@ import {
 } from '@/api/user'
 import { getDevicePageList } from '@/api/device'
 import { dateTimeFormatter } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 const route = useRoute()
 const router = useRouter()
@@ -174,8 +177,9 @@ async function loadData() {
       params.userId = userId.value
     }
     const res = await getDevicePage(params)
-    tableData.value = res.data?.records || []
-    total.value = res.data?.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = records
+    total.value = pageTotal
   } finally {
     loading.value = false
   }
@@ -237,7 +241,7 @@ async function loadDeviceOptions() {
       pageNum: 1,
       pageSize: 500
     })
-    deviceOptions.value = res.data?.records || []
+    deviceOptions.value = parsePageData(res.data).records
   } finally {
     deviceOptionsLoading.value = false
   }

+ 6 - 2
code/frontend/src/views/user/plan/index.vue

@@ -66,7 +66,9 @@
         v-model:page-size="pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -125,6 +127,7 @@ import { ref, computed, onMounted } from 'vue'
 import { getUserPlanPage, getUserPlanDetail } from '@/api/plan'
 import { getAllUserList } from '@/api/user'
 import { formatDateTime } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 
 // 用户列表
 const userList = ref([])
@@ -189,8 +192,9 @@ async function loadData() {
       pageNum: pageNum.value,
       pageSize: pageSize.value
     })
-    tableData.value = sortByModeType(res.data?.records || [])
-    total.value = res.data?.total || 0
+    const { records, total: pageTotal } = parsePageData(res.data)
+    tableData.value = sortByModeType(records)
+    total.value = pageTotal
   } finally {
     loading.value = false
   }

+ 6 - 2
code/frontend/src/views/user/profile/index.vue

@@ -190,7 +190,9 @@
         v-model:page-size="queryForm.pageSize"
         :page-sizes="[10, 20, 50]"
         :total="total"
+        :hide-on-single-page="false"
         layout="total, sizes, prev, pager, next, jumper"
+        background
         class="pagination"
         @size-change="loadData"
         @current-change="loadData"
@@ -352,6 +354,7 @@ import { regionData, codeToText } from 'element-china-area-data'
 import ExcelExport from '@/components/ExcelExport.vue'
 import ExcelImport from '@/components/ExcelImport.vue'
 import { dateTimeFormatter } from '@/utils/date'
+import { parsePageData } from '@/utils/pagination'
 import { getUserCategoryList } from '@/api/userCategory'
 import {
   getProfilePage,
@@ -522,8 +525,9 @@ async function loadData() {
       pageSize: queryForm.pageSize
     }
     const res = await getProfilePage(params)
+    const { records: pageRecords, total: pageTotal } = parsePageData(res.data)
     // 附加显示文本字段(用于 Excel 导出)
-    const records = (res.data?.records || []).map(r => ({
+    const records = pageRecords.map(r => ({
       ...r,
       genderText: r.gender === 1 ? '男' : r.gender === 2 ? '女' : '-',
       userCategoryText: r.userCategoryName || '-',
@@ -531,7 +535,7 @@ async function loadData() {
       acupointText: r.acupointTableId ? '已生成' : '未生成'
     }))
     tableData.value = records
-    total.value = res.data?.total || 0
+    total.value = pageTotal
   } finally {
     loading.value = false
   }