Browse Source

Merge pull request #1152 from colinin/tenant-login

Tenant login
pull/1162/head
yx lin 11 months ago
committed by GitHub
parent
commit
6207a9c6eb
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      apps/vben5/apps/app-antd/src/adapter/component/index.ts
  2. 5
      apps/vben5/packages/@abp/features/src/components/definitions/features/FeatureDefinitionModal.vue
  3. 27
      apps/vben5/packages/@abp/features/src/components/state-check/FeatureStateCheck.vue
  4. 2
      apps/vben5/packages/@abp/saas/package.json
  5. 1
      apps/vben5/packages/@abp/saas/src/api/index.ts
  6. 31
      apps/vben5/packages/@abp/saas/src/api/useMultiTenancyApi.ts
  7. 1
      apps/vben5/packages/@abp/saas/src/components/index.ts
  8. 58
      apps/vben5/packages/@abp/saas/src/components/tenants/TenantSelect.vue
  9. 98
      apps/vben5/packages/@abp/saas/src/components/tenants/TenantSelectModal.vue
  10. 1
      apps/vben5/packages/@abp/saas/src/types/index.ts
  11. 9
      apps/vben5/packages/@abp/saas/src/types/multiTenancys.ts
  12. 1
      apps/vben5/pnpm-workspace.yaml

2
apps/vben5/apps/app-antd/src/adapter/component/index.ts

@ -14,6 +14,7 @@ import { $t } from '@vben/locales';
import { FeatureStateCheck, GlobalFeatureStateCheck } from '@abp/features';
import { PermissionStateCheck } from '@abp/permissions';
import { TenantSelect } from '@abp/saas';
import {
AutoComplete,
Button,
@ -158,6 +159,7 @@ async function initComponentAdapter() {
FeatureStateCheck,
GlobalFeatureStateCheck,
PermissionStateCheck,
TenantSelect,
};
// 将组件注册到全局共享状态中

5
apps/vben5/packages/@abp/features/src/components/definitions/features/FeatureDefinitionModal.vue

@ -259,7 +259,10 @@ function onValueTypeNameChange(valueTypeName: string) {
break;
}
default: {
formModel.value.defaultValue ??= undefined;
formModel.value.defaultValue = undefined;
if (isBoolean(formModel.value.defaultValue)) {
formModel.value.defaultValue = 'false';
}
break;
}
}

27
apps/vben5/packages/@abp/features/src/components/state-check/FeatureStateCheck.vue

@ -7,10 +7,12 @@ import type {
import { computed, onMounted, ref } from 'vue';
import {
isNullOrWhiteSpace,
listToTree,
useLocalization,
useLocalizationSerializer,
} from '@abp/core';
import { valueTypeSerializer } from '@abp/ui';
import { Checkbox, FormItemRest, TreeSelect } from 'ant-design-vue';
import { useFeatureDefinitionsApi } from '../../api/useFeatureDefinitionsApi';
@ -96,13 +98,24 @@ async function onInit() {
displayName: Lr(displayName.resourceName, displayName.name),
};
});
features.value = featuresRes.items.map((item) => {
const displayName = deserialize(item.displayName);
return {
...item,
displayName: Lr(displayName.resourceName, displayName.name),
};
});
features.value = featuresRes.items
.filter((item) => {
if (!isNullOrWhiteSpace(item.valueType)) {
const valueType = valueTypeSerializer.deserialize(item.valueType);
if (valueType.validator.name !== 'BOOLEAN') {
return false;
}
}
return true;
})
.map((item) => {
const displayName = deserialize(item.displayName);
const feature = {
...item,
displayName: Lr(displayName.resourceName, displayName.name),
};
return feature;
});
}
onMounted(onInit);

2
apps/vben5/packages/@abp/saas/package.json

@ -31,9 +31,11 @@
"@vben/hooks": "workspace:*",
"@vben/icons": "workspace:*",
"@vben/locales": "workspace:*",
"@vueuse/integrations": "catalog:",
"ant-design-vue": "catalog:",
"dayjs": "catalog:",
"lodash.debounce": "catalog:",
"universal-cookie": "catalog:",
"vue": "catalog:*",
"vxe-table": "catalog:"
},

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

@ -1,2 +1,3 @@
export { useEditionsApi } from './useEditionsApi';
export { useMultiTenancyApi } from './useMultiTenancyApi';
export { useTenantsApi } from './useTenantsApi';

31
apps/vben5/packages/@abp/saas/src/api/useMultiTenancyApi.ts

@ -0,0 +1,31 @@
import type { FindTenantResultDto } from '../types/multiTenancys';
import { useRequest } from '@abp/request';
export function useMultiTenancyApi() {
const { cancel, request } = useRequest();
function findTenantByNameApi(name: string): Promise<FindTenantResultDto> {
return request<FindTenantResultDto>(
`/api/abp/multi-tenancy/tenants/by-name/${name}`,
{
method: 'GET',
},
);
}
function findTenantByIdApi(id: string): Promise<FindTenantResultDto> {
return request<FindTenantResultDto>(
`/api/abp/multi-tenancy/tenants/by-id/${id}`,
{
method: 'GET',
},
);
}
return {
cancel,
findTenantByIdApi,
findTenantByNameApi,
};
}

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

@ -1,2 +1,3 @@
export { default as EditionTable } from './editions/EditionTable.vue';
export { default as TenantSelect } from './tenants/TenantSelect.vue';
export { default as TenantTable } from './tenants/TenantTable.vue';

58
apps/vben5/packages/@abp/saas/src/components/tenants/TenantSelect.vue

@ -0,0 +1,58 @@
<script setup lang="ts">
import { computed, defineAsyncComponent } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { useAbpStore } from '@abp/core';
import { Button, InputSearch } from 'ant-design-vue';
defineOptions({
name: 'TenantSelect',
});
const emits = defineEmits<{
(event: 'change', data?: { id?: string; name?: string }): void;
}>();
const abpStore = useAbpStore();
const getCurrentTenant = computed(() => {
return abpStore.application?.currentTenant;
});
const [Modal, modapApi] = useVbenModal({
connectedComponent: defineAsyncComponent(
() => import('./TenantSelectModal.vue'),
),
});
function onSwitchClick() {
modapApi.setData({
name: getCurrentTenant.value?.name,
});
modapApi.open();
}
function onChange(tenant?: { id?: string; name?: string }) {
emits('change', tenant);
}
</script>
<template>
<div class="w-full">
<InputSearch
readonly
:value="getCurrentTenant?.name"
:placeholder="$t('AbpUiMultiTenancy.NotSelected')"
>
<template #enterButton>
<Button @click="onSwitchClick">
({{ $t('AbpUiMultiTenancy.Switch') }})
</Button>
</template>
</InputSearch>
<Modal @change="onChange" />
</div>
</template>
<style scoped></style>

98
apps/vben5/packages/@abp/saas/src/components/tenants/TenantSelectModal.vue

@ -0,0 +1,98 @@
<script setup lang="ts">
import { ref } from 'vue';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { useCookies } from '@vueuse/integrations/useCookies';
import { message } from 'ant-design-vue';
import { useMultiTenancyApi } from '../../api/useMultiTenancyApi';
interface Tenant {
id?: string;
name?: string;
}
const emits = defineEmits<{
(event: 'change', data?: Tenant): void;
}>();
const tenant = ref<Tenant>();
const cookies = useCookies();
const { findTenantByNameApi } = useMultiTenancyApi();
const [Form, formApi] = useVbenForm({
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
componentProps: {
allowClear: true,
placeholder: $t('AbpUiMultiTenancy.SwitchTenantHint'),
},
fieldName: 'name',
label: $t('AbpUiMultiTenancy.Name'),
},
],
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onCancel() {
emits('change', tenant.value);
},
async onConfirm() {
await formApi.validateAndSubmitForm();
},
onOpenChange(isOpen) {
if (isOpen) {
const { name } = modalApi.getData<Tenant>();
formApi.setFieldValue('name', name);
}
},
});
async function onSubmit(values: Record<string, any>) {
modalApi.setState({ submitting: true });
try {
tenant.value = undefined;
cookies.remove('__tenant', {
path: '/',
});
// localStorage.removeItem('__tenant');
if (values.name) {
const result = await findTenantByNameApi(values.name);
if (!result.success) {
message.warning(
$t('AbpUiMultiTenancy.GivenTenantIsNotExist', [values.name]),
);
return;
}
if (!result.isActive) {
message.warning(
$t('AbpUiMultiTenancy.GivenTenantIsNotAvailable', [values.name]),
);
return;
}
tenant.value = { id: result.tenantId, name: result.normalizedName };
if (result.tenantId) {
// localStorage.setItem('__tenant', result.tenantId);
cookies.set('__tenant', result.tenantId, {
path: '/',
});
}
}
emits('change', tenant.value);
modalApi.close();
} finally {
modalApi.setState({ submitting: false });
}
}
</script>
<template>
<Modal :title="$t('AbpUiMultiTenancy.SwitchTenant')">
<Form />
</Modal>
</template>
<style scoped></style>

1
apps/vben5/packages/@abp/saas/src/types/index.ts

@ -1,2 +1,3 @@
export * from './editions';
export * from './multiTenancys';
export * from './tenants';

9
apps/vben5/packages/@abp/saas/src/types/multiTenancys.ts

@ -0,0 +1,9 @@
interface FindTenantResultDto {
isActive: boolean;
name?: string;
normalizedName?: string;
success: boolean;
tenantId?: string;
}
export type { FindTenantResultDto };

1
apps/vben5/pnpm-workspace.yaml

@ -174,6 +174,7 @@ catalog:
turbo: ^2.4.0
typescript: ^5.7.3
unbuild: ^3.3.1
universal-cookie: ^7
unplugin-element-plus: ^0.9.0
vee-validate: ^4.15.0
vditor: ^3.10.9

Loading…
Cancel
Save