feat: 优化其他
parent
9a15a88eb0
commit
01df5849cf
5
.env
5
.env
|
|
@ -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文件
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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([]);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,9 @@ const { component: UserTable } = useTable({
|
|||
],
|
||||
},
|
||||
],
|
||||
source: search => api.user.getUsers(search),
|
||||
source: search => {
|
||||
return [];
|
||||
},
|
||||
search: [
|
||||
{
|
||||
field: 'username',
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ const { component: UserTable } = useTable({
|
|||
],
|
||||
},
|
||||
],
|
||||
source: model => api.user.getUsers(model),
|
||||
source: model => {
|
||||
return api.user.getUsers(model);
|
||||
},
|
||||
search: [
|
||||
{
|
||||
field: 'nickname',
|
||||
|
|
|
|||
Loading…
Reference in New Issue