Browse Source

feat(saas): added editions management ui.

pull/523/head
cKey 4 years ago
parent
commit
baf0c7b3de
  1. 50
      apps/vue/src/api/saas/editions.ts
  2. 23
      apps/vue/src/api/saas/model/editionsModel.ts
  3. 70
      apps/vue/src/views/saas/editions/components/EditionModal.vue
  4. 108
      apps/vue/src/views/saas/editions/components/EditionTable.vue
  5. 44
      apps/vue/src/views/saas/editions/datas/ModalData.ts
  6. 22
      apps/vue/src/views/saas/editions/datas/TableData.ts
  7. 14
      apps/vue/src/views/saas/editions/hooks/useFeatureModal.ts
  8. 13
      apps/vue/src/views/saas/editions/index.vue
  9. 8
      apps/vue/src/views/saas/tenant/datas/ModalData.ts
  10. 8
      aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/AbpUINavigationVueVbenAdminNavigationDefinitionProvider.cs
  11. 4
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Editions/Dto/EditionDto.cs
  12. 6
      aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantDto.cs

50
apps/vue/src/api/saas/editions.ts

@ -0,0 +1,50 @@
import { defAbpHttp } from '/@/utils/http/abp';
import {
Edition,
EditionCreate,
EditionUpdate,
EditionGetListInput,
} from './model/editionsModel';
import { format } from '/@/utils/strings';
import { PagedResultDto } from '../model/baseModel';
enum Api {
Create = '/api/saas/editions',
DeleteById = '/api/saas/editions/{id}',
GetById = '/api/saas/editions/{id}',
GetList = '/api/saas/editions',
Update = '/api/saas/editions/{id}',
}
export const getById = (id: string) => {
return defAbpHttp.get<Edition>({
url: format(Api.GetById, { id: id }),
});
};
export const getList = (input: EditionGetListInput) => {
return defAbpHttp.get<PagedResultDto<Edition>>({
url: Api.GetList,
params: input,
});
};
export const create = (input: EditionCreate) => {
return defAbpHttp.post<Edition>({
url: Api.Create,
data: input,
});
};
export const deleteById = (id: string) => {
return defAbpHttp.delete<void>({
url: format(Api.GetById, { id: id }),
});
};
export const update = (id: string, input: EditionUpdate) => {
return defAbpHttp.put<Edition>({
url: format(Api.Update, { id: id }),
data: input,
});
};

23
apps/vue/src/api/saas/model/editionsModel.ts

@ -0,0 +1,23 @@
import {
IHasConcurrencyStamp,
AuditedEntityDto,
PagedAndSortedResultRequestDto,
} from '../../model/baseModel';
export interface Edition extends AuditedEntityDto {
id: string;
displayName: string;
}
interface EditionCreateOrUpdate {
displayName: string;
}
export type EditionCreate = EditionCreateOrUpdate;
export interface EditionUpdate extends EditionCreateOrUpdate, IHasConcurrencyStamp {
}
export interface EditionGetListInput extends PagedAndSortedResultRequestDto {
filter?: string;
}

70
apps/vue/src/views/saas/editions/components/EditionModal.vue

@ -0,0 +1,70 @@
<template>
<BasicModal
v-bind="$attrs"
:title="modalTitle"
:loading="loading"
:showOkBtn="!loading"
:showCancelBtn="!loading"
:maskClosable="!loading"
:closable="!loading"
:width="500"
:height="300"
@register="registerModal"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import { computed, ref, unref, nextTick } from 'vue';
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { BasicForm, useForm } from '/@/components/Form';
import { BasicModal, useModalInner } from '/@/components/Modal';
import { getModalFormSchemas } from '../datas//ModalData';
import { getById, create, update } from '/@/api/saas/editions';
const emits = defineEmits(['change', 'register']);
const { L } = useLocalization('AbpSaas');
const loading = ref(false);
const editionIdRef = ref('');
const [registerModal, { closeModal, changeOkLoading }] = useModalInner((data) => {
editionIdRef.value = data.id;
fetchEdition();
});
const [registerForm, { setFieldsValue, resetFields, validate }] = useForm({
schemas: getModalFormSchemas(),
showActionButtonGroup: false,
});
const modalTitle = computed(() => {
return unref(editionIdRef) ? L('Edit') : L('NewEdition');
});
function fetchEdition() {
const editionId = unref(editionIdRef);
if (!editionId) {
nextTick(() => {
resetFields();
});
return;
}
getById(editionId).then((edition) => {
nextTick(() => {
setFieldsValue(edition);
});
});
}
function handleSubmit() {
validate().then((input) => {
changeOkLoading(true);
const api = input.id ? update(input.id, input) : create(input);
api.then((edition) => {
emits('change', edition);
closeModal();
}).finally(() => {
changeOkLoading(false);
});
});
}
</script>

108
apps/vue/src/views/saas/editions/components/EditionTable.vue

@ -0,0 +1,108 @@
<template>
<div>
<BasicTable @register="registerTable">
<template #toolbar>
<a-button
v-if="hasPermission('AbpSaas.Editions.Create')"
type="primary"
@click="handleAddNew"
>{{ L('NewEdition') }}</a-button
>
</template>
<template #action="{ record }">
<TableAction
:actions="[
{
auth: 'AbpSaas.Editions.Update',
label: L('Edit'),
icon: 'ant-design:edit-outlined',
onClick: handleEdit.bind(null, record),
},
{
auth: 'AbpSaas.Editions.Delete',
color: 'error',
label: L('Delete'),
icon: 'ant-design:delete-outlined',
onClick: handleDelete.bind(null, record),
},
]"
:dropDownActions="[
{
auth: 'AbpSaas.Editions.ManageFeatures',
label: L('ManageFeatures'),
onClick: handleManageFeature.bind(null, record),
},
]"
/>
</template>
</BasicTable>
<EditionModal @register="registerModal" @change="reload" />
<FeatureModal @register="registerFeatureModal" />
</div>
</template>
<script lang="ts" setup>
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { usePermission } from '/@/hooks/web/usePermission';
import { useMessage } from '/@/hooks/web/useMessage';
import { useModal } from '/@/components/Modal';
import { BasicTable, TableAction, useTable } from '/@/components/Table';
import { useFeatureModal } from '../hooks/useFeatureModal';
import { FeatureModal } from '../../../feature';
import { deleteById, getList } from '../../../../api/saas/editions';
import { getDataColumns } from '../datas/TableData';
import { getSearchFormSchemas } from '../datas//ModalData';
import { formatPagedRequest } from '/@/utils/http/abp/helper';
import EditionModal from './EditionModal.vue';
const { L } = useLocalization('AbpSaas', 'AbpFeatureManagement');
const { createConfirm } = useMessage();
const { hasPermission } = usePermission();
const [registerModal, { openModal }] = useModal();
const { registerModal: registerFeatureModal, handleManageFeature } = useFeatureModal();
const [registerTable, { reload }] = useTable({
rowKey: 'id',
title: L('Tenants'),
columns: getDataColumns(),
api: getList,
beforeFetch: formatPagedRequest,
pagination: true,
striped: false,
useSearchForm: true,
showTableSetting: true,
bordered: true,
showIndexColumn: false,
canResize: true,
immediate: true,
canColDrag: true,
formConfig: getSearchFormSchemas(),
actionColumn: {
width: 200,
title: L('Actions'),
dataIndex: 'action',
slots: { customRender: 'action' },
},
});
function handleAddNew() {
openModal(true, {});
}
function handleEdit(record) {
openModal(true, record);
}
function handleDelete(record) {
createConfirm({
iconType: 'warning',
title: L('AreYouSure'),
content: L('ItemWillBeDeletedMessageWithFormat', record.displayName),
okCancel: true,
onOk: () => {
deleteById(record.id).then(() => {
reload();
});
},
});
}
</script>

44
apps/vue/src/views/saas/editions/datas/ModalData.ts

@ -0,0 +1,44 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { FormProps, FormSchema } from '/@/components/Form';
const { L } = useLocalization('AbpSaas');
export function getSearchFormSchemas(): Partial<FormProps> {
return {
labelWidth: 120,
schemas: [
{
field: 'filter',
component: 'Input',
label: L('Search'),
colProps: { span: 24 },
},
],
};
}
export function getModalFormSchemas(): FormSchema[] {
return [
{
field: 'id',
component: 'Input',
label: 'id',
show: false,
dynamicDisabled: true,
},
{
field: 'concurrencyStamp',
component: 'Input',
label: 'concurrencyStamp',
show: false,
dynamicDisabled: true,
},
{
field: 'displayName',
component: 'Input',
label: L('DisplayName:EditionName'),
colProps: { span: 24 },
required: true,
},
];
}

