From e9283ffe6822b12ec5dd2ccf4dc13a369b227a61 Mon Sep 17 00:00:00 2001
From: zhou zhou <3272660260@qq.com>
Date: 星期一, 30 三月 2026 08:32:06 +0800
Subject: [PATCH] chore: sync rsf-design from isolated worktree
---
rsf-design/src/views/system/role/index.vue | 428 +++++++++++++++++++++++++++++++++++++++++------------
1 files changed, 332 insertions(+), 96 deletions(-)
diff --git a/rsf-design/src/views/system/role/index.vue b/rsf-design/src/views/system/role/index.vue
index d6a11ca..b6787aa 100644
--- a/rsf-design/src/views/system/role/index.vue
+++ b/rsf-design/src/views/system/role/index.vue
@@ -5,8 +5,8 @@
v-show="showSearchBar"
v-model="searchForm"
@search="handleSearch"
- @reset="resetSearchParams"
- ></RoleSearch>
+ @reset="handleReset"
+ />
<ElCard class="art-table-card" :style="{ 'margin-top': showSearchBar ? '12px' : '0' }">
<ArtTableHeader
@@ -17,62 +17,115 @@
>
<template #left>
<ElSpace wrap>
- <ElButton @click="showDialog('add')" v-ripple>鏂板瑙掕壊</ElButton>
+ <ElButton v-auth="'add'" @click="showDialog('add')" v-ripple>鏂板瑙掕壊</ElButton>
+ <ElButton
+ v-auth="'delete'"
+ :disabled="selectedRows.length === 0"
+ @click="handleBatchDelete"
+ v-ripple
+ >
+ 鎵归噺鍒犻櫎
+ </ElButton>
+ <span v-auth="'query'" class="inline-flex">
+ <ListExportPrint
+ :preview-visible="previewVisible"
+ @update:previewVisible="handlePreviewVisibleChange"
+ :report-title="reportTitle"
+ :selected-rows="selectedRows"
+ :query-params="reportQueryParams"
+ :columns="roleReportColumns"
+ :preview-rows="previewRows"
+ :preview-meta="resolvedPreviewMeta"
+ :total="pagination.total"
+ :disabled="loading"
+ @export="handleExport"
+ @print="handlePrint"
+ />
+ </span>
</ElSpace>
</template>
</ArtTableHeader>
- <!-- 琛ㄦ牸 -->
<ArtTable
:loading="loading"
:data="data"
:columns="columns"
:pagination="pagination"
+ @selection-change="handleSelectionChange"
@pagination:size-change="handleSizeChange"
@pagination:current-change="handleCurrentChange"
- >
- </ArtTable>
+ />
</ElCard>
- <!-- 瑙掕壊缂栬緫寮圭獥 -->
<RoleEditDialog
- v-model="dialogVisible"
+ v-model:visible="dialogVisible"
:dialog-type="dialogType"
:role-data="currentRoleData"
- @success="refreshData"
+ @submit="handleDialogSubmit"
/>
- <!-- 鑿滃崟鏉冮檺寮圭獥 -->
<RolePermissionDialog
- v-model="permissionDialog"
+ v-model:visible="permissionDialogVisible"
:role-data="currentRoleData"
+ :scope-type="permissionScopeType"
@success="refreshData"
/>
</div>
</template>
<script setup>
+ import { useUserStore } from '@/store/modules/user'
+ import {
+ fetchExportRoleReport,
+ fetchDeleteRole,
+ fetchGetRoleMany,
+ fetchRolePrintPage,
+ fetchRolePage,
+ fetchSaveRole,
+ fetchUpdateRole
+ } from '@/api/system-manage'
+ import { useTable } from '@/hooks/core/useTable'
+ 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 { useTable } from '@/hooks/core/useTable'
- import { fetchGetRoleList } from '@/api/system-manage'
import ArtButtonMore from '@/components/core/forms/art-button-more/index.vue'
- import { ElTag, ElMessageBox } from 'element-plus'
+ import { defaultResponseAdapter } from '@/utils/table/tableUtils'
+ import { ElMessage, ElMessageBox, ElTag } from 'element-plus'
+ import {
+ buildRoleDialogModel,
+ buildRolePageQueryParams,
+ buildRolePrintRows,
+ buildRoleReportMeta,
+ buildRoleSavePayload,
+ buildRoleSearchParams,
+ createRoleSearchState,
+ getRoleStatusMeta,
+ normalizeRoleListRow,
+ ROLE_REPORT_STYLE,
+ ROLE_REPORT_TITLE,
+ resolveRoleReportColumns
+ } from './rolePage.helpers'
+
defineOptions({ name: 'Role' })
- const searchForm = ref({
- roleName: void 0,
- roleCode: void 0,
- description: void 0,
- enabled: void 0,
- daterange: void 0
- })
+
+ const searchForm = ref(createRoleSearchState())
const showSearchBar = ref(false)
const dialogVisible = ref(false)
- const permissionDialog = ref(false)
- const currentRoleData = ref(void 0)
+ 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,
@@ -84,130 +137,313 @@
resetSearchParams,
handleSizeChange,
handleCurrentChange,
- refreshData
+ refreshData,
+ refreshCreate,
+ refreshUpdate,
+ refreshRemove
} = useTable({
- // 鏍稿績閰嶇疆
core: {
- apiFn: fetchGetRoleList,
- apiParams: {
- current: 1,
- size: 20
- },
- // 鎺掗櫎 apiParams 涓殑灞炴��
- excludeParams: ['daterange'],
+ apiFn: fetchRolePage,
+ apiParams: buildRolePageQueryParams(searchForm.value),
columnsFactory: () => [
+ { type: 'selection', width: 52, fixed: 'left' },
{
- prop: 'roleId',
- label: '瑙掕壊ID',
- width: 100
- },
- {
- prop: 'roleName',
+ prop: 'name',
label: '瑙掕壊鍚嶇О',
- minWidth: 120
- },
- {
- prop: 'roleCode',
- label: '瑙掕壊缂栫爜',
- minWidth: 120
- },
- {
- prop: 'description',
- label: '瑙掕壊鎻忚堪',
- minWidth: 150,
+ minWidth: 140,
showOverflowTooltip: true
},
{
- prop: 'enabled',
- label: '瑙掕壊鐘舵��',
- width: 100,
+ prop: 'code',
+ label: '瑙掕壊缂栫爜',
+ minWidth: 140,
+ showOverflowTooltip: true
+ },
+ {
+ prop: 'memo',
+ label: '澶囨敞',
+ minWidth: 180,
+ showOverflowTooltip: true
+ },
+ {
+ prop: 'status',
+ label: '鐘舵��',
+ width: 120,
formatter: (row) => {
- const statusConfig = row.enabled
- ? { type: 'success', text: '鍚敤' }
- : { type: 'warning', text: '绂佺敤' }
- return h(ElTag, { type: statusConfig.type }, () => statusConfig.text)
+ const statusMeta = getRoleStatusMeta(row.statusBool ?? row.status)
+ return h(ElTag, { type: statusMeta.type, effect: 'light' }, () => statusMeta.text)
}
},
{
- prop: 'createTime',
- label: '鍒涘缓鏃ユ湡',
- width: 180,
- sortable: true
+ 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: 80,
+ width: 120,
fixed: 'right',
formatter: (row) =>
h('div', [
h(ArtButtonMore, {
list: [
{
- key: 'permission',
- label: '鑿滃崟鏉冮檺',
- icon: 'ri:user-3-line'
+ 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'
+ icon: 'ri:edit-2-line',
+ auth: 'edit'
},
{
key: 'delete',
label: '鍒犻櫎瑙掕壊',
icon: 'ri:delete-bin-4-line',
- color: '#f56c6c'
+ color: '#f56c6c',
+ auth: 'delete'
}
],
- onClick: (item) => buttonMoreClick(item, row)
+ onClick: (item) => handleActionClick(item, row)
})
])
}
]
+ },
+ transform: {
+ dataTransformer: (records) => {
+ if (!Array.isArray(records)) {
+ return []
+ }
+ return records.map((item) => normalizeRoleListRow(item))
+ }
}
})
- const dialogType = ref('add')
- const showDialog = (type, row) => {
- dialogVisible.value = true
- dialogType.value = type
- currentRoleData.value = row
- }
+
+ 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) => {
- const { daterange, ...filtersParams } = params
- const [startTime, endTime] = Array.isArray(daterange) ? daterange : [null, null]
- replaceSearchParams({ ...filtersParams, startTime, endTime })
+ replaceSearchParams(buildRoleSearchParams(params))
getData()
}
- const buttonMoreClick = (item, row) => {
+
+ 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) => {
switch (item.key) {
- case 'permission':
- showPermissionDialog(row)
+ case 'scope-menu':
+ openScopeDialog('menu', row)
+ break
+ case 'scope-pda':
+ openScopeDialog('pda', row)
+ break
+ case 'scope-matnr':
+ openScopeDialog('matnr', row)
+ break
+ case 'scope-warehouse':
+ openScopeDialog('warehouse', row)
break
case 'edit':
showDialog('edit', row)
break
case 'delete':
- deleteRole(row)
+ handleDelete(row)
+ break
+ default:
break
}
}
- const showPermissionDialog = (row) => {
- permissionDialog.value = true
- currentRoleData.value = row
+
+ const openScopeDialog = (scopeType, row) => {
+ permissionScopeType.value = scopeType
+ currentRoleData.value = buildRoleDialogModel(row)
+ permissionDialogVisible.value = true
}
- const deleteRole = (row) => {
- ElMessageBox.confirm(`纭畾鍒犻櫎瑙掕壊"${row.roleName}"鍚楋紵姝ゆ搷浣滀笉鍙仮澶嶏紒`, '鍒犻櫎纭', {
- confirmButtonText: '纭畾',
- cancelButtonText: '鍙栨秷',
- type: 'warning'
- })
- .then(() => {
- ElMessage.success('鍒犻櫎鎴愬姛')
- refreshData()
+
+ 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
+ }
+ await fetchSaveRole(payload)
+ ElMessage.success('鏂板鎴愬姛')
+ dialogVisible.value = false
+ currentRoleData.value = buildRoleDialogModel()
+ await refreshCreate()
+ } catch (error) {
+ ElMessage.error(error?.message || '鎻愪氦澶辫触')
+ }
+ }
+
+ const handleDelete = async (row) => {
+ try {
+ await ElMessageBox.confirm(`纭畾瑕佸垹闄よ鑹层��${row.name || row.code || row.id}銆嶅悧锛焋, '鍒犻櫎纭', {
+ confirmButtonText: '纭畾',
+ cancelButtonText: '鍙栨秷',
+ type: 'warning'
})
- .catch(() => {
- ElMessage.info('宸插彇娑堝垹闄�')
+ await fetchDeleteRole(row.id)
+ ElMessage.success('鍒犻櫎鎴愬姛')
+ await refreshRemove()
+ } catch (error) {
+ if (error !== 'cancel') {
+ ElMessage.error(error?.message || '鍒犻櫎澶辫触')
+ }
+ }
+ }
+
+ 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, {
+ 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 || '瀵煎嚭澶辫触')
+ }
+ }
+
+ 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 || '鎵撳嵃澶辫触')
+ }
}
</script>
--
Gitblit v1.9.1