feat: 添加字典管理
parent
09498ec02e
commit
1133555ca2
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,156 @@
|
||||||
|
<template>
|
||||||
|
<bread-page>
|
||||||
|
<template #content>
|
||||||
|
<div class="h-full w-full grid grid-cols-[auto_1fr] gap-4 p-4">
|
||||||
|
<div class="bg-white w-[256px]">
|
||||||
|
<div class="flex items-center justify-between gap-2 px-4 h-14">
|
||||||
|
<span class="text-base">菜单列表</span>
|
||||||
|
<div>
|
||||||
|
<a-button>
|
||||||
|
<template #icon>
|
||||||
|
<i class="icon-park-outline-plus"></i>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-tree
|
||||||
|
:data="menus"
|
||||||
|
:default-expand-all="true"
|
||||||
|
:block-node="true"
|
||||||
|
:field-names="{
|
||||||
|
icon: undefined,
|
||||||
|
title: 'name',
|
||||||
|
key: 'id',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<template #title="node">
|
||||||
|
<div class="group flex-1 flex items-center justify-between gap-2">
|
||||||
|
<div @click="onEdit(node)">
|
||||||
|
<!-- <a-tag :color="MenuTypes.fmt(node.type, 'color')" size="small" :bordered="true">
|
||||||
|
{{ MenuTypes.fmt(node.type) }}
|
||||||
|
</a-tag> -->
|
||||||
|
<i :class="node.icon" class="ml-2"></i>
|
||||||
|
{{ node.name }}
|
||||||
|
</div>
|
||||||
|
<div class="hidden group-hover:block">
|
||||||
|
<i
|
||||||
|
v-if="node.type === MenuType.MENU"
|
||||||
|
class="text-sm text-gray-400 hover:text-gray-700 icon-park-outline-plus"
|
||||||
|
></i>
|
||||||
|
<i class="text-sm text-gray-400 hover:text-gray-700 icon-park-outline-delete"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-tree>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white">
|
||||||
|
<a-card title="菜单信息" :bordered="false">
|
||||||
|
<Form ref="formRef" v-bind="form"></Form>
|
||||||
|
</a-card>
|
||||||
|
<a-divider :margin="0"></a-divider>
|
||||||
|
<div class="px-4 mt-4">
|
||||||
|
<btn-table></btn-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</bread-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import { Menu, api } from "@/api";
|
||||||
|
import { useForm, Form, useAniTable, FormInstance } from "@/components";
|
||||||
|
import { MenuType, MenuTypes } from "@/constants/menu";
|
||||||
|
|
||||||
|
const formRef = ref<FormInstance | null>(null);
|
||||||
|
const menus = ref<any[]>([]);
|
||||||
|
const treeEach = (tree: any[], fn: any) => {
|
||||||
|
for (const item of tree) {
|
||||||
|
if (item.children) {
|
||||||
|
treeEach(item.children, fn);
|
||||||
|
}
|
||||||
|
fn(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onEdit = (row: any) => {
|
||||||
|
formRef.value?.setModel(row);
|
||||||
|
(btn.props as any).data = row.buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const res = await api.menu.getMenus({ tree: true });
|
||||||
|
const data = res.data.data ?? [];
|
||||||
|
treeEach(data, (item: Menu) => {
|
||||||
|
if (item.type === MenuType.BUTTON) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (item.type === MenuType.PAGE) {
|
||||||
|
(item as any).buttons = (item as any).children;
|
||||||
|
delete (item as any).children;
|
||||||
|
}
|
||||||
|
(item as any).iconRender = () => <i class={item.icon} />;
|
||||||
|
});
|
||||||
|
menus.value = data;
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = useForm({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
field: "name",
|
||||||
|
label: "菜单名称",
|
||||||
|
type: "input",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "icon",
|
||||||
|
label: "菜单图标",
|
||||||
|
type: "input",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
async submit(arg) {
|
||||||
|
console.log(arg);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const [btnTable, btn] = useAniTable({
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: " 名称",
|
||||||
|
dataIndex: "name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "标识",
|
||||||
|
dataIndex: "code",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "操作",
|
||||||
|
type: "button",
|
||||||
|
width: 140,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: "modify",
|
||||||
|
text: "修改",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: "删除",
|
||||||
|
type: "delete",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
create: {},
|
||||||
|
modify: {},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
|
|
||||||
|
<route lang="json">
|
||||||
|
{
|
||||||
|
"meta": {
|
||||||
|
"sort": 10302,
|
||||||
|
"title": "菜单管理",
|
||||||
|
"icon": "icon-park-outline-add-subtract"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</route>
|
||||||
|
|
@ -143,7 +143,7 @@ export const FormModal = defineComponent({
|
||||||
}
|
}
|
||||||
if (typeof props.trigger === "object") {
|
if (typeof props.trigger === "object") {
|
||||||
content = (
|
content = (
|
||||||
<Button type="primary" {...omit(props.trigger, "text")}>
|
<Button type="primary" {...props.trigger.buttonProps}>
|
||||||
{props.trigger?.text || "新增"}
|
{props.trigger?.text || "新增"}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<bread-page>
|
<bread-page>
|
||||||
<iframe
|
<template #content>
|
||||||
src="https://apifox.com/apidoc/shared-f1ea65e6-cee8-4fe3-949f-288a7cd1af49"
|
<iframe
|
||||||
frameborder="0"
|
src="https://apifox.com/apidoc/shared-f1ea65e6-cee8-4fe3-949f-288a7cd1af49"
|
||||||
class="w-full h-full"
|
frameborder="0"
|
||||||
></iframe>
|
class="w-full h-full"
|
||||||
|
></iframe>
|
||||||
|
</template>
|
||||||
</bread-page>
|
</bread-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import doc from "@/dd.json";
|
import doc from "./data.json";
|
||||||
import editorModal from "./editor.vue";
|
import editorModal from "./editor.vue";
|
||||||
import ejs from "ejs";
|
import ejs from "ejs";
|
||||||
import template from "./page.ejs?raw";
|
import template from "./page.ejs?raw";
|
||||||
|
|
@ -85,8 +85,8 @@ const onChange = (value: string | number) => {
|
||||||
|
|
||||||
const onOpen = () => {
|
const onOpen = () => {
|
||||||
const data = {
|
const data = {
|
||||||
tag: '',
|
tag: "",
|
||||||
operationId: '',
|
operationId: "",
|
||||||
create: {},
|
create: {},
|
||||||
select: {},
|
select: {},
|
||||||
modify: {},
|
modify: {},
|
||||||
|
|
@ -106,7 +106,6 @@ const onOpen = () => {
|
||||||
data.delete = route;
|
data.delete = route;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(data);
|
|
||||||
content.value = ejs.render(template, data);
|
content.value = ejs.render(template, data);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="w-[210px] h-full overflow-hidden grid grid-rows-[auto_1fr]">
|
<div class="w-[210px] h-full overflow-hidden grid grid-rows-[auto_1fr]">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<a-input-search allow-clear placeholder="字典名称..." class="mb-2"></a-input-search>
|
<a-input-search allow-clear placeholder="字典类型" class="mb-2"></a-input-search>
|
||||||
<a-button @click="onCreateRow">
|
<a-button @click="formCtx.open">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-add"></i>
|
<i class="icon-park-outline-add"></i>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -13,12 +13,13 @@
|
||||||
<ul class="pl-0 mt-0">
|
<ul class="pl-0 mt-0">
|
||||||
<li
|
<li
|
||||||
v-for="item in list"
|
v-for="item in list"
|
||||||
:key="item.id"
|
:key="item.code"
|
||||||
|
:class="{ active: item.id === current?.id }"
|
||||||
class="group flex items-center justify-between gap-1 h-8 rounded mb-2 pl-3 hover:bg-gray-100 cursor-pointer"
|
class="group flex items-center justify-between gap-1 h-8 rounded mb-2 pl-3 hover:bg-gray-100 cursor-pointer"
|
||||||
>
|
>
|
||||||
<div>
|
<div class="flex-1 h-full flex items-center gap-2 overflow-hidden" @click="emit('change', item)">
|
||||||
<i class="icon-park-outline-folder-close align-[-2px]"></i>
|
<i class="icon-park-outline-folder-close align-[-2px]"></i>
|
||||||
{{ item.title }}
|
<span class="flex-1 truncate">{{ item.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
|
|
@ -28,13 +29,13 @@
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-doption @click="onModifyRow(item)">
|
<a-doption @click="formCtx.open(item)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-edit"></i>
|
<i class="icon-park-outline-edit"></i>
|
||||||
</template>
|
</template>
|
||||||
修改
|
修改
|
||||||
</a-doption>
|
</a-doption>
|
||||||
<a-doption class="!text-red-500" @click="onDeleteRow">
|
<a-doption class="!text-red-500" @click="onDeleteRow(item)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-delete"></i>
|
<i class="icon-park-outline-delete"></i>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -50,86 +51,77 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { DictType, api } from "@/api";
|
||||||
import { useAniFormModal } from "@/components";
|
import { useAniFormModal } from "@/components";
|
||||||
import { delConfirm } from "@/utils";
|
import { delConfirm } from "@/utils";
|
||||||
|
import { Message } from "@arco-design/web-vue";
|
||||||
|
import { PropType } from "vue";
|
||||||
|
|
||||||
const data = [
|
defineProps({
|
||||||
{
|
current: {
|
||||||
id: 1,
|
type: Object as PropType<DictType>,
|
||||||
title: "用户性别",
|
|
||||||
count: 23,
|
|
||||||
},
|
},
|
||||||
{
|
});
|
||||||
id: 2,
|
|
||||||
title: "微信头像",
|
|
||||||
count: 52,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
title: "文章封面",
|
|
||||||
count: 19,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
title: "山水诗画",
|
|
||||||
count: 81,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
title: "虾米沙雕",
|
|
||||||
count: 12,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const list = ref(data);
|
const emit = defineEmits(["change"]);
|
||||||
|
const list = ref<DictType[]>([]);
|
||||||
|
|
||||||
const onModifyRow = (row: any) => {
|
const updateDictTypes = async () => {
|
||||||
formCtx.props.title = "修改字典";
|
const res = await api.dictType.getDictTypes({ size: 0 });
|
||||||
formCtx.open(row);
|
list.value = res.data.data ?? [];
|
||||||
|
list.value.length && emit("change", list.value[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCreateRow = () => {
|
onMounted(updateDictTypes);
|
||||||
formCtx.props.title = "新建字典";
|
|
||||||
formCtx.open();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteRow = async () => {
|
const onDeleteRow = async (row: DictType) => {
|
||||||
await delConfirm();
|
await delConfirm();
|
||||||
|
const res = await api.dictType.delDictType(row.id);
|
||||||
|
Message.success(res.data.message);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [formModal, formCtx] = useAniFormModal({
|
const [formModal, formCtx] = useAniFormModal({
|
||||||
title: "修改分组",
|
title: ({ model }) => (!model.id ? "新建字典类型" : "修改字典类型"),
|
||||||
trigger: false,
|
trigger: false,
|
||||||
modalProps: {
|
modalProps: {
|
||||||
width: 432,
|
width: 580,
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
field: "title",
|
field: "name",
|
||||||
label: "分组名称",
|
label: "名称",
|
||||||
type: "input",
|
type: "input",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: "code",
|
||||||
|
label: "唯一编码",
|
||||||
|
type: "input",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "description",
|
||||||
|
label: "备注信息",
|
||||||
|
type: "textarea",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
submit: async ({ model }) => {
|
submit: async ({ model }) => {
|
||||||
|
let res;
|
||||||
if (model.id) {
|
if (model.id) {
|
||||||
const item = list.value.find((i) => i.id === model.id);
|
res = await api.dictType.setDictType(model.id, model);
|
||||||
if (item) {
|
|
||||||
item.title = model.title;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const ids = list.value.map((i) => i.id);
|
res = await api.dictType.addDictType(model);
|
||||||
const maxId = Math.max.apply(null, ids);
|
|
||||||
list.value.push({
|
|
||||||
id: maxId,
|
|
||||||
title: model.title,
|
|
||||||
count: 0,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
updateDictTypes();
|
||||||
|
return res;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped>
|
||||||
|
.active {
|
||||||
|
color: rgb(var(--primary-6));
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -3,56 +3,125 @@
|
||||||
<div class="py-2 px-4 bg-white">
|
<div class="py-2 px-4 bg-white">
|
||||||
<bread-crumb></bread-crumb>
|
<bread-crumb></bread-crumb>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid grid-cols-[auto_auto_1fr] h-full overflow-hidden bg-white p-4 m-4 rounded">
|
<div class="grid grid-cols-[auto_1fr] gap-4 overflow-hidden bg-white p-4 m-4 rounded">
|
||||||
<div>
|
<div>
|
||||||
<ani-group></ani-group>
|
<ani-group :current="current" @change="onTypeChange"></ani-group>
|
||||||
</div>
|
</div>
|
||||||
<a-divider direction="vertical"></a-divider>
|
|
||||||
<div>
|
<div>
|
||||||
|
<a-alert :show-icon="false" class="mb-3 !border-brand-500">
|
||||||
|
<span class="text-brand-500 font-bold">{{ current?.name }}</span>
|
||||||
|
<div class="mt-1">描述:{{ current?.description }}</div>
|
||||||
|
</a-alert>
|
||||||
<dict-table></dict-table>
|
<dict-table></dict-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="tsx">
|
||||||
|
import { DictType, api } from "@/api";
|
||||||
import aniGroup from "./components/group.vue";
|
import aniGroup from "./components/group.vue";
|
||||||
import { useAniTable, useForm, Form } from "@/components";
|
import { useAniTable, createColumn, updateColumn } from "@/components";
|
||||||
|
|
||||||
const form = useForm({
|
const current = ref<DictType>();
|
||||||
items: [
|
const onTypeChange = (item: DictType) => {
|
||||||
{
|
current.value = item;
|
||||||
field: "字典名",
|
dict.refresh();
|
||||||
label: "字典名",
|
};
|
||||||
type: "input",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
field: "字典名",
|
|
||||||
label: "",
|
|
||||||
type: "submit",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const [dictTable, dict] = useAniTable({
|
const [dictTable, dict] = useAniTable({
|
||||||
|
async data(search, paging) {
|
||||||
|
return api.dict.getDicts({ ...search, ...paging, typeId: current.value?.id } as any);
|
||||||
|
},
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
title: "字典名",
|
title: "字典项",
|
||||||
dataIndex: "name",
|
dataIndex: "name",
|
||||||
|
render: ({ record }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
{record.name}: {record.code}
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-400 text-xs">{record.description}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
createColumn,
|
||||||
|
updateColumn,
|
||||||
{
|
{
|
||||||
title: "字典值",
|
title: "操作",
|
||||||
dataIndex: "name",
|
type: "button",
|
||||||
|
width: 140,
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
type: "modify",
|
||||||
|
text: "修改",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "delete",
|
||||||
|
text: "删除",
|
||||||
|
onClick: ({ record }) => {
|
||||||
|
return api.dict.delDict(record.id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
create: {
|
search: {
|
||||||
|
button: false,
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
field: "字典名",
|
field: "name",
|
||||||
|
label: "名称",
|
||||||
|
type: "search",
|
||||||
|
searchable: true,
|
||||||
|
enterable: true,
|
||||||
|
nodeProps: {
|
||||||
|
placeholder: "字典名称",
|
||||||
|
},
|
||||||
|
itemProps: {
|
||||||
|
hideLabel: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
title: '新增字典',
|
||||||
|
model: {
|
||||||
|
typeId: undefined,
|
||||||
|
},
|
||||||
|
modalProps: {
|
||||||
|
width: 580,
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
field: "name",
|
||||||
label: "字典名",
|
label: "字典名",
|
||||||
type: "input",
|
type: "input",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: "code",
|
||||||
|
label: "字典指",
|
||||||
|
type: "input",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "description",
|
||||||
|
label: "备注",
|
||||||
|
type: "textarea",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
submit: async ({ model }) => {
|
||||||
|
return api.dict.addDict({ ...model, typeId: current.value?.id });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modify: {
|
||||||
|
extend: true,
|
||||||
|
title: "修改字典",
|
||||||
|
submit: async ({ model }) => {
|
||||||
|
return api.dict.setDict(model.id, { ...model, typeId: current.value?.id });
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ const menuArr = flatedMenus.map((i) => ({ label: i.title, value: i.id }));
|
||||||
|
|
||||||
const expanded = ref(false);
|
const expanded = ref(false);
|
||||||
const toggleExpand = () => {
|
const toggleExpand = () => {
|
||||||
console.log(menu.tableRef.value);
|
|
||||||
expanded.value = !expanded.value;
|
expanded.value = !expanded.value;
|
||||||
menu.tableRef.value?.tableRef?.expandAll(expanded.value);
|
menu.tableRef.value?.tableRef?.expandAll(expanded.value);
|
||||||
};
|
};
|
||||||
|
|
@ -64,12 +63,7 @@ const [menuTable, menu] = useAniTable({
|
||||||
<span>{record.name ?? "无"}</span>
|
<span>{record.name ?? "无"}</span>
|
||||||
<span class="text-gray-400 text-xs truncate">{id}</span>
|
<span class="text-gray-400 text-xs truncate">{id}</span>
|
||||||
</div>
|
</div>
|
||||||
<a-switch checked-color="#3c9" size="small">
|
<a-switch checked-color="#3c9" size="small"></a-switch>
|
||||||
{{
|
|
||||||
"checked-icon": () => <i class="icon-park-outline-check"></i>,
|
|
||||||
"unchecked-icon": () => <i class="icon-park-outline-close"></i>,
|
|
||||||
}}
|
|
||||||
</a-switch>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -102,13 +96,6 @@ const [menuTable, menu] = useAniTable({
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// title: "启用",
|
|
||||||
// dataIndex: "createdAt",
|
|
||||||
// width: 80,
|
|
||||||
// align: "center",
|
|
||||||
// render: ({ record }) => <a-switch checked-color="#3c9"></a-switch>,
|
|
||||||
// },
|
|
||||||
],
|
],
|
||||||
search: {
|
search: {
|
||||||
items: [
|
items: [
|
||||||
|
|
@ -137,10 +124,9 @@ const [menuTable, menu] = useAniTable({
|
||||||
initial: 0,
|
initial: 0,
|
||||||
label: "父级",
|
label: "父级",
|
||||||
type: "treeSelect",
|
type: "treeSelect",
|
||||||
async options(arg) {
|
async options() {
|
||||||
const res = await api.menu.getMenus({ size: 0, tree: true });
|
const res = await api.menu.getMenus({ size: 0, tree: true });
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
console.log(arg);
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ declare module '@vue/runtime-core' {
|
||||||
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
|
ACheckbox: typeof import('@arco-design/web-vue')['Checkbox']
|
||||||
ACheckboxGroup: typeof import('@arco-design/web-vue')['CheckboxGroup']
|
ACheckboxGroup: typeof import('@arco-design/web-vue')['CheckboxGroup']
|
||||||
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
|
AConfigProvider: typeof import('@arco-design/web-vue')['ConfigProvider']
|
||||||
ADatePicker: typeof import('@arco-design/web-vue')['DatePicker']
|
|
||||||
ADivider: typeof import('@arco-design/web-vue')['Divider']
|
ADivider: typeof import('@arco-design/web-vue')['Divider']
|
||||||
ADoption: typeof import('@arco-design/web-vue')['Doption']
|
ADoption: typeof import('@arco-design/web-vue')['Doption']
|
||||||
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
|
ADrawer: typeof import('@arco-design/web-vue')['Drawer']
|
||||||
|
|
@ -68,6 +67,7 @@ declare module '@vue/runtime-core' {
|
||||||
Editor: typeof import('./../components/editor/index.vue')['default']
|
Editor: typeof import('./../components/editor/index.vue')['default']
|
||||||
Header: typeof import('./../components/editor/panel-main/components/header.vue')['default']
|
Header: typeof import('./../components/editor/panel-main/components/header.vue')['default']
|
||||||
ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default']
|
ImagePicker: typeof import('./../components/editor/components/ImagePicker.vue')['default']
|
||||||
|
'Index.dev1': typeof import('./../components/breadcrumb/index.dev1.vue')['default']
|
||||||
InputColor: typeof import('./../components/editor/components/InputColor.vue')['default']
|
InputColor: typeof import('./../components/editor/components/InputColor.vue')['default']
|
||||||
InputImage: typeof import('./../components/editor/components/InputImage.vue')['default']
|
InputImage: typeof import('./../components/editor/components/InputImage.vue')['default']
|
||||||
Marquee: typeof import('./../components/editor/blocks/text/marquee.vue')['default']
|
Marquee: typeof import('./../components/editor/blocks/text/marquee.vue')['default']
|
||||||
|
|
@ -81,6 +81,7 @@ declare module '@vue/runtime-core' {
|
||||||
Render: typeof import('./../components/editor/blocks/date/render.vue')['default']
|
Render: typeof import('./../components/editor/blocks/date/render.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
'Temp.dev1': typeof import('./../components/breadcrumb/temp.dev1.vue')['default']
|
||||||
Texter: typeof import('./../components/editor/panel-main/components/texter.vue')['default']
|
Texter: typeof import('./../components/editor/panel-main/components/texter.vue')['default']
|
||||||
Toast: typeof import('./../components/toast/toast.vue')['default']
|
Toast: typeof import('./../components/toast/toast.vue')['default']
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,11 @@
|
||||||
|
/**
|
||||||
|
* 列表转树结构
|
||||||
|
* @param list 数组
|
||||||
|
* @param id ID key
|
||||||
|
* @param pid 父级key
|
||||||
|
* @param cid 子项key
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export const listToTree = (list: any[], id = "id", pid = "parentId", cid = "children") => {
|
export const listToTree = (list: any[], id = "id", pid = "parentId", cid = "children") => {
|
||||||
const map = list.reduce((res, v) => ((res[v[id]] = v), res), {});
|
const map = list.reduce((res, v) => ((res[v[id]] = v), res), {});
|
||||||
return list.filter((item) => {
|
return list.filter((item) => {
|
||||||
|
|
@ -10,11 +18,18 @@ export const listToTree = (list: any[], id = "id", pid = "parentId", cid = "chil
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function treeEach(tree: any[], fn: (item: any) => void) {
|
/**
|
||||||
|
* 遍历树结构
|
||||||
|
* @param tree 数组
|
||||||
|
* @param fn 函数
|
||||||
|
* @param before 是否广度遍历
|
||||||
|
*/
|
||||||
|
export function treeEach(tree: any[], fn: (item: any) => void, before = true) {
|
||||||
for (const item of tree) {
|
for (const item of tree) {
|
||||||
fn(item);
|
before && fn(item);
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
treeEach(item.children, fn);
|
treeEach(item.children, fn);
|
||||||
}
|
}
|
||||||
|
!before && fn(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue