feat: 优化其他
parent
9a15a88eb0
commit
01df5849cf
5
.env
5
.env
|
|
@ -8,7 +8,8 @@ VITE_SUBTITLE = 绝弹管理中心
|
||||||
# 部署路径: 当为 ./ 时路由模式需为 hash
|
# 部署路径: 当为 ./ 时路由模式需为 hash
|
||||||
VITE_BASE = /
|
VITE_BASE = /
|
||||||
# 接口前缀:参见 axios 的 baseURL
|
# 接口前缀:参见 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
|
VITE_HOME_PATH = /home
|
||||||
# 路由模式:web(路径) hash(锚点)
|
# 路由模式:web(路径) hash(锚点)
|
||||||
|
|
@ -24,7 +25,7 @@ VITE_PORT = 3020
|
||||||
# 代理前缀
|
# 代理前缀
|
||||||
VITE_PROXY_PREFIX = /api,/upload
|
VITE_PROXY_PREFIX = /api,/upload
|
||||||
# 代理地址
|
# 代理地址
|
||||||
VITE_PROXY = http://127.0.0.1:3030/
|
VITE_PROXY = https://appnify.app.juetan.cn/
|
||||||
# API文档 说明:需返回符合 OPENAPI 规范的json内容
|
# API文档 说明:需返回符合 OPENAPI 规范的json内容
|
||||||
VITE_OPENAPI = http://127.0.0.1:3030/openapi.json
|
VITE_OPENAPI = http://127.0.0.1:3030/openapi.json
|
||||||
# 文件后缀 说明:设为dev时会优先加载index.dev.vue文件,否则回退至index.vue文件
|
# 文件后缀 说明:设为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>;
|
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>;
|
export const AnTableContextKey = Symbol('AnTableContextKey') as InjectionKey<AnTableContext>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -64,9 +69,7 @@ export const AnTable = defineComponent({
|
||||||
* 传递给 Table 组件的属性
|
* 传递给 Table 组件的属性
|
||||||
*/
|
*/
|
||||||
tableProps: {
|
tableProps: {
|
||||||
type: Object as PropType<
|
type: Object as PropType<ArcoTableProps>,
|
||||||
Omit<TableInstance['$props'], 'ref' | 'pagination' | 'loading' | 'data' | 'onPageChange' | 'onPageSizeChange'>
|
|
||||||
>,
|
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 插件列表
|
* 插件列表
|
||||||
|
|
@ -126,8 +129,9 @@ export const AnTable = defineComponent({
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
let params = { ...search, ...paging };
|
let params = { ...search, ...paging };
|
||||||
params = props.pluginer?.callBeforeSearchHook(params) ?? params;
|
params = props.pluginer?.callLoadHook(params) ?? params;
|
||||||
const resData = await props.source(params);
|
let resData = await props.source(params);
|
||||||
|
resData = props.pluginer?.callLoadedHook(resData) ?? params;
|
||||||
const { data = [], total = 0 } = resData?.data || {};
|
const { data = [], total = 0 } = resData?.data || {};
|
||||||
renderData.value = data;
|
renderData.value = data;
|
||||||
setPaging({ total });
|
setPaging({ total });
|
||||||
|
|
@ -160,13 +164,11 @@ export const AnTable = defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
const onPageChange = (page: number) => {
|
const onPageChange = (page: number) => {
|
||||||
props.pluginer?.callPageChangeHook(page);
|
|
||||||
setPaging({ current: page });
|
setPaging({ current: page });
|
||||||
loadData();
|
loadData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPageSizeChange = (size: number) => {
|
const onPageSizeChange = (size: number) => {
|
||||||
props.pluginer?.callSizeChangeHook(size);
|
|
||||||
setPaging({ current: 1, pageSize: size });
|
setPaging({ current: 1, pageSize: size });
|
||||||
loadData();
|
loadData();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,8 @@ export interface AnTablePlugin {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
onBeforeSearch?: (args: { page: number; size: number; [key: string]: any }) => Recordable | null | undefined | void;
|
onBeforeSearch?: (args: { page: number; size: number; [key: string]: any }) => Recordable | null | undefined | void;
|
||||||
onPageChange?: (page: number) => void;
|
onLoad?: (search: Recordable) => void;
|
||||||
onSizeChange?: (size: number) => void;
|
onLoaded?: (res: any) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PluginContainer {
|
export class PluginContainer {
|
||||||
|
|
@ -76,13 +76,7 @@ export class PluginContainer {
|
||||||
widgets: any[] = [];
|
widgets: any[] = [];
|
||||||
|
|
||||||
constructor(private plugins: AnTablePlugin[]) {
|
constructor(private plugins: AnTablePlugin[]) {
|
||||||
this.plugins.unshift(
|
this.plugins.unshift(useTableRefresh(), useColumnConfig(), useRowFormat(), useRowDelete(), useRowModify());
|
||||||
useTableRefresh(),
|
|
||||||
useColumnConfig(),
|
|
||||||
useRowFormat(),
|
|
||||||
useRowDelete(),
|
|
||||||
useRowModify()
|
|
||||||
);
|
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
const action = plugin.action?.();
|
const action = plugin.action?.();
|
||||||
if (action) {
|
if (action) {
|
||||||
|
|
@ -129,15 +123,17 @@ export class PluginContainer {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
callPageChangeHook(page: number) {
|
callLoadHook(search: Recordable) {
|
||||||
for (const plugin of this.plugins) {
|
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) {
|
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 { Ref } from 'vue';
|
||||||
import { AnTableContext } from '../components/Table';
|
import { AnTableContext, ArcoTableProps } from '../components/Table';
|
||||||
import { AnTablePlugin } from '../hooks/useTablePlugin';
|
import { AnTablePlugin } from '../hooks/useTablePlugin';
|
||||||
import { useTableSelect } from './useTableSelect';
|
import { useTableSelect } from './useTableSelect';
|
||||||
import { delConfirm, delOptions, sleep } from '@/utils';
|
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 selected: Ref<any[]>;
|
||||||
let context: AnTableContext;
|
let context: AnTableContext;
|
||||||
|
let tableProps: ArcoTableProps;
|
||||||
|
const { confirm, onDelete } = options;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: 'deletemany',
|
id: 'deletemany',
|
||||||
|
onSetup(ctx) {
|
||||||
|
context = ctx;
|
||||||
|
tableProps = ctx.props.tableProps!;
|
||||||
|
},
|
||||||
options(options) {
|
options(options) {
|
||||||
let selectPlugin = options.plugins?.find(i => i.id === 'selection');
|
let selectPlugin = options.plugins?.find(i => i.id === 'selection');
|
||||||
if (!selectPlugin) {
|
if (!selectPlugin) {
|
||||||
|
|
@ -20,18 +31,31 @@ export function useTableDelete(): AnTablePlugin {
|
||||||
selected = selectPlugin.provide!.selectedKeys;
|
selected = selectPlugin.provide!.selectedKeys;
|
||||||
return options;
|
return options;
|
||||||
},
|
},
|
||||||
|
onLoaded() {
|
||||||
|
console.log('loaded');
|
||||||
|
selected.value = [];
|
||||||
|
},
|
||||||
action() {
|
action() {
|
||||||
const onClick = async (props: any) => {
|
const onClick = async (props: any) => {
|
||||||
delConfirm({
|
delConfirm({
|
||||||
...delOptions,
|
...delOptions,
|
||||||
content: '危险操作,确定删除所选数据吗?',
|
content: confirm ?? '危险操作,确定删除所选数据吗?',
|
||||||
async onBeforeOk() {
|
async onBeforeOk() {
|
||||||
await sleep(3000);
|
await sleep(3000);
|
||||||
const res: any = await onClick?.(props);
|
try {
|
||||||
const msg = res?.data?.message;
|
const res: any = await onDelete?.(props);
|
||||||
msg && Message.success(`提示: ${msg}`);
|
const msg = res?.data?.message;
|
||||||
selected.value = [];
|
msg && Message.success(`提示: ${msg}`);
|
||||||
context.refresh();
|
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 { cloneDeep, defaultsDeep, merge } from 'lodash-es';
|
||||||
import { TableUseOptions } from '../hooks/useTable';
|
import { TableUseOptions } from '../hooks/useTable';
|
||||||
import { AnTablePlugin } from '../hooks/useTablePlugin';
|
import { AnTablePlugin } from '../hooks/useTablePlugin';
|
||||||
|
import { AnTableContext, ArcoTableProps } from '../components/Table';
|
||||||
// declare module '@/components/AnTable/hooks/useTable' {
|
|
||||||
// interface TableUseOptions {
|
|
||||||
// todo?: string;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
const defaults: TableUseOptions = {
|
const defaults: TableUseOptions = {
|
||||||
tableProps: {
|
tableProps: {
|
||||||
|
|
@ -26,8 +21,15 @@ interface UseTableSelectOptions {
|
||||||
* @description 请配合其他插件使用
|
* @description 请配合其他插件使用
|
||||||
*/
|
*/
|
||||||
export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptions = {}): AnTablePlugin {
|
export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptions = {}): AnTablePlugin {
|
||||||
|
let context: AnTableContext;
|
||||||
const selectedKeys = ref<(string | number)[]>([]);
|
const selectedKeys = ref<(string | number)[]>([]);
|
||||||
const selectedRows = ref<any[]>([]);
|
const selectedRows = ref<any[]>([]);
|
||||||
|
const setKeys = (keys: any[]) => {
|
||||||
|
const tableProps = context.props.tableProps;
|
||||||
|
if (tableProps) {
|
||||||
|
(tableProps as any).selectedKeys = keys;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: 'selection',
|
id: 'selection',
|
||||||
|
|
@ -35,6 +37,9 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
|
||||||
selectedKeys,
|
selectedKeys,
|
||||||
selectedRows,
|
selectedRows,
|
||||||
},
|
},
|
||||||
|
onSetup(ctx) {
|
||||||
|
context = ctx;
|
||||||
|
},
|
||||||
options(options) {
|
options(options) {
|
||||||
const opts: TableUseOptions = defaultsDeep({}, defaults);
|
const opts: TableUseOptions = defaultsDeep({}, defaults);
|
||||||
|
|
||||||
|
|
@ -45,6 +50,8 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
|
||||||
if (mode === 'both' || mode === 'key') {
|
if (mode === 'both' || mode === 'key') {
|
||||||
opts.tableProps!.onSelectionChange = rowkeys => {
|
opts.tableProps!.onSelectionChange = rowkeys => {
|
||||||
selectedKeys.value = rowkeys;
|
selectedKeys.value = rowkeys;
|
||||||
|
setKeys(rowkeys);
|
||||||
|
console.log(rowkeys);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,6 +61,7 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
selectedRows.value.splice(index, 1);
|
selectedRows.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
setKeys(selectedRows.value.map(i => i.id));
|
||||||
};
|
};
|
||||||
opts.tableProps!.onSelectAll = checked => {
|
opts.tableProps!.onSelectAll = checked => {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
|
|
@ -61,10 +69,14 @@ export function useTableSelect({ key = 'id', mode = 'key' }: UseTableSelectOptio
|
||||||
} else {
|
} else {
|
||||||
selectedRows.value = [];
|
selectedRows.value = [];
|
||||||
}
|
}
|
||||||
|
setKeys(selectedRows.value.map(i => i.id));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return merge(options, opts);
|
return merge(options, opts);
|
||||||
},
|
},
|
||||||
|
onLoaded() {
|
||||||
|
setKeys([]);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,9 @@ const { component: UserTable } = useTable({
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
source: search => api.user.getUsers(search),
|
source: search => {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
search: [
|
search: [
|
||||||
{
|
{
|
||||||
field: 'username',
|
field: 'username',
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
<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="formCtx.open">
|
<a-button @click="open()">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-add"></i>
|
<i class="icon-park-outline-add"></i>
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
<form-modal></form-modal>
|
<DictTypeModal />
|
||||||
</div>
|
</div>
|
||||||
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto">
|
<a-scrollbar outer-class="h-full overflow-hidden" class="h-full overflow-auto">
|
||||||
<ul v-if="list.length" class="pl-0 mt-0">
|
<ul v-if="list.length" class="pl-0 mt-0">
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</template>
|
</template>
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #content>
|
<template #content>
|
||||||
<a-doption @click="formCtx.open(item)">
|
<a-doption @click="open(item)">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<i class="icon-park-outline-edit"></i>
|
<i class="icon-park-outline-edit"></i>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -46,17 +46,17 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<ani-empty v-else></ani-empty>
|
<an-empty v-else></an-empty>
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DictType, api } from "@/api";
|
import { DictType, api } from '@/api';
|
||||||
import { useAniFormModal } from "@/components";
|
import { useFormModal } from '@/components/AnForm';
|
||||||
import { delConfirm } from "@/utils";
|
import { delConfirm } from '@/utils';
|
||||||
import { Message } from "@arco-design/web-vue";
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { PropType } from "vue";
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
current: {
|
current: {
|
||||||
|
|
@ -64,13 +64,13 @@ defineProps({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(['change']);
|
||||||
const list = ref<DictType[]>([]);
|
const list = ref<DictType[]>([]);
|
||||||
|
|
||||||
const updateDictTypes = async () => {
|
const updateDictTypes = async () => {
|
||||||
const res = await api.dictType.getDictTypes({ size: 0 });
|
const res = await api.dictType.getDictTypes({ size: 0 });
|
||||||
list.value = res.data.data ?? [];
|
list.value = res.data.data ?? [];
|
||||||
list.value.length && emit("change", list.value[0]);
|
list.value.length && emit('change', list.value[0]);
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(updateDictTypes);
|
onMounted(updateDictTypes);
|
||||||
|
|
@ -81,38 +81,33 @@ const onDeleteRow = async (row: DictType) => {
|
||||||
Message.success(res.data.message);
|
Message.success(res.data.message);
|
||||||
};
|
};
|
||||||
|
|
||||||
const [formModal, formCtx] = useAniFormModal({
|
const { component: DictTypeModal, open } = useFormModal({
|
||||||
title: ({ model }) => (!model.id ? "新建字典类型" : "修改字典类型"),
|
title: ({ model }) => (!model.id ? '新建字典类型' : '修改字典类型'),
|
||||||
trigger: false,
|
trigger: false,
|
||||||
modalProps: {
|
width: 580,
|
||||||
width: 580,
|
|
||||||
},
|
|
||||||
model: {
|
|
||||||
id: undefined,
|
|
||||||
},
|
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
field: "name",
|
field: 'name',
|
||||||
label: "名称",
|
label: '名称',
|
||||||
type: "input",
|
setter: 'input',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "code",
|
field: 'code',
|
||||||
label: "唯一编码",
|
label: '唯一编码',
|
||||||
type: "input",
|
setter: 'input',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: "description",
|
field: 'description',
|
||||||
label: "备注信息",
|
label: '备注信息',
|
||||||
type: "textarea",
|
setter: 'textarea',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
submit: async ({ model }) => {
|
submit: async model => {
|
||||||
let res;
|
let res;
|
||||||
if (model.id) {
|
if (model.id) {
|
||||||
res = await api.dictType.setDictType(model.id, model);
|
res = await api.dictType.setDictType(model.id, model as any);
|
||||||
} else {
|
} else {
|
||||||
res = await api.dictType.addDictType(model);
|
res = await api.dictType.addDictType(model as any);
|
||||||
}
|
}
|
||||||
updateDictTypes();
|
updateDictTypes();
|
||||||
return res;
|
return res;
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ const { component: OperationTable } = useTable({
|
||||||
render: ({ record }) => dayjs(record.createdAt).fromNow(),
|
render: ({ record }) => dayjs(record.createdAt).fromNow(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
source: model => api.log.getLoginLogs(model),
|
source: model => {
|
||||||
|
return api.log.getLoginLogs(model);
|
||||||
|
},
|
||||||
search: [
|
search: [
|
||||||
{
|
{
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,9 @@ const { component: UserTable } = useTable({
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
source: model => api.user.getUsers(model),
|
source: model => {
|
||||||
|
return api.user.getUsers(model);
|
||||||
|
},
|
||||||
search: [
|
search: [
|
||||||
{
|
{
|
||||||
field: 'nickname',
|
field: 'nickname',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue