From 3fdcf1d5e6468c735532e67bde5ff1cdf85bb0c6 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期一, 30 三月 2026 09:14:16 +0800
Subject: [PATCH] refactor: simplify role page and fix pagination keys

---
 rsf-design/src/views/system/role/index.vue |  409 ++++++++++++++++------------------------------------------
 1 files changed, 115 insertions(+), 294 deletions(-)

diff --git a/rsf-design/src/views/system/role/index.vue b/rsf-design/src/views/system/role/index.vue
index b6787aa..49d2e34 100644
--- a/rsf-design/src/views/system/role/index.vue
+++ b/rsf-design/src/views/system/role/index.vue
@@ -20,6 +20,7 @@
             <ElButton v-auth="'add'" @click="showDialog('add')" v-ripple>鏂板瑙掕壊</ElButton>
             <ElButton
               v-auth="'delete'"
+              type="danger"
               :disabled="selectedRows.length === 0"
               @click="handleBatchDelete"
               v-ripple
@@ -85,13 +86,14 @@
     fetchUpdateRole
   } from '@/api/system-manage'
   import { useTable } from '@/hooks/core/useTable'
+  import { useCrudPage } from '@/views/system/common/useCrudPage'
+  import { usePrintExportPage } from '@/views/system/common/usePrintExportPage'
   import ListExportPrint from '@/components/biz/list-export-print/index.vue'
   import RoleSearch from './modules/role-search.vue'
   import RoleEditDialog from './modules/role-edit-dialog.vue'
   import RolePermissionDialog from './modules/role-permission-dialog.vue'
-  import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue'
+  import { createRoleTableColumns } from './roleTable.columns'
   import { defaultResponseAdapter } from '@/utils/table/tableUtils'
