feat: 优化表格hook的使用
parent
12e1ca4c63
commit
8c0c5037b5
|
|
@ -75,14 +75,10 @@ export const Form = defineComponent({
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const res = await props.submit?.({ model, items: props.items });
|
const res = await props.submit?.({ model, items: props.items });
|
||||||
if (res?.message) {
|
res?.message && Message.success(`提示: ${res.message}`);
|
||||||
Message.success(`提示: ${res.message}`);
|
|
||||||
}
|
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const message = error?.response?.data?.message || error?.message || "提交失败";
|
const message = error?.response?.data?.message || error?.message;
|
||||||
if (message) {
|
message && Message.error(`提示: ${message}`);
|
||||||
Message.error(`提示: ${message}`);
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,61 @@
|
||||||
import { Modal } from "@arco-design/web-vue";
|
import { Modal } from "@arco-design/web-vue";
|
||||||
import { assign, merge } from "lodash-es";
|
import { merge } from "lodash-es";
|
||||||
import { reactive } from "vue";
|
import { Component, Ref, reactive } from "vue";
|
||||||
import { useForm } from "./use-form";
|
import { useForm } from "./use-form";
|
||||||
import { FormModalProps } from "./form-modal";
|
import FormModal, { FormModalInstance, FormModalProps } from "./form-modal";
|
||||||
|
|
||||||
const defaults: Partial<InstanceType<typeof Modal>> = {
|
const defaults: Partial<InstanceType<typeof Modal>> = {
|
||||||
width: 1080,
|
width: 1080,
|
||||||
titleAlign: "start",
|
titleAlign: "start",
|
||||||
closable: false
|
closable: false,
|
||||||
|
maskClosable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建传给FormModal组件的参数
|
* 构建传给FormModal组件的参数
|
||||||
* @see src/components/form/use-form-modal.tsx
|
* @see src/components/form/use-form-modal.tsx
|
||||||
*/
|
*/
|
||||||
export const useFormModal = (options: FormModalProps): FormModalProps & { model: Record<string, any> } => {
|
export const useFormModal = (options: Partial<FormModalProps>): FormModalProps => {
|
||||||
const { model, items } = options || {};
|
const { model = {}, items = [] } = options || {};
|
||||||
|
|
||||||
const form = useForm({ model, items });
|
const form = useForm({ model, items });
|
||||||
|
|
||||||
return reactive(merge({ modalProps: { ...defaults } }, { ...options, ...form }));
|
return reactive(
|
||||||
|
merge(
|
||||||
|
{
|
||||||
|
modalProps: { ...defaults },
|
||||||
|
formProps: {
|
||||||
|
layout: "vertical",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
...form,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
props: any;
|
||||||
|
modalRef: Ref<FormModalInstance | null>;
|
||||||
|
open: (args?: Record<string, any>) => Promise<void> | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAniFormModal = (options: Partial<FormModalProps>): [Component, Context] => {
|
||||||
|
const props = useFormModal(options);
|
||||||
|
const modalRef = ref<FormModalInstance | null>(null);
|
||||||
|
const onModalRef = (el: any) => (modalRef.value = el);
|
||||||
|
const component = defineComponent({
|
||||||
|
name: "AniFormModalWrapper",
|
||||||
|
render() {
|
||||||
|
return <FormModal {...this.$attrs} {...props} ref={onModalRef} />;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const component1 = (p: any) => <FormModal {...p} {...props} ref={onModalRef} />;
|
||||||
|
const context = {
|
||||||
|
props,
|
||||||
|
modalRef,
|
||||||
|
open: (args?: Record<string, any>) => modalRef.value?.open(args),
|
||||||
|
};
|
||||||
|
return [component1, context];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -161,18 +161,14 @@ export const Table = defineComponent({
|
||||||
<div class="table w-full">
|
<div class="table w-full">
|
||||||
{!this.inlined && (
|
{!this.inlined && (
|
||||||
<div class="border-b pb-2 border-slate-200 mb-5">
|
<div class="border-b pb-2 border-slate-200 mb-5">
|
||||||
<Form ref="searchRef" class="!grid grid-cols-4 gap-x-6" {...this.search}></Form>
|
<Form ref="searchRef" class="!grid grid-cols-4 gap-x-6" {...this.search}></Form>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div class={`mb-3 flex justify-between ${!this.inlined && "mt-2"}`}>
|
<div class={`mb-3 flex justify-between ${!this.inlined && "mt-2"}`}>
|
||||||
<div class={`${this.create || this.$slots.action ? null : '!hidden'} flex-1 flex gap-2 `}>
|
<div class={`${this.create || this.$slots.action ? null : "!hidden"} flex-1 flex gap-2 `}>
|
||||||
{this.create && (
|
{this.create && (
|
||||||
<FormModal
|
<FormModal {...(this.create as any)} ref="createRef" onSubmited={this.reloadData}></FormModal>
|
||||||
{...(this.create as any)}
|
|
||||||
ref="createRef"
|
|
||||||
onSubmited={this.reloadData}
|
|
||||||
></FormModal>
|
|
||||||
)}
|
)}
|
||||||
{this.modify && (
|
{this.modify && (
|
||||||
<FormModal
|
<FormModal
|
||||||
|
|
@ -184,14 +180,13 @@ export const Table = defineComponent({
|
||||||
)}
|
)}
|
||||||
{this.$slots.action?.()}
|
{this.$slots.action?.()}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>{this.inlined && <Form ref="searchRef" {...this.search}></Form>}</div>
|
||||||
{this.inlined && <Form ref="searchRef" {...this.search}></Form>}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BaseTable
|
<BaseTable
|
||||||
row-key="id"
|
row-key="id"
|
||||||
bordered={false}
|
bordered={false}
|
||||||
|
{...this.$attrs}
|
||||||
{...this.tableProps}
|
{...this.tableProps}
|
||||||
loading={this.loading}
|
loading={this.loading}
|
||||||
pagination={this.pagination}
|
pagination={this.pagination}
|
||||||
|
|
@ -204,6 +199,12 @@ export const Table = defineComponent({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格组件实例
|
||||||
|
*/
|
||||||
export type TableInstance = InstanceType<typeof Table>;
|
export type TableInstance = InstanceType<typeof Table>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格组件参数
|
||||||
|
*/
|
||||||
export type TableProps = TableInstance["$props"];
|
export type TableProps = TableInstance["$props"];
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ interface TableColumnDropdown {
|
||||||
doptionProps?: Partial<InstanceType<typeof Doption> & Record<string, any>>;
|
doptionProps?: Partial<InstanceType<typeof Doption> & Record<string, any>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UseTableColumn extends TableColumnData {
|
export interface TableColumn extends TableColumnData {
|
||||||
/**
|
/**
|
||||||
* 表格列类型
|
* 表格列类型
|
||||||
*/
|
*/
|
||||||
|
|
@ -113,7 +113,7 @@ type Search = Partial<
|
||||||
*/
|
*/
|
||||||
items?: SearchFormItem[];
|
items?: SearchFormItem[];
|
||||||
/**
|
/**
|
||||||
* bu
|
* 显示/隐藏搜索按钮
|
||||||
*/
|
*/
|
||||||
button?: boolean
|
button?: boolean
|
||||||
}
|
}
|
||||||
|
|
@ -137,7 +137,7 @@ export interface UseTableOptions extends Omit<TableProps, "search" | "create" |
|
||||||
* 表格列配置
|
* 表格列配置
|
||||||
* @see https://arco.design/web-vue/components/table/#tablecolumn
|
* @see https://arco.design/web-vue/components/table/#tablecolumn
|
||||||
*/
|
*/
|
||||||
columns: UseTableColumn[];
|
columns: TableColumn[];
|
||||||
/**
|
/**
|
||||||
* 搜索表单配置
|
* 搜索表单配置
|
||||||
* @see FormProps
|
* @see FormProps
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { delConfirm } from "@/utils";
|
import { delConfirm } from "@/utils";
|
||||||
import { Doption, Dropdown, Link, Message, TableColumnData } from "@arco-design/web-vue";
|
import { Doption, Dropdown, Link, Message, TableColumnData } from "@arco-design/web-vue";
|
||||||
import { isArray, merge } from "lodash-es";
|
import { isArray, merge } from "lodash-es";
|
||||||
import { reactive } from "vue";
|
import { Component, Ref, reactive } from "vue";
|
||||||
import { useFormModal } from "../form";
|
import { useFormModal } from "../form";
|
||||||
import { TableInstance } from "./table";
|
import { Table, TableInstance, TableProps } from "./table";
|
||||||
import { config } from "./table.config";
|
import { config } from "./table.config";
|
||||||
import { UseTableOptions } from "./use-interface";
|
import { UseTableOptions } from "./use-interface";
|
||||||
|
|
||||||
|
|
@ -18,15 +18,11 @@ const onClick = async (item: any, columnData: any, getTable: any) => {
|
||||||
try {
|
try {
|
||||||
const resData: any = await item?.onClick?.(columnData);
|
const resData: any = await item?.onClick?.(columnData);
|
||||||
const message = resData?.data?.message;
|
const message = resData?.data?.message;
|
||||||
if (message) {
|
message && Message.success(`提示:${message}`);
|
||||||
Message.success(`提示:${message}`);
|
|
||||||
}
|
|
||||||
getTable()?.loadData();
|
getTable()?.loadData();
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
const message = error.response?.data?.message;
|
const message = error.response?.data?.message;
|
||||||
if (message) {
|
message && Message.warning(`提示:${message}`);
|
||||||
Message.warning(`提示:${message}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -171,13 +167,13 @@ export const useTable = (optionsOrFn: UseTableOptions | (() => UseTableOptions))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const search = !item.enableLoad ? undefined : () => getTable().reloadData()
|
const search = !item.enableLoad ? undefined : () => getTable().reloadData();
|
||||||
searchItems.push(
|
searchItems.push(
|
||||||
merge(
|
merge(
|
||||||
{
|
{
|
||||||
nodeProps: {
|
nodeProps: {
|
||||||
onSearch: search,
|
onSearch: search,
|
||||||
onPressEnter: search
|
onPressEnter: search,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
item
|
item
|
||||||
|
|
@ -213,3 +209,54 @@ export const useTable = (optionsOrFn: UseTableOptions | (() => UseTableOptions))
|
||||||
|
|
||||||
return reactive({ ...options, columns });
|
return reactive({ ...options, columns });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提供操作的上下文
|
||||||
|
*/
|
||||||
|
interface TableContext {
|
||||||
|
/**
|
||||||
|
* 传递给表格的参数(响应式)
|
||||||
|
*/
|
||||||
|
props: TableProps;
|
||||||
|
/**
|
||||||
|
* 表格实例
|
||||||
|
*/
|
||||||
|
tableRef: Ref<TableInstance | null>;
|
||||||
|
/**
|
||||||
|
* 刷新表格
|
||||||
|
*/
|
||||||
|
refresh: () => void;
|
||||||
|
/**
|
||||||
|
* 重置表格
|
||||||
|
*/
|
||||||
|
reload?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TableReturnType = [
|
||||||
|
/**
|
||||||
|
* 绑定好参数的组件
|
||||||
|
*/
|
||||||
|
Component,
|
||||||
|
/**
|
||||||
|
* 提供操作的上下文
|
||||||
|
*/
|
||||||
|
TableContext
|
||||||
|
];
|
||||||
|
|
||||||
|
export const useAniTable = (options: UseTableOptions): TableReturnType => {
|
||||||
|
const props = useTable(options);
|
||||||
|
const tableRef = ref<TableInstance | null>(null);
|
||||||
|
const context = {
|
||||||
|
props,
|
||||||
|
tableRef,
|
||||||
|
refresh: () => tableRef.value?.reloadData(),
|
||||||
|
};
|
||||||
|
const aniTable = defineComponent({
|
||||||
|
name: "AniTableWrapper",
|
||||||
|
setup() {
|
||||||
|
const onRef = (el: TableInstance) => (tableRef.value = el);
|
||||||
|
return () => <Table ref={onRef} {...props}></Table>;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return [aniTable, context];
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -44,11 +44,15 @@
|
||||||
:breakpoint="'lg'"
|
:breakpoint="'lg'"
|
||||||
@collapse="onCollapse"
|
@collapse="onCollapse"
|
||||||
>
|
>
|
||||||
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-hidden pt-2">
|
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-hidden pt-0.5">
|
||||||
<Menu />
|
<Menu />
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
<template #trigger="{ collapsed }">
|
<template #trigger="{ collapsed }">
|
||||||
<i :class="`text-gray-400 text-base ${collapsed ? 'icon-park-outline-expand-left' : 'icon-park-outline-expand-right'}`"></i>
|
<i
|
||||||
|
:class="`text-gray-400 text-base ${
|
||||||
|
collapsed ? 'icon-park-outline-expand-left' : 'icon-park-outline-expand-right'
|
||||||
|
}`"
|
||||||
|
></i>
|
||||||
</template>
|
</template>
|
||||||
</a-layout-sider>
|
</a-layout-sider>
|
||||||
<a-layout class="layout-content flex-1">
|
<a-layout class="layout-content flex-1">
|
||||||
|
|
@ -56,15 +60,17 @@
|
||||||
<div class="h-full flex items-center justify-between gap-2 px-4">
|
<div class="h-full flex items-center justify-between gap-2 px-4">
|
||||||
<div class="space-x-2">
|
<div class="space-x-2">
|
||||||
<a-tag
|
<a-tag
|
||||||
v-for="item in tagItems"
|
v-for="item in appStore.pageTags"
|
||||||
:key="item.text"
|
:key="item.id"
|
||||||
:color="item.active ? 'rgb(var(--primary-6))' : ''"
|
:color="item.path === route.fullPath ? 'blue' : undefined"
|
||||||
:closable="item.showClose"
|
:closable="item.closible"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
@mouseenter="item.showClose = true"
|
@mouseenter="item.closable && (item.closible = true)"
|
||||||
@mouseleave="item.showClose = false"
|
@mouseleave="item.closable && (item.closible = false)"
|
||||||
|
@close="appStore.delPageTag(item)"
|
||||||
|
@click="router.push(item.path)"
|
||||||
>
|
>
|
||||||
{{ item.text }}
|
{{ item.title }}
|
||||||
</a-tag>
|
</a-tag>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -77,10 +83,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a-layout-header>
|
</a-layout-header>
|
||||||
<a-layout-content class="overflow-x-auto">
|
<a-layout-content class="overflow-x-auto">
|
||||||
<a-spin :loading="appStore.pageLoding" tip="正在加载中,请稍等..." class="block h-full w-full">
|
<a-spin :loading="appStore.pageLoding" tip="加载中,请稍等..." class="block h-full w-full">
|
||||||
<template #icon>
|
|
||||||
<IconSync></IconSync>
|
|
||||||
</template>
|
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<component :is="Component"></component>
|
<component :is="Component"></component>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
@ -94,7 +97,6 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useAppStore, useUserStore } from "@/store";
|
import { useAppStore, useUserStore } from "@/store";
|
||||||
import { Message } from "@arco-design/web-vue";
|
import { Message } from "@arco-design/web-vue";
|
||||||
import { IconSync } from "@arco-design/web-vue/es/icon";
|
|
||||||
import Menu from "./components/menu.vue";
|
import Menu from "./components/menu.vue";
|
||||||
import userDropdown from "./components/userDropdown.vue";
|
import userDropdown from "./components/userDropdown.vue";
|
||||||
|
|
||||||
|
|
@ -106,6 +108,21 @@ const router = useRouter();
|
||||||
const themeConfig = ref({ visible: false });
|
const themeConfig = ref({ visible: false });
|
||||||
const isDev = import.meta.env.DEV;
|
const isDev = import.meta.env.DEV;
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => route.path,
|
||||||
|
() => {
|
||||||
|
console.log("path change");
|
||||||
|
appStore.addPageTag({
|
||||||
|
id: route.fullPath,
|
||||||
|
path: route.path,
|
||||||
|
title: route.meta.title!,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const onCollapse = (val: boolean) => {
|
const onCollapse = (val: boolean) => {
|
||||||
isCollapsed.value = val;
|
isCollapsed.value = val;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,59 +1,98 @@
|
||||||
<template>
|
<template>
|
||||||
<BreadPage>
|
<BreadPage>
|
||||||
<div class="min-h-full grid grid-cols-[auto_auto_1fr]">
|
<template #content>
|
||||||
<div class="w-[200px]">
|
<div class="overflow-hidden grid grid-cols-[auto_auto_1fr] m-4 p-4 bg-white">
|
||||||
<div class="flex gap-2">
|
<div class="w-[210px] h-full overflow-hidden grid grid-rows-[auto_1fr]">
|
||||||
<a-input-search allow-clear placeholder="分组名称..." class="mb-2"></a-input-search>
|
<div class="flex gap-2 pr-2">
|
||||||
<a-button>
|
<a-input-search allow-clear placeholder="分组名称..." class="mb-2"></a-input-search>
|
||||||
<template #icon>
|
<a-button>
|
||||||
<i class="icon-park-outline-add"></i>
|
<template #icon>
|
||||||
</template>
|
<i class="icon-park-outline-add"></i>
|
||||||
</a-button>
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto">
|
||||||
|
<ul class="pr-4 pl-0 mt-0">
|
||||||
|
<li
|
||||||
|
v-for="i in 50"
|
||||||
|
class="group flex items-center justify-between gap-2 h-8 rounded mb-2 pl-3 hover:bg-gray-100 cursor-pointer"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<i class="icon-file-folder text-gray-600"></i>
|
||||||
|
日常素材
|
||||||
|
<span class="text-xs text-gray-400">(10)</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a-dropdown>
|
||||||
|
<a-button size="small" type="text">
|
||||||
|
<template #icon>
|
||||||
|
<i class="icon-park-outline-more-one text-gray-400 hover:text-gray-700"></i>
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
<template #content>
|
||||||
|
<a-doption @click="typeCtx.open()">
|
||||||
|
<template #icon>
|
||||||
|
<i class="icon-park-outline-edit"></i>
|
||||||
|
</template>
|
||||||
|
修改
|
||||||
|
</a-doption>
|
||||||
|
<a-doption class="!text-red-500">
|
||||||
|
<template #icon>
|
||||||
|
<i class="icon-park-outline-delete"></i>
|
||||||
|
</template>
|
||||||
|
删除
|
||||||
|
</a-doption>
|
||||||
|
</template>
|
||||||
|
</a-dropdown>
|
||||||
|
<type-modal></type-modal>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</a-scrollbar>
|
||||||
|
</div>
|
||||||
|
<a-divider direction="vertical" :margin="16"></a-divider>
|
||||||
|
<div>
|
||||||
|
<Table v-bind="table">
|
||||||
|
<template #action>
|
||||||
|
<a-button type="primary" @click="uploadRef?.open()">
|
||||||
|
<template #icon>
|
||||||
|
<i class="icon-park-outline-upload"></i>
|
||||||
|
</template>
|
||||||
|
上传
|
||||||
|
</a-button>
|
||||||
|
<ani-upload ref="uploadRef"></ani-upload>
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
<li
|
|
||||||
v-for="i in 10"
|
|
||||||
class="group flex items-center justify-between gap-2 h-8 rounded mb-2 pl-3 hover:bg-gray-100 cursor-pointer"
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<i class="icon-file-folder text-gray-600"></i>
|
|
||||||
日常素材
|
|
||||||
<span class="text-xs text-gray-400">(10)</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<a-button size="small" type="text" class="!hidden !group-hover:inline-block">
|
|
||||||
<template #icon>
|
|
||||||
<i class="icon-park-outline-more-one text-gray-400 hover:text-gray-700"></i>
|
|
||||||
</template>
|
|
||||||
</a-button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</div>
|
</div>
|
||||||
<a-divider direction="vertical" :margin="16"></a-divider>
|
</template>
|
||||||
<div>
|
|
||||||
<Table v-bind="table">
|
|
||||||
<template #action>
|
|
||||||
<a-button type="primary" @click="uploadRef?.open()">
|
|
||||||
<template #icon>
|
|
||||||
<i class="icon-park-outline-upload"></i>
|
|
||||||
</template>
|
|
||||||
上传
|
|
||||||
</a-button>
|
|
||||||
<ani-upload ref="uploadRef"></ani-upload>
|
|
||||||
</template>
|
|
||||||
</Table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</BreadPage>
|
</BreadPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import { Table, useTable } from "@/components";
|
import { Table, useAniFormModal, useTable } from "@/components";
|
||||||
import { dayjs } from "@/libs/dayjs";
|
import { dayjs } from "@/libs/dayjs";
|
||||||
import numeral from "numeral";
|
import numeral from "numeral";
|
||||||
import AniUpload from './components/upload.vue';
|
import AniUpload from "./components/upload.vue";
|
||||||
|
|
||||||
const uploadRef = ref<InstanceType<typeof AniUpload>>()
|
const [typeModal, typeCtx] = useAniFormModal({
|
||||||
|
title: "修改分组",
|
||||||
|
trigger: false,
|
||||||
|
modalProps: {
|
||||||
|
width: 432,
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
field: "name",
|
||||||
|
label: "分组名称",
|
||||||
|
type: "input",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
submit: async () => {},
|
||||||
|
});
|
||||||
|
|
||||||
|
const uploadRef = ref<InstanceType<typeof AniUpload>>();
|
||||||
|
|
||||||
const getIcon = (mimetype: string) => {
|
const getIcon = (mimetype: string) => {
|
||||||
if (mimetype.startsWith("image")) {
|
if (mimetype.startsWith("image")) {
|
||||||
|
|
@ -131,7 +170,7 @@ const table = useTable({
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
},
|
},
|
||||||
nodeProps: {
|
nodeProps: {
|
||||||
placeholder: "素材名称...",
|
placeholder: "素材名称",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<BreadPage>
|
<BreadPage>
|
||||||
<Table v-bind="table"></Table>
|
<a-button @click="roleCtx.refresh()">刷新</a-button>
|
||||||
|
<role-table></role-table>
|
||||||
</BreadPage>
|
</BreadPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { api } from "@/api";
|
import { api } from "@/api";
|
||||||
import { Table, useTable } from "@/components";
|
import { useAniTable } from "@/components";
|
||||||
import { dayjs } from "@/libs";
|
import { dayjs } from "@/libs";
|
||||||
|
|
||||||
const table = useTable({
|
const [roleTable, roleCtx] = useAniTable({
|
||||||
data: async (model, paging) => {
|
data: async () => {
|
||||||
return api.role.getRoles();
|
return api.role.getRoles();
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
|
|
@ -47,7 +48,7 @@ const table = useTable({
|
||||||
text: "修改",
|
text: "修改",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: '分配权限',
|
text: "分配权限",
|
||||||
onClick: ({ record }) => {
|
onClick: ({ record }) => {
|
||||||
console.log(record);
|
console.log(record);
|
||||||
},
|
},
|
||||||
|
|
@ -58,21 +59,21 @@ const table = useTable({
|
||||||
onClick: ({ record }) => {
|
onClick: ({ record }) => {
|
||||||
return api.role.delRole(record.id);
|
return api.role.delRole(record.id);
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
search: {
|
search: {
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
extend: "name",
|
field: "name",
|
||||||
required: false,
|
type: "input",
|
||||||
nodeProps: {
|
nodeProps: {
|
||||||
placeholder: '请输入角色名称'
|
placeholder: "角色名称",
|
||||||
},
|
},
|
||||||
itemProps: {
|
itemProps: {
|
||||||
hideLabel: true,
|
hideLabel: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import generatedRoutes from "virtual:generated-pages";
|
import generatedRoutes from "virtual:generated-pages";
|
||||||
import { RouteRecordRaw } from "vue-router";
|
import { RouteRecordRaw } from "vue-router";
|
||||||
|
import { routes as rawRoutes } from "vue-router/auto/routes";
|
||||||
|
|
||||||
const APP_ROUTE_NAME = "_layout";
|
const APP_ROUTE_NAME = "_layout";
|
||||||
|
|
||||||
|
|
@ -13,6 +14,9 @@ const transformRoutes = (routes: RouteRecordRaw[]) => {
|
||||||
|
|
||||||
for (const route of routes) {
|
for (const route of routes) {
|
||||||
if ((route.name as string)?.startsWith("_")) {
|
if ((route.name as string)?.startsWith("_")) {
|
||||||
|
if (route.name === APP_ROUTE_NAME) {
|
||||||
|
route.children = appRoutes;
|
||||||
|
}
|
||||||
route.path = route.path.replace("_", "");
|
route.path = route.path.replace("_", "");
|
||||||
topRoutes.push(route);
|
topRoutes.push(route);
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -20,11 +24,6 @@ const transformRoutes = (routes: RouteRecordRaw[]) => {
|
||||||
appRoutes.push(route);
|
appRoutes.push(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
const appRoute = routes.find((i) => i.name === APP_ROUTE_NAME);
|
|
||||||
if (appRoute) {
|
|
||||||
appRoute.children = appRoutes;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [topRoutes, appRoutes];
|
return [topRoutes, appRoutes];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,14 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
|
interface PageTag {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
path: string;
|
||||||
|
closable?: boolean;
|
||||||
|
closible?: boolean;
|
||||||
|
actived?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export const useAppStore = defineStore({
|
export const useAppStore = defineStore({
|
||||||
id: "app",
|
id: "app",
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
|
@ -19,6 +28,16 @@ export const useAppStore = defineStore({
|
||||||
* 页面是否加载中,用于路由首次加载
|
* 页面是否加载中,用于路由首次加载
|
||||||
*/
|
*/
|
||||||
pageLoding: false,
|
pageLoding: false,
|
||||||
|
pageTags: [
|
||||||
|
{
|
||||||
|
id: "/",
|
||||||
|
title: "首页",
|
||||||
|
path: "/",
|
||||||
|
closable: false,
|
||||||
|
closible: false,
|
||||||
|
actived: false,
|
||||||
|
},
|
||||||
|
] as PageTag[],
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
/**
|
/**
|
||||||
|
|
@ -48,7 +67,35 @@ export const useAppStore = defineStore({
|
||||||
*/
|
*/
|
||||||
setPageLoading(loading: boolean) {
|
setPageLoading(loading: boolean) {
|
||||||
this.pageLoding = loading;
|
this.pageLoding = loading;
|
||||||
}
|
},
|
||||||
|
/**
|
||||||
|
* 添加页面标签
|
||||||
|
* @param tag 标签
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
addPageTag(tag: PageTag) {
|
||||||
|
if (this.pageTags.some((i) => i.id === tag.id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pageTags.push({
|
||||||
|
closable: true,
|
||||||
|
closible: false,
|
||||||
|
actived: false,
|
||||||
|
...tag,
|
||||||
|
});
|
||||||
|
console.log(this.pageTags);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 移除页面标签
|
||||||
|
* @param tag 标签
|
||||||
|
*/
|
||||||
|
delPageTag(tag: PageTag) {
|
||||||
|
console.log("del page tag");
|
||||||
|
const index = this.pageTags.findIndex((i) => i.id === tag.id);
|
||||||
|
if (index > -1) {
|
||||||
|
this.pageTags.splice(index, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
persist: !import.meta.env.DEV,
|
persist: !import.meta.env.DEV,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ declare module '@vue/runtime-core' {
|
||||||
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
|
AListItemMeta: typeof import('@arco-design/web-vue')['ListItemMeta']
|
||||||
AMenu: typeof import('@arco-design/web-vue')['Menu']
|
AMenu: typeof import('@arco-design/web-vue')['Menu']
|
||||||
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
|
AMenuItem: typeof import('@arco-design/web-vue')['MenuItem']
|
||||||
AMenuItemGroup: typeof import('@arco-design/web-vue')['MenuItemGroup']
|
|
||||||
AModal: typeof import('@arco-design/web-vue')['Modal']
|
AModal: typeof import('@arco-design/web-vue')['Modal']
|
||||||
APagination: typeof import('@arco-design/web-vue')['Pagination']
|
APagination: typeof import('@arco-design/web-vue')['Pagination']
|
||||||
APopover: typeof import('@arco-design/web-vue')['Popover']
|
APopover: typeof import('@arco-design/web-vue')['Popover']
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue