yx lin 9 months ago
committed by GitHub
parent
commit
eabcf7881c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      .github/workflows/publish.yml
  2. 2
      .github/workflows/release.yml
  3. 18
      Directory.Packages.props
  4. 3
      apps/vben5/apps/app-antd/.env
  5. 7
      apps/vben5/apps/app-antd/package.json
  6. 3
      apps/vben5/apps/app-antd/src/adapter/component/index.ts
  7. 6
      apps/vben5/apps/app-antd/src/hooks/useSessions.ts
  8. 34
      apps/vben5/apps/app-antd/src/locales/langs/en-US/abp.json
  9. 34
      apps/vben5/apps/app-antd/src/locales/langs/zh-CN/abp.json
  10. 1
      apps/vben5/apps/app-antd/src/preferences.ts
  11. 11
      apps/vben5/apps/app-antd/src/router/access.ts
  12. 759
      apps/vben5/apps/app-antd/src/router/routes/modules/abp.ts
  13. 8
      apps/vben5/apps/app-antd/src/views/_core/authentication/login.vue
  14. 37
      apps/vben5/apps/app-antd/src/views/_core/authentication/third-party-login.vue
  15. 2
      apps/vben5/apps/app-antd/src/views/account/my-profile/index.vue
  16. 2
      apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue
  17. 2
      apps/vben5/apps/app-antd/src/views/auditing/audit-logs/index.vue
  18. 15
      apps/vben5/apps/app-antd/src/views/auditing/loggings/index.vue
  19. 2
      apps/vben5/apps/app-antd/src/views/data-protection/entity-type-infos/index.vue
  20. 2
      apps/vben5/apps/app-antd/src/views/demos/books/index.vue
  21. 2
      apps/vben5/apps/app-antd/src/views/features/definitions/index.vue
  22. 2
      apps/vben5/apps/app-antd/src/views/features/groups/index.vue
  23. 2
      apps/vben5/apps/app-antd/src/views/identity/claim-types/index.vue
  24. 2
      apps/vben5/apps/app-antd/src/views/identity/organization-units/index.vue
  25. 2
      apps/vben5/apps/app-antd/src/views/identity/roles/index.vue
  26. 2
      apps/vben5/apps/app-antd/src/views/identity/security-logs/index.vue
  27. 2
      apps/vben5/apps/app-antd/src/views/identity/sessions/index.vue
  28. 2
      apps/vben5/apps/app-antd/src/views/identity/users/index.vue
  29. 2
      apps/vben5/apps/app-antd/src/views/localization/languages/index.vue
  30. 2
      apps/vben5/apps/app-antd/src/views/localization/resources/index.vue
  31. 2
      apps/vben5/apps/app-antd/src/views/localization/texts/index.vue
  32. 2
      apps/vben5/apps/app-antd/src/views/notifications/definitions/index.vue
  33. 2
      apps/vben5/apps/app-antd/src/views/notifications/groups/index.vue
  34. 2
      apps/vben5/apps/app-antd/src/views/notifications/my-notifilers/index.vue
  35. 2
      apps/vben5/apps/app-antd/src/views/openiddict/applications/index.vue
  36. 2
      apps/vben5/apps/app-antd/src/views/openiddict/authorizations/index.vue
  37. 2
      apps/vben5/apps/app-antd/src/views/openiddict/scopes/index.vue
  38. 2
      apps/vben5/apps/app-antd/src/views/openiddict/tokens/index.vue
  39. 15
      apps/vben5/apps/app-antd/src/views/oss/containers/index.vue
  40. 15
      apps/vben5/apps/app-antd/src/views/oss/objects/index.vue
  41. 2
      apps/vben5/apps/app-antd/src/views/permissions/definitions/index.vue
  42. 2
      apps/vben5/apps/app-antd/src/views/permissions/groups/index.vue
  43. 15
      apps/vben5/apps/app-antd/src/views/platform/data-dictionaries/index.vue
  44. 15
      apps/vben5/apps/app-antd/src/views/platform/layouts/index.vue
  45. 15
      apps/vben5/apps/app-antd/src/views/platform/menus/index.vue
  46. 2
      apps/vben5/apps/app-antd/src/views/platform/messages/email/index.vue
  47. 2
      apps/vben5/apps/app-antd/src/views/platform/messages/sms/index.vue
  48. 2
      apps/vben5/apps/app-antd/src/views/saas/editions/index.vue
  49. 2
      apps/vben5/apps/app-antd/src/views/saas/tenants/index.vue
  50. 2
      apps/vben5/apps/app-antd/src/views/settings/definitions/index.vue
  51. 2
      apps/vben5/apps/app-antd/src/views/settings/system/index.vue
  52. 15
      apps/vben5/apps/app-antd/src/views/tasks/job-infos/index.vue
  53. 15
      apps/vben5/apps/app-antd/src/views/text-templating/definitions/index.vue
  54. 15
      apps/vben5/apps/app-antd/src/views/webhooks/definitions/index.vue
  55. 15
      apps/vben5/apps/app-antd/src/views/webhooks/groups/index.vue
  56. 15
      apps/vben5/apps/app-antd/src/views/webhooks/send-attempts/index.vue
  57. 15
      apps/vben5/apps/app-antd/src/views/webhooks/subscriptions/index.vue
  58. 2
      apps/vben5/packages/@abp/account/package.json
  59. 12
      apps/vben5/packages/@abp/account/src/components/MySetting.vue
  60. 2
      apps/vben5/packages/@abp/auditing/package.json
  61. 1
      apps/vben5/packages/@abp/auditing/src/api/index.ts
  62. 38
      apps/vben5/packages/@abp/auditing/src/api/useLoggingsApi.ts
  63. 3
      apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue
  64. 1
      apps/vben5/packages/@abp/auditing/src/components/index.ts
  65. 138
      apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue
  66. 345
      apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue
  67. 4
      apps/vben5/packages/@abp/auditing/src/constants/permissions.ts
  68. 1
      apps/vben5/packages/@abp/auditing/src/types/index.ts
  69. 65
      apps/vben5/packages/@abp/auditing/src/types/loggings.ts
  70. 2
      apps/vben5/packages/@abp/components/package.json
  71. 82
      apps/vben5/packages/@abp/components/src/vditor/Viewer.vue
  72. 1
      apps/vben5/packages/@abp/components/src/vditor/index.ts
  73. 2
      apps/vben5/packages/@abp/core/package.json
  74. 2
      apps/vben5/packages/@abp/data-protection/package.json
  75. 2
      apps/vben5/packages/@abp/demo/package.json
  76. 2
      apps/vben5/packages/@abp/features/package.json
  77. 2
      apps/vben5/packages/@abp/gdpr/package.json
  78. 3
      apps/vben5/packages/@abp/identity/package.json
  79. 14
      apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue
  80. 12
      apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue
  81. 2
      apps/vben5/packages/@abp/localization/package.json
  82. 2
      apps/vben5/packages/@abp/notifications/package.json
  83. 2
      apps/vben5/packages/@abp/openiddict/package.json
  84. 16
      apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationModal.vue
  85. 44
      apps/vben5/packages/@abp/oss/package.json
  86. 2
      apps/vben5/packages/@abp/oss/src/api/index.ts
  87. 61
      apps/vben5/packages/@abp/oss/src/api/useContainesApi.ts
  88. 50
      apps/vben5/packages/@abp/oss/src/api/useObjectsApi.ts
  89. 55
      apps/vben5/packages/@abp/oss/src/components/containers/ContainerModal.vue
  90. 190
      apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue
  91. 2
      apps/vben5/packages/@abp/oss/src/components/index.ts
  92. 282
      apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue
  93. 286
      apps/vben5/packages/@abp/oss/src/components/objects/FileUploadModal.vue
  94. 66
      apps/vben5/packages/@abp/oss/src/components/objects/FolderModal.vue
  95. 192
      apps/vben5/packages/@abp/oss/src/components/objects/FolderTree.vue
  96. 34
      apps/vben5/packages/@abp/oss/src/components/objects/ObjectPage.vue
  97. 18
      apps/vben5/packages/@abp/oss/src/constants/permissions.ts
  98. 1
      apps/vben5/packages/@abp/oss/src/global.d.ts
  99. 3
      apps/vben5/packages/@abp/oss/src/index.ts
  100. 38
      apps/vben5/packages/@abp/oss/src/types/containes.ts

3
.github/workflows/publish.yml

@ -25,7 +25,6 @@ jobs:
working-directory: .\build
shell: powershell
- name: Publish Packages
run:
dotnet nuget push *.nupkg --api-key ${{ secrets.NUGETKEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate --no-symbols
run: ..\..\build\package-aspnetcore-publish.ps1
working-directory: .\aspnet-core\LocalNuget

2
.github/workflows/release.yml

@ -14,4 +14,4 @@ jobs:
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
automatic_release_tag: "9.1.1"
automatic_release_tag: "9.1.3"

18
Directory.Packages.props

@ -1,18 +1,18 @@
<Project>
<PropertyGroup>
<DotNetCoreCAPPackageVersion>8.3.2</DotNetCoreCAPPackageVersion>
<ElsaPackageVersion>2.14.1</ElsaPackageVersion>
<ElsaNextPackageVersion>3.3.0-rc7</ElsaNextPackageVersion>
<VoloAbpPackageVersion>9.1.1</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>9.1.1</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>9.0.2</MicrosoftExtensionsPackageVersion>
<MicrosoftAspNetCorePackageVersion>9.0.2</MicrosoftAspNetCorePackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>9.0.2</MicrosoftEntityFrameworkCorePackageVersion>
<ElsaPackageVersion>2.15.1</ElsaPackageVersion>
<ElsaNextPackageVersion>3.3.5</ElsaNextPackageVersion>
<VoloAbpPackageVersion>9.1.3</VoloAbpPackageVersion>
<LINGYUNAbpPackageVersion>9.1.3</LINGYUNAbpPackageVersion>
<MicrosoftExtensionsPackageVersion>9.0.0</MicrosoftExtensionsPackageVersion>
<MicrosoftAspNetCorePackageVersion>9.0.0</MicrosoftAspNetCorePackageVersion>
<MicrosoftEntityFrameworkCorePackageVersion>9.0.0</MicrosoftEntityFrameworkCorePackageVersion>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- Abp Framework -->
<ItemGroup>
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="3.2.0" />
<PackageVersion Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite" Version="4.1.3" />
<PackageVersion Include="Volo.Abp.Core" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Account.Application" Version="$(VoloAbpPackageVersion)" />
<PackageVersion Include="Volo.Abp.Account.Application.Contracts" Version="$(VoloAbpPackageVersion)" />
@ -150,7 +150,7 @@
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.Protocols.Json" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="$(MicrosoftAspNetCorePackageVersion)" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.2" />
<PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
<PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.InMemory" Version="$(MicrosoftEntityFrameworkCorePackageVersion)" />

3
apps/vben5/apps/app-antd/.env

@ -3,3 +3,6 @@ VITE_APP_TITLE=Vben Admin Antd
# 应用命名空间,用于缓存、store等功能的前缀,确保隔离
VITE_APP_NAMESPACE=vben-web-antd
# 对应后端UI框架名称
VITE_GLOB_UI_FRAMEWORK=vben5

7
apps/vben5/apps/app-antd/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/app-antd",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {
@ -36,12 +36,17 @@
"@abp/localization": "workspace:*",
"@abp/notifications": "workspace:*",
"@abp/openiddict": "workspace:*",
"@abp/oss": "workspace:*",
"@abp/permissions": "workspace:*",
"@abp/platform": "workspace:*",
"@abp/request": "workspace:*",
"@abp/saas": "workspace:*",
"@abp/settings": "workspace:*",
"@abp/tasks": "workspace:*",
"@abp/text-templating": "workspace:*",
"@abp/ui": "workspace:*",
"@abp/webhooks": "workspace:*",
"@vben-core/shadcn-ui": "workspace:*",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/constants": "workspace:*",

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

@ -38,6 +38,7 @@ import {
Switch,
Textarea,
TimePicker,
Tree,
TreeSelect,
Upload,
} from 'ant-design-vue';
@ -78,6 +79,7 @@ export type ComponentType =
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'Tree'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
@ -154,6 +156,7 @@ async function initComponentAdapter() {
Switch,
Textarea: withDefaultPlaceholder(Textarea, 'input'),
TimePicker,
Tree,
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload,
FeatureStateCheck,

6
apps/vben5/apps/app-antd/src/hooks/useSessions.ts

@ -1,4 +1,3 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { Notification as NotificationInfo } from '@abp/notifications';
import { onMounted, onUnmounted } from 'vue';
@ -27,7 +26,10 @@ export function useSessions() {
/** 处理会话过期事件 */
function _onSessionExpired(event?: NotificationInfo) {
const { data, title, message } = event!;
if (!event) {
return;
}
const { data, title, message } = event;
const sessionId = data.SessionId;
if (sessionId === abpStore.application?.currentUser?.sessionId) {
_release();

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

@ -22,7 +22,6 @@
"claimTypes": "Claim Types",
"securityLogs": "Security Logs",
"organizationUnits": "Organization Units",
"auditLogs": "Audit Logs",
"sessions": "Sessions"
},
"permissions": {
@ -55,7 +54,11 @@
"dataProtection": {
"title": "Data Protection",
"entityTypeInfos": "Entity Type Infos"
}
},
"auditLogs": "Audit Logs",
"loggings": "System Logs",
"openApi": "Api Document",
"cache": "Cache Management"
},
"openiddict": {
"title": "OpenIddict",
@ -96,7 +99,10 @@
"title": "Message Manage",
"email": "Email Messages",
"sms": "Sms Messages"
}
},
"dataDictionaries": "Data Dictionaries",
"layouts": "Layouts",
"menus": "Menus"
},
"saas": {
"title": "Saas",
@ -106,5 +112,27 @@
"demo": {
"title": "Demo",
"books": "Books"
},
"tasks": {
"title": "Task Management",
"jobInfo": {
"title": "Job Manage"
}
},
"webhooks": {
"title": "Webhooks",
"groups": "Groups",
"definitions": "Definitions",
"subscriptions": "Subscriptions",
"sendAttempts": "Send Attempts"
},
"textTemplating": {
"title": "Text Templating",
"definitions": "Definitions"
},
"oss": {
"title": "Object storage",
"containers": "Containers",
"objects": "Files"
}
}

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

@ -22,7 +22,6 @@
"claimTypes": "身份标识",
"securityLogs": "安全日志",
"organizationUnits": "组织机构",
"auditLogs": "审计日志",
"sessions": "会话管理"
},
"permissions": {
@ -55,7 +54,11 @@
"dataProtection": {
"title": "数据权限",
"entityTypeInfos": "实体列表"
}
},
"auditLogs": "审计日志",
"loggings": "系统日志",
"openApi": "接口文档",
"cache": "缓存管理"
},
"openiddict": {
"title": "OpenIddict",
@ -96,7 +99,10 @@
"title": "消息管理",
"email": "邮件消息",
"sms": "短信消息"
}
},
"dataDictionaries": "数据字典",
"layouts": "布局管理",
"menus": "菜单管理"
},
"saas": {
"title": "Saas",
@ -106,5 +112,27 @@
"demo": {
"title": "演示",
"books": "书籍列表"
},
"tasks": {
"title": "后台作业",
"jobInfo": {
"title": "作业管理"
}
},
"webhooks": {
"title": "Webhook管理",
"groups": "Webhook分组",
"definitions": "Webhook定义",
"subscriptions": "管理订阅",
"sendAttempts": "发送记录"
},
"textTemplating": {
"title": "文本模板",
"definitions": "模板定义"
},
"oss": {
"title": "对象存储",
"containers": "容器管理",
"objects": "文件管理"
}
}

