feat: 优化其他

master
luoer 2023-11-27 17:23:53 +08:00
parent 9a15a88eb0
commit 01df5849cf
9 changed files with 107 additions and 71 deletions

5
.env
View File

@ -8,7 +8,8 @@ VITE_SUBTITLE = 绝弹管理中心
# 部署路径: 当为 ./ 时路由模式需为 hash
VITE_BASE = /
# 接口前缀:参见 axios 的 baseURL
VITE_API = http://127.0.0.1:3030/
# VITE_API = http://127.0.0.1:3030/
VITE_API = https://appnify.app.juetan.cn/
# 首页路径
VITE_HOME_PATH = /home
# 路由模式web(路径) hash(锚点)
@ -24,7 +25,7 @@ VITE_PORT = 3020
# 代理前缀
VITE_PROXY_PREFIX = /api,/upload
# 代理地址
VITE_PROXY = http://127.0.0.1:3030/
VITE_PROXY = https://appnify.app.juetan.cn/
# API文档 说明:需返回符合 OPENAPI 规范的json内容
VITE_OPENAPI = http://127.0.0.1:3030/openapi.json
# 文件后缀 说明设为dev时会优先加载index.dev.vue文件否则回退至index.vue文件

View File

@ -14,6 +14,11 @@ import { PluginContainer } from '../hooks/useTablePlugin';
type DataFn = (filter: { page: number; size: number; [key: string]: any }) => any | Promise<any>;
export type ArcoTableProps = Omit<
TableInstance['$props'],
'ref' | 'pagination' | 'loading' | 'data' | 'onPageChange' | 'onPageSizeChange'
>;
export const AnTableContextKey = Symbol('AnTableContextKey') as InjectionKey<AnTableContext>;
/**
@ -64,9 +69,7 @@ export const AnTable = defineComponent({
* Table
*/
tableProps: {
type: Object as PropType<
Omit<TableInstance['$props'], 'ref' | 'pagination' | 'loading' | 'data' | 'onPageChange' | 'onPageSizeChange'>
>,
type: Object as PropType<ArcoTableProps>,
},
/**
*
@ -126,8 +129,9 @@ export const AnTable = defineComponent({
try {
loading.value = true;
let params = { ...search, ...paging };
params = props.pluginer?.callBeforeSearchHook(params) ?? params;
const resData = await props.source(params);
params = props.pluginer?.callLoadHook(params) ?? params;
let resData = await props.source(params);
resData = props.pluginer?.callLoadedHook(resData) ?? params;
const { data = [], total = 0 } = resData?.data || {};
renderData.value = data;
setPaging({ total });
@ -160,13 +164,11 @@ export const AnTable = defineComponent({
});
const onPageChange = (page: number) => {
props.pluginer?.callPageChangeHook(page);
setPaging({ current: page });
loadData();
};
const onPageSizeChange = (size: number) => {
props.pluginer?.callSizeChangeHook(size);
setPaging({ current: 1, pageSize: size });
loadData();
};

View File

@ -67,8 +67,8 @@ export interface AnTablePlugin {
*
*/
onBeforeSearch?: (args: { page: number; size: number; [key: string]: any }) => Recordable | null | undefined | void;
onPageChange?: (page: number) => void;
onSizeChange?: (size: number) => void;
onLoad?: (search: Recordable) => void;
onLoaded?: (res: any) => void;
}
export class PluginContainer {
@ -76,13 +76,7 @@ export class PluginContainer {
widgets: any[] = [];
constructor(private plugins: AnTablePlugin[]) {
this.plugins.unshift(
useTableRefresh(),
useColumnConfig(),
useRowFormat(),
useRowDelete(),
useRowModify()
);
this.plugins.unshift(useTableRefresh(), useColumnConfig(), useRowFormat(), useRowDelete(), useRowModify());
for (const plugin of plugins) {
const action = plugin.action?.();
if (action) {
@ -129,15 +123,17 @@ export class PluginContainer {
return options;
}
callPageChangeHook(page: number) {
callLoadHook(search: Recordable) {
for (const plugin of this.plugins) {
plugin.onPageChange?.(page);
search = plugin.onLoad?.(search) ?? search;
}
return search as any;
}
callSizeChangeHook(page: number) {
callLoadedHook(res: any) {
for (const plugin of this.plugins) {
plugin.onPageChange?.(page);
res = plugin.onLoaded?.(res) ?? res;
}
return res;
}
}

View File

@ -1,16 +1,27 @@
import { Ref } from 'vue';
import { AnTableContext } from '../components/Table';
import { AnTableContext, ArcoTableProps } from '../components/Table';
import { AnTablePlugin } from '../hooks/useTablePlugin';
import { useTableSelect } from './useTableSelect';
import { delConfirm, delOptions, sleep } from '@/utils';
import { Button, Message } from '@arco-design/web-vue';
import { Button, Message, TableInstance } from '@arco-design/web-vue';
export function useTableDelete(): AnTablePlugin {
interface UseTableDeleteOptions {
confirm?: string;
onDelete?: (keys: (string | number)[]) => any | Promise<any>;
}
export function useTableDelete(options: UseTableDeleteOptions = {}): AnTablePlugin {
let selected: Ref<any[]>;
let context: AnTableContext;
let tableProps: ArcoTableProps;
const { confirm, onDelete } = options;
return {
id: 'deletemany',
onSetup(ctx) {
context = ctx;
tableProps = ctx.props.tableProps!;
},
options(options) {
let selectPlugin = options.plugins?.find(i => i.id === 'selection');
if (!selectPlugin) {
@ -20,18 +31,31 @@ export function useTableDelete(): AnTablePlugin {
selected = selectPlugin.provide!.selectedKeys;
return options;
},
onLoaded() {
console.log('loaded');
selected.value = [];
},
action() {
const onClick = async (props: any) => {
delConfirm({
...delOptions,
content: '危险操作,确定删除所选数据吗?',
content: confirm ?? '危险操作,确定删除所选数据吗?',
async onBeforeOk() {
await sleep(3000);
const res: any = await onClick?.(props);
const msg = res?.data?.message;
msg && Message.success(`提示: ${msg}`);
selected.value = [];
context.refresh();
try {
const res: any = await onDelete?.(props);
const msg = res?.data?.message;
msg && Message.success(`提示: ${msg}`);
if (tableProps) {
(tableProps as any).selectedKeys = [];
}
selected.value = [];
context.refresh();
return true;
} catch (e) {
console.log('删除失败:', e);
}
return false;
},
});
};

View File

@ -1,12 +1,7 @@
import { cloneDeep, defaultsDeep, merge } from 'lodash-es';
import { TableUseOptions } from '../hooks/useTable';
import { AnTablePlugin } from '../hooks/useTablePlugin';
// declare module '@/components/AnTable/hooks/useTable' {
// interface TableUseOptions {
// todo?: string;
// }
// }
import { AnTableContext, ArcoTableProps } from '../components/Table';
const defaults: TableUseOptions = {
tableProps: {
@ -26,8 +21,15 @@ interface UseTableSelectOptions {
* @description 使
*/
export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptions = {}): AnTablePlugin {
let context: AnTableContext;
const selectedKeys = ref<(string | number)[]>([]);
const selectedRows = ref<any[]>([]);
const setKeys = (keys: any[]) => {
const tableProps = context.props.tableProps;
if (tableProps) {
(tableProps as any).selectedKeys = keys;
}
};
return {
id: 'selection',
@ -35,6 +37,9 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
selectedKeys,
selectedRows,
},
onSetup(ctx) {
context = ctx;
},
options(options) {
const opts: TableUseOptions = defaultsDeep({}, defaults);
@ -45,6 +50,8 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
if (mode === 'both' || mode === 'key') {
opts.tableProps!.onSelectionChange = rowkeys => {
selectedKeys.value = rowkeys;
setKeys(rowkeys);
console.log(rowkeys);
};
}
@ -54,6 +61,7 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
if (index > -1) {
selectedRows.value.splice(index, 1);
}
setKeys(selectedRows.value.map(i => i.id));
};
opts.tableProps!.onSelectAll = checked => {
if (checked) {
@ -61,10 +69,14 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
} else {
selectedRows.value = [];
}
setKeys(selectedRows.value.map(i => i.id));
};
}
return merge(options, opts);
},
onLoaded() {
setKeys([]);
},
};
}

View File

@ -73,7 +73,9 @@ const { component: UserTable } = useTable({
],
},
],
source: search => api.user.getUsers(search),
source: search => {
return [];
},
search: [
{
field: 'username',

View File

@ -2,12 +2,12 @@
<div class="w-[210px] h-full overflow-hidden grid grid-rows-[auto_1fr]">
<div class="flex gap-2">
<a-input-search allow-clear placeholder="字典类型" class="mb-2"></a-input-search>
<a-button @click="formCtx.open">
<a-button @click="open()">
<template #icon>
<i class="icon-park-outline-add"></i>
</template>
</a-button>
<form-modal></form-modal>
<DictTypeModal />
</div>
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto">
<ul v-if="list.length" class="pl-0 mt-0">
@ -29,7 +29,7 @@
</template>
</a-button>
<template #content>
<a-doption @click="formCtx.open(item)">
<a-doption @click="open(item)">
<template #icon>
<i class="icon-park-outline-edit"></i>
</template>
@ -46,17 +46,17 @@
</div>
</li>
</ul>
<ani-empty v-else></ani-empty>
<an-empty v-else></an-empty>
</a-scrollbar>
</div>
</template>
<script setup lang="ts">
import { DictType, api } from "@/api";
import { useAniFormModal } from "@/components";
import { delConfirm } from "@/utils";
import { Message } from "@arco-design/web-vue";
import { PropType } from "vue";
import { DictType, api } from '@/api';
import { useFormModal } from '@/components/AnForm';
import { delConfirm } from '@/utils';
import { Message } from '@arco-design/web-vue';
import { PropType } from 'vue';
defineProps({
current: {
@ -64,13 +64,13 @@ defineProps({
},
});
const emit = defineEmits(["change"]);
const emit = defineEmits(['change']);
const list = ref<DictType[]>([]);
const updateDictTypes = async () => {
const res = await api.dictType.getDictTypes({ size: 0 });
list.value = res.data.data ?? [];
list.value.length && emit("change", list.value[0]);
list.value.length && emit('change', list.value[0]);
};
onMounted(updateDictTypes);
@ -81,38 +81,33 @@ const onDeleteRow = async (row: DictType) => {
Message.success(res.data.message);
};
const [formModal, formCtx] = useAniFormModal({
title: ({ model }) => (!model.id ? "新建字典类型" : "修改字典类型"),
const { component: DictTypeModal, open } = useFormModal({
title: ({ model }) => (!model.id ? '新建字典类型' : '修改字典类型'),
trigger: false,
modalProps: {
width: 580,
},
model: {
id: undefined,
},
width: 580,
items: [
{
field: "name",
label: "名称",
type: "input",
field: 'name',
label: '名称',
setter: 'input',
},
{
field: "code",
label: "唯一编码",
type: "input",
field: 'code',
label: '唯一编码',
setter: 'input',
},
{
field: "description",
label: "备注信息",
type: "textarea",
field: 'description',
label: '备注信息',
setter: 'textarea',
},
],
submit: async ({ model }) => {
submit: async model => {
let res;
if (model.id) {
res = await api.dictType.setDictType(model.id, model);
res = await api.dictType.setDictType(model.id, model as any);
} else {
res = await api.dictType.addDictType(model);
res = await api.dictType.addDictType(model as any);
}
updateDictTypes();
return res;

View File

@ -56,7 +56,9 @@ const { component: OperationTable } = useTable({
render: ({ record }) => dayjs(record.createdAt).fromNow(),
},
],
source: model => api.log.getLoginLogs(model),
source: model => {
return api.log.getLoginLogs(model);
},
search: [
{
field: 'nickname',

View File

@ -84,7 +84,9 @@ const { component: UserTable } = useTable({
],
},
],
source: model => api.user.getUsers(model),
source: model => {
return api.user.getUsers(model);
},
search: [
{
field: 'nickname',