Browse Source

feat(vben5): add layouts manage

pull/1186/head
colin 11 months ago
parent
commit
bf64d0d7ed
  1. 3
      apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json
  2. 3
      apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json
  3. 9
      apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts
  4. 15
      apps/vben5/apps/app-antd/src/views/platform/layouts/index.vue
  5. 1
      apps/vben5/packages/@abp/platform/src/api/index.ts
  6. 58
      apps/vben5/packages/@abp/platform/src/api/useLayoutsApi.ts
  7. 2
      apps/vben5/packages/@abp/platform/src/components/data-dictionaries/DataDictionaryItemDrawer.vue
  8. 1
      apps/vben5/packages/@abp/platform/src/components/index.ts
  9. 174
      apps/vben5/packages/@abp/platform/src/components/layouts/LayoutModal.vue
  10. 206
      apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue
  11. 35
      apps/vben5/packages/@abp/platform/src/types/layouts.ts
  12. 12
      apps/vben5/packages/@abp/platform/src/types/routes.ts

3
apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json

@ -98,7 +98,8 @@
"email": "Email Messages",
"sms": "Sms Messages"
},
"dataDictionaries": "Data Dictionaries"
"dataDictionaries": "Data Dictionaries",
"layouts": "Layouts"
},
"saas": {
"title": "Saas",

3
apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json

@ -98,7 +98,8 @@
"email": "邮件消息",
"sms": "短信消息"
},
"dataDictionaries": "数据字典"
"dataDictionaries": "数据字典",
"layouts": "布局管理"
},
"saas": {
"title": "Saas",

9
apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts

@ -409,6 +409,15 @@ const routes: RouteRecordRaw[] = [
component: () =>
import('#/views/platform/data-dictionaries/index.vue'),
},
{
meta: {
title: $t('abp.platform.layouts'),
icon: 'material-symbols-light:responsive-layout',
},
name: 'PlatformLayouts',
path: '/platform/layouts',
component: () => import('#/views/platform/layouts/index.vue'),
},
{
meta: {
title: $t('abp.platform.messages.title'),

15
apps/vben5/apps/app-antd/src/views/platform/layouts/index.vue

@ -0,0 +1,15 @@
<script lang="ts" setup>
import { Page } from '@vben/common-ui';
import { LayoutTable } from '@abp/platform';
defineOptions({
name: 'PlatformLayouts',
});
</script>
<template>
<Page>
<LayoutTable />
</Page>
</template>

1
apps/vben5/packages/@abp/platform/src/api/index.ts

@ -1,3 +1,4 @@
export { useDataDictionariesApi } from './useDataDictionariesApi';
export { useEmailMessagesApi } from './useEmailMessagesApi';
export { useLayoutsApi } from './useLayoutsApi';
export { useSmsMessagesApi } from './useSmsMessagesApi';

58
apps/vben5/packages/@abp/platform/src/api/useLayoutsApi.ts

@ -0,0 +1,58 @@
import type { PagedResultDto } from '@abp/core';
import type {
LayoutCreateDto,
LayoutDto,
LayoutGetPagedListInput,
LayoutUpdateDto,
} from '../types/layouts';
import { useRequest } from '@abp/request';
export function useLayoutsApi() {
const { cancel, request } = useRequest();
function createApi(input: LayoutCreateDto): Promise<LayoutDto> {
return request<LayoutDto>(`/api/platform/layouts`, {
data: input,
method: 'POST',
});
}
function getPagedListApi(
input?: LayoutGetPagedListInput,
): Promise<PagedResultDto<LayoutDto>> {
return request<PagedResultDto<LayoutDto>>('/api/platform/layouts', {
method: 'GET',
params: input,
});
}
function getApi(id: string): Promise<LayoutDto> {
return request<LayoutDto>(`/api/platform/layouts/${id}`, {
method: 'GET',
});
}
function deleteApi(id: string): Promise<void> {
return request(`/api/platform/layouts/${id}`, {
method: 'DELETE',
});
}
function updateApi(id: string, input: LayoutUpdateDto): Promise<LayoutDto> {
return request<LayoutDto>(`/api/platform/layouts/${id}`, {
data: input,
method: 'PUT',
});
}
return {
cancel,
createApi,
deleteApi,
getApi,
getPagedListApi,
updateApi,
};
}

2
apps/vben5/packages/@abp/platform/src/components/data-dictionaries/DataDictionaryItemDrawer.vue

@ -41,7 +41,7 @@ const valueTypeMaps: { [key: number]: string } = {
};
const [Drawer, drawerApi] = useVbenDrawer({
class: 'w-1/2',
class: 'w-2/3',
async onOpenChange(isOpen) {
if (isOpen) {
const { name } = drawerApi.getData<DataDto>();

1
apps/vben5/packages/@abp/platform/src/components/index.ts

@ -1,3 +1,4 @@
export { default as DataDictionaryTable } from './data-dictionaries/DataDictionaryTable.vue';
export { default as LayoutTable } from './layouts/LayoutTable.vue';
export { default as EmailMessageTable } from './messages/email/EmailMessageTable.vue';
export { default as SmsMessageTable } from './messages/sms/SmsMessageTable.vue';

174
apps/vben5/packages/@abp/platform/src/components/layouts/LayoutModal.vue

@ -0,0 +1,174 @@
<script setup lang="ts">
import type {
LayoutCreateDto,
LayoutDto,
LayoutUpdateDto,
} from '../../types/layouts';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { isNullOrWhiteSpace, listToTree } from '@abp/core';
import { message } from 'ant-design-vue';
import { useDataDictionariesApi, useLayoutsApi } from '../../api';
const emits = defineEmits<{
(event: 'change', data: LayoutDto): void;
}>();
const { createApi, getApi, updateApi } = useLayoutsApi();
const {
getAllApi: getDataDictionariesApi,
getByNameApi: getDataDictionaryByNameApi,
} = useDataDictionariesApi();
const [Form, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
},
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
dependencies: {
show: false,
triggerFields: ['name'],
},
fieldName: 'id',
},
{
component: 'ApiSelect',
componentProps: {
allowClear: true,
api: () => getDataDictionaryByNameApi('UI Framework'),
labelField: 'displayName',
resultField: 'items',
valueField: 'name',
},
dependencies: {
if: (values) => {
return !values?.id;
},
triggerFields: ['id'],
},
fieldName: 'framework',
label: $t('AppPlatform.DisplayName:UIFramework'),
rules: 'selectRequired',
},
{
component: 'ApiTreeSelect',
componentProps: {
allowClear: true,
api: async () => {
const { items } = await getDataDictionariesApi();
return listToTree(items, {
id: 'id',
pid: 'parentId',
});
},
labelField: 'displayName',
valueField: 'id',
childrenField: 'children',
},
dependencies: {
if: (values) => {
return !values?.id;
},
triggerFields: ['id'],
},
fieldName: 'dataId',
label: $t('AppPlatform.DisplayName:LayoutConstraint'),
rules: 'selectRequired',
},
{
component: 'Input',
fieldName: 'name',
label: $t('AppPlatform.DisplayName:Name'),
rules: 'required',
},
{
component: 'Input',
fieldName: 'displayName',
label: $t('AppPlatform.DisplayName:DisplayName'),
rules: 'required',
},
{
component: 'Input',
fieldName: 'path',
label: $t('AppPlatform.DisplayName:Path'),
rules: 'required',
},
{
component: 'Input',
fieldName: 'redirect',
label: $t('AppPlatform.DisplayName:Redirect'),
},
{
component: 'Textarea',
componentProps: {
autoSize: {
minRows: 3,
},
},
fieldName: 'description',
label: $t('AppPlatform.DisplayName:Description'),
},
],
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
closeOnClickModal: false,
closeOnPressEscape: false,
draggable: true,
onConfirm: async () => {
await formApi.validateAndSubmitForm();
},
onOpenChange: async (isOpen) => {
if (isOpen) {
await onGet();
}
},
});
async function onGet() {
formApi.resetForm();
const { id } = modalApi.getData<LayoutDto>();
if (isNullOrWhiteSpace(id)) {
modalApi.setState({ title: $t('AppPlatform.Layout:AddNew') });
return;
}
try {
modalApi.setState({ loading: true });
const dto = await getApi(id);
formApi.setValues(dto, false);
} finally {
modalApi.setState({ loading: false });
}
}
async function onSubmit(values: Record<string, any>) {
try {
modalApi.setState({ submitting: true });
const api = values.id
? updateApi(values.id, values as LayoutUpdateDto)
: createApi(values as LayoutCreateDto);
const dto = await api;
message.success($t('AbpUi.SavedSuccessfully'));
emits('change', dto);
modalApi.close();
} finally {
modalApi.setState({ submitting: false });
}
}
</script>
<template>
<Modal>
<Form />
</Modal>
</template>
<style scoped></style>

206
apps/vben5/packages/@abp/platform/src/components/layouts/LayoutTable.vue

@ -0,0 +1,206 @@
<script setup lang="ts">
import type { VxeGridProps } from '@abp/ui';
import type { VbenFormProps } from '@vben/common-ui';
import type { LayoutDto } from '../../types/layouts';
import { defineAsyncComponent, h } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useVbenVxeGrid } from '@abp/ui';
import {
DeleteOutlined,
EditOutlined,
PlusOutlined,
} from '@ant-design/icons-vue';
import { Button, message, Modal } from 'ant-design-vue';
import { useLayoutsApi } from '../../api/useLayoutsApi';
defineOptions({
name: 'LayoutTable',
});
const { deleteApi, getPagedListApi } = useLayoutsApi();
const formOptions: VbenFormProps = {
//
collapsed: true,
//
commonConfig: {
// label
colon: true,
//
componentProps: {
class: 'w-full',
},
},
schema: [
{
component: 'Input',
fieldName: 'filter',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpUi.Search'),
},
],
//
showCollapseButton: true,
//
submitOnEnter: true,
};
const gridOptions: VxeGridProps<LayoutDto> = {
columns: [
{
align: 'center',
fixed: 'left',
type: 'seq',
width: 80,
},
{
align: 'left',
field: 'name',
fixed: 'left',
minWidth: 180,
title: $t('AppPlatform.DisplayName:Name'),
},
{
align: 'left',
field: 'displayName',
minWidth: 150,
title: $t('AppPlatform.DisplayName:DisplayName'),
},
{
align: 'center',
field: 'path',
minWidth: 200,
title: $t('AppPlatform.DisplayName:Path'),
},
{
align: 'left',
field: 'framework',
minWidth: 180,
title: $t('AppPlatform.DisplayName:UIFramework'),
},
{
align: 'left',
field: 'description',
minWidth: 220,
title: $t('AppPlatform.DisplayName:Description'),
},
{
align: 'left',
field: 'redirect',
minWidth: 160,
title: $t('AppPlatform.DisplayName:Redirect'),
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: $t('AbpUi.Actions'),
width: 220,
},
],
exportConfig: {},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
return await getPagedListApi({
maxResultCount: page.pageSize,
skipCount: (page.currentPage - 1) * page.pageSize,
...formValues,
});
},
},
response: {
total: 'totalCount',
list: 'items',
},
},
toolbarConfig: {
custom: true,
export: true,
refresh: true,
zoom: true,
},
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions,
});
const [LayoutModal, modalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(() => import('./LayoutModal.vue')),
});
function onCreate() {
modalApi.setData({});
modalApi.open();
}
function onUpdate(row: LayoutDto) {
modalApi.setData(row);
modalApi.open();
}
function onDelete(row: LayoutDto) {
Modal.confirm({
afterClose: () => {
gridApi.setLoading(false);
},
centered: true,
content: `${$t('AbpUi.ItemWillBeDeletedMessage')}`,
onOk: async () => {
try {
gridApi.setLoading(true);
await deleteApi(row.id);
message.success($t('AbpUi.DeletedSuccessfully'));
gridApi.query();
} finally {
gridApi.setLoading(false);
}
},
title: $t('AbpUi.AreYouSure'),
});
}
</script>
<template>
<Grid :table-title="$t('AppPlatform.DisplayName:Layout')">
<template #toolbar-tools>
<Button :icon="h(PlusOutlined)" type="primary" @click="onCreate">
{{ $t('AppPlatform.Layout:AddNew') }}
</Button>
</template>
<template #action="{ row }">
<div class="flex flex-row">
<Button
:icon="h(EditOutlined)"
block
type="link"
@click="onUpdate(row)"
>
{{ $t('AbpUi.Edit') }}
</Button>
<Button
:icon="h(DeleteOutlined)"
block
danger
type="link"
@click="onDelete(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
<LayoutModal @change="() => gridApi.query()" />
</template>
<style lang="scss" scoped></style>

35
apps/vben5/packages/@abp/platform/src/types/layouts.ts

@ -0,0 +1,35 @@
import type { PagedAndSortedResultRequestDto } from '@abp/core';
import type { RouteDto } from './routes';
interface LayoutDto extends RouteDto {
dataId: string;
framework: string;
}
interface LayoutCreateOrUpdateDto {
description?: string;
displayName: string;
name: string;
path: string;
redirect?: string;
}
interface LayoutCreateDto extends LayoutCreateOrUpdateDto {
dataId: string;
framework: string;
}
type LayoutUpdateDto = LayoutCreateOrUpdateDto;
interface LayoutGetPagedListInput extends PagedAndSortedResultRequestDto {
filter?: string;
framework?: string;
}
export type {
LayoutCreateDto,
LayoutDto,
LayoutGetPagedListInput,
LayoutUpdateDto,
};

12
apps/vben5/packages/@abp/platform/src/types/routes.ts

@ -0,0 +1,12 @@
import type { EntityDto } from '@abp/core';
interface RouteDto extends EntityDto<string> {
description?: string;
displayName: string;
meta: Record<string, string>;
name: string;
path: string;
redirect?: string;
}
export type { RouteDto };
Loading…
Cancel
Save