mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-21 02:56:38 +08:00
fix(projects): fix example code
This commit is contained in:
parent
54c9511bf8
commit
47e7ade11b
@ -241,7 +241,6 @@ const local: App.I18n.Schema = {
|
||||
function: 'System Function',
|
||||
alova: 'Alova Example',
|
||||
alova_request: 'Alova Request',
|
||||
alova_user: 'User List',
|
||||
alova_scenes: 'Scenario Request',
|
||||
'pro-naive': 'Pro Naive Example',
|
||||
'pro-naive_form': 'Form',
|
||||
|
@ -238,7 +238,6 @@ const local: App.I18n.Schema = {
|
||||
function: '系统功能',
|
||||
alova: 'alova示例',
|
||||
alova_request: 'alova请求',
|
||||
alova_user: '用户列表',
|
||||
alova_scenes: '场景化请求',
|
||||
'pro-naive': 'Pro Naive UI 示例',
|
||||
'pro-naive_form': '表单',
|
||||
|
@ -23,7 +23,6 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
||||
about: () => import("@/views/about/index.vue"),
|
||||
alova_request: () => import("@/views/alova/request/index.vue"),
|
||||
alova_scenes: () => import("@/views/alova/scenes/index.vue"),
|
||||
alova_user: () => import("@/views/alova/user/index.vue"),
|
||||
"function_hide-child_one": () => import("@/views/function/hide-child/one/index.vue"),
|
||||
"function_hide-child_three": () => import("@/views/function/hide-child/three/index.vue"),
|
||||
"function_hide-child_two": () => import("@/views/function/hide-child/two/index.vue"),
|
||||
|
@ -81,17 +81,6 @@ export const generatedRoutes: GeneratedRoute[] = [
|
||||
icon: 'cbi:scene-dynamic',
|
||||
order: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'alova_user',
|
||||
path: '/alova/user',
|
||||
component: 'view.alova_user',
|
||||
meta: {
|
||||
title: 'alova_user',
|
||||
i18nKey: 'route.alova_user',
|
||||
icon: 'carbon:user-multiple',
|
||||
order: 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -185,7 +185,6 @@ const routeMap: RouteMap = {
|
||||
"alova": "/alova",
|
||||
"alova_request": "/alova/request",
|
||||
"alova_scenes": "/alova/scenes",
|
||||
"alova_user": "/alova/user",
|
||||
"function": "/function",
|
||||
"function_hide-child": "/function/hide-child",
|
||||
"function_hide-child_one": "/function/hide-child/one",
|
||||
|
2
src/typings/elegant-router.d.ts
vendored
2
src/typings/elegant-router.d.ts
vendored
@ -39,7 +39,6 @@ declare module "@elegant-router/types" {
|
||||
"alova": "/alova";
|
||||
"alova_request": "/alova/request";
|
||||
"alova_scenes": "/alova/scenes";
|
||||
"alova_user": "/alova/user";
|
||||
"function": "/function";
|
||||
"function_hide-child": "/function/hide-child";
|
||||
"function_hide-child_one": "/function/hide-child/one";
|
||||
@ -183,7 +182,6 @@ declare module "@elegant-router/types" {
|
||||
| "about"
|
||||
| "alova_request"
|
||||
| "alova_scenes"
|
||||
| "alova_user"
|
||||
| "function_hide-child_one"
|
||||
| "function_hide-child_three"
|
||||
| "function_hide-child_two"
|
||||
|
@ -1,78 +0,0 @@
|
||||
import { computed, ref } from 'vue';
|
||||
import type { DataTableBaseColumn, DataTableColumn } from 'naive-ui';
|
||||
import type { TableColumnCheck } from '@sa/hooks';
|
||||
import { $t } from '@/locales';
|
||||
import type { AlovaGenerics, Method } from '~/packages/alova/src';
|
||||
|
||||
function isTableColumnHasKey<T>(column: DataTableColumn<T>): column is DataTableBaseColumn<T> {
|
||||
return Boolean((column as NaiveUI.TableColumnWithKey<T>).key);
|
||||
}
|
||||
|
||||
type TableAlovaApiFn<T = any, R = Api.Common.CommonSearchParams> = (
|
||||
params: R
|
||||
) => Method<AlovaGenerics<Api.Common.PaginatingQueryRecord<T>>>;
|
||||
|
||||
// this hook is used to manage table columns
|
||||
// if you choose alova, you can move this hook to the `src/hooks` to handle all list page in your project
|
||||
export default function useCheckedColumns<A extends TableAlovaApiFn, T = Awaited<ReturnType<A>>['records'][number]>(
|
||||
getColumns: () => DataTableColumn<T>[]
|
||||
) {
|
||||
const SELECTION_KEY = '__selection__';
|
||||
|
||||
const EXPAND_KEY = '__expand__';
|
||||
|
||||
const getColumnChecks = (cols: DataTableColumn<T>[]) => {
|
||||
const checks: NaiveUI.TableColumnCheck[] = [];
|
||||
cols.forEach(column => {
|
||||
if (isTableColumnHasKey(column)) {
|
||||
checks.push({
|
||||
key: column.key as string,
|
||||
title: column.title as string,
|
||||
checked: true
|
||||
});
|
||||
} else if (column.type === 'selection') {
|
||||
checks.push({
|
||||
key: SELECTION_KEY,
|
||||
title: $t('common.check'),
|
||||
checked: true
|
||||
});
|
||||
} else if (column.type === 'expand') {
|
||||
checks.push({
|
||||
key: EXPAND_KEY,
|
||||
title: $t('common.expandColumn'),
|
||||
checked: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return checks;
|
||||
};
|
||||
|
||||
const columnChecks = ref<TableColumnCheck[]>(getColumnChecks(getColumns()));
|
||||
|
||||
const columns = computed(() => {
|
||||
const cols = getColumns();
|
||||
const columnMap = new Map<string, DataTableColumn<T>>();
|
||||
|
||||
cols.forEach(column => {
|
||||
if (isTableColumnHasKey(column)) {
|
||||
columnMap.set(column.key as string, column);
|
||||
} else if (column.type === 'selection') {
|
||||
columnMap.set(SELECTION_KEY, column);
|
||||
} else if (column.type === 'expand') {
|
||||
columnMap.set(EXPAND_KEY, column);
|
||||
}
|
||||
});
|
||||
|
||||
const filteredColumns = columnChecks.value
|
||||
.filter(item => item.checked)
|
||||
.map(check => columnMap.get(check.key) as NaiveUI.TableColumn<T>);
|
||||
|
||||
return filteredColumns;
|
||||
});
|
||||
|
||||
return {
|
||||
columnChecks,
|
||||
columns
|
||||
};
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
import type { Ref } from 'vue';
|
||||
import { ref } from 'vue';
|
||||
import { useBoolean } from '@sa/hooks';
|
||||
import { jsonClone } from '@sa/utils';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
type TableData = NaiveUI.TableData;
|
||||
interface Operations<T> {
|
||||
delete?: (row: T) => Promise<void>;
|
||||
batchDelete?: (rows: T[]) => Promise<void>;
|
||||
}
|
||||
|
||||
// this hook is used to handle the table operations
|
||||
// if you choose alova, you can move this hook to the `src/hooks` to handle all list page in your project
|
||||
export default function useTableOperate<T extends TableData = TableData>(data: Ref<T[]>, operations: Operations<T>) {
|
||||
const { bool: drawerVisible, setTrue: openDrawer, setFalse: closeDrawer } = useBoolean();
|
||||
const { bool: deleting, setTrue: deletify, setFalse: antiDelete } = useBoolean();
|
||||
const { bool: batchDeleting, setTrue: batchDeletify, setFalse: antiBatchDelete } = useBoolean();
|
||||
|
||||
const operateType = ref<NaiveUI.TableOperateType>('add');
|
||||
|
||||
const getRowByDataId = (id: T['id']) => data.value.find(item => item.id === id) || null;
|
||||
|
||||
function handleAdd() {
|
||||
operateType.value = 'add';
|
||||
openDrawer();
|
||||
}
|
||||
|
||||
/** the editing row data */
|
||||
const editingData: Ref<T | null> = ref(null);
|
||||
|
||||
function handleEdit(id: T['id']) {
|
||||
operateType.value = 'edit';
|
||||
editingData.value = jsonClone(getRowByDataId(id));
|
||||
|
||||
openDrawer();
|
||||
}
|
||||
|
||||
/** the checked row keys of table */
|
||||
const checkedRowKeys = ref<T['id'][]>([]);
|
||||
|
||||
/** handler to batch delete rows */
|
||||
async function handleBatchDelete() {
|
||||
batchDeletify();
|
||||
try {
|
||||
const rows = checkedRowKeys.value.map(id => getRowByDataId(id)).filter(Boolean);
|
||||
await operations.batchDelete?.(rows as T[]);
|
||||
window.$message?.success($t('common.deleteSuccess'));
|
||||
checkedRowKeys.value = [];
|
||||
} finally {
|
||||
antiBatchDelete();
|
||||
}
|
||||
}
|
||||
|
||||
/** handler to delete row */
|
||||
async function handleDelete(id: T['id']) {
|
||||
deletify();
|
||||
const row = getRowByDataId(id);
|
||||
if (!row) return;
|
||||
try {
|
||||
await operations.delete?.(row);
|
||||
window.$message?.success($t('common.deleteSuccess'));
|
||||
checkedRowKeys.value = [];
|
||||
} finally {
|
||||
antiDelete();
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
drawerVisible,
|
||||
openDrawer,
|
||||
closeDrawer,
|
||||
operateType,
|
||||
handleAdd,
|
||||
editingData,
|
||||
handleEdit,
|
||||
checkedRowKeys,
|
||||
deleting,
|
||||
handleDelete,
|
||||
batchDeleting,
|
||||
handleBatchDelete
|
||||
};
|
||||
}
|
@ -1,226 +0,0 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { usePagination } from '@sa/alova/client';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { batchDeleteUser, deleteUser, fetchGetUserList } from '@/service-alova/api';
|
||||
import { $t } from '@/locales';
|
||||
import useCheckedColumns from './hooks/use-checked-columns';
|
||||
import useTableOperate from './hooks/use-table-operate';
|
||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||
import UserSearch from './modules/user-search.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const searchParams = reactive({
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
});
|
||||
const { loading, data, refresh, reload, page, pageSize, pageCount, send, remove } = usePagination(
|
||||
(pageNum, size) =>
|
||||
fetchGetUserList({
|
||||
...searchParams,
|
||||
current: pageNum,
|
||||
size
|
||||
}),
|
||||
{
|
||||
data: ({ records }) => records,
|
||||
total: ({ total }) => total,
|
||||
|
||||
// trigger reload when states in `searchParams` changed
|
||||
watchingStates: [searchParams],
|
||||
|
||||
// debounce of `searchParams`
|
||||
debounce: [1000]
|
||||
}
|
||||
);
|
||||
const getDataByPage = (newPage = 1) => {
|
||||
page.value = newPage;
|
||||
send(page.value, pageSize.value);
|
||||
};
|
||||
|
||||
const {
|
||||
drawerVisible,
|
||||
operateType,
|
||||
editingData,
|
||||
handleAdd,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleBatchDelete,
|
||||
checkedRowKeys,
|
||||
deleting
|
||||
// batchDeleting
|
||||
// closeDrawer
|
||||
} = useTableOperate(data, {
|
||||
async delete(row) {
|
||||
await deleteUser(row.id);
|
||||
remove(row);
|
||||
},
|
||||
async batchDelete(rows) {
|
||||
await batchDeleteUser(rows.map(({ id }) => id));
|
||||
remove(...rows);
|
||||
}
|
||||
});
|
||||
|
||||
function edit(id: number) {
|
||||
handleEdit(id);
|
||||
}
|
||||
|
||||
const { columnChecks, columns } = useCheckedColumns<typeof fetchGetUserList>(() => [
|
||||
{
|
||||
type: 'selection',
|
||||
align: 'center',
|
||||
width: 48
|
||||
},
|
||||
{
|
||||
key: 'userName',
|
||||
title: $t('page.manage.user.userName'),
|
||||
align: 'center',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
key: 'userGender',
|
||||
title: $t('page.manage.user.userGender'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: row => {
|
||||
if (row.userGender === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tagMap: Record<Api.SystemManage.UserGender, NaiveUI.ThemeColor> = {
|
||||
1: 'primary',
|
||||
2: 'error'
|
||||
};
|
||||
|
||||
const label = $t(userGenderRecord[row.userGender]);
|
||||
|
||||
return <NTag type={tagMap[row.userGender]}>{label}</NTag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'nickName',
|
||||
title: $t('page.manage.user.nickName'),
|
||||
align: 'center',
|
||||
minWidth: 100
|
||||
},
|
||||
{
|
||||
key: 'userPhone',
|
||||
title: $t('page.manage.user.userPhone'),
|
||||
align: 'center',
|
||||
width: 120
|
||||
},
|
||||
{
|
||||
key: 'userEmail',
|
||||
title: $t('page.manage.user.userEmail'),
|
||||
align: 'center',
|
||||
minWidth: 200
|
||||
},
|
||||
{
|
||||
key: 'status',
|
||||
title: $t('page.manage.user.userStatus'),
|
||||
align: 'center',
|
||||
width: 100,
|
||||
render: row => {
|
||||
if (row.status === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tagMap: Record<Api.Common.EnableStatus, NaiveUI.ThemeColor> = {
|
||||
1: 'success',
|
||||
2: 'warning'
|
||||
};
|
||||
|
||||
const label = $t(enableStatusRecord[row.status]);
|
||||
|
||||
return <NTag type={tagMap[row.status]}>{label}</NTag>;
|
||||
}
|
||||
},
|
||||
{
|
||||
key: 'operate',
|
||||
title: $t('common.operate'),
|
||||
align: 'center',
|
||||
width: 130,
|
||||
render: row => (
|
||||
<div class="flex-center gap-8px">
|
||||
<NButton type="primary" ghost size="small" onClick={() => edit(row.id)}>
|
||||
{$t('common.edit')}
|
||||
</NButton>
|
||||
<NPopconfirm
|
||||
onPositiveClick={() => handleDelete(row.id)}
|
||||
positiveButtonProps={{
|
||||
loading: deleting.value
|
||||
}}
|
||||
>
|
||||
{{
|
||||
default: () => $t('common.confirmDelete'),
|
||||
trigger: () => (
|
||||
<NButton type="error" ghost size="small">
|
||||
{$t('common.delete')}
|
||||
</NButton>
|
||||
)
|
||||
}}
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<UserSearch v-model:model="searchParams" @search="getDataByPage" />
|
||||
<NCard :title="$t('page.manage.user.title')" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
v-model:columns="columnChecks"
|
||||
:disabled-delete="checkedRowKeys.length === 0"
|
||||
:loading="loading"
|
||||
@add="handleAdd"
|
||||
@delete="handleBatchDelete"
|
||||
@refresh="refresh"
|
||||
/>
|
||||
</template>
|
||||
<NDataTable
|
||||
v-model:checked-row-keys="checkedRowKeys"
|
||||
:columns="columns"
|
||||
:data="data"
|
||||
size="small"
|
||||
:flex-height="!appStore.isMobile"
|
||||
:scroll-x="962"
|
||||
:loading="loading"
|
||||
remote
|
||||
:row-key="row => row.id"
|
||||
:pagination="{
|
||||
page,
|
||||
pageSize,
|
||||
showSizePicker: true,
|
||||
pageCount,
|
||||
pageSizes: [10, 15, 20, 25, 30],
|
||||
onUpdatePage(value) {
|
||||
page = value;
|
||||
},
|
||||
onUpdatePageSize(value) {
|
||||
pageSize = value;
|
||||
}
|
||||
}"
|
||||
class="sm:h-full"
|
||||
/>
|
||||
<UserOperateDrawer
|
||||
v-model:visible="drawerVisible"
|
||||
:operate-type="operateType"
|
||||
:row-data="editingData"
|
||||
@submitted="reload"
|
||||
/>
|
||||
</NCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,169 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue';
|
||||
import { useForm, useWatcher } from '@sa/alova/client';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import type { UserModel } from '@/service-alova/api';
|
||||
import { addUser, fetchGetAllRoles, updateUser } from '@/service-alova/api';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserOperateDrawer'
|
||||
});
|
||||
|
||||
interface Props {
|
||||
/** the type of operation */
|
||||
operateType: NaiveUI.TableOperateType;
|
||||
/** the edit row data */
|
||||
rowData?: Api.SystemManage.User | null;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'submitted'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
const { defaultRequiredRule } = useFormRules();
|
||||
|
||||
const title = computed(() => {
|
||||
const titles: Record<NaiveUI.TableOperateType, string> = {
|
||||
add: $t('page.manage.user.addUser'),
|
||||
edit: $t('page.manage.user.editUser')
|
||||
};
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
const {
|
||||
loading: submiting,
|
||||
reset,
|
||||
send: submit,
|
||||
form,
|
||||
updateForm
|
||||
} = useForm(formData => (props.operateType === 'add' ? addUser(formData) : updateUser(formData)), {
|
||||
initialForm: {
|
||||
userName: '',
|
||||
userGender: null,
|
||||
nickName: '',
|
||||
userPhone: '',
|
||||
userEmail: '',
|
||||
userRoles: [],
|
||||
status: null
|
||||
} as UserModel,
|
||||
resetAfterSubmiting: true
|
||||
});
|
||||
|
||||
type RuleKey = Extract<keyof UserModel, 'userName' | 'status'>;
|
||||
|
||||
const rules: Record<RuleKey, App.Global.FormRule> = {
|
||||
userName: defaultRequiredRule,
|
||||
status: defaultRequiredRule
|
||||
};
|
||||
|
||||
/** the enabled role options */
|
||||
const { data: roleOptionsRaw, loading } = useWatcher(fetchGetAllRoles, [visible], {
|
||||
initialData: [],
|
||||
middleware(_, next) {
|
||||
return visible.value ? next() : undefined;
|
||||
}
|
||||
});
|
||||
const roleOptions = computed<CommonType.Option<string>[]>(() => {
|
||||
const options = roleOptionsRaw.value.map(item => ({
|
||||
label: item.roleName,
|
||||
value: item.roleCode
|
||||
}));
|
||||
|
||||
// the mock data does not have the roleCode, so fill it
|
||||
// if the real request, remove the following code
|
||||
const userRoleOptions = form.value.userRoles.map(item => ({
|
||||
label: item,
|
||||
value: item
|
||||
}));
|
||||
// end
|
||||
|
||||
return [...userRoleOptions, ...options];
|
||||
});
|
||||
|
||||
function handleInitModel() {
|
||||
if (props.operateType === 'edit' && props.rowData) {
|
||||
updateForm(props.rowData);
|
||||
} else if (props.operateType === 'add') {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
// request
|
||||
await submit();
|
||||
window.$message?.success($t('common.updateSuccess'));
|
||||
closeDrawer();
|
||||
emit('submitted');
|
||||
}
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
restoreValidation();
|
||||
handleInitModel();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NDrawer v-model:show="visible" display-directive="show" :width="360">
|
||||
<NDrawerContent :title="title" :native-scrollbar="false" closable>
|
||||
<NForm ref="formRef" :model="form" :rules="rules">
|
||||
<NFormItem :label="$t('page.manage.user.userName')" path="userName">
|
||||
<NInput v-model:value="form.userName" :placeholder="$t('page.manage.user.form.userName')" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.userGender')" path="userGender">
|
||||
<NRadioGroup v-model:value="form.userGender">
|
||||
<NRadio v-for="item in userGenderOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.nickName')" path="nickName">
|
||||
<NInput v-model:value="form.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.userPhone')" path="userPhone">
|
||||
<NInput v-model:value="form.userPhone" :placeholder="$t('page.manage.user.form.userPhone')" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.userEmail')" path="email">
|
||||
<NInput v-model:value="form.userEmail" :placeholder="$t('page.manage.user.form.userEmail')" />
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.userStatus')" path="status">
|
||||
<NRadioGroup v-model:value="form.status">
|
||||
<NRadio v-for="item in enableStatusOptions" :key="item.value" :value="item.value" :label="$t(item.label)" />
|
||||
</NRadioGroup>
|
||||
</NFormItem>
|
||||
<NFormItem :label="$t('page.manage.user.userRole')" path="roles">
|
||||
<NSelect
|
||||
v-model:value="form.userRoles"
|
||||
multiple
|
||||
:loading="loading"
|
||||
:options="roleOptions"
|
||||
:placeholder="$t('page.manage.user.form.userRole')"
|
||||
/>
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
<template #footer>
|
||||
<NSpace :size="16">
|
||||
<NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
|
||||
<NButton type="primary" :loading="submiting" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -1,113 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { enableStatusOptions, userGenderOptions } from '@/constants/business';
|
||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({
|
||||
name: 'UserSearch'
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||
|
||||
const model = defineModel<Api.SystemManage.UserSearchParams>('model', { required: true });
|
||||
|
||||
const initialParams = { ...model.value };
|
||||
|
||||
type RuleKey = Extract<keyof Api.SystemManage.UserSearchParams, 'userEmail' | 'userPhone'>;
|
||||
|
||||
const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
|
||||
const { patternRules } = useFormRules(); // inside computed to make locale reactive
|
||||
|
||||
return {
|
||||
userEmail: patternRules.email,
|
||||
userPhone: patternRules.phone
|
||||
};
|
||||
});
|
||||
|
||||
async function reset() {
|
||||
await restoreValidation();
|
||||
Object.assign(model.value, initialParams);
|
||||
}
|
||||
|
||||
async function search() {
|
||||
await validate();
|
||||
emit('search');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard :bordered="false" size="small" class="card-wrapper">
|
||||
<NCollapse :default-expanded-names="['user-search']">
|
||||
<NCollapseItem :title="$t('common.search')" name="user-search">
|
||||
<NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="80">
|
||||
<NGrid responsive="screen" item-responsive>
|
||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userName')" path="userName" class="pr-24px">
|
||||
<NInput v-model:value="model.userName" :placeholder="$t('page.manage.user.form.userName')" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi
|
||||
span="24 s:12 m:6"
|
||||
:label="$t('page.manage.user.userGender')"
|
||||
path="userGender"
|
||||
class="pr-24px"
|
||||
>
|
||||
<NSelect
|
||||
v-model:value="model.userGender"
|
||||
:placeholder="$t('page.manage.user.form.userGender')"
|
||||
:options="translateOptions(userGenderOptions)"
|
||||
clearable
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.nickName')" path="nickName" class="pr-24px">
|
||||
<NInput v-model:value="model.nickName" :placeholder="$t('page.manage.user.form.nickName')" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userPhone')" path="userPhone" class="pr-24px">
|
||||
<NInput v-model:value="model.userPhone" :placeholder="$t('page.manage.user.form.userPhone')" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6" :label="$t('page.manage.user.userEmail')" path="userEmail" class="pr-24px">
|
||||
<NInput v-model:value="model.userEmail" :placeholder="$t('page.manage.user.form.userEmail')" />
|
||||
</NFormItemGi>
|
||||
<NFormItemGi
|
||||
span="24 s:12 m:6"
|
||||
:label="$t('page.manage.user.userStatus')"
|
||||
path="userStatus"
|
||||
class="pr-24px"
|
||||
>
|
||||
<NSelect
|
||||
v-model:value="model.status"
|
||||
:placeholder="$t('page.manage.user.form.userStatus')"
|
||||
:options="translateOptions(enableStatusOptions)"
|
||||
clearable
|
||||
/>
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 m:12" class="pr-24px">
|
||||
<NSpace class="w-full" justify="end">
|
||||
<NButton @click="reset">
|
||||
<template #icon>
|
||||
<icon-ic-round-refresh class="text-icon" />
|
||||
</template>
|
||||
{{ $t('common.reset') }}
|
||||
</NButton>
|
||||
<NButton type="primary" ghost @click="search">
|
||||
<template #icon>
|
||||
<icon-ic-round-search class="text-icon" />
|
||||
</template>
|
||||
{{ $t('common.search') }}
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NFormItemGi>
|
||||
</NGrid>
|
||||
</NForm>
|
||||
</NCollapseItem>
|
||||
</NCollapse>
|
||||
</NCard>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
@ -7,7 +7,7 @@ import { yesOrNoRecord } from '@/constants/common';
|
||||
import { enableStatusRecord, menuTypeRecord } from '@/constants/business';
|
||||
import { fetchGetAllPages, fetchGetMenuList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import SvgIcon from '@/components/custom/svg-icon.vue';
|
||||
import MenuOperateModal, { type OperateType } from './modules/menu-operate-modal.vue';
|
||||
@ -18,8 +18,9 @@ const { bool: visible, setTrue: openModal } = useBoolean();
|
||||
|
||||
const wrapperRef = ref<HTMLElement | null>(null);
|
||||
|
||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useTable({
|
||||
apiFn: fetchGetMenuList,
|
||||
const { columns, columnChecks, data, loading, pagination, getData, getDataByPage } = useNaivePaginatedTable({
|
||||
api: () => fetchGetMenuList(),
|
||||
transform: response => defaultTransform(response),
|
||||
columns: () => [
|
||||
{
|
||||
type: 'selection',
|
||||
@ -170,7 +171,7 @@ const { columns, columnChecks, data, loading, pagination, getData, getDataByPage
|
||||
]
|
||||
});
|
||||
|
||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, getData);
|
||||
const { checkedRowKeys, onBatchDeleted, onDeleted } = useTableOperate(data, 'id', getData);
|
||||
|
||||
const operateType = ref<OperateType>('add');
|
||||
|
||||
|
@ -1,35 +1,30 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { enableStatusRecord } from '@/constants/business';
|
||||
import { fetchGetRoleList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import RoleOperateDrawer from './modules/role-operate-drawer.vue';
|
||||
import RoleSearch from './modules/role-search.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
data,
|
||||
loading,
|
||||
getData,
|
||||
getDataByPage,
|
||||
mobilePagination,
|
||||
searchParams,
|
||||
resetSearchParams
|
||||
} = useTable({
|
||||
apiFn: fetchGetRoleList,
|
||||
apiParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
status: null,
|
||||
roleName: null,
|
||||
roleCode: null
|
||||
const searchParams: Api.SystemManage.RoleSearchParams = reactive({
|
||||
current: 1,
|
||||
size: 10,
|
||||
roleName: null,
|
||||
roleCode: null,
|
||||
status: null
|
||||
});
|
||||
|
||||
const { columns, columnChecks, data, loading, getData, getDataByPage, mobilePagination } = useNaivePaginatedTable({
|
||||
api: () => fetchGetRoleList(searchParams),
|
||||
transform: response => defaultTransform(response),
|
||||
onPaginationParamsChange: params => {
|
||||
searchParams.current = params.page;
|
||||
searchParams.size = params.pageSize;
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
@ -41,7 +36,8 @@ const {
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
width: 64,
|
||||
align: 'center'
|
||||
align: 'center',
|
||||
render: (_, index) => index + 1
|
||||
},
|
||||
{
|
||||
key: 'roleName',
|
||||
@ -116,7 +112,7 @@ const {
|
||||
onBatchDeleted,
|
||||
onDeleted
|
||||
// closeDrawer
|
||||
} = useTableOperate(data, getData);
|
||||
} = useTableOperate(data, 'id', getData);
|
||||
|
||||
async function handleBatchDelete() {
|
||||
// request
|
||||
@ -139,7 +135,7 @@ function edit(id: number) {
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<RoleSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
|
||||
<RoleSearch v-model:model="searchParams" @search="getDataByPage" />
|
||||
<NCard :title="$t('page.manage.role.title')" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
|
@ -8,7 +8,6 @@ defineOptions({
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
@ -16,8 +15,14 @@ const emit = defineEmits<Emits>();
|
||||
|
||||
const model = defineModel<Api.SystemManage.RoleSearchParams>('model', { required: true });
|
||||
|
||||
function reset() {
|
||||
emit('reset');
|
||||
function resetModel() {
|
||||
model.value = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
roleName: null,
|
||||
roleCode: null,
|
||||
status: null
|
||||
};
|
||||
}
|
||||
|
||||
function search() {
|
||||
@ -47,7 +52,7 @@ function search() {
|
||||
</NFormItemGi>
|
||||
<NFormItemGi span="24 s:12 m:6">
|
||||
<NSpace class="w-full" justify="end">
|
||||
<NButton @click="reset">
|
||||
<NButton @click="resetModel">
|
||||
<template #icon>
|
||||
<icon-ic-round-refresh class="text-icon" />
|
||||
</template>
|
||||
|
@ -1,39 +1,33 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { NButton, NPopconfirm, NTag } from 'naive-ui';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
import UserOperateDrawer from './modules/user-operate-drawer.vue';
|
||||
import UserSearch from './modules/user-search.vue';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const {
|
||||
columns,
|
||||
columnChecks,
|
||||
data,
|
||||
getData,
|
||||
getDataByPage,
|
||||
loading,
|
||||
mobilePagination,
|
||||
searchParams,
|
||||
resetSearchParams
|
||||
} = useTable({
|
||||
apiFn: fetchGetUserList,
|
||||
showTotal: true,
|
||||
apiParams: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
const searchParams: Api.SystemManage.UserSearchParams = reactive({
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
});
|
||||
|
||||
const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination } = useNaivePaginatedTable({
|
||||
api: () => fetchGetUserList(searchParams),
|
||||
transform: response => defaultTransform(response),
|
||||
onPaginationParamsChange: params => {
|
||||
searchParams.current = params.page;
|
||||
searchParams.size = params.pageSize;
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
@ -45,7 +39,8 @@ const {
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
width: 64,
|
||||
render: (_, index) => index + 1
|
||||
},
|
||||
{
|
||||
key: 'userName',
|
||||
@ -147,7 +142,7 @@ const {
|
||||
onBatchDeleted,
|
||||
onDeleted
|
||||
// closeDrawer
|
||||
} = useTableOperate(data, getData);
|
||||
} = useTableOperate(data, 'id', getData);
|
||||
|
||||
async function handleBatchDelete() {
|
||||
// request
|
||||
@ -170,7 +165,7 @@ function edit(id: number) {
|
||||
|
||||
<template>
|
||||
<div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
|
||||
<UserSearch v-model:model="searchParams" @reset="resetSearchParams" @search="getDataByPage" />
|
||||
<UserSearch v-model:model="searchParams" @search="getDataByPage" />
|
||||
<NCard :title="$t('page.manage.user.title')" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
|
||||
<template #header-extra>
|
||||
<TableHeaderOperation
|
||||
|
@ -10,7 +10,6 @@ defineOptions({
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'reset'): void;
|
||||
(e: 'search'): void;
|
||||
}
|
||||
|
||||
@ -31,9 +30,22 @@ const rules = computed<Record<RuleKey, App.Global.FormRule>>(() => {
|
||||
};
|
||||
});
|
||||
|
||||
function resetModel() {
|
||||
model.value = {
|
||||
current: 1,
|
||||
size: 10,
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
};
|
||||
}
|
||||
|
||||
async function reset() {
|
||||
await restoreValidation();
|
||||
emit('reset');
|
||||
resetModel();
|
||||
}
|
||||
|
||||
async function search() {
|
||||
|
@ -1,28 +1,36 @@
|
||||
<script setup lang="tsx">
|
||||
import { reactive } from 'vue';
|
||||
import { NButton, NTag } from 'naive-ui';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
import { enableStatusRecord, userGenderRecord } from '@/constants/business';
|
||||
import { fetchGetUserList } from '@/service/api';
|
||||
import { useAppStore } from '@/store/modules/app';
|
||||
import { useTable } from '@/hooks/common/table';
|
||||
import { isTableColumnHasKey, useNaiveTable } from '@/hooks/common/table';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
const appStore = useAppStore();
|
||||
|
||||
const { columns, data, loading } = useTable({
|
||||
apiFn: fetchGetUserList,
|
||||
showTotal: true,
|
||||
apiParams: {
|
||||
current: 1,
|
||||
size: 999,
|
||||
// if you want to use the searchParams in Form, you need to define the following properties, and the value is null
|
||||
// the value can not be undefined, otherwise the property in Form will not be reactive
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
const searchParams: Api.SystemManage.UserSearchParams = reactive({
|
||||
current: 1,
|
||||
size: 999,
|
||||
status: null,
|
||||
userName: null,
|
||||
userGender: null,
|
||||
nickName: null,
|
||||
userPhone: null,
|
||||
userEmail: null
|
||||
});
|
||||
|
||||
const { columns, data, loading } = useNaiveTable({
|
||||
api: () => fetchGetUserList(searchParams),
|
||||
transform: response => {
|
||||
const { data: list, error } = response;
|
||||
|
||||
if (!error) {
|
||||
return list.records;
|
||||
}
|
||||
|
||||
return [];
|
||||
},
|
||||
columns: () => [
|
||||
{
|
||||
@ -34,7 +42,8 @@ const { columns, data, loading } = useTable({
|
||||
key: 'index',
|
||||
title: $t('common.index'),
|
||||
align: 'center',
|
||||
width: 64
|
||||
width: 64,
|
||||
render: (_, index) => index + 1
|
||||
},
|
||||
{
|
||||
key: 'userName',
|
||||
@ -125,20 +134,13 @@ function exportExcel() {
|
||||
writeFile(workBook, '用户数据.xlsx');
|
||||
}
|
||||
|
||||
function getTableValue(
|
||||
col: NaiveUI.TableColumn<NaiveUI.TableDataWithIndex<Api.SystemManage.User>>,
|
||||
item: NaiveUI.TableDataWithIndex<Api.SystemManage.User>
|
||||
) {
|
||||
function getTableValue(col: NaiveUI.TableColumn<Api.SystemManage.User>, item: Api.SystemManage.User) {
|
||||
if (!isTableColumnHasKey(col)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { key } = col;
|
||||
|
||||
if (key === 'operate') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (key === 'userRoles') {
|
||||
return item.userRoles.map(role => role).join(',');
|
||||
}
|
||||
@ -151,11 +153,8 @@ function getTableValue(
|
||||
return (item.userGender && $t(userGenderRecord[item.userGender])) || null;
|
||||
}
|
||||
|
||||
return item[key];
|
||||
}
|
||||
|
||||
function isTableColumnHasKey<T>(column: NaiveUI.TableColumn<T>): column is NaiveUI.TableColumnWithKey<T> {
|
||||
return Boolean((column as NaiveUI.TableColumnWithKey<T>).key);
|
||||
// @ts-expect-error the key is not in the type of Api.SystemManage.User
|
||||
return item[key] || null;
|
||||
}
|
||||
|
||||
function isTableColumnHasTitle<T>(column: NaiveUI.TableColumn<T>): column is NaiveUI.TableColumnWithKey<T> & {
|
||||
|
Loading…
Reference in New Issue
Block a user