31 changed files with 852 additions and 52 deletions
@ -1,4 +1,2 @@ |
|||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
export { default as PageFooter } from './src/PageFooter.vue'; |
||||
export const PageFooter = createAsyncComponent(() => import('./src/PageFooter.vue')); |
|
||||
|
|
||||
export { default as PageWrapper } from './src/PageWrapper.vue'; |
export { default as PageWrapper } from './src/PageWrapper.vue'; |
||||
|
|||||
@ -1,4 +1,3 @@ |
|||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
export { default as QrCode } from './src/index.vue'; |
||||
export const QrCode = createAsyncComponent(() => import('./src/index.vue')); |
|
||||
|
|
||||
export * from './src/types'; |
export * from './src/types'; |
||||
|
|||||
@ -1,3 +1 @@ |
|||||
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent'; |
export { default as StrengthMeter } from './src/index.vue'; |
||||
|
|
||||
export const StrengthMeter = createAsyncComponent(() => import('./src/index.vue')); |
|
||||
|
|||||
@ -0,0 +1,70 @@ |
|||||
|
<template> |
||||
|
<BasicDrawer |
||||
|
v-bind="$attrs" |
||||
|
@register="registerDrawer" |
||||
|
showFooter |
||||
|
:title="getTitle" |
||||
|
width="50%" |
||||
|
@ok="handleSubmit" |
||||
|
> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</BasicDrawer> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, computed, unref } from 'vue'; |
||||
|
import { BasicForm, useForm } from '/@/components/Form/index'; |
||||
|
import { formSchema } from './menu.data'; |
||||
|
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
||||
|
|
||||
|
import { getMenuList } from '/@/api/demo/system'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'MenuDrawer', |
||||
|
components: { BasicDrawer, BasicForm }, |
||||
|
emits: ['success', 'register'], |
||||
|
setup(_, { emit }) { |
||||
|
const isUpdate = ref(true); |
||||
|
|
||||
|
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({ |
||||
|
labelWidth: 100, |
||||
|
schemas: formSchema, |
||||
|
showActionButtonGroup: false, |
||||
|
baseColProps: { lg: 12, md: 24 }, |
||||
|
}); |
||||
|
|
||||
|
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
||||
|
resetFields(); |
||||
|
setDrawerProps({ confirmLoading: false }); |
||||
|
isUpdate.value = !!data?.isUpdate; |
||||
|
|
||||
|
if (unref(isUpdate)) { |
||||
|
setFieldsValue({ |
||||
|
...data.record, |
||||
|
}); |
||||
|
} |
||||
|
const treeData = await getMenuList(); |
||||
|
updateSchema({ |
||||
|
field: 'parentMenu', |
||||
|
componentProps: { treeData }, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const getTitle = computed(() => (!unref(isUpdate) ? '新增菜单' : '编辑菜单')); |
||||
|
|
||||
|
async function handleSubmit() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
setDrawerProps({ confirmLoading: true }); |
||||
|
// TODO custom api |
||||
|
console.log(values); |
||||
|
closeDrawer(); |
||||
|
emit('success'); |
||||
|
} finally { |
||||
|
setDrawerProps({ confirmLoading: false }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { registerDrawer, registerForm, getTitle, handleSubmit }; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,100 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<a-button type="primary" @click="handleCreate"> 新增菜单 </a-button> |
||||
|
</template> |
||||
|
<template #action="{ record }"> |
||||
|
<TableAction |
||||
|
:actions="[ |
||||
|
{ |
||||
|
icon: 'clarity:note-edit-line', |
||||
|
onClick: handleEdit.bind(null, record), |
||||
|
}, |
||||
|
{ |
||||
|
icon: 'ant-design:delete-outlined', |
||||
|
color: 'error', |
||||
|
popConfirm: { |
||||
|
title: '是否确认删除', |
||||
|
confirm: handleDelete.bind(null, record), |
||||
|
}, |
||||
|
}, |
||||
|
]" |
||||
|
/> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<MenuDrawer @register="registerDrawer" @success="handleSuccess" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent } from 'vue'; |
||||
|
|
||||
|
import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
||||
|
import { getMenuList } from '/@/api/demo/system'; |
||||
|
|
||||
|
import { useDrawer } from '/@/components/Drawer'; |
||||
|
import MenuDrawer from './MenuDrawer.vue'; |
||||
|
|
||||
|
import { columns, searchFormSchema } from './menu.data'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'MenuManagement', |
||||
|
components: { BasicTable, MenuDrawer, TableAction }, |
||||
|
setup() { |
||||
|
const [registerDrawer, { openDrawer }] = useDrawer(); |
||||
|
const [registerTable, { reload }] = useTable({ |
||||
|
title: '菜单列表', |
||||
|
api: getMenuList, |
||||
|
columns, |
||||
|
formConfig: { |
||||
|
labelWidth: 120, |
||||
|
schemas: searchFormSchema, |
||||
|
}, |
||||
|
pagination: false, |
||||
|
striped: false, |
||||
|
useSearchForm: true, |
||||
|
showTableSetting: true, |
||||
|
bordered: true, |
||||
|
showIndexColumn: false, |
||||
|
canResize: false, |
||||
|
actionColumn: { |
||||
|
width: 80, |
||||
|
title: '操作', |
||||
|
dataIndex: 'action', |
||||
|
slots: { customRender: 'action' }, |
||||
|
fixed: undefined, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
function handleCreate() { |
||||
|
openDrawer(true, { |
||||
|
isUpdate: false, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function handleEdit(record: Recordable) { |
||||
|
openDrawer(true, { |
||||
|
record, |
||||
|
isUpdate: true, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function handleDelete(record: Recordable) { |
||||
|
console.log(record); |
||||
|
} |
||||
|
|
||||
|
function handleSuccess() { |
||||
|
reload(); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
registerTable, |
||||
|
registerDrawer, |
||||
|
handleCreate, |
||||
|
handleEdit, |
||||
|
handleDelete, |
||||
|
handleSuccess, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,202 @@ |
|||||
|
import { BasicColumn } from '/@/components/Table'; |
||||
|
import { FormSchema } from '/@/components/Table'; |
||||
|
import { h } from 'vue'; |
||||
|
import { Tag } from 'ant-design-vue'; |
||||
|
import { Icon } from '/@/components/Icon'; |
||||
|
|
||||
|
export const columns: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '菜单名称', |
||||
|
dataIndex: 'menuName', |
||||
|
width: 200, |
||||
|
align: 'left', |
||||
|
}, |
||||
|
{ |
||||
|
title: '图标', |
||||
|
dataIndex: 'icon', |
||||
|
width: 50, |
||||
|
customRender: ({ record }) => { |
||||
|
return h(Icon, { icon: record.icon }); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '权限标识', |
||||
|
dataIndex: 'permission', |
||||
|
width: 180, |
||||
|
}, |
||||
|
{ |
||||
|
title: '组件', |
||||
|
dataIndex: 'component', |
||||
|
}, |
||||
|
{ |
||||
|
title: '排序', |
||||
|
dataIndex: 'orderNo', |
||||
|
width: 50, |
||||
|
}, |
||||
|
{ |
||||
|
title: '状态', |
||||
|
dataIndex: 'status', |
||||
|
width: 80, |
||||
|
customRender: ({ record }) => { |
||||
|
const status = record.status; |
||||
|
const enable = ~~status === 0; |
||||
|
const color = enable ? 'green' : 'red'; |
||||
|
const text = enable ? '启用' : '停用'; |
||||
|
return h(Tag, { color: color }, () => text); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '创建时间', |
||||
|
dataIndex: 'createTime', |
||||
|
width: 180, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
const isDir = (type: string) => type === '0'; |
||||
|
const isMenu = (type: string) => type === '1'; |
||||
|
const isButton = (type: string) => type === '2'; |
||||
|
|
||||
|
export const searchFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'menuName', |
||||
|
label: '菜单名称', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 8 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'status', |
||||
|
label: '状态', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '启用', value: '0' }, |
||||
|
{ label: '停用', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
colProps: { span: 8 }, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const formSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'type', |
||||
|
label: '菜单类型', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '目录', value: '0' }, |
||||
|
{ label: '菜单', value: '1' }, |
||||
|
{ label: '按钮', value: '2' }, |
||||
|
], |
||||
|
}, |
||||
|
colProps: { lg: 24, md: 24 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'menuName', |
||||
|
label: '菜单名称', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'parentMenu', |
||||
|
label: '上级菜单', |
||||
|
component: 'TreeSelect', |
||||
|
componentProps: { |
||||
|
replaceFields: { |
||||
|
title: 'menuName', |
||||
|
key: 'id', |
||||
|
value: 'id', |
||||
|
}, |
||||
|
getPopupContainer: () => document.body, |
||||
|
}, |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'orderNo', |
||||
|
label: '排序', |
||||
|
component: 'InputNumber', |
||||
|
required: true, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'icon', |
||||
|
label: '图标', |
||||
|
component: 'IconPicker', |
||||
|
required: true, |
||||
|
show: ({ values }) => !isButton(values.type), |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'routePath', |
||||
|
label: '路由地址', |
||||
|
component: 'Input', |
||||
|
required: true, |
||||
|
show: ({ values }) => !isButton(values.type), |
||||
|
}, |
||||
|
{ |
||||
|
field: 'component', |
||||
|
label: '组件路径', |
||||
|
component: 'Input', |
||||
|
show: ({ values }) => isMenu(values.type), |
||||
|
}, |
||||
|
{ |
||||
|
field: 'permission', |
||||
|
label: '权限标识', |
||||
|
component: 'Input', |
||||
|
show: ({ values }) => !isDir(values.type), |
||||
|
}, |
||||
|
{ |
||||
|
field: 'status', |
||||
|
label: '状态', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '启用', value: '0' }, |
||||
|
{ label: '禁用', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'isExt', |
||||
|
label: '是否外链', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '否', value: '0' }, |
||||
|
{ label: '是', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
show: ({ values }) => !isButton(values.type), |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'keepalive', |
||||
|
label: '是否缓存', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '否', value: '0' }, |
||||
|
{ label: '是', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
show: ({ values }) => isMenu(values.type), |
||||
|
}, |
||||
|
|
||||
|
{ |
||||
|
field: 'show', |
||||
|
label: '是否显示', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '是', value: '0' }, |
||||
|
{ label: '否', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
show: ({ values }) => !isButton(values.type), |
||||
|
}, |
||||
|
]; |
||||
@ -0,0 +1,69 @@ |
|||||
|
<template> |
||||
|
<BasicDrawer |
||||
|
v-bind="$attrs" |
||||
|
@register="registerDrawer" |
||||
|
showFooter |
||||
|
:title="getTitle" |
||||
|
width="500px" |
||||
|
@ok="handleSubmit" |
||||
|
> |
||||
|
<BasicForm @register="registerForm" /> |
||||
|
</BasicDrawer> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent, ref, computed, unref } from 'vue'; |
||||
|
import { BasicForm, useForm } from '/@/components/Form/index'; |
||||
|
import { formSchema } from './role.data'; |
||||
|
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
||||
|
|
||||
|
import { getMenuList } from '/@/api/demo/system'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'RoleDrawer', |
||||
|
components: { BasicDrawer, BasicForm }, |
||||
|
emits: ['success', 'register'], |
||||
|
setup(_, { emit }) { |
||||
|
const isUpdate = ref(true); |
||||
|
|
||||
|
const [registerForm, { resetFields, setFieldsValue, updateSchema, validate }] = useForm({ |
||||
|
labelWidth: 90, |
||||
|
schemas: formSchema, |
||||
|
showActionButtonGroup: false, |
||||
|
}); |
||||
|
|
||||
|
const [registerDrawer, { setDrawerProps, closeDrawer }] = useDrawerInner(async (data) => { |
||||
|
resetFields(); |
||||
|
setDrawerProps({ confirmLoading: false }); |
||||
|
isUpdate.value = !!data?.isUpdate; |
||||
|
|
||||
|
if (unref(isUpdate)) { |
||||
|
setFieldsValue({ |
||||
|
...data.record, |
||||
|
}); |
||||
|
} |
||||
|
const treeData = await getMenuList(); |
||||
|
updateSchema({ |
||||
|
field: 'parentMenu', |
||||
|
componentProps: { treeData }, |
||||
|
}); |
||||
|
}); |
||||
|
|
||||
|
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色')); |
||||
|
|
||||
|
async function handleSubmit() { |
||||
|
try { |
||||
|
const values = await validate(); |
||||
|
setDrawerProps({ confirmLoading: true }); |
||||
|
// TODO custom api |
||||
|
console.log(values); |
||||
|
closeDrawer(); |
||||
|
emit('success'); |
||||
|
} finally { |
||||
|
setDrawerProps({ confirmLoading: false }); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return { registerDrawer, registerForm, getTitle, handleSubmit }; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,97 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<BasicTable @register="registerTable"> |
||||
|
<template #toolbar> |
||||
|
<a-button type="primary" @click="handleCreate"> 新增角色 </a-button> |
||||
|
</template> |
||||
|
<template #action="{ record }"> |
||||
|
<TableAction |
||||
|
:actions="[ |
||||
|
{ |
||||
|
icon: 'clarity:note-edit-line', |
||||
|
onClick: handleEdit.bind(null, record), |
||||
|
}, |
||||
|
{ |
||||
|
icon: 'ant-design:delete-outlined', |
||||
|
color: 'error', |
||||
|
popConfirm: { |
||||
|
title: '是否确认删除', |
||||
|
confirm: handleDelete.bind(null, record), |
||||
|
}, |
||||
|
}, |
||||
|
]" |
||||
|
/> |
||||
|
</template> |
||||
|
</BasicTable> |
||||
|
<RoleDrawer @register="registerDrawer" @success="handleSuccess" /> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script lang="ts"> |
||||
|
import { defineComponent } from 'vue'; |
||||
|
|
||||
|
import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
||||
|
import { getRoleList } from '/@/api/demo/system'; |
||||
|
|
||||
|
import { useDrawer } from '/@/components/Drawer'; |
||||
|
import RoleDrawer from './RoleDrawer.vue'; |
||||
|
|
||||
|
import { columns, searchFormSchema } from './role.data'; |
||||
|
|
||||
|
export default defineComponent({ |
||||
|
name: 'RoleManagement', |
||||
|
components: { BasicTable, RoleDrawer, TableAction }, |
||||
|
setup() { |
||||
|
const [registerDrawer, { openDrawer }] = useDrawer(); |
||||
|
const [registerTable, { reload }] = useTable({ |
||||
|
title: '角色列表', |
||||
|
api: getRoleList, |
||||
|
columns, |
||||
|
formConfig: { |
||||
|
labelWidth: 120, |
||||
|
schemas: searchFormSchema, |
||||
|
}, |
||||
|
useSearchForm: true, |
||||
|
showTableSetting: true, |
||||
|
bordered: true, |
||||
|
showIndexColumn: false, |
||||
|
actionColumn: { |
||||
|
width: 80, |
||||
|
title: '操作', |
||||
|
dataIndex: 'action', |
||||
|
slots: { customRender: 'action' }, |
||||
|
fixed: undefined, |
||||
|
}, |
||||
|
}); |
||||
|
|
||||
|
function handleCreate() { |
||||
|
openDrawer(true, { |
||||
|
isUpdate: false, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function handleEdit(record: Recordable) { |
||||
|
openDrawer(true, { |
||||
|
record, |
||||
|
isUpdate: true, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function handleDelete(record: Recordable) { |
||||
|
console.log(record); |
||||
|
} |
||||
|
|
||||
|
function handleSuccess() { |
||||
|
reload(); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
registerTable, |
||||
|
registerDrawer, |
||||
|
handleCreate, |
||||
|
handleEdit, |
||||
|
handleDelete, |
||||
|
handleSuccess, |
||||
|
}; |
||||
|
}, |
||||
|
}); |
||||
|
</script> |
||||
@ -0,0 +1,102 @@ |
|||||
|
import { BasicColumn } from '/@/components/Table'; |
||||
|
import { FormSchema } from '/@/components/Table'; |
||||
|
import { h } from 'vue'; |
||||
|
import { Tag } from 'ant-design-vue'; |
||||
|
|
||||
|
export const columns: BasicColumn[] = [ |
||||
|
{ |
||||
|
title: '角色名称', |
||||
|
dataIndex: 'roleName', |
||||
|
width: 200, |
||||
|
}, |
||||
|
{ |
||||
|
title: '角色值', |
||||
|
dataIndex: 'roleValue', |
||||
|
width: 180, |
||||
|
}, |
||||
|
{ |
||||
|
title: '排序', |
||||
|
dataIndex: 'orderNo', |
||||
|
width: 50, |
||||
|
}, |
||||
|
{ |
||||
|
title: '状态', |
||||
|
dataIndex: 'status', |
||||
|
width: 80, |
||||
|
customRender: ({ record }) => { |
||||
|
const status = record.status; |
||||
|
const enable = ~~status === 0; |
||||
|
const color = enable ? 'green' : 'red'; |
||||
|
const text = enable ? '启用' : '停用'; |
||||
|
return h(Tag, { color: color }, () => text); |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
title: '创建时间', |
||||
|
dataIndex: 'createTime', |
||||
|
width: 180, |
||||
|
}, |
||||
|
{ |
||||
|
title: '备注', |
||||
|
dataIndex: 'remark', |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const searchFormSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'roleNme', |
||||
|
label: '角色名称', |
||||
|
component: 'Input', |
||||
|
colProps: { span: 8 }, |
||||
|
}, |
||||
|
{ |
||||
|
field: 'status', |
||||
|
label: '状态', |
||||
|
component: 'Select', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '启用', value: '0' }, |
||||
|
{ label: '停用', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
colProps: { span: 8 }, |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export const formSchema: FormSchema[] = [ |
||||
|
{ |
||||
|
field: 'roleName', |
||||
|
label: '角色名称', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'roleValue', |
||||
|
label: '角色值', |
||||
|
required: true, |
||||
|
component: 'Input', |
||||
|
}, |
||||
|
{ |
||||
|
field: 'status', |
||||
|
label: '状态', |
||||
|
component: 'RadioButtonGroup', |
||||
|
defaultValue: '0', |
||||
|
componentProps: { |
||||
|
options: [ |
||||
|
{ label: '启用', value: '0' }, |
||||
|
{ label: '停用', value: '1' }, |
||||
|
], |
||||
|
}, |
||||
|
}, |
||||
|
{ |
||||
|
label: '备注', |
||||
|
field: 'remark', |
||||
|
component: 'InputTextArea', |
||||
|
}, |
||||
|
{ |
||||
|
label: '菜单分配', |
||||
|
field: 'menu', |
||||
|
slot: 'menu', |
||||
|
component: 'Render', |
||||
|
}, |
||||
|
]; |
||||
Loading…
Reference in new issue