1
apps/vben5/apps/app-antd/src/preferences.ts

@ -8,6 +8,7 @@ import { defineOverridesPreferences } from '@vben/preferences';
export const overridesPreferences = defineOverridesPreferences({
// overrides
app: {
accessMode: 'backend',
enableRefreshToken: true,
name: import.meta.env.VITE_APP_TITLE,
},

11
apps/vben5/apps/app-antd/src/router/access.ts

@ -4,18 +4,22 @@ import type {
} from '@vben/types';
import { generateAccessible } from '@vben/access';
import { useAppConfig } from '@vben/hooks';
import { preferences } from '@vben/preferences';
import { useMenuTransform, useMyMenusApi } from '@abp/platform';
import { message } from 'ant-design-vue';
import { getAllMenusApi } from '#/api';
import { BasicLayout, IFrameView } from '#/layouts';
import { $t } from '#/locales';
const forbiddenComponent = () => import('#/views/_core/fallback/forbidden.vue');
async function generateAccess(options: GenerateMenuAndRoutesOptions) {
const { getAllApi } = useMyMenusApi();
const { transformRoutes } = useMenuTransform();
const pageMap: ComponentRecordType = import.meta.glob('../views/**/*.vue');
const { uiFramework } = useAppConfig(import.meta.env, import.meta.env.PROD);
const layoutMap: ComponentRecordType = {
BasicLayout,
@ -29,7 +33,10 @@ async function generateAccess(options: GenerateMenuAndRoutesOptions) {
content: `${$t('common.loadingMenu')}...`,
duration: 1.5,
});
return await getAllMenusApi();
const { items } = await getAllApi({
framework: uiFramework,
});
return transformRoutes(items);
},
// 可以指定没有权限跳转403页面
forbiddenComponent,

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

@ -5,444 +5,543 @@ import { $t } from '#/locales';
const routes: RouteRecordRaw[] = [
{
meta: {
icon: 'https://abp.io/assets/favicon.ico/favicon-16x16.png',
keepAlive: true,
order: 1000,
title: $t('abp.title'),
title: $t('abp.manage.title'),
icon: 'arcticons:activity-manager',
},
name: 'AbpFramework',
path: '/abp',
name: 'Vben5Manage',
path: '/manage',
children: [
{
meta: {
title: $t('abp.manage.title'),
icon: 'arcticons:activity-manager',
title: $t('abp.manage.identity.title'),
icon: 'teenyicons:id-outline',
},
name: 'Manage',
path: '/manage',
name: 'Vben5Identity',
path: '/manage/identity',
children: [
{
component: () => import('#/views/identity/users/index.vue'),
name: 'Vben5IdentityUsers',
path: '/manage/identity/users',
meta: {
title: $t('abp.manage.identity.title'),
icon: 'teenyicons:id-outline',
title: $t('abp.manage.identity.user'),
icon: 'mdi:user-outline',
},
name: 'Identity',
path: '/manage/identity',
children: [
{
component: () => import('#/views/identity/users/index.vue'),
name: 'Users',
path: '/manage/identity/users',
meta: {
title: $t('abp.manage.identity.user'),
icon: 'mdi:user-outline',
},
},
{
component: () => import('#/views/identity/roles/index.vue'),
name: 'Roles',
path: '/manage/identity/roles',
meta: {
title: $t('abp.manage.identity.role'),
icon: 'carbon:user-role',
},
},
{
component: () =>
import('#/views/identity/claim-types/index.vue'),
name: 'ClaimTypes',
path: '/manage/identity/claim-types',
meta: {
title: $t('abp.manage.identity.claimTypes'),
icon: 'la:id-card-solid',
},
},
{
component: () =>
import('#/views/identity/security-logs/index.vue'),
name: 'SecurityLogs',
path: '/manage/identity/security-logs',
meta: {
title: $t('abp.manage.identity.securityLogs'),
icon: 'carbon:security',
},
},
{
component: () =>
import('#/views/identity/organization-units/index.vue'),
name: 'OrganizationUnits',
path: '/manage/identity/organization-units',
meta: {
title: $t('abp.manage.identity.organizationUnits'),
icon: 'clarity:organization-line',
},
},
{
component: () => import('#/views/identity/sessions/index.vue'),
name: 'IdentitySessions',
path: '/manage/identity/sessions',
meta: {
title: $t('abp.manage.identity.sessions'),
icon: 'carbon:prompt-session',
},
},
],
},
{
component: () => import('#/views/identity/roles/index.vue'),
name: 'Vben5IdentityRoles',
path: '/manage/identity/roles',
meta: {
title: $t('abp.manage.permissions.title'),
icon: 'arcticons:permissionsmanager',
title: $t('abp.manage.identity.role'),
icon: 'carbon:user-role',
},
name: 'PermissionManagement',
path: '/manage/permissions',
children: [
{
meta: {
title: $t('abp.manage.permissions.groups'),
icon: 'lucide:group',
},
name: 'PermissionGroupDefinitions',
path: '/manage/permissions/groups',
component: () => import('#/views/permissions/groups/index.vue'),
},
{
meta: {
title: $t('abp.manage.permissions.definitions'),
icon: 'icon-park-outline:permissions',
},
name: 'PermissionDefinitions',
path: '/manage/permissions/definitions',
component: () =>
import('#/views/permissions/definitions/index.vue'),
},
],
},
{
component: () => import('#/views/identity/claim-types/index.vue'),
name: 'Vben5IdentityClaimTypes',
path: '/manage/identity/claim-types',
meta: {
title: $t('abp.manage.features.title'),
icon: 'ant-design:gold-outlined',
title: $t('abp.manage.identity.claimTypes'),
icon: 'la:id-card-solid',
},
name: 'FeatureManagement',
path: '/manage/features',
children: [
{
meta: {
title: $t('abp.manage.features.groups'),
icon: 'lucide:group',
},
name: 'FeatureGroupDefinitions',
path: '/manage/features/groups',
component: () => import('#/views/features/groups/index.vue'),
},
{
meta: {
title: $t('abp.manage.features.definitions'),
icon: 'pajamas:feature-flag',
},
name: 'FeatureDefinitions',
path: '/manage/features/definitions',
component: () =>
import('#/views/features/definitions/index.vue'),
},
],
},
{
component: () => import('#/views/identity/security-logs/index.vue'),
name: 'Vben5IdentitySecurityLogs',
path: '/manage/identity/security-logs',
meta: {
title: $t('abp.manage.settings.title'),
icon: 'ic:outline-settings',
title: $t('abp.manage.identity.securityLogs'),
icon: 'carbon:security',
},
name: 'SettingManagement',
path: '/manage/settings',
children: [
{
meta: {
title: $t('abp.manage.settings.definitions'),
icon: 'codicon:settings',
},
name: 'SettingDefinitions',
path: '/manage/settings/definitions',
component: () =>
import('#/views/settings/definitions/index.vue'),
},
{
meta: {
title: $t('abp.manage.settings.system'),
icon: 'tabler:settings-cog',
},
name: 'SystemSettings',
path: '/manage/settings/system',
component: () => import('#/views/settings/system/index.vue'),
},
],
},
{
component: () =>
import('#/views/identity/organization-units/index.vue'),
name: 'Vben5IdentityOrganizationUnits',
path: '/manage/identity/organization-units',
meta: {
title: $t('abp.manage.localization.title'),
icon: 'ion:globe-outline',
title: $t('abp.manage.identity.organizationUnits'),
icon: 'clarity:organization-line',
},
name: 'LocalizationManagement',
path: '/manage/localization',
children: [
{
meta: {
title: $t('abp.manage.localization.resources'),
icon: 'grommet-icons:resources',
},
name: 'LocalizationResources',
path: '/manage/localization/resources',
component: () =>
import('#/views/localization/resources/index.vue'),
},
{
meta: {
title: $t('abp.manage.localization.languages'),
icon: 'cil:language',
},
name: 'LocalizationLanguages',
path: '/manage/localization/languages',
component: () =>
import('#/views/localization/languages/index.vue'),
},
{
meta: {
title: $t('abp.manage.localization.texts'),
icon: 'mi:text',
},
name: 'LocalizationTexts',
path: '/manage/localization/texts',
component: () => import('#/views/localization/texts/index.vue'),
},
],
},
{
component: () => import('#/views/identity/sessions/index.vue'),
name: 'Vben5IdentitySessions',
path: '/manage/identity/sessions',
meta: {
title: $t('abp.manage.dataProtection.title'),
icon: 'icon-park-outline:protect',
title: $t('abp.manage.identity.sessions'),
icon: 'carbon:prompt-session',
},
name: 'DataProtectionManagement',
path: '/manage/data-protection',
children: [
{
meta: {
title: $t('abp.manage.dataProtection.entityTypeInfos'),
icon: 'iconamoon:type',
keepAlive: true,
},
name: 'EntityTypeInfos',
path: '/manage/data-protection/entity-type-infos',
component: () =>
import('#/views/data-protection/entity-type-infos/index.vue'),
},
],
},
],
},
{
meta: {
title: $t('abp.manage.permissions.title'),
icon: 'arcticons:permissionsmanager',
},
name: 'Vben5Permissions',
path: '/manage/permissions',
children: [
{
meta: {
title: $t('abp.manage.identity.auditLogs'),
icon: 'fluent-mdl2:compliance-audit',
title: $t('abp.manage.permissions.groups'),
icon: 'lucide:group',
},
name: 'AuditingAuditLogs',
path: '/manage/audit-logs',
component: () => import('#/views/auditing/audit-logs/index.vue'),
name: 'Vben5PermissionsGroupDefinitions',
path: '/manage/permissions/groups',
component: () => import('#/views/permissions/groups/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.title'),
icon: 'tabler:notification',
title: $t('abp.manage.permissions.definitions'),
icon: 'icon-park-outline:permissions',
},
name: 'Notifications',
path: '/manage/notifications',
children: [
{
meta: {
title: $t('abp.manage.notifications.myNotifilers'),
icon: 'ant-design:notification-outlined',
},
name: 'MyNotifications',
path: '/manage/notifications/my-notifilers',
component: () =>
import('#/views/notifications/my-notifilers/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.groups'),
icon: 'lucide:group',
},
name: 'NotificationGroupDefinitions',
path: '/manage/notifications/groups',
component: () =>
import('#/views/notifications/groups/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.definitions'),
icon: 'nimbus:notification',
},
name: 'NotificationDefinitions',
path: '/manage/notifications/definitions',
component: () =>
import('#/views/notifications/definitions/index.vue'),
},
],
name: 'Vben5PermissionsDefinitions',
path: '/manage/permissions/definitions',
component: () =>
import('#/views/permissions/definitions/index.vue'),
},
],
},
{
meta: {
title: $t('abp.saas.title'),
icon: 'ant-design:cloud-server-outlined',
title: $t('abp.manage.features.title'),
icon: 'ant-design:gold-outlined',
},
name: 'Saas',
path: '/saas',
name: 'Vben5Features',
path: '/manage/features',
children: [
{
meta: {
title: $t('abp.saas.editions'),
icon: 'icon-park-outline:multi-rectangle',
title: $t('abp.manage.features.groups'),
icon: 'lucide:group',
},
name: 'SaasEditions',
path: '/saas/editions',
component: () => import('#/views/saas/editions/index.vue'),
name: 'Vben5FeaturesGroupDefinitions',
path: '/manage/features/groups',
component: () => import('#/views/features/groups/index.vue'),
},
{
meta: {
title: $t('abp.saas.tenants'),
icon: 'arcticons:tenantcloud-pro',
title: $t('abp.manage.features.definitions'),
icon: 'pajamas:feature-flag',
},
name: 'SaasTenants',
path: '/saas/tenants',
component: () => import('#/views/saas/tenants/index.vue'),
name: 'Vben5FeaturesDefinitions',
path: '/manage/features/definitions',
component: () => import('#/views/features/definitions/index.vue'),
},
],
},
{
meta: {
title: $t('abp.openiddict.title'),
icon: 'mdi:openid',
title: $t('abp.manage.settings.title'),
icon: 'ic:outline-settings',
},
name: 'OpenIddict',
path: '/openiddict',
name: 'Vben5Settings',
path: '/manage/settings',
children: [
{
meta: {
title: $t('abp.openiddict.applications'),
icon: 'carbon:application',
title: $t('abp.manage.settings.definitions'),
icon: 'codicon:settings',
},
name: 'OpenIddictApplications',
path: '/openiddict/applications',
component: () =>
import('#/views/openiddict/applications/index.vue'),
name: 'Vben5SettingsDefinitions',
path: '/manage/settings/definitions',
component: () => import('#/views/settings/definitions/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.authorizations'),
icon: 'arcticons:ente-authenticator',
title: $t('abp.manage.settings.system'),
icon: 'tabler:settings-cog',
},
name: 'OpenIddictAuthorizations',
path: '/openiddict/authorizations',
component: () =>
import('#/views/openiddict/authorizations/index.vue'),
name: 'Vben5SettingsSystem',
path: '/manage/settings/system',
component: () => import('#/views/settings/system/index.vue'),
},
],
},
{
meta: {
title: $t('abp.manage.localization.title'),
icon: 'ion:globe-outline',
},
name: 'Vben5Localizations',
path: '/manage/localization',
children: [
{
meta: {
title: $t('abp.manage.localization.resources'),
icon: 'grommet-icons:resources',
},
name: 'Vben5LocalizationsResources',
path: '/manage/localization/resources',
component: () => import('#/views/localization/resources/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.scopes'),
icon: 'et:scope',
title: $t('abp.manage.localization.languages'),
icon: 'cil:language',
},
name: 'OpenIddictScopes',
path: '/openiddict/scopes',
component: () => import('#/views/openiddict/scopes/index.vue'),
name: 'Vben5LocalizationsLanguages',
path: '/manage/localization/languages',
component: () => import('#/views/localization/languages/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.tokens'),
icon: 'oui:token-key',
title: $t('abp.manage.localization.texts'),
icon: 'mi:text',
},
name: 'OpenIddictTokens',
path: '/openiddict/tokens',
component: () => import('#/views/openiddict/tokens/index.vue'),
name: 'Vben5LocalizationsTexts',
path: '/manage/localization/texts',
component: () => import('#/views/localization/texts/index.vue'),
},
],
},
{
name: 'Account',
path: '/account',
meta: {
title: $t('abp.account.title'),
icon: 'mdi:account-outline',
hideInMenu: true,
title: $t('abp.manage.dataProtection.title'),
icon: 'icon-park-outline:protect',
},
name: 'Vben5DataProtection',
path: '/manage/data-protection',
children: [
{
meta: {
title: $t('abp.account.settings.title'),
icon: 'tdesign:user-setting',
title: $t('abp.manage.dataProtection.entityTypeInfos'),
icon: 'iconamoon:type',
keepAlive: true,
},
name: 'MySettings',
path: '/account/my-settings',
component: () => import('#/views/account/my-settings/index.vue'),
name: 'Vben5DataProtectionEntityTypeInfos',
path: '/manage/data-protection/entity-type-infos',
component: () =>
import('#/views/data-protection/entity-type-infos/index.vue'),
},
],
},
{
name: 'Platform',
path: '/platform',
meta: {
title: $t('abp.platform.title'),
icon: 'ep:platform',
title: $t('abp.manage.auditLogs'),
icon: 'fluent-mdl2:compliance-audit',
},
name: 'Vben5AuditingAuditLogs',
path: '/manage/audit-logs',
component: () => import('#/views/auditing/audit-logs/index.vue'),
},
{
meta: {
title: $t('abp.manage.loggings'),
icon: 'icon-park-outline:log',
},
name: 'Vben5AuditingLoggings',
path: '/manage/sys-logs',
component: () => import('#/views/auditing/loggings/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.title'),
icon: 'tabler:notification',
},
name: 'Vben5Notifications',
path: '/manage/notifications',
children: [
{
meta: {
title: $t('abp.platform.messages.title'),
icon: 'tabler:message-cog',
title: $t('abp.manage.notifications.myNotifilers'),
icon: 'ant-design:notification-outlined',
},
name: 'Vben5NotificationsMyNotifilers',
path: '/manage/notifications/my-notifilers',
component: () =>
import('#/views/notifications/my-notifilers/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.groups'),
icon: 'lucide:group',
},
name: 'Vben5NotificationsGroupDefinitions',
path: '/manage/notifications/groups',
component: () => import('#/views/notifications/groups/index.vue'),
},
{
meta: {
title: $t('abp.manage.notifications.definitions'),
icon: 'nimbus:notification',
},
name: 'PlatformMessages',
path: '/platform/messages',
children: [
{
meta: {
title: $t('abp.platform.messages.email'),
icon: 'material-symbols:attach-email-outline',
},
name: 'PlatformEmailMessages',
path: '/platform/messages/email',
component: () =>
import('#/views/platform/messages/email/index.vue'),
},
{
meta: {
title: $t('abp.platform.messages.sms'),
icon: 'material-symbols:sms-outline',
},
name: 'PlatformSmsMessages',
path: '/platform/messages/sms',
component: () =>
import('#/views/platform/messages/sms/index.vue'),
},
],
name: 'Vben5NotificationsDefinitions',
path: '/manage/notifications/definitions',
component: () =>
import('#/views/notifications/definitions/index.vue'),
},
],
},
],
},
{
meta: {
title: $t('abp.saas.title'),
icon: 'ant-design:cloud-server-outlined',
},
name: 'Vben5Saas',
path: '/saas',
children: [
{
meta: {
title: $t('abp.saas.editions'),
icon: 'icon-park-outline:multi-rectangle',
},
name: 'Vben5SaasEditions',
path: '/saas/editions',
component: () => import('#/views/saas/editions/index.vue'),
},
{
meta: {
title: $t('abp.saas.tenants'),
icon: 'arcticons:tenantcloud-pro',
},
name: 'Vben5SaasTenants',
path: '/saas/tenants',
component: () => import('#/views/saas/tenants/index.vue'),
},
],
},
{
meta: {
title: $t('abp.openiddict.title'),
icon: 'mdi:openid',
},
name: 'Vben5OpenIddict',
path: '/openiddict',
children: [
{
meta: {
title: $t('abp.openiddict.applications'),
icon: 'carbon:application',
},
name: 'Vben5OpenIddictApplications',
path: '/openiddict/applications',
component: () => import('#/views/openiddict/applications/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.authorizations'),
icon: 'arcticons:ente-authenticator',
},
name: 'Vben5OpenIddictAuthorizations',
path: '/openiddict/authorizations',
component: () => import('#/views/openiddict/authorizations/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.scopes'),
icon: 'et:scope',
},
name: 'Vben5OpenIddictScopes',
path: '/openiddict/scopes',
component: () => import('#/views/openiddict/scopes/index.vue'),
},
{
meta: {
title: $t('abp.openiddict.tokens'),
icon: 'oui:token-key',
},
name: 'Vben5OpenIddictTokens',
path: '/openiddict/tokens',
component: () => import('#/views/openiddict/tokens/index.vue'),
},
],
},
{
name: 'Vben5Account',
path: '/account',
meta: {
title: $t('abp.account.title'),
icon: 'mdi:account-outline',
hideInMenu: true,
},
children: [
{
meta: {
title: $t('abp.account.settings.title'),
icon: 'tdesign:user-setting',
},
name: 'Vben5AccountMySettings',
path: '/account/my-settings',
component: () => import('#/views/account/my-settings/index.vue'),
},
],
},
{
name: 'Vben5Platform',
path: '/platform',
meta: {
title: $t('abp.platform.title'),
icon: 'ep:platform',
},
children: [
{
meta: {
title: $t('abp.platform.dataDictionaries'),
icon: 'material-symbols:dictionary-outline',
},
name: 'Vben5PlatformDataDictionaries',
path: '/platform/data-dictionaries',
component: () => import('#/views/platform/data-dictionaries/index.vue'),
},
{
meta: {
title: $t('abp.platform.layouts'),
icon: 'material-symbols-light:responsive-layout',
},
name: 'Vben5PlatformLayouts',
path: '/platform/layouts',
component: () => import('#/views/platform/layouts/index.vue'),
},
{
meta: {
title: $t('abp.platform.menus'),
icon: 'material-symbols-light:menu',
},
name: 'Vben5PlatformMenus',
path: '/platform/menus',
component: () => import('#/views/platform/menus/index.vue'),
},
{
name: 'AbpDemo',
path: '/abp/demos',
meta: {
title: $t('abp.demo.title'),
icon: 'carbon:demo',
title: $t('abp.platform.messages.title'),
icon: 'tabler:message-cog',
},
name: 'Vben5PlatformMessages',
path: '/platform/messages',
children: [
{
meta: {
title: $t('abp.demo.books'),
icon: 'mingcute:book-line',
title: $t('abp.platform.messages.email'),
icon: 'material-symbols:attach-email-outline',
},
name: 'Vben5PlatformEmailMessages',
path: '/platform/messages/email',
component: () =>
import('#/views/platform/messages/email/index.vue'),
},
{
meta: {
title: $t('abp.platform.messages.sms'),
icon: 'material-symbols:sms-outline',
},
name: 'DemoBooks',
path: '/abp/demos/books',
component: () => import('#/views/demos/books/index.vue'),
name: 'Vben5PlatformSmsMessages',
path: '/platform/messages/sms',
component: () => import('#/views/platform/messages/sms/index.vue'),
},
],
},
],
},
{
name: 'Vben5Tasks',
path: '/task-management',
meta: {
title: $t('abp.tasks.title'),
icon: 'eos-icons:background-tasks',
},
children: [
{
meta: {
title: $t('abp.tasks.jobInfo.title'),
icon: 'eos-icons:job',
},
name: 'Vben5TasksJobInfos',
path: '/task-management/background-jobs',
component: () => import('#/views/tasks/job-infos/index.vue'),
},
],
},
{
meta: {
title: $t('abp.webhooks.title'),
icon: 'material-symbols:webhook',
},
name: 'Vben5Webhooks',
path: '/webhooks',
children: [
{
meta: {
title: $t('abp.webhooks.groups'),
icon: 'lucide:group',
},
name: 'Vben5WebhooksGroupDefinitions',
path: '/webhooks/groups',
component: () => import('#/views/webhooks/groups/index.vue'),
},
{
meta: {
title: $t('abp.webhooks.definitions'),
icon: 'material-symbols:webhook',
},
name: 'Vben5WebhooksDefinitions',
path: '/webhooks/definitions',
component: () => import('#/views/webhooks/definitions/index.vue'),
},
{
meta: {
title: $t('abp.webhooks.subscriptions'),
icon: 'material-symbols:subscriptions',
},
name: 'Vben5WebhooksSubscriptions',
path: '/webhooks/subscriptions',
component: () => import('#/views/webhooks/subscriptions/index.vue'),
},
{
meta: {
title: $t('abp.webhooks.sendAttempts'),
icon: 'material-symbols:history',
},
name: 'Vben5WebhooksSendAttempts',
path: '/webhooks/send-attempts',
component: () => import('#/views/webhooks/send-attempts/index.vue'),
},
],
},
{
meta: {
title: $t('abp.textTemplating.title'),
icon: 'tdesign:template',
},
name: 'Vben5TextTemplating',
path: '/text-templating',
children: [
{
meta: {
title: $t('abp.textTemplating.definitions'),
icon: 'qlementine-icons:template-16',
},
name: 'Vben5TextTemplatingDefinitions',
path: '/text-templating/definitions',
component: () =>
import('#/views/text-templating/definitions/index.vue'),
},
],
},
{
name: 'Vben5AbpDemo',
path: '/abp/demos',
meta: {
title: $t('abp.demo.title'),
icon: 'carbon:demo',
},
children: [
{
meta: {
title: $t('abp.demo.books'),
icon: 'mingcute:book-line',
},
name: 'Vben5AbpDemoBooks',
path: '/abp/demos/books',
component: () => import('#/views/demos/books/index.vue'),
},
],
},
];
export default routes;

