注意:别再增加子目录,如mldong-art-design/src/,这样子的,你增加后,就会导致目录结构混乱,请勿再增加子目录。
src/api/{模块名}/{实体文件名}.ts
src/views/{模块名}/实体文件名
├── index.vue # 页面入口文件
├── schemas/
│ └── index.tsx # CRUD 配置定义
└── components/ # 模块特定组件(可选)
命名规范:
sys_user、sys_user_rolesysuser,如果有多个部分则用中横线连接,如 user-roleuser-role.ts约束规则:
colSpan默认为24,如果字段太多,可以设置colSpan为12示例:sys_user
sysuseruser./src/api/sys/user.tsUserServicesys_user_role
sysuser-roleuserRole./src/api/sys/user-role.tsUserRoleService创建 src/api/{模块名}/{实体名}.ts:
import request from '@/utils/http'
export class {EntityName}Service {
// 分页查询
static page(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/page',
params
})
}
// 树形接口,注意,只有id/name/parentId字段的树形接口才需要此方法
static tree(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/tree',
params
})
}
// 添加
static save(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/save',
params
})
}
// 修改
static update(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/update',
params
})
}
// 删除
static remove(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/remove',
params
})
}
// 详情
static detail(params: any) {
return request.post({
url: '/{模块路径}/{实体小驼峰名}/detail',
params
})
}
}
创建 src/views/{模块名}/schemas/index.tsx:
import { CrudSchema } from '@/components/crud'
import { {EntityName}Service } from '@/api/{模块名}/{实体名}'
// crud配置
export const crudSchema: CrudSchema = {
// 接口地址
api: {EntityName}Service.page,
dialogTitle: '{模块标题}',
crudApi: {
// 新增接口
add: {EntityName}Service.save,
// 修改接口
edit: {EntityName}Service.update,
// 删除接口
remove: {EntityName}Service.remove,
// 详情接口
view: {EntityName}Service.detail
},
// 使用crud
useCrud: true,
// 是否有新增
hasAdd: true,
// 是否有删除
hasRemove: true,
// 是否有修改
hasEdit: true,
// 是否有详情
hasView: true,
// 新增权限码
addAuth: '{模块名}:{实体名}:save',
// 删除权限码
removeAuth: '{模块名}:{实体名}:remove',
// 修改权限码
editAuth: '{模块名}:{实体名}:update',
// 详情权限码
viewAuth: '{模块名}:{实体名}:detail',
// 表格列定义
columns: [
{
type: 'selection'
},
// 在此处添加表格列定义
],
// 搜索表单定义
searchFormSchema: {
schema: [
// 在此处添加搜索表单字段定义
]
},
// 内置弹窗配置
dialogProps: {
// 需要你根据实际需求来填写弹窗宽度
width: '50%'
// dialogType: 'drawer'
},
// crud表单配置
formSchema: {
showDefaultActions: false,
// 需要你根据实际需求来填写表单标签宽度
labelWidth: '100px',
schema: [
// 在此处添加表单字段定义
]
}
}
创建 src/views/{模块名}/index.vue:
<template>
<div class="{模块名}-page art-full-height">
<BasicCrud />
</div>
</template>
<script setup lang="tsx">
import { useCrud } from '@/components/crud'
import { crudSchema } from './schemas'
const [BasicCrud] = useCrud({
...crudSchema,
// 左侧工具栏
toolbarActions: [],
// 左侧栏工具-下拉菜单
dropDownToolbarActions: [],
// 表格行操作
tableActions: [],
// 表格行操作-下拉菜单
dropDownActions: []
})
</script>
<style lang="scss" scoped></style>
{
prop: '字段名',
label: '列标题',
// 可选配置
component: '组件名', // 如 'ApiDict', 'ApiSelect' 等
componentProps: {
// 组件属性
},
width: 120, // 列宽度
fixed: 'left' // 固定列
}
{
label: '字段标签',
prop: '字段名',
component: '组件名', // 如 'Input', 'Select', 'ApiDict' 等
colSpan: 12, // 栅格占比 (1-24)
rules: [
{
required: true,
message: '校验提示信息'
}
],
componentProps: {
// 组件属性
placeholder: '占位符',
clearable: true
},
ifShow(values) {
// 动态显示条件
return !!values.条件字段
}
}
{
prop: 'm_操作符_字段名', // 如 'm_LIKE_name', 'm_EQ_status'
label: '搜索字段标签',
component: 'Input', // 搜索组件
componentProps: {
clearable: true,
placeholder: '请输入搜索条件'
},
colSpan: 6 // 栅格占比
}
对于具有树形结构的数据(如菜单、组织架构等),需要配置 tree 属性来启用树形功能:
export const crudSchema: CrudSchema = {
// 使用 tree 接口而不是 page 接口
api: {EntityName}Service.tree,
// 树型是全量数据,不需要搜索
useSearchForm: false,
// 树形结构配置
tree: {
id: 'id', // 树形节点唯一标识字段名,默认为 'id'
pid: 'parentId', // 父节点字段名,默认为 'parentId'
children: 'children' // 子节点字段名,默认为 'children'
},
// 其他配置...
}
表单组件:
Input: 普通输入框InputNumber: 数字输入框Select: 下拉选择框RadioGroup: 单选框组CheckboxGroup: 多选框组DatePicker: 日期选择器ApiDict: 字典组件(支持Select/Radio/Checkbox渲染)
ApiSelect: 异步下拉选择组件ApiCascader: 异步级联选择组件ApiTreeSelect: 异步树形选择组件ApiRadioGroup: 异步单选框组ApiCheckboxGroup: 异步多选框组IconPicker: 图标选择器Editor: 富文本编辑器Upload: 文件上传组件Avatar: 头像上传组件Divider: 分割线通过以下属性控制功能权限:
通过 useCrud 返回的方法可以控制 CRUD 行为:
src/api/sys/post.ts
import request from '@/utils/http'
export class PostService {
// 分页查询
static page(params: any) {
return request.post({
url: '/sys/post/page',
params
})
}
// 添加
static save(params: any) {
return request.post({
url: '/sys/post/save',
params
})
}
// 修改
static update(params: any) {
return request.post({
url: '/sys/post/update',
params
})
}
// 删除
static remove(params: any) {
return request.post({
url: '/sys/post/remove',
params
})
}
// 详情
static detail(params: any) {
return request.post({
url: '/sys/post/detail',
params
})
}
}
src/views/sys/post/schemas/index.tsx
import { CrudSchema } from '@/components/crud'
import { PostService } from '@/api/sys/post'
// crud配置
export const crudSchema: CrudSchema = {
// 接口地址
api: PostService.page,
dialogTitle: '岗位',
crudApi: {
// 新增接口
add: PostService.save,
// 修改接口
edit: PostService.update,
// 删除接口
remove: PostService.remove,
// 详情接口
view: PostService.detail
},
// 使用crud
useCrud: true,
// 是否有新增
hasAdd: true,
// 是否有删除
hasRemove: true,
// 是否有修改
hasEdit: true,
// 是否有详情
hasView: true,
// 新增权限码
addAuth: 'sys:post:save',
// 删除权限码
removeAuth: 'sys:post:remove',
// 修改权限码
editAuth: 'sys:post:update',
// 详情权限码
viewAuth: 'sys:post:detail',
// 表格列定义
columns: [
{
type: 'selection'
},
{
prop: 'name',
label: '岗位名称'
},
{
prop: 'code',
label: '唯一编码'
},
{
prop: 'sort',
label: '排序'
},
{
prop: 'enabled',
label: '是否启用',
component: 'ApiDict',
componentProps: {
code: 'yes_no'
}
},
{
prop: 'remark',
label: '备注'
}
],
// 搜索表单定义
searchFormSchema: {
schema: [
{
prop: 'm_LIKE_name',
label: '岗位名称',
component: 'Input',
componentProps: {
clearable: true,
placeholder: '请输入岗位名称'
},
colSpan: 6
},
{
prop: 'm_EQ_enabled',
label: '状态',
component: 'ApiDict',
componentProps: {
code: 'yes_no',
placeholder: '请选择状态'
},
colSpan: 6
}
]
},
// 内置弹窗配置
dialogProps: {
width: '50%'
},
// crud表单配置
formSchema: {
showDefaultActions: false,
labelWidth: '100px',
schema: [
{
label: '岗位ID',
prop: 'id',
component: 'Input',
colSpan: 24,
show: false,
ifDetail: false
},
{
label: '岗位名称',
prop: 'name',
component: 'Input',
rules: [
{
required: true,
message: '请输入岗位名称'
}
],
componentProps: {
placeholder: '请输入岗位名称'
},
colSpan: 24
},
{
label: '唯一编码',
prop: 'code',
component: 'Input',
rules: [
{
required: true,
message: '请输入唯一编码'
}
],
componentProps: {
placeholder: '请输入唯一编码'
},
colSpan: 24
},
{
label: '排序',
prop: 'sort',
component: 'InputNumber',
componentProps: {
min: 0,
placeholder: '请输入排序值'
},
colSpan: 24
},
{
label: '是否启用',
prop: 'enabled',
component: 'ApiDict',
componentProps: {
code: 'yes_no',
isBtn: true,
renderType: 'RadioGroup'
},
rules: [
{
required: true,
message: '请选择是否启用'
}
],
colSpan: 24
},
{
label: '备注',
prop: 'remark',
component: 'Input',
componentProps: {
type: 'textarea',
placeholder: '请输入备注'
},
colSpan: 24
}
]
}
}
src/views/sys/post/schemas/index.tsx
<template>
<div class="sys-post-page art-full-height">
<BasicCrud />
</div>
</template>
<script setup lang="tsx">
import { useCrud } from '@/components/crud'
import { crudSchema } from './schemas'
const [BasicCrud] = useCrud({
...crudSchema,
// 左侧工具栏
toolbarActions: [],
// 左侧栏工具-下拉菜单
dropDownToolbarActions: [],
// 表格行操作
tableActions: [],
// 表格行操作-下拉菜单
dropDownActions: []
})
</script>
<style lang="scss" scoped></style>
src/api/sys/dept.ts
import request from '@/utils/http'
export class DeptService {
// 分页查询
static page(params: any) {
return request.post({
url: '/sys/dept/page',
params
})
}
// 树形接口
static tree(params: any) {
return request.post({
url: '/sys/dept/tree',
params
})
}
// 添加
static save(params: any) {
return request.post({
url: '/sys/dept/save',
params
})
}
// 修改
static update(params: any) {
return request.post({
url: '/sys/dept/update',
params
})
}
// 删除
static remove(params: any) {
return request.post({
url: '/sys/dept/remove',
params
})
}
// 详情
static detail(params: any) {
return request.post({
url: '/sys/dept/detail',
params
})
}
}
src/views/sys/dept/schemas/index.tsx
import { CrudSchema } from '@/components/crud'
import { DeptService } from '@/api/sys/dept'
// crud配置
export const crudSchema: CrudSchema = {
// 接口地址:改为 tree 接口以支持树形结构
api: DeptService.tree,
dialogTitle: '部门',
crudApi: {
add: DeptService.save,
edit: DeptService.update,
remove: DeptService.remove,
view: DeptService.detail
},
useCrud: true,
hasAdd: true,
hasRemove: true,
hasEdit: true,
hasView: true,
addAuth: 'sys:dept:save',
removeAuth: 'sys:dept:remove',
editAuth: 'sys:dept:update',
viewAuth: 'sys:dept:detail',
// 禁用搜索表单,因为树形结构是全量数据
useSearchForm: false,
// 树形结构配置
tree: {
id: 'id',
pid: 'parentId',
children: 'children'
},
columns: [
{
type: 'selection'
},
{
prop: 'name',
label: '部门名称',
component: 'Input'
},
{
prop: 'code',
label: '唯一编码',
component: 'Input'
},
{
prop: 'sort',
label: '排序',
component: 'InputNumber'
},
{
prop: 'enabled',
label: '状态',
component: 'ApiDict',
componentProps: {
code: 'yes_no',
renderType: 'RadioGroup'
}
}
],
searchFormSchema: {
schema: []
},
dialogProps: {
width: '50%'
},
formSchema: {
showDefaultActions: false,
labelWidth: '100px',
schema: [
{
label: '部门ID',
prop: 'id',
component: 'Input',
colSpan: 24,
show: false,
ifDetail: false
},
{
label: '父级部门',
prop: 'parentId',
component: 'ApiTreeSelect',
componentProps: {
api: '/sys/dept/tree',
labelField: 'name',
valueField: 'id',
// 任意节点可选
checkStrictly: true,
clearable: true,
placeholder: '请选择父级部门'
},
colSpan: 24,
rules: [
{
required: true,
message: '请选择父级部门'
}
]
},
{
label: '部门名称',
prop: 'name',
component: 'Input',
componentProps: {
placeholder: '请输入部门名称'
},
colSpan: 24,
rules: [
{
required: true,
message: '请输入部门名称'
}
]
},
{
label: '唯一编码',
prop: 'code',
component: 'Input',
componentProps: {
placeholder: '请输入唯一编码'
},
colSpan: 24,
rules: [
{
required: true,
message: '请输入唯一编码'
}
]
},
{
label: '排序',
prop: 'sort',
component: 'InputNumber',
componentProps: {
min: 0,
max: 9999
},
colSpan: 24,
rules: [
{
required: true,
message: '请输入排序值'
}
]
},
{
label: '是否启用',
prop: 'enabled',
component: 'ApiDict',
componentProps: {
code: 'yes_no',
isBtn: true,
renderType: 'RadioGroup'
},
colSpan: 24,
rules: [
{
required: true,
message: '请选择启用状态'
}
]
},
{
label: '部门负责人',
prop: 'leaderIdList',
component: 'ApiSelect',
componentProps: {
api: '/sys/user/select',
placeholder: '请选择负责人',
multiple: true
},
colSpan: 24
},
{
label: '分管领导',
prop: 'mainLeaderId',
component: 'ApiSelect',
componentProps: {
api: '/sys/user/select',
placeholder: '请选择分管领导'
},
colSpan: 24
},
{
label: '备注',
prop: 'remark',
component: 'Input',
componentProps: {
type: 'textarea',
rows: 3,
placeholder: '请输入备注'
},
colSpan: 24
}
]
}
}
src/views/sys/dept/schemas/index.tsx
<template>
<div class="sys-dept-page art-full-height">
<BasicCrud />
</div>
</template>
<script setup lang="tsx">
import { useCrud } from '@/components/crud'
import { crudSchema } from './schemas'
const [BasicCrud] = useCrud({
...crudSchema,
toolbarActions: [],
dropDownToolbarActions: [],
tableActions: [],
dropDownActions: []
})
</script>
<style lang="scss" scoped>
.sys-dept-page {
height: 100%;
}
</style>