-  import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
   import {
     buildRoleDialogModel,
     buildRolePageQueryParams,
@@ -100,7 +102,7 @@
     buildRoleSavePayload,
     buildRoleSearchParams,
     createRoleSearchState,
-    getRoleStatusMeta,
+    getRolePaginationKey,
     normalizeRoleListRow,
     ROLE_REPORT_STYLE,
     ROLE_REPORT_TITLE,
@@ -111,184 +113,19 @@
 
   const searchForm = ref(createRoleSearchState())
   const showSearchBar = ref(false)
-  const dialogVisible = ref(false)
-  const dialogType = ref('add')
-  const currentRoleData = ref(buildRoleDialogModel())
   const permissionDialogVisible = ref(false)
   const permissionScopeType = ref('menu')
-  const selectedRows = ref([])
-  const previewVisible = ref(false)
-  const previewRows = ref([])
-  const previewMeta = ref({})
-  const previewToken = ref(0)
-  const activePrintToken = ref(0)
   const userStore = useUserStore()
   const reportTitle = ROLE_REPORT_TITLE
   const reportQueryParams = computed(() => buildRoleSearchParams(searchForm.value))
 
-  const {
-    columns,
-    columnChecks,
-    data,
-    loading,
-    pagination,
-    getData,
-    replaceSearchParams,
-    resetSearchParams,
-    handleSizeChange,
-    handleCurrentChange,
-    refreshData,
-    refreshCreate,
-    refreshUpdate,
-    refreshRemove
-  } = useTable({
-    core: {
-      apiFn: fetchRolePage,
-      apiParams: buildRolePageQueryParams(searchForm.value),
-      columnsFactory: () => [
-        { type: 'selection', width: 52, fixed: 'left' },
-        {
-          prop: 'name',
-          label: '瑙掕壊鍚嶇О',
-          minWidth: 140,
-          showOverflowTooltip: true
-        },
-        {
-          prop: 'code',
-          label: '瑙掕壊缂栫爜',
-          minWidth: 140,
-          showOverflowTooltip: true
-        },
-        {
-          prop: 'memo',
-          label: '澶囨敞',
-          minWidth: 180,
-          showOverflowTooltip: true
-        },
-        {
-          prop: 'status',
-          label: '鐘舵��',
-          width: 120,
-          formatter: (row) => {
-            const statusMeta = getRoleStatusMeta(row.statusBool ?? row.status)
-            return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
-          }
-        },
-        {
-          prop: 'updateTimeText',
-          label: '鏇存柊鏃堕棿',
-          minWidth: 180,
-          sortable: true,
-          formatter: (row) => row.updateTimeText || '-'
-        },
-        {
-          prop: 'createTimeText',
-          label: '鍒涘缓鏃堕棿',
-          minWidth: 180,
-          sortable: true,
-          formatter: (row) => row.createTimeText || '-'
-        },
-        {
-          prop: 'operation',
-          label: '鎿嶄綔',
-          width: 120,
-          fixed: 'right',
-          formatter: (row) =>
-            h('div', [
-              h(ArtButtonMore, {
-                list: [
-                  {
-                    key: 'scope-menu',
-                    label: '缃戦〉鏉冮檺',
-                    icon: 'ri:layout-2-line',
-                    auth: 'edit'
-                  },
-                  {
-                    key: 'scope-pda',
-                    label: 'PDA鏉冮檺',
-                    icon: 'ri:smartphone-line',
-                    auth: 'edit'
-                  },
-                  {
-                    key: 'scope-matnr',
-                    label: '鐗╂枡鏉冮檺',
-                    icon: 'ri:archive-line',
-                    auth: 'edit'
-                  },
-                  {
-                    key: 'scope-warehouse',
-                    label: '浠撳簱鏉冮檺',
-                    icon: 'ri:store-2-line',
-                    auth: 'edit'
-                  },
-                  {
-                    key: 'edit',
-                    label: '缂栬緫瑙掕壊',
-                    icon: 'ri:edit-2-line',
-                    auth: 'edit'
-                  },
-                  {
-                    key: 'delete',
-                    label: '鍒犻櫎瑙掕壊',
-                    icon: 'ri:delete-bin-4-line',
-                    color: '#f56c6c',
-                    auth: 'delete'
-                  }
-                ],
-                onClick: (item) => handleActionClick(item, row)
-              })
-            ])
-        }
-      ]
-    },
-    transform: {
-      dataTransformer: (records) => {
-        if (!Array.isArray(records)) {
-          return []
-        }
-        return records.map((item) => normalizeRoleListRow(item))
-      }
-    }
-  })
-
-  const roleReportColumns = computed(() => resolveRoleReportColumns(columns.value))
-  const resolvedPreviewMeta = computed(() =>
-    buildRoleReportMeta({
-      previewMeta: previewMeta.value,
-      count: previewRows.value.length,
-      titleAlign: ROLE_REPORT_STYLE.titleAlign,
-      titleLevel: ROLE_REPORT_STYLE.titleLevel
-    })
-  )
-
-  const handleSearch = (params) => {
-    replaceSearchParams(buildRoleSearchParams(params))
-    getData()
+  function openScopeDialog(scopeType, row) {
+    permissionScopeType.value = scopeType
+    currentRoleData.value = buildRoleDialogModel(row)
+    permissionDialogVisible.value = true
   }
 
-  const handleReset = () => {
-    Object.assign(searchForm.value, createRoleSearchState())
-    resetSearchParams()
-  }
-
-  const handleSelectionChange = (rows) => {
-    selectedRows.value = Array.isArray(rows) ? rows : []
-  }
-
-  const handlePreviewVisibleChange = (visible) => {
-    previewVisible.value = Boolean(visible)
-    if (!visible) {
-      activePrintToken.value = 0
-    }
-  }
-
-  const showDialog = (type, row) => {
-    dialogType.value = type
-    currentRoleData.value = type === 'edit' ? buildRoleDialogModel(row) : buildRoleDialogModel()
-    dialogVisible.value = true
-  }
-
-  const handleActionClick = (item, row) => {
+  function handleActionClick(item, row) {
     switch (item.key) {
       case 'scope-menu':
         openScopeDialog('menu', row)
@@ -313,137 +150,121 @@
     }
   }
 
-  const openScopeDialog = (scopeType, row) => {
-    permissionScopeType.value = scopeType
-    currentRoleData.value = buildRoleDialogModel(row)
-    permissionDialogVisible.value = true
-  }
-
-  const handleDialogSubmit = async (formData) => {
-    const payload = buildRoleSavePayload(formData)
-    try {
-      if (dialogType.value === 'edit') {
-        await fetchUpdateRole(payload)
-        ElMessage.success('淇敼鎴愬姛')
-        dialogVisible.value = false
-        currentRoleData.value = buildRoleDialogModel()
-        await refreshUpdate()
-        return
+  const {
+    columns,
+    columnChecks,
+    data,
+    loading,
+    pagination,
+    getData,
+    replaceSearchParams,
+    resetSearchParams,
+    handleSizeChange,
+    handleCurrentChange,
+    refreshData,
+    refreshCreate,
+    refreshUpdate,
+    refreshRemove
+  } = useTable({
+    core: {
+      apiFn: fetchRolePage,
+      apiParams: buildRolePageQueryParams(searchForm.value),
+      paginationKey: getRolePaginationKey(),
+      columnsFactory: () => createRoleTableColumns(handleActionClick)
+    },
+    transform: {
+      dataTransformer: (records) => {
+        if (!Array.isArray(records)) {
+          return []
+        }
+        return records.map((item) => normalizeRoleListRow(item))
       }
-      await fetchSaveRole(payload)
-      ElMessage.success('鏂板鎴愬姛')
-      dialogVisible.value = false
-      currentRoleData.value = buildRoleDialogModel()
-      await refreshCreate()
-    } catch (error) {
-      ElMessage.error(error?.message || '鎻愪氦澶辫触')
+    }
+  })
+
+  const {
+    dialogVisible,
+    dialogType,
+    currentRecord: currentRoleData,
+    selectedRows,
+    handleSelectionChange,
+    showDialog,
+    handleDialogSubmit,
+    handleDelete,
+    handleBatchDelete
+  } = useCrudPage({
+    createEmptyModel: () => buildRoleDialogModel(),
+    buildEditModel: (record) => buildRoleDialogModel(record),
+    buildSavePayload: (formData) => buildRoleSavePayload(formData),
+    saveRequest: fetchSaveRole,
+    updateRequest: fetchUpdateRole,
+    deleteRequest: fetchDeleteRole,
+    entityName: '瑙掕壊',
+    resolveRecordLabel: (record) => record?.name || record?.code || record?.id,
+    refreshCreate,
+    refreshUpdate,
+    refreshRemove
+  })
+
+  const buildPreviewDialogMeta = (rows) => {
+    const now = new Date()
+    return {
+      reportTitle,
+      reportDate: now.toLocaleDateString('zh-CN'),
+      printedAt: now.toLocaleString('zh-CN', { hour12: false }),
+      operator: userStore.getUserInfo?.name || userStore.getUserInfo?.username || '',
+      count: rows.length
     }
   }
 
-  const handleDelete = async (row) => {
-    try {
-      await ElMessageBox.confirm(`纭畾瑕佸垹闄よ鑹层��${row.name || row.code || row.id}銆嶅悧锛焋, '鍒犻櫎纭', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      })
-      await fetchDeleteRole(row.id)
-      ElMessage.success('鍒犻櫎鎴愬姛')
-      await refreshRemove()
-    } catch (error) {
-      if (error !== 'cancel') {
-        ElMessage.error(error?.message || '鍒犻櫎澶辫触')
-      }
-    }
+  const resolvePrintRecords = async (payload) => {
+    const response = Array.isArray(payload?.ids) && payload.ids.length > 0
+      ? await fetchGetRoleMany(payload.ids)
+      : await fetchRolePrintPage({
+          ...reportQueryParams.value,
+          current: 1,
+          pageSize: Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20
+        })
+    return defaultResponseAdapter(response).records
   }
 
-  const handleBatchDelete = async () => {
-    if (!selectedRows.value.length) return
-    const ids = selectedRows.value.map((item) => item.id).filter((id) => id !== void 0 && id !== null)
-    if (!ids.length) return
-
-    try {
-      await ElMessageBox.confirm(`纭畾瑕佹壒閲忓垹闄ら�変腑鐨� ${ids.length} 涓鑹插悧锛焋, '鎵归噺鍒犻櫎纭', {
-        confirmButtonText: '纭畾',
-        cancelButtonText: '鍙栨秷',
-        type: 'warning'
-      })
-      await fetchDeleteRole(ids.join(','))
-      ElMessage.success('鎵归噺鍒犻櫎鎴愬姛')
-      selectedRows.value = []
-      await refreshRemove()
-    } catch (error) {
-      if (error !== 'cancel') {
-        ElMessage.error(error?.message || '鎵归噺鍒犻櫎澶辫触')
-      }
-    }
-  }
-
-  const handleExport = async (payload) => {
-    try {
-      const response = await fetchExportRoleReport(payload, {
+  const {
+    previewVisible,
+    previewRows,
+    previewMeta,
+    handlePreviewVisibleChange,
+    handleExport,
+    handlePrint
+  } = usePrintExportPage({
+    downloadFileName: 'role.xlsx',
+    requestExport: (payload) =>
+      fetchExportRoleReport(payload, {
         headers: {
           Authorization: userStore.accessToken || ''
         }
-      })
-      if (!response.ok) {
-        throw new Error(`瀵煎嚭澶辫触 (${response.status})`)
-      }
-      const blob = await response.blob()
-      const downloadUrl = window.URL.createObjectURL(blob)
-      const link = document.createElement('a')
-      link.href = downloadUrl
-      link.download = 'role.xlsx'
-      document.body.appendChild(link)
-      link.click()
-      link.remove()
-      window.URL.revokeObjectURL(downloadUrl)
-      ElMessage.success('瀵煎嚭鎴愬姛')
-    } catch (error) {
-      ElMessage.error(error?.message || '瀵煎嚭澶辫触')
-    }
+      }),
+    resolvePrintRecords,
+    buildPreviewRows: (records) => buildRolePrintRows(records),
+    buildPreviewMeta: (rows) => buildPreviewDialogMeta(rows)
+  })
+
+  const roleReportColumns = computed(() => resolveRoleReportColumns(columns.value))
+  const resolvedPreviewMeta = computed(() =>
+    buildRoleReportMeta({
+      previewMeta: previewMeta.value,
+      count: previewRows.value.length,
+      titleAlign: ROLE_REPORT_STYLE.titleAlign,
+      titleLevel: ROLE_REPORT_STYLE.titleLevel
+    })
+  )
+
+  const handleSearch = (params) => {
+    replaceSearchParams(buildRoleSearchParams(params))
+    getData()
   }
 
-  const handlePrint = async (payload) => {
-    const token = previewToken.value + 1
-    previewToken.value = token
-    activePrintToken.value = token
-    previewVisible.value = false
-    previewRows.value = []
-    previewMeta.value = {}
-
-    try {
-      const response = Array.isArray(payload?.ids) && payload.ids.length > 0
-        ? await fetchGetRoleMany(payload.ids)
-        : await fetchRolePrintPage({
-            ...reportQueryParams.value,
-            current: 1,
-            pageSize: Number(pagination.total) > 0 ? Number(pagination.total) : Number(payload?.pageSize) || 20
-          })
-      if (activePrintToken.value !== token) {
-        return
-      }
-      const records = defaultResponseAdapter(response).records
-      if (activePrintToken.value !== token) {
-        return
-      }
-
-      const rows = buildRolePrintRows(records)
-      const now = new Date()
-      previewRows.value = rows
-      previewMeta.value = {
-        reportTitle,
-        reportDate: now.toLocaleDateString('zh-CN'),
-        printedAt: now.toLocaleString('zh-CN', { hour12: false }),
-        operator: userStore.getUserInfo?.name || userStore.getUserInfo?.username || '',
-        count: rows.length
-      }
-      handlePreviewVisibleChange(true)
-    } catch (error) {
-      if (activePrintToken.value !== token) {
-        return
-      }
-      ElMessage.error(error?.message || '鎵撳嵃澶辫触')
-    }
+  const handleReset = () => {
+    Object.assign(searchForm.value, createRoleSearchState())
+    resetSearchParams()
   }
 </script>

--
Gitblit v1.9.1