8
apps/vben5/apps/app-antd/src/views/_core/authentication/login.vue

@ -14,6 +14,7 @@ import { useAbpStore } from '@abp/core';
import { useAbpConfigApi } from '#/api/core/useAbpConfigApi';
import { useAuthStore } from '#/store';
import ThirdPartyLogin from './third-party-login.vue';
import TwoFactorLogin from './two-factor-login.vue';
interface LoginInstance {
@ -103,7 +104,12 @@ onMounted(onInit);
:form-schema="formSchema"
:loading="authStore.loginLoading"
@submit="onLogin"
/>
>
<!-- 第三方登录 -->
<template #third-party-login>
<ThirdPartyLogin />
</template>
</AuthenticationLogin>
<TwoFactorModal />
</div>
</template>

37
apps/vben5/apps/app-antd/src/views/_core/authentication/third-party-login.vue

@ -0,0 +1,37 @@
<script setup lang="ts">
import { MdiGithub, MdiGoogle, MdiQqchat, MdiWechat } from '@vben/icons';
import { $t } from '@vben/locales';
import { VbenIconButton } from '@vben-core/shadcn-ui';
defineOptions({
name: 'ThirdPartyLogin',
});
</script>
<template>
<div class="w-full sm:mx-auto md:max-w-md">
<div class="mt-4 flex items-center justify-between">
<span class="border-input w-[35%] border-b dark:border-gray-600"></span>
<span class="text-muted-foreground text-center text-xs uppercase">
{{ $t('authentication.thirdPartyLogin') }}
</span>
<span class="border-input w-[35%] border-b dark:border-gray-600"></span>
</div>
<div class="mt-4 flex flex-wrap justify-center">
<VbenIconButton class="mb-3">
<MdiWechat />
</VbenIconButton>
<VbenIconButton class="mb-3">
<MdiQqchat />
</VbenIconButton>
<VbenIconButton class="mb-3">
<MdiGithub />
</VbenIconButton>
<VbenIconButton class="mb-3">
<MdiGoogle />
</VbenIconButton>
</div>
</div>
</template>

2
apps/vben5/apps/app-antd/src/views/account/my-profile/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { MyProfile } from '@abp/account';
defineOptions({
name: 'MyProfiles',
name: 'Vben5AccountMyProfiles',
});
</script>

2
apps/vben5/apps/app-antd/src/views/account/my-settings/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { MySetting } from '@abp/account';
defineOptions({
name: 'MySettings',
name: 'Vben5AccountMySettings',
});
</script>

2
apps/vben5/apps/app-antd/src/views/auditing/audit-logs/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { AuditLogTable } from '@abp/auditing';
defineOptions({
name: 'AuditingAuditLogs',
name: 'Vben5AuditingAuditLogs',
});
</script>

15
apps/vben5/apps/app-antd/src/views/auditing/loggings/index.vue

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

2
apps/vben5/apps/app-antd/src/views/data-protection/entity-type-infos/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { EntityTypeInfoTable } from '@abp/data-protection';
defineOptions({
name: 'EntityTypeInfos',
name: 'Vben5DataProtectionEntityTypeInfos',
});
</script>

2
apps/vben5/apps/app-antd/src/views/demos/books/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { BookTable } from '@abp/demo';
defineOptions({
name: 'DemoBooks',
name: 'Vben5AbpDemoBooks',
});
</script>

2
apps/vben5/apps/app-antd/src/views/features/definitions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { FeatureDefinitionTable } from '@abp/features';
defineOptions({
name: 'FeatureDefinitions',
name: 'Vben5FeaturesDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/features/groups/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { FeatureGroupDefinitionTable } from '@abp/features';
defineOptions({
name: 'FeatureGroupDefinitions',
name: 'Vben5FeaturesGroupDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/claim-types/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { ClaimTypeTable } from '@abp/identity';
defineOptions({
name: 'IdentityClaimTypes',
name: 'Vben5IdentityClaimTypes',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/organization-units/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { OrganizationUnitPage } from '@abp/identity';
defineOptions({
name: 'IdentityOrganizationUnits',
name: 'Vben5IdentityOrganizationUnits',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/roles/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { RoleTable } from '@abp/identity';
defineOptions({
name: 'IdentityRoles',
name: 'Vben5IdentityRoles',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/security-logs/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { SecurityLogTable } from '@abp/identity';
defineOptions({
name: 'IdentitySecurityLogs',
name: 'Vben5IdentitySecurityLogs',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/sessions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { SessionTable } from '@abp/identity';
defineOptions({
name: 'IdentitySessions',
name: 'Vben5IdentitySessions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/identity/users/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { UserTable } from '@abp/identity';
defineOptions({
name: 'IdentityUsers',
name: 'Vben5IdentityUsers',
});
</script>

2
apps/vben5/apps/app-antd/src/views/localization/languages/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { LocalizationLanguageTable } from '@abp/localization';
defineOptions({
name: 'LocalizationLanguages',
name: 'Vben5LocalizationsLanguages',
});
</script>

2
apps/vben5/apps/app-antd/src/views/localization/resources/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { LocalizationResourceTable } from '@abp/localization';
defineOptions({
name: 'LocalizationResources',
name: 'Vben5LocalizationsResources',
});
</script>

2
apps/vben5/apps/app-antd/src/views/localization/texts/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { LocalizationTextTable } from '@abp/localization';
defineOptions({
name: 'LocalizationTexts',
name: 'Vben5LocalizationsTexts',
});
</script>

2
apps/vben5/apps/app-antd/src/views/notifications/definitions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { NotificationDefinitionTable } from '@abp/notifications';
defineOptions({
name: 'NotificationDefinitions',
name: 'Vben5NotificationsDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/notifications/groups/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { NotificationGroupDefinitionTable } from '@abp/notifications';
defineOptions({
name: 'NotificationGroupDefinitions',
name: 'Vben5NotificationsGroupDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/notifications/my-notifilers/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { MyNotificationTable } from '@abp/notifications';
defineOptions({
name: 'MyNotifications',
name: 'Vben5NotificationsMyNotifilers',
});
</script>

2
apps/vben5/apps/app-antd/src/views/openiddict/applications/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { ApplicationTable } from '@abp/openiddict';
defineOptions({
name: 'OpenIddictApplications',
name: 'Vben5OpenIddictApplications',
});
</script>

2
apps/vben5/apps/app-antd/src/views/openiddict/authorizations/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { AuthorizationTable } from '@abp/openiddict';
defineOptions({
name: 'OpenIddictAuthorizations',
name: 'Vben5OpenIddictAuthorizations',
});
</script>

2
apps/vben5/apps/app-antd/src/views/openiddict/scopes/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { ScopeTable } from '@abp/openiddict';
defineOptions({
name: 'OpenIddictScopes',
name: 'Vben5OpenIddictScopes',
});
</script>

2
apps/vben5/apps/app-antd/src/views/openiddict/tokens/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { TokenTable } from '@abp/openiddict';
defineOptions({
name: 'OpenIddictTokens',
name: 'Vben5OpenIddictTokens',
});
</script>

15
apps/vben5/apps/app-antd/src/views/oss/containers/index.vue

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

15
apps/vben5/apps/app-antd/src/views/oss/objects/index.vue

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

2
apps/vben5/apps/app-antd/src/views/permissions/definitions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { PermissionDefinitionTable } from '@abp/permissions';
defineOptions({
name: 'PermissionDefinitions',
name: 'Vben5PermissionsDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/permissions/groups/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { PermissionGroupDefinitionTable } from '@abp/permissions';
defineOptions({
name: 'PermissionGroupDefinitions',
name: 'Vben5PermissionsGroupDefinitions',
});
</script>

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

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

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: 'Vben5PlatformLayouts',
});
</script>
<template>
<Page>
<LayoutTable />
</Page>
</template>

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

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

2
apps/vben5/apps/app-antd/src/views/platform/messages/email/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { EmailMessageTable } from '@abp/platform';
defineOptions({
name: 'PlatformEmailMessages',
name: 'Vben5PlatformEmailMessages',
});
</script>

2
apps/vben5/apps/app-antd/src/views/platform/messages/sms/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { SmsMessageTable } from '@abp/platform';
defineOptions({
name: 'PlatformSmsMessages',
name: 'Vben5PlatformSmsMessages',
});
</script>

2
apps/vben5/apps/app-antd/src/views/saas/editions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { EditionTable } from '@abp/saas';
defineOptions({
name: 'SaasEditions',
name: 'Vben5SaasEditions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/saas/tenants/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { TenantTable } from '@abp/saas';
defineOptions({
name: 'SaasTenants',
name: 'Vben5SaasTenants',
});
</script>

2
apps/vben5/apps/app-antd/src/views/settings/definitions/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { SettingDefinitionTable } from '@abp/settings';
defineOptions({
name: 'SettingDefinitions',
name: 'Vben5SettingsDefinitions',
});
</script>

2
apps/vben5/apps/app-antd/src/views/settings/system/index.vue

@ -4,7 +4,7 @@ import { Page } from '@vben/common-ui';
import { SystemSetting } from '@abp/settings';
defineOptions({
name: 'SystemSettings',
name: 'Vben5SettingsSystem',
});
</script>

15
apps/vben5/apps/app-antd/src/views/tasks/job-infos/index.vue

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

15
apps/vben5/apps/app-antd/src/views/text-templating/definitions/index.vue

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

15
apps/vben5/apps/app-antd/src/views/webhooks/definitions/index.vue

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

15
apps/vben5/apps/app-antd/src/views/webhooks/groups/index.vue

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

15
apps/vben5/apps/app-antd/src/views/webhooks/send-attempts/index.vue

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

15
apps/vben5/apps/app-antd/src/views/webhooks/subscriptions/index.vue

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

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

@ -1,6 +1,6 @@
{
"name": "@abp/account",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

12
apps/vben5/packages/@abp/account/src/components/MySetting.vue

@ -103,11 +103,13 @@ const [ChangePhoneNumberModal, changePhoneNumberModalApi] = useVbenModal({
});
function onEmailConfirm() {
if (query?.confirmToken) {
emailConfirmModalApi.setData({
email: myProfile.value.email,
...query,
});
emailConfirmModalApi.open();
setTimeout(() => {
emailConfirmModalApi.setData({
email: myProfile.value.email,
...query,
});
emailConfirmModalApi.open();
}, 300);
}
}
async function onGetProfile() {

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

@ -1,6 +1,6 @@
{
"name": "@abp/auditing",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,2 +1,3 @@
export { useAuditLogsApi } from './useAuditLogsApi';
export { useEntityChangesApi } from './useEntityChangesApi';
export { useLoggingsApi } from './useLoggingsApi';

38
apps/vben5/packages/@abp/auditing/src/api/useLoggingsApi.ts

@ -0,0 +1,38 @@
import type { PagedResultDto } from '@abp/core';
import type { LogDto, LogGetListInput } from '../types/loggings';
import { useRequest } from '@abp/request';
export function useLoggingsApi() {
const { cancel, request } = useRequest();
/**
*
* @param id id
*/
function getApi(id: string): Promise<LogDto> {
return request<LogDto>(`/api/auditing/logging/${id}`, {
method: 'GET',
});
}
/**
*
* @param input
*/
function getPagedListApi(
input: LogGetListInput,
): Promise<PagedResultDto<LogDto>> {
return request<PagedResultDto<LogDto>>('/api/auditing/logging', {
method: 'GET',
params: input,
});
}
return {
cancel,
getApi,
getPagedListApi,
};
}

3
apps/vben5/packages/@abp/auditing/src/components/audit-logs/AuditLogTable.vue

@ -41,6 +41,9 @@ const formOptions: VbenFormProps = {
schema: [
{
component: 'RangePicker',
componentProps: {
showTime: true,
},
fieldName: 'executionTime',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpAuditLogging.ExecutionTime'),

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

@ -1,2 +1,3 @@
export { default as AuditLogTable } from './audit-logs/AuditLogTable.vue';
export { default as EntityChangeDrawer } from './entity-changes/EntityChangeDrawer.vue';
export { default as LoggingTable } from './loggings/LoggingTable.vue';

138
apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingDrawer.vue

@ -0,0 +1,138 @@
<script setup lang="ts">
import type { LogDto, LogLevel } from '../../types/loggings';
import { ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { Descriptions, Tabs, Tag } from 'ant-design-vue';
import { useLoggingsApi } from '../../api/useLoggingsApi';
defineOptions({
name: 'LoggingDrawer',
});
defineProps<{
logLevelOptions: { color: string; label: string; value: LogLevel }[];
}>();
const TabPane = Tabs.TabPane;
const DescriptionsItem = Descriptions.Item;
const activedTab = ref('basic');
const logModel = ref<LogDto>({} as LogDto);
const { getApi } = useLoggingsApi();
const [Drawer, drawerApi] = useVbenDrawer({
class: 'w-auto',
onCancel() {
drawerApi.close();
},
onConfirm: async () => {
drawerApi.close();
},
onOpenChange: async (isOpen: boolean) => {
if (isOpen) {
try {
logModel.value = {} as LogDto;
drawerApi.setState({ loading: true });
const dto = drawerApi.getData<LogDto>();
await onGet(dto.fields.id);
} finally {
drawerApi.setState({ loading: false });
}
}
},
title: $t('AbpAuditLogging.AuditLog'),
});
async function onGet(id: string) {
const dto = await getApi(id);
logModel.value = dto;
}
</script>
<template>
<Drawer>
<div style="width: 800px">
<Tabs v-model="activedTab">
<TabPane key="basic" :tab="$t('AbpAuditLogging.Operation')">
<Descriptions
:colon="false"
:column="1"
bordered
size="small"
:label-style="{ minWidth: '110px' }"
>
<DescriptionsItem :label="$t('AbpAuditLogging.TimeStamp')">
{{ formatToDateTime(logModel.timeStamp) }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Level')">
<Tag :color="logLevelOptions[logModel.level]?.color">
{{ logLevelOptions[logModel.level]?.label }}
</Tag>
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Message')" :span="2">
{{ logModel.message }}
</DescriptionsItem>
</Descriptions>
</TabPane>
<TabPane key="fields" :tab="$t('AbpAuditLogging.Fields')">
<Descriptions
:colon="false"
:column="1"
bordered
size="small"
:label-style="{ minWidth: '110px' }"
>
<DescriptionsItem :label="$t('AbpAuditLogging.ApplicationName')">
{{ logModel.fields.application }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.MachineName')">
{{ logModel.fields.machineName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Environment')">
{{ logModel.fields.environment }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ProcessId')">
{{ logModel.fields.processId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ThreadId')">
{{ logModel.fields.threadId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.Context')">
{{ logModel.fields.context }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ActionId')">
{{ logModel.fields.actionId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.MethodName')">
{{ logModel.fields.actionName }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.RequestId')">
{{ logModel.fields.requestId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.RequestPath')">
{{ logModel.fields.requestPath }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ConnectionId')">
{{ logModel.fields.connectionId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.CorrelationId')">
{{ logModel.fields.correlationId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.ClientId')">
{{ logModel.fields.clientId }}
</DescriptionsItem>
<DescriptionsItem :label="$t('AbpAuditLogging.UserId')">
{{ logModel.fields.userId }}
</DescriptionsItem>
</Descriptions>
</TabPane>
</Tabs>
</div>
</Drawer>
</template>
<style scoped></style>

345
apps/vben5/packages/@abp/auditing/src/components/loggings/LoggingTable.vue

@ -0,0 +1,345 @@
<script setup lang="ts">
import type { SortOrder } from '@abp/core';
import type { VxeGridListeners, VxeGridProps } from '@abp/ui';
import type { VbenFormProps } from '@vben/common-ui';
import type { LogDto } from '../../types/loggings';
import { defineAsyncComponent, h, reactive, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import { EditOutlined } from '@ant-design/icons-vue';
import { Button, Tag } from 'ant-design-vue';
import { useLoggingsApi } from '../../api/useLoggingsApi';
import { SystemLogPermissions } from '../../constants/permissions';
import { LogLevel } from '../../types/loggings';
defineOptions({
name: 'LoggingTable',
});
const { getPagedListApi } = useLoggingsApi();
const selectedKeys = ref<string[]>([]);
const logLevelOptions = reactive([
{
color: 'purple',
label: 'Trace',
value: LogLevel.Trace,
},
{
color: 'blue',
label: 'Debug',
value: LogLevel.Debug,
},
{
color: 'green',
label: 'Information',
value: LogLevel.Information,
},
{
color: 'orange',
label: 'Warning',
value: LogLevel.Warning,
},
{
color: 'red',
label: 'Error',
value: LogLevel.Error,
},
{
color: '#f50',
label: 'Critical',
value: LogLevel.Critical,
},
{
color: '',
label: 'None',
value: LogLevel.None,
},
]);
const formOptions: VbenFormProps = {
//
collapsed: true,
collapsedRows: 2,
fieldMappingTime: [
[
'timeStamp',
['startTime', 'endTime'],
['YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss'],
],
],
schema: [
{
component: 'Select',
componentProps: {
options: logLevelOptions,
},
fieldName: 'level',
label: $t('AbpAuditLogging.Level'),
},
{
component: 'RangePicker',
componentProps: {
showTime: true,
},
fieldName: 'timeStamp',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpAuditLogging.TimeStamp'),
},
{
component: 'Input',
fieldName: 'application',
label: $t('AbpAuditLogging.ApplicationName'),
},
{
component: 'Input',
fieldName: 'machineName',
label: $t('AbpAuditLogging.MachineName'),
},
{
component: 'Input',
fieldName: 'environment',
label: $t('AbpAuditLogging.Environment'),
},
{
component: 'Input',
fieldName: 'requestId',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpAuditLogging.RequestId'),
},
{
component: 'Input',
fieldName: 'requestPath',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpAuditLogging.RequestPath'),
labelWidth: 150,
},
{
component: 'Input',
fieldName: 'correlationId',
formItemClass: 'col-span-2 items-baseline',
label: $t('AbpAuditLogging.CorrelationId'),
},
{
component: 'Checkbox',
componentProps: {
render: () => {
return h('span', $t('AbpAuditLogging.HasException'));
},
},
fieldName: 'hasException',
label: $t('AbpAuditLogging.HasException'),
},
],
//
showCollapseButton: true,
//
submitOnEnter: true,
wrapperClass: 'grid-cols-4',
};
const gridOptions: VxeGridProps<LogDto> = {
columns: [
{
align: 'left',
field: 'applicationName',
formatter: ({ row }) => {
return row.fields?.application;
},
sortable: true,
title: $t('AbpAuditLogging.ApplicationName'),
width: 150,
},
{
align: 'left',
field: 'timeStamp',
formatter: ({ cellValue }) => {
return cellValue ? formatToDateTime(cellValue) : cellValue;
},
sortable: true,
title: $t('AbpAuditLogging.TimeStamp'),
width: 150,
},
{
align: 'left',
field: 'level',
slots: { default: 'level' },
sortable: true,
title: $t('AbpAuditLogging.Level'),
width: 120,
},
{
align: 'left',
field: 'message',
sortable: true,
title: $t('AbpAuditLogging.Message'),
width: 500,
},
{
align: 'left',
field: 'machineName',
formatter: ({ row }) => {
return row.fields?.machineName;
},
sortable: true,
title: $t('AbpAuditLogging.MachineName'),
width: 140,
},
{
align: 'left',
field: 'environment',
formatter: ({ row }) => {
return row.fields?.environment;
},
sortable: true,
title: $t('AbpAuditLogging.Environment'),
width: 150,
},
{
align: 'left',
field: 'requestId',
formatter: ({ row }) => {
return row.fields?.requestId;
},
sortable: true,
title: $t('AbpAuditLogging.RequestId'),
width: 200,
},
{
align: 'left',
field: 'requestPath',
formatter: ({ row }) => {
return row.fields?.requestPath;
},
sortable: true,
title: $t('AbpAuditLogging.RequestPath'),
width: 300,
},
{
align: 'left',
field: 'connectionId',
formatter: ({ row }) => {
return row.fields?.connectionId;
},
sortable: true,
title: $t('AbpAuditLogging.ConnectionId'),
width: 150,
},
{
align: 'left',
field: 'correlationId',
formatter: ({ row }) => {
return row.fields?.correlationId;
},
sortable: true,
title: $t('AbpAuditLogging.CorrelationId'),
width: 240,
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: $t('AbpUi.Actions'),
width: 180,
},
],
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',
},
},
sortConfig: {
remote: true,
},
toolbarConfig: {
custom: true,
export: true,
// import: true,
refresh: true,
zoom: true,
},
};
const gridEvents: VxeGridListeners<LogDto> = {
checkboxAll: (params) => {
selectedKeys.value = params.records.map((x) => x.fields.id);
},
checkboxChange: (params) => {
selectedKeys.value = params.records.map((x) => x.fields.id);
},
sortChange: onSort,
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridEvents,
gridOptions,
});
const [LoggingDrawer, logDrawerApi] = useVbenDrawer({
connectedComponent: defineAsyncComponent(() => import('./LoggingDrawer.vue')),
});
function onUpdate(row: LogDto) {
logDrawerApi.setData(row);
logDrawerApi.open();
}
function onSort(params: { field: string; order: SortOrder }) {
const sorting = params.order ? `${params.field} ${params.order}` : undefined;
gridApi.query({ sorting });
}
function onFilter(field: string, value: any) {
gridApi.formApi.setFieldValue(field, value);
gridApi.formApi.validateAndSubmitForm();
}
</script>
<template>
<Grid :table-title="$t('AbpAuditLogging.Logging')">
<template #level="{ row }">
<Tag :color="logLevelOptions[row.level]?.color">
<a
class="link"
href="javaScript:void(0);"
@click="onFilter('level', row.level)"
>{{ logLevelOptions[row.level]?.label }}
</a>
</Tag>
</template>
<template #action="{ row }">
<div class="flex flex-row">
<Button
:icon="h(EditOutlined)"
block
type="link"
v-access:code="[SystemLogPermissions.Default]"
@click="onUpdate(row)"
>
{{ $t('AbpAuditLogging.ShowLogDialog') }}
</Button>
</div>
</template>
</Grid>
<LoggingDrawer :log-level-options="logLevelOptions" />
</template>
<style lang="scss" scoped></style>

4
apps/vben5/packages/@abp/auditing/src/constants/permissions.ts

@ -4,3 +4,7 @@ export const AuditLogPermissions = {
/** 删除 */
Delete: 'AbpAuditing.AuditLog.Delete',
};
/** 系统日志权限 */
export const SystemLogPermissions = {
Default: 'AbpAuditing.SystemLog',
};

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

@ -1,2 +1,3 @@
export * from './audit-logs';
export * from './entity-changes';
export * from './loggings';

65
apps/vben5/packages/@abp/auditing/src/types/loggings.ts

@ -0,0 +1,65 @@
interface LogExceptionDto {
class?: string;
depth?: number;
helpUrl?: string;
hResult?: number;
message?: string;
source?: string;
stackTrace?: string;
}
interface LogFieldDto {
actionId?: string;
actionName?: string;
application?: string;
clientId?: string;
connectionId?: string;
context?: string;
correlationId?: string;
environment?: string;
id: string;
machineName?: string;
processId?: number;
requestId?: string;
requestPath?: string;
threadId?: number;
userId?: string;
}
enum LogLevel {
Critical = 5,
Debug = 1,
Error = 4,
Information = 2,
None = 6,
Trace = 0,
Warning = 3,
}
interface LogDto {
exceptions: LogExceptionDto[];
fields: LogFieldDto;
level: LogLevel;
message: string;
timeStamp: Date;
}
interface LogGetListInput {
application?: string;
context?: string;
correlationId?: string;
endTime?: Date;
environment?: string;
hasException?: boolean;
level?: LogLevel;
machineName?: string;
processId?: number;
requestId?: string;
requestPath?: string;
startTime?: Date;
threadId?: number;
}
export type { LogDto, LogExceptionDto, LogFieldDto, LogGetListInput };
export { LogLevel };

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

@ -1,6 +1,6 @@
{
"name": "@abp/components",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

82
apps/vben5/packages/@abp/components/src/vditor/Viewer.vue

@ -0,0 +1,82 @@
<script lang="ts" setup>
import {
computed,
nextTick,
onBeforeUnmount,
onDeactivated,
ref,
unref,
watch,
} from 'vue';
import { preferences } from '@vben/preferences';
import VditorPreview from 'vditor';
const props = defineProps<{
class?: string;
value: string;
}>();
const viewerRef = ref<HTMLDivElement>();
const vditorPreviewRef = ref<VditorPreview>();
const skinName = computed(() => {
return preferences.theme.mode === 'light' ? 'light' : 'dark';
});
function init() {
const viewerEl = unref(viewerRef) as HTMLDivElement;
const isDark = skinName.value === 'dark';
VditorPreview.preview(viewerEl, props.value, {
hljs: {
style: isDark ? 'dracula' : 'github',
},
mode: isDark ? 'dark' : 'light',
theme: {
current: isDark ? 'dark' : 'light',
},
});
}
watch(
() => skinName.value,
(val) => {
const isDark = val === 'dark';
VditorPreview.setContentTheme(isDark ? 'dark' : 'light', '');
VditorPreview.setCodeTheme(isDark ? 'dracula' : 'github');
init();
},
);
watch(
() => props.value,
(v, oldValue) => {
v !== oldValue && nextTick(init);
},
{
immediate: true,
},
);
function destroy() {
const vditorInstance = unref(vditorPreviewRef);
if (!vditorInstance) return;
try {
vditorInstance?.destroy?.();
} catch {}
vditorPreviewRef.value = undefined;
}
onBeforeUnmount(destroy);
onDeactivated(destroy);
</script>
<template>
<div ref="viewerRef" id="markdownViewer" :class="$props.class"></div>
</template>
<style scoped>
.markdown-viewer {
width: 100%;
}
</style>

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

@ -1 +1,2 @@
export { default as MarkdownEditor } from './Editor.vue';
export { default as MarkdownViewer } from './Viewer.vue';

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

@ -1,6 +1,6 @@
{
"name": "@abp/core",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

2
apps/vben5/packages/@abp/data-protection/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/data-protection",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,6 +1,6 @@
{
"name": "@abp/demo",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,6 +1,6 @@
{
"name": "@abp/features",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,6 +1,6 @@
{
"name": "@abp/gdpr",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

3
apps/vben5/packages/@abp/identity/package.json

@ -1,6 +1,6 @@
{
"name": "@abp/identity",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {
@ -24,6 +24,7 @@
"@abp/core": "workspace:*",
"@abp/data-protection": "workspace:*",
"@abp/permissions": "workspace:*",
"@abp/platform": "workspace:*",
"@abp/request": "workspace:*",
"@abp/ui": "workspace:*",
"@ant-design/icons-vue": "catalog:",

14
apps/vben5/packages/@abp/identity/src/components/roles/RoleTable.vue

@ -16,6 +16,7 @@ import { $t } from '@vben/locales';
import { AuditLogPermissions, EntityChangeDrawer } from '@abp/auditing';
import { Events, useAbpStore, useEventBus, useFeatures } from '@abp/core';
import { PermissionModal } from '@abp/permissions';
import { MenuAllotModal } from '@abp/platform';
import { useVbenVxeGrid } from '@abp/ui';
import {
DeleteOutlined,
@ -53,6 +54,9 @@ const [RolePermissionModal, permissionModalApi] = useVbenModal({
const [RoleClaimModal, claimModalApi] = useVbenModal({
connectedComponent: ClaimModal,
});
const [RoleMenuModal, menuModalApi] = useVbenModal({
connectedComponent: MenuAllotModal,
});
const [RoleRuleDrawer, roleRuleDrawerApi] = useVbenDrawer({
connectedComponent: RuleModal,
});
@ -178,13 +182,18 @@ const handleMenuClick = async (row: IdentityRoleDto, info: MenuInfo) => {
roleRuleDrawerApi.open();
break;
}
case 'menus': {
menuModalApi.setData({
identity: row.name,
});
menuModalApi.open();
break;
}
case 'permissions': {
const roles = abpStore.application?.currentUser.roles ?? [];
permissionModalApi.setData({
displayName: row.name,
providerKey: row.name,
providerName: 'R',
readonly: roles.includes(row.name),
});
permissionModalApi.open();
break;
@ -296,6 +305,7 @@ function onPermissionChange(_name: string, key: string) {
<RolePermissionModal @change="onPermissionChange" />
<RoleChangeDrawer />
<RoleRuleDrawer />
<RoleMenuModal subject="role" />
</template>
<style lang="scss" scoped></style>

12
apps/vben5/packages/@abp/identity/src/components/users/UserTable.vue

@ -16,6 +16,7 @@ import { $t } from '@vben/locales';
import { AuditLogPermissions, EntityChangeDrawer } from '@abp/auditing';
import { formatToDateTime, useAbpStore, useFeatures } from '@abp/core';
import { PermissionModal } from '@abp/permissions';
import { MenuAllotModal } from '@abp/platform';
import { useVbenVxeGrid } from '@abp/ui';
import {
DeleteOutlined,
@ -169,6 +170,9 @@ const [UserClaimModal, claimModalApi] = useVbenModal({
const [UserPermissionModal, permissionModalApi] = useVbenModal({
connectedComponent: PermissionModal,
});
const [UserMenuModal, menuModalApi] = useVbenModal({
connectedComponent: MenuAllotModal,
});
const [UserChangeDrawer, userChangeDrawerApi] = useVbenDrawer({
connectedComponent: EntityChangeDrawer,
});
@ -235,6 +239,13 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
lockModalApi.open();
break;
}
case 'menus': {
menuModalApi.setData({
identity: row.id,
});
menuModalApi.open();
break;
}
case 'password': {
pwdModalApi.setData(row);
pwdModalApi.open();
@ -401,6 +412,7 @@ const handleMenuClick = async (row: IdentityUserDto, info: MenuInfo) => {
<UserPermissionModal />
<UserSessionDrawer />
<UserChangeDrawer />
<UserMenuModal subject="user" />
</template>
<style lang="scss" scoped></style>

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

@ -1,6 +1,6 @@
{
"name": "@abp/localization",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,6 +1,6 @@
{
"name": "@abp/notifications",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

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

@ -1,6 +1,6 @@
{
"name": "@abp/openiddict",
"version": "9.0.4",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {

16
apps/vben5/packages/@abp/openiddict/src/components/applications/ApplicationModal.vue

@ -64,11 +64,23 @@ type TabKeys =
| 'props'
| 'scope';
const defaultModel = {
const defaultModel: OpenIddictApplicationDto = {
applicationType: 'web',
clientId: '',
clientType: 'public',
consentType: 'explicit',
} as OpenIddictApplicationDto;
creationTime: new Date(),
extraProperties: {},
id: '',
requirements: {
features: {
requirePkce: false,
},
},
settings: {
tokenLifetime: {},
},
};
const form = ref<FormInstance>();
const formModel = ref<OpenIddictApplicationDto>({ ...defaultModel });

44
apps/vben5/packages/@abp/oss/package.json

@ -0,0 +1,44 @@
{
"name": "@abp/oss",
"version": "9.1.3",
"homepage": "https://github.com/colinin/abp-next-admin",
"bugs": "https://github.com/colinin/abp-next-admin/issues",
"repository": {
"type": "git",
"url": "git+https://github.com/colinin/abp-next-admin.git",
"directory": "packages/@abp/oss"
},
"license": "MIT",
"type": "module",
"sideEffects": [
"**/*.css"
],
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
},
"./global": {
"types": "./global.d.ts"
}
},
"dependencies": {
"@abp/components": "workspace:*",
"@abp/core": "workspace:*",
"@abp/features": "workspace:*",
"@abp/request": "workspace:*",
"@abp/ui": "workspace:*",
"@ant-design/icons-vue": "catalog:",
"@vben/access": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/hooks": "workspace:*",
"@vben/icons": "workspace:*",
"@vben/layouts": "workspace:*",
"@vben/locales": "workspace:*",
"@vben/stores": "workspace:*",
"ant-design-vue": "catalog:",
"vue": "catalog:*",
"vue-simple-uploader": "catalog:",
"vxe-table": "catalog:"
}
}

2
apps/vben5/packages/@abp/oss/src/api/index.ts

@ -0,0 +1,2 @@
export { useContainesApi } from './useContainesApi';
export { useObjectsApi } from './useObjectsApi';

61
apps/vben5/packages/@abp/oss/src/api/useContainesApi.ts

@ -0,0 +1,61 @@
import type {
GetOssContainersInput,
GetOssObjectsInput,
OssContainerDto,
OssContainersResultDto,
} from '../types/containes';
import type { OssObjectsResultDto } from '../types/objects';
import { useRequest } from '@abp/request';
export function useContainesApi() {
const { cancel, request } = useRequest();
function deleteApi(name: string): Promise<void> {
return request(`/api/oss-management/containes/${name}`, {
method: 'DELETE',
});
}
function getApi(name: string): Promise<OssContainerDto> {
return request<OssContainerDto>(`/api/oss-management/containes/${name}`, {
method: 'GET',
});
}
function getListApi(
input?: GetOssContainersInput,
): Promise<OssContainersResultDto> {
return request<OssContainersResultDto>(`/api/oss-management/containes`, {
method: 'GET',
params: input,
});
}
function getObjectsApi(
input: GetOssObjectsInput,
): Promise<OssObjectsResultDto> {
return request<OssObjectsResultDto>(
`/api/oss-management/containes/objects`,
{
method: 'GET',
params: input,
},
);
}
function createApi(name: string): Promise<OssContainerDto> {
return request<OssContainerDto>(`/api/oss-management/containes/${name}`, {
method: 'POST',
});
}
return {
cancel,
createApi,
deleteApi,
getApi,
getListApi,
getObjectsApi,
};
}

50
apps/vben5/packages/@abp/oss/src/api/useObjectsApi.ts

@ -0,0 +1,50 @@
import type {
CreateOssObjectInput,
GetOssObjectInput,
OssObjectDto,
} from '../types/objects';
import { useRequest } from '@abp/request';
export function useObjectsApi() {
const { cancel, request } = useRequest();
function createApi(input: CreateOssObjectInput): Promise<OssObjectDto> {
const formData = new window.FormData();
formData.append('bucket', input.bucket);
formData.append('fileName', input.fileName);
formData.append('overwrite', String(input.overwrite));
input.expirationTime &&
formData.append('expirationTime', input.expirationTime.toString());
input.path && formData.append('path', input.path);
input.file && formData.append('file', input.file);
return request<OssObjectDto>(`/api/oss-management/objects`, {
data: formData,
headers: {
'Content-Type': 'multipart/form-data;charset=utf-8',
},
method: 'POST',
});
}
function generateUrlApi(input: GetOssObjectInput): Promise<string> {
return request<string>('/api/oss-management/objects/generate-url', {
method: 'GET',
params: input,
});
}
function deleteApi(input: GetOssObjectInput): Promise<void> {
return request('/api/oss-management/objects', {
method: 'DELETE',
params: input,
});
}
return {
cancel,
createApi,
deleteApi,
generateUrlApi,
};
}

55
apps/vben5/packages/@abp/oss/src/components/containers/ContainerModal.vue

@ -0,0 +1,55 @@
<script setup lang="ts">
import type { OssContainerDto } from '../../types';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { message } from 'ant-design-vue';
import { useContainesApi } from '../../api';
const emits = defineEmits<{
(event: 'change', data: OssContainerDto): void;
}>();
const { cancel, createApi } = useContainesApi();
const [Form, formApi] = useVbenForm({
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
fieldName: 'name',
label: $t('AbpOssManagement.DisplayName:Name'),
rules: 'required',
},
],
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onCancel: cancel,
onConfirm: async () => {
await formApi.validateAndSubmitForm();
},
});
async function onSubmit(values: Record<string, any>) {
try {
modalApi.setState({ submitting: true });
const dto = await createApi(values.name);
message.success($t('AbpUi.SavedSuccessfully'));
emits('change', dto);
modalApi.close();
} finally {
modalApi.setState({ submitting: false });
}
}
</script>
<template>
<Modal :title="$t('AbpOssManagement.Containers:Create')">
<Form />
</Modal>
</template>
<style scoped></style>

190
apps/vben5/packages/@abp/oss/src/components/containers/ContainerTable.vue

@ -0,0 +1,190 @@
<script setup lang="ts">
import type { VxeGridListeners, VxeGridProps } from '@abp/ui';
import type { VbenFormProps } from '@vben/common-ui';
import type { OssContainerDto } from '../../types/containes';
import { defineAsyncComponent, h, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime } from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import { DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
import { Button, message, Modal } from 'ant-design-vue';
import { useContainesApi } from '../../api/useContainesApi';
defineOptions({
name: 'ContainerTable',
});
const { cancel, deleteApi, getListApi } = useContainesApi();
const selectedKeys = ref<string[]>([]);
const formOptions: VbenFormProps = {
collapsed: true,
collapsedRows: 2,
commonConfig: {
componentProps: {
class: 'w-full',
},
},
schema: [
{
component: 'Input',
componentProps: {
allowClear: true,
},
fieldName: 'filter',
formItemClass: 'col-span-3 items-baseline',
label: $t('AbpUi.Search'),
},
],
//
showCollapseButton: true,
//
submitOnEnter: true,
};
const gridOptions: VxeGridProps<OssContainerDto> = {
columns: [
{
align: 'left',
field: 'name',
minWidth: 150,
title: $t('AbpOssManagement.DisplayName:Name'),
},
{
align: 'left',
field: 'creationDate',
formatter({ cellValue }) {
return cellValue ? formatToDateTime(cellValue) : '';
},
minWidth: 120,
title: $t('AbpOssManagement.DisplayName:CreationDate'),
},
{
align: 'left',
field: 'lastModifiedDate',
formatter({ cellValue }) {
return cellValue ? formatToDateTime(cellValue) : '';
},
minWidth: 120,
title: $t('AbpOssManagement.DisplayName:LastModifiedDate'),
},
{
align: 'left',
field: 'size',
minWidth: 150,
title: $t('AbpOssManagement.DisplayName:Size'),
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: $t('AbpUi.Actions'),
width: 150,
},
],
exportConfig: {},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }, formValues) => {
const res = await getListApi({
maxResultCount: page.pageSize,
skipCount: (page.currentPage - 1) * page.pageSize,
...formValues,
});
return {
totalCount: res.maxKeys,
items: res.containers,
};
},
},
response: {
total: 'totalCount',
list: 'items',
},
},
toolbarConfig: {
custom: true,
export: true,
// import: true,
refresh: true,
zoom: true,
},
};
const gridEvents: VxeGridListeners<OssContainerDto> = {
checkboxAll: (params) => {
selectedKeys.value = params.records.map((record) => record.name);
},
checkboxChange: (params) => {
selectedKeys.value = params.records.map((record) => record.name);
},
};
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridEvents,
gridOptions,
});
const [ContainerModal, modalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(
() => import('./ContainerModal.vue'),
),
});
function onCreate() {
modalApi.setData({});
modalApi.open();
}
function onDelete(row: OssContainerDto) {
Modal.confirm({
centered: true,
content: $t('AbpUi.ItemWillBeDeletedMessageWithFormat', [row.name]),
onCancel: () => {
cancel();
},
onOk: async () => {
await deleteApi(row.name);
message.success($t('AbpUi.DeletedSuccessfully'));
await gridApi.query();
},
title: $t('AbpUi.AreYouSure'),
});
}
</script>
<template>
<Grid :table-title="$t('AbpOssManagement.Containers')">
<template #toolbar-tools>
<Button :icon="h(PlusOutlined)" type="primary" @click="onCreate">
{{ $t('AbpOssManagement.Containers:Create') }}
</Button>
</template>
<template #action="{ row }">
<div class="flex flex-row">
<Button
:icon="h(DeleteOutlined)"
danger
block
type="link"
@click="onDelete(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
<ContainerModal @change="() => gridApi.query()" />
</template>
<style lang="scss" scoped></style>

2
apps/vben5/packages/@abp/oss/src/components/index.ts

@ -0,0 +1,2 @@
export { default as ContainerTable } from './containers/ContainerTable.vue';
export { default as ObjectPage } from './objects/ObjectPage.vue';

282
apps/vben5/packages/@abp/oss/src/components/objects/FileList.vue

@ -0,0 +1,282 @@
<script setup lang="ts">
import type { VxeGridListeners, VxeGridProps } from '@abp/ui';
import type { OssContainerDto } from '../../types/containes';
import type { OssObjectDto } from '../../types/objects';
import { defineAsyncComponent, h, nextTick, ref, watch } from 'vue';
import { useAccess } from '@vben/access';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { formatToDateTime, isNullOrWhiteSpace } from '@abp/core';
import { useVbenVxeGrid } from '@abp/ui';
import {
DeleteOutlined,
DownloadOutlined,
UploadOutlined,
} from '@ant-design/icons-vue';
import { Button, message, Modal } from 'ant-design-vue';
import { useObjectsApi } from '../../api';
import { useContainesApi } from '../../api/useContainesApi';
import { OssObjectPermissions } from '../../constants/permissions';
defineOptions({
name: 'FileList',
});
const props = defineProps<{
bucket: string;
path: string;
}>();
const kbUnit = 1 * 1024;
const mbUnit = kbUnit * 1024;
const gbUnit = mbUnit * 1024;
const { hasAccessByCodes } = useAccess();
const { cancel, getObjectsApi } = useContainesApi();
const { deleteApi, generateUrlApi } = useObjectsApi();
const selectedKeys = ref<string[]>([]);
const gridOptions: VxeGridProps<OssContainerDto> = {
columns: [
{
align: 'left',
field: 'name',
minWidth: 150,
title: $t('AbpOssManagement.DisplayName:Name'),
},
{
align: 'left',
field: 'isFolder',
formatter: ({ cellValue }) => {
return cellValue
? $t('AbpOssManagement.DisplayName:Folder')
: $t('AbpOssManagement.DisplayName:Standard');
},
minWidth: 150,
title: $t('AbpOssManagement.DisplayName:FileType'),
},
{
align: 'left',
field: 'size',
formatter: ({ cellValue }) => {
const size = Number(cellValue);
if (size > gbUnit) {
let gb = Math.round(size / gbUnit);
if (gb < 1) {
gb = 1;
}
return `${gb} GB`;
}
if (size > mbUnit) {
let mb = Math.round(size / mbUnit);
if (mb < 1) {
mb = 1;
}
return `${mb} MB`;
}
let kb = Math.round(size / kbUnit);
if (kb < 1) {
kb = 1;
}
return `${kb} KB`;
},
minWidth: 150,
title: $t('AbpOssManagement.DisplayName:Size'),
},
{
align: 'left',
field: 'creationDate',
formatter({ cellValue }) {
return cellValue ? formatToDateTime(cellValue) : '';
},
minWidth: 120,
title: $t('AbpOssManagement.DisplayName:CreationDate'),
},
{
align: 'left',
field: 'lastModifiedDate',
formatter({ cellValue }) {
return cellValue ? formatToDateTime(cellValue) : '';
},
minWidth: 120,
title: $t('AbpOssManagement.DisplayName:LastModifiedDate'),
},
{
field: 'action',
fixed: 'right',
slots: { default: 'action' },
title: $t('AbpUi.Actions'),
width: 200,
},
],
exportConfig: {},
keepSource: true,
proxyConfig: {
ajax: {
query: async ({ page }) => {
const res = await getObjectsApi({
bucket: props.bucket,
maxResultCount: page.pageSize,
prefix: props.path,
skipCount: (page.currentPage - 1) * page.pageSize,
});
return {
totalCount: res.maxKeys,
items: res.objects,
};
},
},
autoLoad: false,
response: {
total: 'totalCount',
list: 'items',
},
},
toolbarConfig: {
custom: true,
export: false,
refresh: false,
zoom: true,
},
};
const gridEvents: VxeGridListeners<OssContainerDto> = {
checkboxAll: (params) => {
selectedKeys.value = params.records.map((record) => record.name);
},
checkboxChange: (params) => {
selectedKeys.value = params.records.map((record) => record.name);
},
};
const [Grid, gridApi] = useVbenVxeGrid({
gridEvents,
gridOptions,
});
const [FileUploadModal, modalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(
() => import('./FileUploadModal.vue'),
),
});
function onUpload() {
modalApi.setData({
bucket: props.bucket,
path: props.path,
});
modalApi.open();
}
function onDelete(row: OssObjectDto) {
Modal.confirm({
centered: true,
content: $t('AbpUi.ItemWillBeDeletedMessageWithFormat', [row.name]),
onCancel: () => {
cancel();
},
onOk: async () => {
await deleteApi({
bucket: props.bucket,
mD5: false,
object: row.name,
path: row.path,
});
message.success($t('AbpUi.DeletedSuccessfully'));
await gridApi.query();
},
title: $t('AbpUi.AreYouSure'),
});
}
async function onDownload(row: OssObjectDto) {
const downloadUrl = await generateUrlApi({
bucket: props.bucket,
mD5: false,
object: row.name,
path: row.path,
});
const link = document.createElement('a');
link.style.display = 'none';
link.href = downloadUrl;
link.setAttribute('download', row.name);
document.body.append(link);
link.click();
}
watch(
() => props.bucket,
(bucket) => {
nextTick(() => {
gridApi.setGridOptions({
toolbarConfig: {
refresh: !isNullOrWhiteSpace(bucket),
},
});
if (!isNullOrWhiteSpace(bucket)) {
gridApi.query();
}
});
},
);
watch(
() => props.path,
(newVal, oldVal) => {
if (newVal !== oldVal) {
nextTick(() => {
gridApi.query();
});
}
},
);
</script>
<template>
<Grid :table-title="$t('AbpOssManagement.FileList')">
<template #toolbar-tools>
<Button
v-if="props.path"
:icon="h(UploadOutlined)"
type="primary"
@click="onUpload"
>
{{ $t('AbpOssManagement.Objects:UploadFile') }}
</Button>
</template>
<template #action="{ row }">
<div class="flex flex-row">
<Button
v-if="
!row.isFolder && hasAccessByCodes([OssObjectPermissions.Download])
"
:icon="h(DownloadOutlined)"
block
type="link"
@click="onDownload(row)"
>
{{ $t('AbpOssManagement.Objects:Download') }}
</Button>
<Button
v-if="hasAccessByCodes([OssObjectPermissions.Delete])"
:icon="h(DeleteOutlined)"
danger
block
type="link"
@click="onDelete(row)"
>
{{ $t('AbpUi.Delete') }}
</Button>
</div>
</template>
</Grid>
<FileUploadModal @file-uploaded="() => gridApi.query()" />
</template>
<style lang="scss" scoped></style>

286
apps/vben5/packages/@abp/oss/src/components/objects/FileUploadModal.vue

@ -0,0 +1,286 @@
<script setup lang="ts">
import type { VxeComponentStyleType } from 'vxe-table';
import { h, ref, useTemplateRef, watch } from 'vue';
import uploader from 'vue-simple-uploader';
import 'vue-simple-uploader/dist/style.css';
import { useVbenModal } from '@vben/common-ui';
import { useRefresh } from '@vben/hooks';
import { $t } from '@vben/locales';
import { useAccessStore } from '@vben/stores';
import { isNullOrWhiteSpace } from '@abp/core';
import {
CaretRightOutlined,
DeleteOutlined,
PauseOutlined,
} from '@ant-design/icons-vue';
import { Button, Tag, Tooltip } from 'ant-design-vue';
import { VxeColumn, VxeTable } from 'vxe-table';
const emits = defineEmits<{
(event: 'fileUploaded', file: any): void;
}>();
const Uploader = uploader.Uploader;
const UploaderDrop = uploader.UploaderDrop;
const UploaderList = uploader.UploaderList;
const UploaderUnsupport = uploader.UploaderUnsupport;
interface ModalState {
bucket: string;
path: string;
}
const selectBtn = useTemplateRef<any>('selectBtn');
const uploaderWrap = useTemplateRef<any>('uploaderWrap');
const { refresh } = useRefresh();
const accessStore = useAccessStore();
const [Modal, modalApi] = useVbenModal({
class: 'w-1/2',
closeOnClickModal: false,
closeOnPressEscape: false,
draggable: true,
footer: false,
onCancel: () => {
uploaderWrap.value?.uploader.cancel();
},
onOpenChange: (isOpen) => {
if (isOpen) {
onInit();
}
},
});
const options = ref({
chunkRetryInterval: null,
headers: {},
initialPaused: true,
maxChunkRetries: 3,
permanentErrors: [400, 401, 403, 404, 415, 500, 501],
processParams: (params: any) => params,
processResponse: (response: any, cb: any) => {
if (!isNullOrWhiteSpace(response)) {
const error = JSON.parse(response);
if (error.code !== '0') {
cb(true, error.message);
return;
}
}
cb(null, response);
},
successStatuses: [200, 201, 202, 204, 205],
target: '/api/oss-management/objects/upload',
testChunks: false,
});
function onInit() {
const state = modalApi.getData<ModalState>();
options.value = {
...options.value,
headers: {
Authorization: accessStore.accessToken,
},
processParams: (params: any) => {
params.bucket = state.bucket;
params.path = state.path;
return params;
},
};
}
function onSelectFiles() {
selectBtn.value?.click();
}
function onResume(file: any) {
if (file.error) {
file.errorMsg = '';
file.retry();
} else {
file.resume();
}
}
function onPause(file: any) {
file.pause();
}
function onDelete(file: any) {
file.cancel();
}
function onFileSubmitted(_: any, files: any[]) {
files.forEach((f) => {
f.paused = true;
f.completed = false;
f.progress = 0;
f.progressText = '0 %';
});
}
function onUploadProgress(_: any, file: any) {
if (file._prevUploadedSize) {
const progress = Math.floor((file._prevUploadedSize / file.size) * 100);
file.progress = progress;
file.progressText = `${progress} %`;
file.completed = progress === 100;
}
}
function onUploadError(_rootFile: any, file: any, message: any, chunk: any) {
if (chunk?.xhr?.status === 401) {
// 401 , axiostoken
refresh();
} else {
file.errorMsg = message;
}
}
function onUploadSuccess(_rootFile: any, file: any) {
emits('fileUploaded', file);
}
function formatSize(size: number) {
if (size < 1024) {
return `${size.toFixed(0)} bytes`;
} else if (size < 1024 * 1024) {
return `${(size / 1024).toFixed(0)} KB`;
} else if (size < 1024 * 1024 * 1024) {
return `${(size / 1024 / 1024).toFixed(1)} MB`;
} else {
return `${(size / 1024 / 1024 / 1024).toFixed(1)} GB`;
}
}
function rowStyle(params: any): VxeComponentStyleType {
// console.log(' --->', params.row.status);
if (params.row.error) {
return {
background: '#ffe0e0',
};
}
const startColor = 'rgba(255, 200, 200, 0.7)';
const endColor = 'rgba(200, 255, 200, 0.7)';
return {
background: `linear-gradient(
to right,
${startColor} 0%,
${endColor} ${params.row.progress}%,
transparent ${params.row.progress}%,
transparent 100%
)`,
backgroundSize: '100% 100%',
transition: 'background 0.5s ease',
};
}
watch(
() => [selectBtn.value, uploaderWrap.value],
([button, wrap]) => {
if (button && wrap) {
wrap.uploader.assignBrowse(button);
}
},
);
</script>
<template>
<Modal :title="$t('AbpOssManagement.Objects:UploadFile')">
<Uploader
:options="options"
ref="uploaderWrap"
@file-error="onUploadError"
@file-progress="onUploadProgress"
@file-success="onUploadSuccess"
@files-submitted="onFileSubmitted"
>
<UploaderUnsupport />
<UploaderDrop>
<div class="flex flex-row gap-2">
<input ref="selectBtn" style="display: none" />
<Button type="primary" @click="onSelectFiles">
{{ $t('AbpOssManagement.Upload:SelectFile') }}
</Button>
</div>
</UploaderDrop>
<UploaderList>
<template #default="{ fileList }">
<VxeTable :data="fileList" :row-style="rowStyle">
<VxeColumn type="seq" width="70" />
<VxeColumn
field="name"
:title="$t('AbpOssManagement.DisplayName:Name')"
/>
<VxeColumn
field="size"
:title="$t('AbpOssManagement.DisplayName:Size')"
width="100"
>
<template #default="{ row }">
<span>{{ formatSize(row.size) }}</span>
</template>
</VxeColumn>
<VxeColumn
field="status"
:title="$t('AbpOssManagement.DisplayName:Status')"
width="180"
>
<template #default="{ row }">
<Tag v-if="row.completed" color="green">
{{ $t('AbpOssManagement.Upload:Completed') }}
</Tag>
<Tooltip v-else-if="row.error" :title="row.errorMsg">
<Tag color="red">
{{ $t('AbpOssManagement.Upload:Error') }}
</Tag>
</Tooltip>
<Tag v-else-if="row.paused" color="orange">
{{ $t('AbpOssManagement.Upload:Pause') }}
</Tag>
<span v-else>{{
`${row.progressText} ${formatSize(row.averageSpeed)}/s`
}}</span>
</template>
</VxeColumn>
<VxeColumn
fixed="right"
field="action"
:title="$t('AbpUi.Actions')"
width="100"
>
<template #default="{ row }">
<div class="flex flex-row">
<div v-if="!row.completed">
<Button
v-if="row.paused || row.error"
:icon="h(CaretRightOutlined)"
@click="onResume(row)"
type="link"
/>
<Button
v-else
:icon="h(PauseOutlined)"
@click="onPause(row)"
type="link"
/>
</div>
<Button
:icon="h(DeleteOutlined)"
@click="onDelete(row)"
type="link"
danger
/>
</div>
</template>
</VxeColumn>
</VxeTable>
</template>
</UploaderList>
</Uploader>
</Modal>
</template>
<style scoped></style>

66
apps/vben5/packages/@abp/oss/src/components/objects/FolderModal.vue

@ -0,0 +1,66 @@
<script setup lang="ts">
import type { OssObjectDto } from '../../types/objects';
import { useVbenForm, useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { message } from 'ant-design-vue';
import { useObjectsApi } from '../../api';
interface ModalState {
bucket: string;
path?: string;
}
const emits = defineEmits<{
(event: 'change', data: OssObjectDto): void;
}>();
const { createApi } = useObjectsApi();
const [Form, formApi] = useVbenForm({
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
fieldName: 'name',
label: $t('AbpOssManagement.DisplayName:Name'),
rules: 'required',
},
],
showDefaultActions: false,
});
const [Modal, modalApi] = useVbenModal({
onConfirm: async () => {
await formApi.validateAndSubmitForm();
},
});
async function onSubmit(values: Record<string, any>) {
try {
const state = modalApi.getData<ModalState>();
modalApi.setState({ submitting: true });
const dto = await createApi({
bucket: state.bucket,
fileName: values.name,
overwrite: false,
path: state.path,
});
message.success($t('AbpUi.SavedSuccessfully'));
emits('change', dto);
modalApi.close();
} finally {
modalApi.setState({ submitting: false });
}
}
</script>
<template>
<Modal :title="$t('AbpOssManagement.Objects:CreateFolder')">
<Form />
</Modal>
</template>
<style scoped></style>

192
apps/vben5/packages/@abp/oss/src/components/objects/FolderTree.vue

@ -0,0 +1,192 @@
<script setup lang="ts">
import type { EventDataNode, Key } from 'ant-design-vue/es/vc-tree/interface';
import type { TreeProps } from 'ant-design-vue/es/vc-tree/props';
import type { OssContainerDto } from '../../types';
import type { OssObjectDto } from '../../types/objects';
import { defineAsyncComponent, onMounted, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { $t } from '@vben/locales';
import { Button, Card, DirectoryTree, Empty, Select } from 'ant-design-vue';
import { useContainesApi } from '../../api';
const emits = defineEmits<{
(event: 'bucketChange', data: string): void;
(event: 'folderChange', data: string): void;
}>();
interface Folder {
children?: Folder[];
isLeaf?: boolean;
key: string;
name: string;
path?: string;
title: string;
}
const { getListApi: getContainersApi, getObjectsApi } = useContainesApi();
const [FolderModal, modalApi] = useVbenModal({
connectedComponent: defineAsyncComponent(() => import('./FolderModal.vue')),
});
const rootFolder: Folder = {
isLeaf: false,
key: './',
name: './',
path: '',
title: $t('AbpOssManagement.Objects:Root'),
children: [],
};
const bucket = ref<string>('');
const loadedFolders = ref<string[]>([]);
const expandedFolders = ref<string[]>([]);
const selectedFolders = ref<string[]>([]);
const containers = ref<OssContainerDto[]>([]);
const folders = ref<Folder[]>([
{
...rootFolder,
},
]);
const onLoadChildFolders: TreeProps['loadData'] = async (treeNode) => {
let path = '';
if (treeNode.dataRef?.path) {
path = path + treeNode.dataRef?.path;
}
if (treeNode.dataRef?.name) {
path = path + treeNode.dataRef?.name;
}
try {
treeNode.dataRef!.children = await getFolders(bucket.value!, path);
} catch {
treeNode.dataRef!.children = [];
}
folders.value = [...folders.value];
loadedFolders.value = [...loadedFolders.value, treeNode.key.toString()];
};
async function onInit() {
const getContainersRes = await getContainersApi({
maxResultCount: 1000,
});
containers.value = getContainersRes.containers;
}
async function getFolders(bucket: string, path?: string) {
const { objects } = await getObjectsApi({
bucket,
delimiter: '/',
maxResultCount: 1000,
prefix: path ?? '',
});
return objects
.filter((f) => f.isFolder)
.map((folder) => {
return {
isLeaf: false,
key: `${folder.path ?? ''}${folder.name}`,
name: folder.name,
path: folder.path,
title: folder.name,
children: [],
};
});
}
function onFolderExpand(
_: Key[],
info: {
expanded: boolean;
node: EventDataNode;
},
) {
if (!info.expanded) {
const keys = loadedFolders.value;
const findIndex = keys.lastIndexOf(info.node.key.toString());
findIndex !== -1 && keys.splice(findIndex);
loadedFolders.value = keys;
}
}
function onFolderChange(selectedKeys: Key[]) {
if (selectedKeys.length === 1) {
emits('folderChange', selectedKeys[0]!.toString());
}
}
async function onBucketChange(bucket: string) {
emits('bucketChange', bucket);
expandedFolders.value = [];
loadedFolders.value = [];
folders.value = [
{
...rootFolder,
},
];
}
function onCreate() {
modalApi.setData({
bucket: bucket.value,
path: selectedFolders.value[0],
});
modalApi.open();
}
function onFolderCreated(ossObject: OssObjectDto) {
const keys = expandedFolders.value;
const findIndex = keys.lastIndexOf(ossObject.path);
if (findIndex !== -1) {
keys.splice(findIndex);
expandedFolders.value = keys;
loadedFolders.value = [];
}
}
onMounted(onInit);
</script>
<template>
<Card :title="$t('AbpOssManagement.Containers')">
<div class="flex flex-col gap-2">
<Select
:placeholder="$t('AbpOssManagement.Containers:Select')"
:options="containers"
:field-names="{ label: 'name', value: 'name' }"
v-model:value="bucket"
@change="(e) => onBucketChange(e!.toString())"
/>
<Button v-if="bucket" block type="primary" ghost @click="onCreate">
{{ $t('AbpOssManagement.Objects:CreateFolder') }}
</Button>
<DirectoryTree
v-if="bucket"
block-node
v-model:expanded-keys="expandedFolders"
v-model:selected-keys="selectedFolders"
:loaded-keys="loadedFolders"
:tree-data="folders"
:load-data="onLoadChildFolders"
@select="onFolderChange"
@expand="onFolderExpand"
/>
<Empty v-else />
</div>
</Card>
<FolderModal @change="onFolderCreated" />
</template>
<style scoped lang="scss">
:deep(.ant-tree) {
.ant-tree-title {
word-break: break-word;
white-space: normal;
}
}
</style>

34
apps/vben5/packages/@abp/oss/src/components/objects/ObjectPage.vue

@ -0,0 +1,34 @@
<script setup lang="ts">
import { defineAsyncComponent, ref } from 'vue';
const FolderTree = defineAsyncComponent(() => import('./FolderTree.vue'));
const FileList = defineAsyncComponent(() => import('./FileList.vue'));
const bucket = ref('');
const path = ref('');
function onBucketChange(val: string) {
bucket.value = val;
path.value = '';
}
function onFolderChange(val: string) {
path.value = val;
}
</script>
<template>
<div class="flex flex-row gap-2">
<div style="width: 30%">
<FolderTree
@bucket-change="onBucketChange"
@folder-change="onFolderChange"
/>
</div>
<div style="width: 70%">
<FileList :bucket="bucket" :path="path" />
</div>
</div>
</template>
<style scoped></style>

18
apps/vben5/packages/@abp/oss/src/constants/permissions.ts

@ -0,0 +1,18 @@
/** 容器权限 */
export const ContainerPermissions = {
/** 新增 */
Create: 'AbpOssManagement.Container.Create',
Default: 'AbpOssManagement.Container',
/** 删除 */
Delete: 'AbpOssManagement.Container.Delete',
};
/** 容器权限 */
export const OssObjectPermissions = {
/** 新增 */
Create: 'AbpOssManagement.OssObject.Create',
Default: 'AbpOssManagement.OssObject',
/** 删除 */
Delete: 'AbpOssManagement.OssObject.Delete',
/** 下载 */
Download: 'AbpOssManagement.OssObject.Download',
};

1
apps/vben5/packages/@abp/oss/src/global.d.ts

@ -0,0 +1 @@
declare module 'vue-simple-uploader';

3
apps/vben5/packages/@abp/oss/src/index.ts

@ -0,0 +1,3 @@
export * from './api';
export * from './components';
export * from './types';

38
apps/vben5/packages/@abp/oss/src/types/containes.ts

@ -0,0 +1,38 @@
import type { PagedAndSortedResultRequestDto } from '@abp/core';
interface OssContainerDto {
creationDate: Date;
lastModifiedDate?: Date;
metadata: Record<string, string>;
name: string;
size: number;
}
interface OssContainersResultDto {
containers: OssContainerDto[];
marker?: string;
maxKeys?: number;
nextMarker?: string;
prefix?: string;
}
interface GetOssContainersInput extends PagedAndSortedResultRequestDto {
marker?: string;
prefix?: string;
}
interface GetOssObjectsInput extends PagedAndSortedResultRequestDto {
bucket?: string;
delimiter?: string;
encodingType?: string;
marker?: string;
mD5?: string;
prefix?: string;
}
export type {
GetOssContainersInput,
GetOssObjectsInput,
OssContainerDto,
OssContainersResultDto,
};

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save