22
apps/vue/src/views/saas/editions/datas/TableData.ts

@ -0,0 +1,22 @@
import { useLocalization } from '/@/hooks/abp/useLocalization';
import { BasicColumn } from '/@/components/Table';
const { L } = useLocalization('AbpSaas');
export function getDataColumns(): BasicColumn[] {
return [
{
title: 'id',
dataIndex: 'id',
width: 1,
ifShow: false,
},
{
title: L('DisplayName:EditionName'),
dataIndex: 'displayName',
align: 'left',
width: 'auto',
sorter: true,
},
];
}

14
apps/vue/src/views/saas/editions/hooks/useFeatureModal.ts

@ -0,0 +1,14 @@
import { useModal } from '/@/components/Modal';
export function useFeatureModal() {
const [registerModal, { openModal }] = useModal();
function handleManageFeature(record) {
openModal(true, { providerName: 'E', providerKey: record.id });
}
return {
registerModal,
handleManageFeature,
};
}

13
apps/vue/src/views/saas/editions/index.vue

@ -0,0 +1,13 @@
<template>
<EditionTable />
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import EditionTable from './components/EditionTable.vue';
export default defineComponent({
name: 'Editions',
components: { EditionTable },
setup() {},
});
</script>

8
apps/vue/src/views/saas/tenant/datas/ModalData.ts

@ -24,6 +24,14 @@ export function getModalFormSchemas(): FormSchema[] {
component: 'Input', component: 'Input',
label: 'id', label: 'id',
show: false, show: false,
dynamicDisabled: true,
},
{
field: 'concurrencyStamp',
component: 'Input',
label: 'concurrencyStamp',
show: false,
dynamicDisabled: true,
}, },
{ {
field: 'isActive', field: 'isActive',

8
aspnet-core/modules/platform/LINGYUN.Abp.UI.Navigation.VueVbenAdmin/LINGYUN/Abp/UI/Navigation/VueVbenAdmin/AbpUINavigationVueVbenAdminNavigationDefinitionProvider.cs

@ -212,6 +212,14 @@ namespace LINGYUN.Abp.UI.Navigation.VueVbenAdmin
component: "/saas/tenant/index", component: "/saas/tenant/index",
description: "租户管理", description: "租户管理",
multiTenancySides: MultiTenancySides.Host)); multiTenancySides: MultiTenancySides.Host));
saas.AddItem(
new ApplicationMenu(
name: "Editions",
displayName: "版本管理",
url: "/saas/editions",
component: "/saas/editions/index",
description: "版本管理",
multiTenancySides: MultiTenancySides.Host));
return new NavigationDefinition(saas); return new NavigationDefinition(saas);
} }

4
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Editions/Dto/EditionDto.cs

@ -1,9 +1,11 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
namespace LINGYUN.Abp.Saas.Editions; namespace LINGYUN.Abp.Saas.Editions;
public class EditionDto : ExtensibleFullAuditedEntityDto<Guid> public class EditionDto : ExtensibleAuditedEntityDto<Guid>, IHasConcurrencyStamp
{ {
public string DisplayName { get; set; } public string DisplayName { get; set; }
public string ConcurrencyStamp { get; set; }
} }

6
aspnet-core/modules/saas/LINGYUN.Abp.Saas.Application.Contracts/LINGYUN/Abp/Saas/Tenants/Dto/TenantDto.cs

@ -1,9 +1,10 @@
using System; using System;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Entities;
namespace LINGYUN.Abp.Saas.Tenants; namespace LINGYUN.Abp.Saas.Tenants;
public class TenantDto : ExtensibleFullAuditedEntityDto<Guid> public class TenantDto : ExtensibleAuditedEntityDto<Guid>, IHasConcurrencyStamp
{ {
public string Name { get; set; } public string Name { get; set; }
@ -16,4 +17,5 @@ public class TenantDto : ExtensibleFullAuditedEntityDto<Guid>
public DateTime? EnableTime { get; set; } public DateTime? EnableTime { get; set; }
public DateTime? DisableTime { get; set; } public DateTime? DisableTime { get; set; }
public string ConcurrencyStamp { get; set; }
} }
Loading…
Cancel
Save