예제 및 실전
이 문서는 Antdv Next Admin을 사용하여 일반적인 기능을 개발하는 방법을 실제 사례로 보여줍니다.
목차
CRUD 완전한 예제
시나리오
목록, 신규 추가, 편집, 삭제 기능을 포함한 완전한 사용자 관리 모듈을 구현합니다.
1. API 인터페이스 생성
typescript
// src/api/user.ts
import request from '@/utils/request'
import type { User, PaginationParams } from '@/types'
export const getUserList = (params: PaginationParams) => {
return request.get('/api/users', { params })
}
export const createUser = (data: Partial<User>) => {
return request.post('/api/users', data)
}
export const updateUser = (id: string, data: Partial<User>) => {
return request.put(`/api/users/${id}`, data)
}
export const deleteUser = (id: string) => {
return request.delete(`/api/users/${id}`)
}2. Mock 데이터 생성
typescript
// mock/data/user.data.ts
import { faker } from '@faker-js/faker/locale/zh_CN'
export interface User {
id: string
username: string
email: string
phone: string
status: 'active' | 'inactive'
role: string
createdAt: string
}
export const userList: User[] = Array.from({ length: 35 }, (_, i) => ({
id: `user_${i + 1}`,
username: faker.internet.userName(),
email: faker.internet.email(),
phone: faker.phone.number(),
status: faker.helpers.arrayElement(['active', 'inactive']),
role: faker.helpers.arrayElement(['admin', 'user', 'editor']),
createdAt: faker.date.past().toISOString(),
}))typescript
// mock/handlers/user.mock.ts
import { defineMock } from 'vite-plugin-mock-dev-server'
import { userList } from '../data/user.data'
export default defineMock([
{
url: '/api/users',
method: 'GET',
response: ({ query }) => {
const { current = 1, pageSize = 10, username, status } = query
let list = [...userList]
if (username) {
list = list.filter(u => u.username.includes(username))
}
if (status) {
list = list.filter(u => u.status === status)
}
const start = (current - 1) * pageSize
const end = start + parseInt(pageSize)
return {
code: 200,
data: {
list: list.slice(start, end),
total: list.length,
},
}
},
},
// ... POST, PUT, DELETE 接口
])3. 페이지 생성
vue
<!-- src/views/system/users/index.vue -->
<template>
<div class="user-management">
<ProTable
ref="tableRef"
:columns="columns"
:request="fetchUserList"
:toolbar="toolbar"
:form-items="formItems"
@form-submit="handleFormSubmit"
>
<template #toolbar-actions>
<a-button type="primary" @click="handleCreate">
<PlusOutlined />
新增用户
</a-button>
</template>
</ProTable>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { message } from 'antdv-next'
import { PlusOutlined } from '@antdv-next/icons'
import ProTable from '@/components/Pro/ProTable/index.vue'
import type { ProTableColumn, ProFormItem, ProTableRequest } from '@/types/pro'
import {
getUserList,
createUser,
updateUser,
deleteUser,
} from '@/api/user'
const tableRef = ref()
// 表格列配置
const columns: ProTableColumn[] = [
{
title: '用户名',
dataIndex: 'username',
search: true,
},
{
title: '邮箱',
dataIndex: 'email',
},
{
title: '手机号',
dataIndex: 'phone',
},
{
title: '状态',
dataIndex: 'status',
valueType: 'tag',
search: true,
options: [
{ label: '启用', value: 'active', color: 'green' },
{ label: '禁用', value: 'inactive', color: 'red' },
],
},
{
title: '角色',
dataIndex: 'role',
valueType: 'tag',
options: [
{ label: '管理员', value: 'admin', color: 'blue' },
{ label: '编辑', value: 'editor', color: 'cyan' },
{ label: '用户', value: 'user' },
],
},
{
title: '创建时间',
dataIndex: 'createdAt',
valueType: 'dateTime',
},
{
title: '操作',
dataIndex: 'actions',
actions: [
{
label: '编辑',
permission: 'user.edit',
onClick: (record) => tableRef.value?.openEditModal(record),
},
{
label: '删除',
danger: true,
permission: 'user.delete',
confirm: '确认删除该用户?',
onClick: (record) => handleDelete(record),
},
],
},
]
// 表单配置
const formItems: ProFormItem[] = [
{ name: 'username', label: '用户名', type: 'input', required: true },
{ name: 'email', label: '邮箱', type: 'input', rules: [{ type: 'email' }] },
{ name: 'phone', label: '手机号', type: 'input' },
{
name: 'status',
label: '状态',
type: 'select',
required: true,
options: [
{ label: '启用', value: 'active' },
{ label: '禁用', value: 'inactive' },
],
},
{
name: 'role',
label: '角色',
type: 'select',
required: true,
options: [
{ label: '管理员', value: 'admin' },
{ label: '编辑', value: 'editor' },
{ label: '用户', value: 'user' },
],
},
]
// 请求数据
const fetchUserList: ProTableRequest = async (params) => {
const res = await getUserList(params)
return {
data: res.data.list,
total: res.data.total,
success: true,
}
}
// 表单提交
const handleFormSubmit = async ({ values, record, isEdit }) => {
try {
if (isEdit) {
await updateUser(record.id, values)
message.success('更新成功')
} else {
await createUser(values)
message.success('创建成功')
}
tableRef.value?.refresh()
} catch (error) {
message.error('操作失败')
}
}
// 删除
const handleDelete = async (record: any) => {
try {
await deleteUser(record.id)
message.success('删除成功')
tableRef.value?.refresh()
} catch (error) {
message.error('删除失败')
}
}
// 打开新增弹窗
const handleCreate = () => {
tableRef.value?.openCreateModal()
}
</script>폼 설계 패턴
단계별 폼
typescript
const stepFormItems: ProFormItem[][] = [
// 第一步
[
{ name: 'name', label: '项目名称', type: 'input', required: true },
{ name: 'type', label: '项目类型', type: 'select', required: true, options: [...] },
],
// 第二步
[
{ name: 'startDate', label: '开始日期', type: 'datePicker', required: true },
{ name: 'endDate', label: '结束日期', type: 'datePicker', required: true },
],
// 第三步
[
{ name: 'members', label: '成员', type: 'select', mode: 'multiple' },
{ name: 'description', label: '描述', type: 'textarea' },
],
]동적 폼
선택에 따라 필드를 동적으로 표시:
typescript
const formItems: ProFormItem[] = [
{
name: 'type',
label: '类型',
type: 'select',
options: [
{ label: '个人', value: 'personal' },
{ label: '企业', value: 'enterprise' },
],
},
{
name: 'idCard',
label: '身份证号',
type: 'input',
hidden: (values) => values.type !== 'personal',
},
{
name: 'businessLicense',
label: '营业执照',
type: 'input',
hidden: (values) => values.type !== 'enterprise',
},
]테이블 고급 사용법
커스텀 열 렌더링
typescript
const columns: ProTableColumn[] = [
{
title: '头像',
dataIndex: 'avatar',
render: (text) => h('img', { src: text, style: { width: '40px', borderRadius: '50%' } }),
},
{
title: '进度',
dataIndex: 'progress',
render: (text) => h(Progress, { percent: text }),
},
]중첩 테이블
vue
<template>
<ProTable :columns="columns" :request="request">
<template #expand="{ record }">
<ProTable
:columns="detailColumns"
:data-source="record.details"
:pagination="false"
/>
</template>
</ProTable>
</template>권한 제어 실전
버튼 레벨 권한
vue
<template>
<div>
<a-button v-permission="'user.create'">新增</a-button>
<a-button v-permission="'user.export'">导出</a-button>
</div>
</template>페이지 레벨 권한
typescript
{
path: '/system/users',
meta: {
requiredPermissions: ['user.view'],
},
}동적 권한 판정
typescript
const { can } = usePermission()
const actions = computed(() => {
const list = []
if (can('user.edit')) {
list.push({ label: '编辑', onClick: handleEdit })
}
if (can('user.delete')) {
list.push({ label: '删除', onClick: handleDelete, danger: true })
}
return list
})