first commit

This commit is contained in:
2026-01-10 10:04:08 +08:00
commit 1cc427cbb0
291 changed files with 51036 additions and 0 deletions

View File

@@ -0,0 +1,261 @@
<!-- 用户管理页面 -->
<!-- art-full-height 自动计算出页面剩余高度 -->
<!-- art-table-card 一个符合系统样式的 class同时自动撑满剩余高度 -->
<!-- 更多 useTable 使用示例请移步至 功能示例 下面的高级表格示例或者查看官方文档 -->
<!-- useTable 文档https://www.artd.pro/docs/zh/guide/hooks/use-table.html -->
<template>
<div class="user-page art-full-height">
<!-- 搜索栏 -->
<UserSearch v-model="searchForm" @search="handleSearch" @reset="resetSearchParams"></UserSearch>
<ElCard class="art-table-card" shadow="never">
<!-- 表格头部 -->
<ArtTableHeader v-model:columns="columnChecks" :loading="loading" @refresh="refreshData">
<template #left>
<ElSpace wrap>
<ElButton @click="showDialog('add')" v-ripple>新增用户</ElButton>
</ElSpace>
</template>
</ArtTableHeader>
<!-- 表格 -->
<ArtTable
:loading="loading"
:data="data"
:columns="columns"
:pagination="pagination"
@selection-change="handleSelectionChange"
@pagination:size-change="handleSizeChange"
@pagination:current-change="handleCurrentChange"
>
</ArtTable>
<!-- 用户弹窗 -->
<UserDialog
v-model:visible="dialogVisible"
:type="dialogType"
:user-data="currentUserData"
@submit="handleDialogSubmit"
/>
</ElCard>
</div>
</template>
<script setup lang="ts">
import ArtButtonTable from '@/components/core/forms/art-button-table/index.vue'
import { ACCOUNT_TABLE_DATA } from '@/mock/temp/formData'
import { useTable } from '@/hooks/core/useTable'
import { fetchGetUserList } from '@/api/system-manage'
import UserSearch from './modules/user-search.vue'
import UserDialog from './modules/user-dialog.vue'
import { ElTag, ElMessageBox, ElImage } from 'element-plus'
import { DialogType } from '@/types'
defineOptions({ name: 'User' })
type UserListItem = Api.SystemManage.UserListItem
// 弹窗相关
const dialogType = ref<DialogType>('add')
const dialogVisible = ref(false)
const currentUserData = ref<Partial<UserListItem>>({})
// 选中行
const selectedRows = ref<UserListItem[]>([])
// 搜索表单
const searchForm = ref({
userName: undefined,
userGender: undefined,
userPhone: undefined,
userEmail: undefined,
status: '1'
})
// 用户状态配置
const USER_STATUS_CONFIG = {
'1': { type: 'success' as const, text: '在线' },
'2': { type: 'info' as const, text: '离线' },
'3': { type: 'warning' as const, text: '异常' },
'4': { type: 'danger' as const, text: '注销' }
} as const
/**
* 获取用户状态配置
*/
const getUserStatusConfig = (status: string) => {
return (
USER_STATUS_CONFIG[status as keyof typeof USER_STATUS_CONFIG] || {
type: 'info' as const,
text: '未知'
}
)
}
const {
columns,
columnChecks,
data,
loading,
pagination,
getData,
searchParams,
resetSearchParams,
handleSizeChange,
handleCurrentChange,
refreshData
} = useTable({
// 核心配置
core: {
apiFn: fetchGetUserList,
apiParams: {
current: 1,
size: 20,
...searchForm.value
},
// 自定义分页字段映射,未设置时将使用全局配置 tableConfig.ts 中的 paginationKey
// paginationKey: {
// current: 'pageNum',
// size: 'pageSize'
// },
columnsFactory: () => [
{ type: 'selection' }, // 勾选列
{ type: 'index', width: 60, label: '序号' }, // 序号
{
prop: 'userInfo',
label: '用户名',
width: 280,
// visible: false, // 默认是否显示列
formatter: (row) => {
return h('div', { class: 'user flex-c' }, [
h(ElImage, {
class: 'size-9.5 rounded-md',
src: row.avatar,
previewSrcList: [row.avatar],
// 图片预览是否插入至 body 元素上,用于解决表格内部图片预览样式异常
previewTeleported: true
}),
h('div', { class: 'ml-2' }, [
h('p', { class: 'user-name' }, row.userName),
h('p', { class: 'email' }, row.userEmail)
])
])
}
},
{
prop: 'userGender',
label: '性别',
sortable: true,
formatter: (row) => row.userGender
},
{ prop: 'userPhone', label: '手机号' },
{
prop: 'status',
label: '状态',
formatter: (row) => {
const statusConfig = getUserStatusConfig(row.status)
return h(ElTag, { type: statusConfig.type }, () => statusConfig.text)
}
},
{
prop: 'createTime',
label: '创建日期',
sortable: true
},
{
prop: 'operation',
label: '操作',
width: 120,
fixed: 'right', // 固定列
formatter: (row) =>
h('div', [
h(ArtButtonTable, {
type: 'edit',
onClick: () => showDialog('edit', row)
}),
h(ArtButtonTable, {
type: 'delete',
onClick: () => deleteUser(row)
})
])
}
]
},
// 数据处理
transform: {
// 数据转换器 - 替换头像
dataTransformer: (records) => {
// 类型守卫检查
if (!Array.isArray(records)) {
console.warn('数据转换器: 期望数组类型,实际收到:', typeof records)
return []
}
// 使用本地头像替换接口返回的头像
return records.map((item, index: number) => {
return {
...item,
avatar: ACCOUNT_TABLE_DATA[index % ACCOUNT_TABLE_DATA.length].avatar
}
})
}
}
})
/**
* 搜索处理
* @param params 参数
*/
const handleSearch = (params: Record<string, any>) => {
console.log(params)
// 搜索参数赋值
Object.assign(searchParams, params)
getData()
}
/**
* 显示用户弹窗
*/
const showDialog = (type: DialogType, row?: UserListItem): void => {
console.log('打开弹窗:', { type, row })
dialogType.value = type
currentUserData.value = row || {}
nextTick(() => {
dialogVisible.value = true
})
}
/**
* 删除用户
*/
const deleteUser = (row: UserListItem): void => {
console.log('删除用户:', row)
ElMessageBox.confirm(`确定要注销该用户吗?`, '注销用户', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(() => {
ElMessage.success('注销成功')
})
}
/**
* 处理弹窗提交事件
*/
const handleDialogSubmit = async () => {
try {
dialogVisible.value = false
currentUserData.value = {}
} catch (error) {
console.error('提交失败:', error)
}
}
/**
* 处理表格行选择变化
*/
const handleSelectionChange = (selection: UserListItem[]): void => {
selectedRows.value = selection
console.log('选中行数据:', selectedRows.value)
}
</script>