import { h, onMounted, ref, resolveDirective, withDirectives } from 'vue'
import { NButton, NCheckbox, NCheckboxGroup, NForm, NFormItem, NImage, NInput, NSpace, NSwitch, NTag, NPopconfirm, NLayout, NLayoutSider, NLayoutContent, NTreeSelect } from 'naive-ui'
讲解:
这里使用了Vue3的Composition API和NaiveUI组件库。
ref
是响应式数据的基本单位,用于定义可变状态。
onMounted
是Vue生命周期钩子,用于在组件挂载后执行初始化逻辑。
NaiveUI组件是UI框架的核心,比如NButton
是按钮,NForm
是表单。
实用技巧:
按需引入组件可以减少打包体积。
使用import {} from 'naive-ui'
的写法,避免引入整个库。
import CommonPage from '@/components/page/CommonPage.vue'
import QueryBarItem from '@/components/query-bar/QueryBarItem.vue'
import CrudModal from '@/components/table/CrudModal.vue'
import CrudTable from '@/components/table/CrudTable.vue'
import { formatDate, renderIcon } from '@/utils'
import { useCRUD } from '@/composables'
import api from '@/api'
讲解:
CommonPage
是一个通用页面布局组件。
CrudTable
和CrudModal
是封装好的表格和弹窗组件,遵循CRUD模式(增删改查)。
useCRUD
是一个组合式函数,封装了CRUD逻辑。
api
是API接口文件,定义了后端交互方法。
开发思维:
组件化开发:将功能拆分为独立组件,提高复用性。
封装CRUD逻辑:避免重复代码,集中管理操作逻辑。
const $table = ref(null)
const queryItems = ref({})
const vPermission = resolveDirective('permission')
讲解:
$table
是对表格组件的引用,用于调用其方法(如handleSearch
)。
queryItems
存储查询条件,初始为空对象。
vPermission
是一个指令,用于权限控制。
实用技巧:
使用ref(null)
初始化引用,确保类型安全。
指令可以复用逻辑,避免在模板中写重复的权限判断。
const {
modalVisible,
modalTitle,
modalAction,
modalLoading,
handleSave,
modalForm,
modalFormRef,
handleEdit,
handleDelete,
handleAdd,
} = useCRUD({
name: '用户',
initForm: {},
doCreate: api.createUser,
doUpdate: api.updateUser,
doDelete: api.deleteUser,
refresh: () => $table.value?.handleSearch(),
})
讲解:
useCRUD
是一个通用的CRUD逻辑封装,返回了一系列状态和方法。
modalVisible
控制弹窗的显示/隐藏。
handleSave
、handleEdit
等是操作方法,直接调用API并刷新表格。
开发思维:
钩子复用:将通用逻辑抽象为Hook,减少重复代码。
状态集中管理:所有CRUD相关状态都在Hook中定义。
const roleOption = ref([])
const deptOption = ref([])
onMounted(() => {
$table.value?.handleSearch()
api.getRoleList({ page: 1, page_size: 9999 }).then((res) => (roleOption.value = res.data))
api.getDepts().then((res) => (deptOption.value = res.data))
})
讲解:
在组件挂载后,加载角色和部门数据,供表格和表单使用。
使用onMounted
确保DOM已渲染后再调用API。
实用技巧:
使用.then()
处理异步数据,确保数据加载完成后再赋值。
在API调用中传递大page_size
获取所有数据。
const columns = [
{
title: '名称',
key: 'username',
width: 60,
align: 'center',
ellipsis: { tooltip: true },
},
// 其他列...
]
讲解:
表格列配置定义了表格的展示内容。
key
对应数据字段,render
用于自定义渲染。
实用技巧:
使用ellipsis
显示省略号,鼠标悬停显示完整内容。
自定义渲染函数(如render
)可以插入复杂组件。
讲解:
使用NaiveUI的NLayout
组件实现页面布局。
NLayoutSider
是侧边栏,NLayoutContent
是主内容区。
开发思维:
布局组件化:通过UI框架的布局组件快速构建页面结构。
分区明确:侧边栏放部门树,主内容区放用户表格。
讲解:
NTree
是树形组件,展示部门结构。
nodeProps
定义节点点击事件,用于筛选用户。
实用技巧:
使用default-expand-all
展开所有节点,方便查看。
在nodeProps
中定义点击事件,实现树节点交互。
讲解:
CrudTable
是封装好的表格组件,接收查询条件、列配置和数据获取函数。
v-model:query-items
实现查询条件的双向绑定。
开发思维:
封装组件:将表格功能封装为独立组件,提高复用性。
插槽设计:通过queryBar
插槽自定义查询条件。
讲解:
CrudModal
是弹窗组件,控制用户添加/编辑操作。
NForm
是表单组件,配合validateAddUser
实现表单验证。
实用技巧:
使用v-model:visible
控制弹窗显示/隐藏。
表单验证规则(如validateAddUser
)确保输入数据合法性。
async function handleUpdateDisable(row) {
if (!row.id) return
const userStore = useUserStore()
if (userStore.userId === row.id) {
$message.error('当前登录用户不可禁用!')
return
}
// 更新逻辑...
}
讲解:
检查当前操作用户是否为登录用户,避免误操作。
使用try-catch
处理API调用,确保异常时恢复原状态。
开发思维:
权限控制:禁止用户禁用自己。
异常处理:保证UI状态与后端数据一致。
const nodeProps = ({ option }) => {
return {
onClick() {
if (lastClickedNodeId === option.id) {
$table.value?.handleSearch()
lastClickedNodeId = null
} else {
api.getUserList({ dept_id: option.id }).then((res) => {
$table.value.tableData = res.data
lastClickedNodeId = option.id
})
}
},
}
}
讲解:
点击树节点时,根据部门ID筛选用户。
使用lastClickedNodeId
防止重复点击触发请求。
实用技巧:
状态记忆:通过变量记录上次点击节点,避免无效请求。
API调用结果直接赋值给表格数据,实现快速筛选。
组件化思维:
将功能拆分为独立组件(如CrudTable
、CrudModal
)。
复用通用逻辑(如useCRUD
Hook)。
状态管理:
使用ref
定义响应式状态。
集中管理CRUD相关状态和逻辑。
API交互:
封装API调用,统一处理数据获取和更新。
使用try-catch
保证异常时的UI一致性。
用户体验优化:
表单验证确保输入合法性。
使用树形组件和筛选功能提升操作效率。
权限控制:
通过指令(如vPermission
)实现细粒度权限管理。
禁止用户禁用自己,避免系统异常。