Browse Source

完善系统配置页面

pull/1/head
cKey 6 years ago
parent
commit
97de8bc271
  1. 58
      aspnet-core/modules/common/LINGYUN.Abp.Identity.OverrideOptions/LINGYUN/Abp/Identity/AbpIdentityOverrideOptionsFactory.cs
  2. 5
      aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN.Abp.Location.Baidu.csproj
  3. 19
      aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs
  4. 2
      aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs
  5. 8
      aspnet-core/services/cleanup-logs.bat
  6. 10
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj
  7. 268
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs
  8. 5
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/en.json
  9. 7
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json
  10. 11
      aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs
  11. 13
      vueJs/src/api/abpconfiguration.ts
  12. 17
      vueJs/src/api/settings.ts
  13. 8
      vueJs/src/lang/zh.ts
  14. 1
      vueJs/src/permission.ts
  15. 10
      vueJs/src/store/modules/abp.ts
  16. 33
      vueJs/src/store/modules/user.ts
  17. 51
      vueJs/src/utils/localStorage.ts
  18. 9
      vueJs/src/utils/request.ts
  19. 2
      vueJs/src/views/admin/apigateway/components/GlobalCreateOrEditForm.vue
  20. 2
      vueJs/src/views/admin/identityServer/api-resources/components/ApiResourceCreateOrEditForm.vue
  21. 2
      vueJs/src/views/admin/identityServer/client/components/ClientPropertyEditForm.vue
  22. 277
      vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue
  23. 42
      vueJs/src/views/admin/settings/index.vue

58
aspnet-core/modules/common/LINGYUN.Abp.Identity.OverrideOptions/LINGYUN/Abp/Identity/AbpIdentityOverrideOptionsFactory.cs

@ -1,23 +1,77 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Identity.Settings;
using Volo.Abp.Options;
using Volo.Abp.Settings;
using Volo.Abp.Threading;
namespace LINGYUN.Abp.Identity
{
public class AbpIdentityOverrideOptionsFactory : AbpOptionsFactory<IdentityOptions>
{
protected ISettingStore SettingStore { get; }
public AbpIdentityOverrideOptionsFactory(
ISettingStore settingStore,
IEnumerable<IConfigureOptions<IdentityOptions>> setups,
IEnumerable<IPostConfigureOptions<IdentityOptions>> postConfigures)
: base(setups, postConfigures)
{
SettingStore = settingStore;
}
public override IdentityOptions Create(string name)
{
return base.Create(name);
var options = base.Create(name);
// 重写为只获取公共配置
OverrideOptions(options);
return options;
}
protected virtual void OverrideOptions(IdentityOptions options)
{
AsyncHelper.RunSync(() => OverrideOptionsAsync(options));
}
protected virtual async Task OverrideOptionsAsync(IdentityOptions options)
{
options.Password.RequiredLength = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredLength, options.Password.RequiredLength);
options.Password.RequiredUniqueChars = await GetOrDefaultAsync(IdentitySettingNames.Password.RequiredUniqueChars, options.Password.RequiredUniqueChars);
options.Password.RequireNonAlphanumeric = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireNonAlphanumeric, options.Password.RequireNonAlphanumeric);
options.Password.RequireLowercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireLowercase, options.Password.RequireLowercase);
options.Password.RequireUppercase = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireUppercase, options.Password.RequireUppercase);
options.Password.RequireDigit = await GetOrDefaultAsync(IdentitySettingNames.Password.RequireDigit, options.Password.RequireDigit);
options.Lockout.AllowedForNewUsers = await GetOrDefaultAsync(IdentitySettingNames.Lockout.AllowedForNewUsers, options.Lockout.AllowedForNewUsers);
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromSeconds(await GetOrDefaultAsync(IdentitySettingNames.Lockout.LockoutDuration, options.Lockout.DefaultLockoutTimeSpan.TotalSeconds.To<int>()));
options.Lockout.MaxFailedAccessAttempts = await GetOrDefaultAsync(IdentitySettingNames.Lockout.MaxFailedAccessAttempts, options.Lockout.MaxFailedAccessAttempts);
options.SignIn.RequireConfirmedEmail = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail, options.SignIn.RequireConfirmedEmail);
options.SignIn.RequireConfirmedPhoneNumber = await GetOrDefaultAsync(IdentitySettingNames.SignIn.RequireConfirmedPhoneNumber, options.SignIn.RequireConfirmedPhoneNumber);
}
protected virtual async Task<T> GetOrDefaultAsync<T>(string name, T defaultValue = default(T)) where T : struct
{
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null);
if (setting.IsNullOrWhiteSpace())
{
return defaultValue;
}
return setting.To<T>();
}
protected virtual async Task<string> GetOrDefaultAsync(string name, string defaultValue = "")
{
var setting = await SettingStore.GetOrNullAsync(name, GlobalSettingValueProvider.ProviderName, null);
if (setting.IsNullOrWhiteSpace())
{
return defaultValue;
}
return setting;
}
}
}

5
aspnet-core/modules/common/LINGYUN.Abp.Location.Baidu/LINGYUN.Abp.Location.Baidu.csproj

@ -5,6 +5,11 @@
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.2" />
<PackageReference Include="Volo.Abp.Json" Version="2.8.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Location\LINGYUN.Abp.Location.csproj" />
</ItemGroup>

19
aspnet-core/modules/settings/LINGYUN.Abp.SettingManagement.Application/LINGYUN/Abp/SettingManagement/SettingAppService.cs

@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Caching;
using Volo.Abp.SettingManagement;
using Volo.Abp.SettingManagement.Localization;
using Volo.Abp.Settings;
@ -16,9 +17,14 @@ namespace LINGYUN.Abp.SettingManagement
{
protected ISettingManager SettingManager { get; }
protected ISettingDefinitionManager SettingDefinitionManager { get; }
public SettingAppService(ISettingManager settingManager,
protected IDistributedCache<SettingCacheItem> Cache { get; }
public SettingAppService(
ISettingManager settingManager,
IDistributedCache<SettingCacheItem> cache,
ISettingDefinitionManager settingDefinitionManager)
{
Cache = cache;
SettingManager = settingManager;
SettingDefinitionManager = settingDefinitionManager;
LocalizationResource = typeof(AbpSettingManagementResource);
@ -54,8 +60,17 @@ namespace LINGYUN.Abp.SettingManagement
{
foreach (var setting in input.Settings)
{
await SettingManager.SetAsync(setting.Name, providerName, providerKey, setting.Value);
await SettingManager.SetAsync(setting.Name, setting.Value, providerName, providerKey);
// 同步变更缓存配置
var settingCacheKey = CalculateCacheKey(setting.Name, providerName, providerKey);
var settignCacheItem = new SettingCacheItem(setting.Value);
await Cache.SetAsync(settingCacheKey, settignCacheItem);
}
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
}
}

2
aspnet-core/services/apigateway/LINGYUN.ApiGateway.HttpApi.Host/ApiGatewayHttpApiHostModule.cs

@ -163,7 +163,7 @@ namespace LINGYUN.ApiGateway
// 审计日志
app.UseAuditing();
// 路由
app.UseMvcWithDefaultRouteAndArea();
app.UseConfiguredEndpoints();
}
}
}

8
aspnet-core/services/cleanup-logs.bat

@ -0,0 +1,8 @@
@echo off
cls
chcp 65001
echo. 启动平台管理服务
cd .\platform\LINGYUN.Platform.HttpApi.Host

10
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN.Platform.HttpApi.Host.csproj

@ -5,6 +5,16 @@
<RootNamespace>LINGYUN.Platform</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Content Remove="LINGYUN\Platform\Identity\Localization\en.json" />
<Content Remove="LINGYUN\Platform\Identity\Localization\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="LINGYUN\Platform\Identity\Localization\en.json" />
<EmbeddedResource Include="LINGYUN\Platform\Identity\Localization\zh-Hans.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DotNetCore.CAP.MySql" Version="3.0.3" />
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="3.0.3" />

268
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs

@ -0,0 +1,268 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations;
using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending;
using Volo.Abp.AspNetCore.Mvc.MultiTenancy;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Clients;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Local;
using Volo.Abp.Features;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.PermissionManagement;
using Volo.Abp.Settings;
using Volo.Abp.Users;
namespace LINGYUN.Platform.AspNetCore.Mvc.ApplicationConfigurations
{
[Dependency(ServiceLifetime.Transient)]
[ExposeServices(typeof(IAbpApplicationConfigurationAppService))]
public class AbpApplicationConfigurationAppService : ApplicationService, IAbpApplicationConfigurationAppService
{
private readonly AbpLocalizationOptions _localizationOptions;
private readonly AbpMultiTenancyOptions _multiTenancyOptions;
private readonly IServiceProvider _serviceProvider;
private readonly ISettingProvider _settingProvider;
private readonly ISettingDefinitionManager _settingDefinitionManager;
private readonly IFeatureDefinitionManager _featureDefinitionManager;
private readonly IPermissionGrantRepository _permissionGrantRepository;
private readonly IPermissionDefinitionManager _permissionDefinitionManager;
private readonly ILanguageProvider _languageProvider;
private readonly ICachedObjectExtensionsDtoService _cachedObjectExtensionsDtoService;
private ICurrentClient _currentClient;
protected ICurrentClient CurrentClient => LazyGetRequiredService(ref _currentClient);
private ILocalEventBus _localEventBus;
//用于发布权限事件,每次请求此接口后,通过事件总线来缓存权限
protected ILocalEventBus LocalEventBus => LazyGetRequiredService(ref _localEventBus);
public AbpApplicationConfigurationAppService(
IOptions<AbpLocalizationOptions> localizationOptions,
IOptions<AbpMultiTenancyOptions> multiTenancyOptions,
IServiceProvider serviceProvider,
ISettingProvider settingProvider,
ISettingDefinitionManager settingDefinitionManager,
IFeatureDefinitionManager featureDefinitionManager,
IPermissionGrantRepository permissionGrantRepository,
IPermissionDefinitionManager permissionDefinitionManager,
ILanguageProvider languageProvider,
ICachedObjectExtensionsDtoService cachedObjectExtensionsDtoService)
{
_serviceProvider = serviceProvider;
_settingProvider = settingProvider;
_settingDefinitionManager = settingDefinitionManager;
_featureDefinitionManager = featureDefinitionManager;
_permissionGrantRepository = permissionGrantRepository;
_permissionDefinitionManager = permissionDefinitionManager;
_languageProvider = languageProvider;
_cachedObjectExtensionsDtoService = cachedObjectExtensionsDtoService;
_localizationOptions = localizationOptions.Value;
_multiTenancyOptions = multiTenancyOptions.Value;
}
public virtual async Task<ApplicationConfigurationDto> GetAsync()
{
//TODO: Optimize & cache..?
Logger.LogDebug("Executing AbpApplicationConfigurationAppService.GetAsync()...");
var result = new ApplicationConfigurationDto
{
Auth = await GetAuthConfigAsync(),
Features = await GetFeaturesConfigAsync(),
Localization = await GetLocalizationConfigAsync(),
CurrentUser = GetCurrentUser(),
Setting = await GetSettingConfigAsync(),
MultiTenancy = GetMultiTenancy(),
CurrentTenant = GetCurrentTenant(),
ObjectExtensions = _cachedObjectExtensionsDtoService.Get()
};
Logger.LogDebug("Executed AbpApplicationConfigurationAppService.GetAsync().");
return result;
}
protected virtual CurrentTenantDto GetCurrentTenant()
{
return new CurrentTenantDto()
{
Id = CurrentTenant.Id,
Name = CurrentTenant.Name,
IsAvailable = CurrentTenant.IsAvailable
};
}
protected virtual MultiTenancyInfoDto GetMultiTenancy()
{
return new MultiTenancyInfoDto
{
IsEnabled = _multiTenancyOptions.IsEnabled
};
}
protected virtual CurrentUserDto GetCurrentUser()
{
return new CurrentUserDto
{
IsAuthenticated = CurrentUser.IsAuthenticated,
Id = CurrentUser.Id,
TenantId = CurrentUser.TenantId,
UserName = CurrentUser.UserName,
Email = CurrentUser.Email
};
}
protected virtual async Task<ApplicationAuthConfigurationDto> GetAuthConfigAsync()
{
var authConfig = new ApplicationAuthConfigurationDto();
var permissions = _permissionDefinitionManager.GetPermissions();
IEnumerable<PermissionGrant> grantPermissions = new List<PermissionGrant>();
// TODO: 重写为每次调用接口都在数据库统一查询权限
// 待框架改进权限Provider机制后再移除
// 如果用户已登录,获取用户和角色权限
if (CurrentUser.IsAuthenticated)
{
var userPermissions = await _permissionGrantRepository.GetListAsync(UserPermissionValueProvider.ProviderName,
CurrentUser.GetId().ToString());
grantPermissions = grantPermissions.Union(userPermissions);
foreach(var userRole in CurrentUser.Roles)
{
var rolePermissions = await _permissionGrantRepository.GetListAsync(RolePermissionValueProvider.ProviderName,
userRole);
grantPermissions = grantPermissions.Union(rolePermissions);
}
}
// 如果客户端已验证,获取客户端权限
if(CurrentClient.IsAuthenticated)
{
var clientPermissions = await _permissionGrantRepository.GetListAsync(ClientPermissionValueProvider.ProviderName,
CurrentClient.Id);
grantPermissions = grantPermissions.Union(clientPermissions);
}
foreach(var permission in permissions)
{
authConfig.Policies[permission.Name] = true;
if(grantPermissions.Any(p => p.Name.Equals(permission.Name)))
{
authConfig.GrantedPolicies[permission.Name] = true;
}
}
return authConfig;
}
protected virtual async Task<ApplicationLocalizationConfigurationDto> GetLocalizationConfigAsync()
{
var localizationConfig = new ApplicationLocalizationConfigurationDto();
localizationConfig.Languages.AddRange(await _languageProvider.GetLanguagesAsync());
foreach (var resource in _localizationOptions.Resources.Values)
{
var dictionary = new Dictionary<string, string>();
var localizer = _serviceProvider.GetRequiredService(
typeof(IStringLocalizer<>).MakeGenericType(resource.ResourceType)
) as IStringLocalizer;
foreach (var localizedString in localizer.GetAllStrings())
{
dictionary[localizedString.Name] = localizedString.Value;
}
localizationConfig.Values[resource.ResourceName] = dictionary;
}
localizationConfig.CurrentCulture = GetCurrentCultureInfo();
if (_localizationOptions.DefaultResourceType != null)
{
localizationConfig.DefaultResourceName = LocalizationResourceNameAttribute.GetName(
_localizationOptions.DefaultResourceType
);
}
return localizationConfig;
}
private static CurrentCultureDto GetCurrentCultureInfo()
{
return new CurrentCultureDto
{
Name = CultureInfo.CurrentUICulture.Name,
DisplayName = CultureInfo.CurrentUICulture.DisplayName,
EnglishName = CultureInfo.CurrentUICulture.EnglishName,
NativeName = CultureInfo.CurrentUICulture.NativeName,
IsRightToLeft = CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft,
CultureName = CultureInfo.CurrentUICulture.TextInfo.CultureName,
TwoLetterIsoLanguageName = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
ThreeLetterIsoLanguageName = CultureInfo.CurrentUICulture.ThreeLetterISOLanguageName,
DateTimeFormat = new DateTimeFormatDto
{
CalendarAlgorithmType = CultureInfo.CurrentUICulture.DateTimeFormat.Calendar.AlgorithmType.ToString(),
DateTimeFormatLong = CultureInfo.CurrentUICulture.DateTimeFormat.LongDatePattern,
ShortDatePattern = CultureInfo.CurrentUICulture.DateTimeFormat.ShortDatePattern,
FullDateTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.FullDateTimePattern,
DateSeparator = CultureInfo.CurrentUICulture.DateTimeFormat.DateSeparator,
ShortTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.ShortTimePattern,
LongTimePattern = CultureInfo.CurrentUICulture.DateTimeFormat.LongTimePattern,
}
};
}
private async Task<ApplicationSettingConfigurationDto> GetSettingConfigAsync()
{
var result = new ApplicationSettingConfigurationDto
{
Values = new Dictionary<string, string>()
};
foreach (var settingDefinition in _settingDefinitionManager.GetAll())
{
if (!settingDefinition.IsVisibleToClients)
{
continue;
}
result.Values[settingDefinition.Name] = await _settingProvider.GetOrNullAsync(settingDefinition.Name);
}
return result;
}
protected virtual async Task<ApplicationFeatureConfigurationDto> GetFeaturesConfigAsync()
{
var result = new ApplicationFeatureConfigurationDto();
foreach (var featureDefinition in _featureDefinitionManager.GetAll())
{
if (!featureDefinition.IsVisibleToClients)
{
continue;
}
result.Values[featureDefinition.Name] = await FeatureChecker.GetOrNullAsync(featureDefinition.Name);
}
return result;
}
}
}

5
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/en.json

@ -0,0 +1,5 @@
{
"culture": "en",
"texts": {
}
}

7
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/LINGYUN/Platform/Identity/Localization/zh-Hans.json

@ -0,0 +1,7 @@
{
"culture": "zh-Hans",
"texts": {
"DisplayName:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "启用电话号码确认",
"Description:Abp.Identity.SignIn.EnablePhoneNumberConfirmation": "用户是否可以确认电话号码."
}
}

11
aspnet-core/services/platform/LINGYUN.Platform.HttpApi.Host/PlatformHttpApiHostModule.cs

@ -29,6 +29,7 @@ using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore.MySQL;
using Volo.Abp.Identity;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.Identity.Localization;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
@ -40,6 +41,7 @@ using Volo.Abp.PermissionManagement.IdentityServer;
using Volo.Abp.Security.Claims;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;
using Volo.Abp.VirtualFileSystem;
using AbpPermissionManagementApplicationModule = LINGYUN.Abp.PermissionManagement.AbpPermissionManagementApplicationModule;
namespace LINGYUN.Platform
@ -107,6 +109,11 @@ namespace LINGYUN.Platform
options.UseMySQL();
});
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<PlatformHttpApiHostModule>("LINGYUN.Platform");
});
// 多租户
Configure<AbpMultiTenancyOptions>(options =>
{
@ -132,6 +139,10 @@ namespace LINGYUN.Platform
{
options.Languages.Add(new LanguageInfo("en", "en", "English"));
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
options.Resources
.Get<IdentityResource>()
.AddVirtualJson("/LINGYUN/Platform/Identity/Localization");
});
context.Services.AddAuthentication("Bearer")

13
vueJs/src/api/abpconfiguration.ts

@ -5,7 +5,12 @@ const serviceUrl = process.env.VUE_APP_BASE_API
export default class AbpConfigurationService {
public static getAbpConfiguration() {
const _url = '/api/abp/application-configuration'
return ApiService.Get<AbpConfiguration>(_url, serviceUrl)
return ApiService.HttpRequest<AbpConfiguration>({
url: _url,
baseURL: serviceUrl,
method: 'GET',
timeout: 120000
})
}
}
@ -65,15 +70,15 @@ export class Localization {
currentCulture!: CurrentCulture
defaultResourceName?: string
languages!: Language[]
values!: {[key:string]: {[key:string]: string}}
values!: {[key:string]:{[key:string]:string}}
}
export class MultiTenancy {
isEnabled!: boolean
isEnabled = false
}
export class Setting {
values?: {[key:string]: string}
values?: {[key:string]:string}
}
export interface IAbpConfiguration {

17
vueJs/src/api/settings.ts

@ -13,7 +13,7 @@ export default class SettingApiService {
public static getSettings(providerName: string, providerKey: string) {
let _url = '/api/abp/setting'
_url += '?providerName=' + providerName
_url += '?providerKey=' + providerKey
_url += '&providerKey=' + providerKey
return ApiService.Get<ListResultDto<Setting>>(_url, IdentityService)
}
@ -24,10 +24,10 @@ export default class SettingApiService {
* @param payload
* @returns Promise对象
*/
public setSettings(providerName: string, providerKey: string, payload: SettingsUpdate) {
public static setSettings(providerName: string, providerKey: string, payload: SettingsUpdate) {
let _url = '/api/abp/setting'
_url += '?providerName=' + providerName
_url += '?providerKey=' + providerKey
_url += '&providerKey=' + providerKey
return ApiService.Put<any>(_url, payload, IdentityService)
}
}
@ -36,17 +36,24 @@ export class SettingBase {
/** 名称 */
name!: string
/** 当前设置值 */
value!: string
value!: any
}
/** 设置对象 */
export class Setting extends SettingBase{
export class Setting extends SettingBase {
/** 显示名称 */
displayName!: string
/** 说明 */
description!: string
/** 默认设置 */
defaultValue!: string
public getValue() {
if (this.value) {
return this.value
}
return this.defaultValue
}
}
/** 配置变更对象 */

8
vueJs/src/lang/zh.ts

@ -197,7 +197,13 @@ export default {
showTagsView: '显示 Tags-View',
showSidebarLogo: '显示侧边栏 Logo',
fixedHeader: '固定 Header',
sidebarTextTheme: '侧边栏文字主题色'
sidebarTextTheme: '侧边栏文字主题色',
globalSetting: '公共设置',
tenantSetting: '租户设置',
userSetting: '用户设置',
passwordSecurity: '密码安全',
systemSetting: '系统配置',
userAccount: '用户账户'
},
task: {
title: '任务管理'

1
vueJs/src/permission.ts

@ -4,6 +4,7 @@ import 'nprogress/nprogress.css'
import { Message } from 'element-ui'
import { Route } from 'vue-router'
import { UserModule } from '@/store/modules/user'
import { AbpConfigurationModule } from '@/store/modules/abp'
import { PermissionModule } from '@/store/modules/permission'
import i18n from '@/lang' // Internationalization
import settings from './settings'

10
vueJs/src/store/modules/abp.ts

@ -1,20 +1,22 @@
import store from '@/store'
import { getAbpConfig, setAbpConfig } from '@/utils/localStorage'
import AbpConfigurationService, { IAbpConfiguration } from '@/api/abpconfiguration'
import { getItemJson, setItem } from '@/utils/localStorage'
import AbpConfigurationService, { IAbpConfiguration, AbpConfiguration as AbpConfig } from '@/api/abpconfiguration'
import { VuexModule, Module, Mutation, Action, getModule } from 'vuex-module-decorators'
export interface IAbpConfigurationState {
configuration: IAbpConfiguration
}
const abpConfigurationKey = 'vue_admin_abp_configuration'
@Module({ dynamic: true, store, name: 'abpconfiguration' })
class AbpConfiguration extends VuexModule implements IAbpConfigurationState {
configuration = getAbpConfig()
configuration = getItemJson(abpConfigurationKey) || new AbpConfig()
@Mutation
private SET_ABPCONFIGURATION(configuration: IAbpConfiguration) {
this.configuration = configuration
setAbpConfig(configuration)
setItem(abpConfigurationKey, JSON.stringify(configuration))
}
@Action({ rawError: true })

33
vueJs/src/store/modules/user.ts

@ -1,7 +1,7 @@
import { VuexModule, Module, Action, Mutation, getModule } from 'vuex-module-decorators'
import UserApiService, { UserLoginData, UserLoginPhoneData } from '@/api/users'
import TenantService from '@/api/tenant'
import { getToken, setToken, removeToken, getRefreshToken, setRefreshToken } from '@/utils/localStorage'
import { getItem, setItem, removeItem } from '@/utils/localStorage'
import { resetRouter } from '@/router'
import { TagsViewModule } from './tags-view'
import { removeTenant, setTenant } from '@/utils/sessions'
@ -11,15 +11,20 @@ import store from '@/store'
export interface IUserState {
token: string
refreshToken: string
id: string
name: string
roles: string[]
email: string
}
const tokenKey = 'vue_typescript_admin_token'
const refreshTokenKey = 'vue_typescript_admin_refresh_token'
@Module({ dynamic: true, store, name: 'user' })
class User extends VuexModule implements IUserState {
public token = getToken() || ''
public token = getItem(tokenKey)
public refreshToken = getItem(refreshTokenKey)
public id = ''
public name = ''
public roles: string[] = []
@ -28,7 +33,13 @@ class User extends VuexModule implements IUserState {
@Mutation
private SET_TOKEN(token: string) {
this.token = token
setToken(token)
setItem(tokenKey, token)
}
@Mutation
private SET_REFRESHTOKEN(token: string) {
this.refreshToken = token
setItem(refreshTokenKey, token)
}
@Mutation
@ -62,7 +73,7 @@ class User extends VuexModule implements IUserState {
const loginResult = await UserApiService.userLogin(userLoginData)
const token = loginResult.token_type + ' ' + loginResult.access_token
this.SET_TOKEN(token)
setRefreshToken(loginResult.refresh_token)
this.SET_REFRESHTOKEN(loginResult.refresh_token)
await this.PostLogin()
}
@ -77,13 +88,13 @@ class User extends VuexModule implements IUserState {
const loginResult = await UserApiService.userLoginWithPhone(userLoginData)
const token = loginResult.token_type + ' ' + loginResult.access_token
this.SET_TOKEN(token)
setRefreshToken(loginResult.refresh_token)
this.SET_REFRESHTOKEN(loginResult.refresh_token)
await this.PostLogin()
}
@Action
public ResetToken() {
removeToken()
removeItem(tokenKey)
removeTenant()
this.SET_TOKEN('')
this.SET_ROLES([])
@ -106,13 +117,15 @@ class User extends VuexModule implements IUserState {
if (this.token === '') {
throw Error('LogOut: token is undefined!')
}
const token = getRefreshToken()
const token = getItem(refreshTokenKey)
if (token) {
await UserApiService.userLogout(token)
}
this.SET_TOKEN('')
this.SET_REFRESHTOKEN('')
this.SET_ROLES([])
removeToken()
removeItem(tokenKey)
removeItem(refreshTokenKey)
removeTenant()
resetRouter()
// Reset visited views and cached views
@ -124,12 +137,12 @@ class User extends VuexModule implements IUserState {
@Action
public RefreshSession() {
return new Promise((resolve, reject) => {
const token = getToken()
const token = getItem(tokenKey)
if (token) {
UserApiService.refreshToken(token).then(result => {
const token = result.token_type + ' ' + result.access_token
setRefreshToken(result.refresh_token)
this.SET_TOKEN(token)
this.SET_REFRESHTOKEN(result.refresh_token)
return resolve(result)
}).catch(error => {
return reject(error)

51
vueJs/src/utils/localStorage.ts

@ -1,38 +1,27 @@
import { AbpConfiguration } from '@/api/abpconfiguration'
const abpConfigKey = 'vue_admin_abp_configuration'
export const getAbpConfig = () => {
const abpConfigItem = localStorage.getItem(abpConfigKey)
if (abpConfigItem) {
return JSON.parse(abpConfigItem) as AbpConfiguration
export function getItem(key: string) {
const item = localStorage.getItem(key)
if (item) {
return item
}
return new AbpConfiguration()
}
export const setAbpConfig = (abpConfig: AbpConfiguration) => {
const abpConfigItem = JSON.stringify(abpConfig)
localStorage.setItem(abpConfigKey, abpConfigItem)
return ''
}
export const removeAbpConfig = () => localStorage.removeItem(abpConfigKey)
// User
const tokenKey = 'vue_typescript_admin_token'
const refreshTokenKey = 'vue_typescript_admin_refresh_token'
export function getToken() {
const tokenItem = localStorage.getItem(tokenKey)
if (tokenItem) {
return tokenItem
export function getItemJson(key: string) {
const item = localStorage.getItem(key)
if (item) {
return JSON.parse(item)
}
return ''
return null
}
export const setToken = (token: string) => localStorage.setItem(tokenKey, token)
export const getRefreshToken = () => {
const tokenItem = localStorage.getItem(refreshTokenKey)
if (tokenItem) {
return tokenItem
}
return ''
export function setItem(key: string, value: string) {
localStorage.setItem(key, value)
}
export function removeItem(key: string) {
localStorage.removeItem(key)
}
export const setRefreshToken = (token: string) => localStorage.setItem(refreshTokenKey, token)
export const removeToken = () => {
localStorage.removeItem(tokenKey)
localStorage.removeItem(refreshTokenKey)
export function clear() {
localStorage.clear()
}

9
vueJs/src/utils/request.ts

@ -4,7 +4,6 @@ import { MessageBox, Notification } from 'element-ui'
import { UserModule } from '@/store/modules/user'
import { getTenant } from '@/utils/sessions'
import { getLanguage } from '@/utils/cookies'
import { getToken, getRefreshToken } from '@/utils/localStorage'
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
@ -18,10 +17,9 @@ service.interceptors.request.use(
if (config.url === '/connect/token') {
return config
}
const token = getToken()
// Add X-Access-Token header to every request, you can add other custom headers here
if (token) {
config.headers.Authorization = token
if (UserModule.token) {
config.headers.Authorization = UserModule.token
}
const tenantId = getTenant()
if (tenantId) {
@ -100,8 +98,7 @@ service.interceptors.response.use(
(error) => {
showError(error.response.data, error.response.status)
if (error.response.status === 401) {
const token = getRefreshToken()
if (token) {
if (UserModule.refreshToken) {
UserModule.RefreshSession().then(() => {
return service.request(error.config)
}).catch(() => {

2
vueJs/src/views/admin/apigateway/components/GlobalCreateOrEditForm.vue

@ -445,7 +445,7 @@ export default class extends Vue {
}
private onCancel() {
this.appId = ''
this.globalConfiguration = new GlobalConfigurationDto()
const formGlobal = this.$refs.formGlobal as any
formGlobal.resetFields()
this.$emit('closed', false)

2
vueJs/src/views/admin/identityServer/api-resources/components/ApiResourceCreateOrEditForm.vue

@ -91,7 +91,7 @@ export default class extends Vue {
private apiResource: ApiResource
private apiResourceRules = {
name: [
{ required: true, message: this.l('pleaseInputBy', { key: this.l('identityServer.apiResourceName') }), trigger: 'blur' }
{ required: true, message: this.l('pleaseInputBy', { key: this.l('identityServer.resourceName') }), trigger: 'blur' }
]
}

2
vueJs/src/views/admin/identityServer/client/components/ClientPropertyEditForm.vue

@ -36,7 +36,7 @@
:disabled="!checkPermission(['IdentityServer.Clients.Properties.Create'])"
@click="onSaveClientProperty"
>
{{ $t('identityServer.createProperty') }}
{{ $t('identityServer.createClientProperty') }}
</el-button>
</el-form-item>
</el-form>

277
vueJs/src/views/admin/settings/components/GlobalSettingEditForm.vue

@ -0,0 +1,277 @@
<template>
<div v-if="globalSettingLoaded">
<el-form
v-if="globalSettingLoaded"
ref="formGlobalSetting"
v-model="globalSetting"
label-width="180px"
style="width: 96%"
>
<el-tabs>
<el-tab-pane :label="$t('settings.systemSetting')">
<el-form-item
prop="globalSetting['Abp.Localization.DefaultLanguage'].value"
:label="globalSetting['Abp.Localization.DefaultLanguage'].displayName"
>
<el-input
v-model="globalSetting['Abp.Localization.DefaultLanguage'].value"
:placeholder="globalSetting['Abp.Localization.DefaultLanguage'].description"
@input="(value) => handleSettingValueChanged('Abp.Localization.DefaultLanguage', value)"
/>
</el-form-item>
</el-tab-pane>
<el-tab-pane
v-if="allowIdentitySetting"
:label="$t('settings.passwordSecurity')"
>
<el-form-item :label="globalSetting['Abp.Identity.Password.RequiredLength'].displayName">
<el-input
v-model="globalSetting['Abp.Identity.Password.RequiredLength'].value"
:placeholder="globalSetting['Abp.Identity.Password.RequiredLength'].description"
type="number"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequiredLength', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Identity.Password.RequiredUniqueChars'].displayName">
<el-input
v-model="globalSetting['Abp.Identity.Password.RequiredUniqueChars'].value"
type="number"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequiredUniqueChars', value)"
/>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.Password.RequireNonAlphanumeric'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.Password.RequireNonAlphanumeric'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequireNonAlphanumeric', value)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.Password.RequireLowercase'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.Password.RequireLowercase'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequireLowercase', value)"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.Password.RequireUppercase'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.Password.RequireUppercase'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequireUppercase', value)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.Password.RequireDigit'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.Password.RequireDigit'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.Password.RequireDigit', value)"
/>
</el-form-item>
</el-col>
<el-form-item :label="globalSetting['Abp.Identity.Lockout.AllowedForNewUsers'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.Lockout.AllowedForNewUsers'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.Lockout.AllowedForNewUsers', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Identity.Lockout.MaxFailedAccessAttempts'].displayName">
<el-input
v-model="globalSetting['Abp.Identity.Lockout.MaxFailedAccessAttempts'].value"
:placeholder="globalSetting['Abp.Identity.Lockout.MaxFailedAccessAttempts'].description"
type="number"
@input="(value) => handleSettingValueChanged('Abp.Identity.Lockout.MaxFailedAccessAttempts', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Identity.Lockout.LockoutDuration'].displayName">
<el-input
v-model="globalSetting['Abp.Identity.Lockout.LockoutDuration'].value"
:placeholder="globalSetting['Abp.Identity.Lockout.LockoutDuration'].description"
type="number"
@input="(value) => handleSettingValueChanged('Abp.Identity.Lockout.LockoutDuration', value)"
/>
</el-form-item>
</el-row>
</el-tab-pane>
<el-tab-pane
v-if="allowAccountSetting"
:label="$t('settings.userAccount')"
>
<el-row>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.SignIn.RequireConfirmedEmail'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.SignIn.RequireConfirmedEmail'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.SignIn.RequireConfirmedEmail', value)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.SignIn.EnablePhoneNumberConfirmation'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.SignIn.EnablePhoneNumberConfirmation'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.SignIn.EnablePhoneNumberConfirmation', value)"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.SignIn.RequireConfirmedPhoneNumber'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.SignIn.RequireConfirmedPhoneNumber'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.SignIn.RequireConfirmedPhoneNumber', value)"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Identity.User.IsUserNameUpdateEnabled'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.User.IsUserNameUpdateEnabled'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.User.IsUserNameUpdateEnabled', value)"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item :label="globalSetting['Abp.Identity.User.IsEmailUpdateEnabled'].displayName">
<el-switch
v-model="globalSetting['Abp.Identity.User.IsEmailUpdateEnabled'].value"
@input="(value) => handleSettingValueChanged('Abp.Identity.User.IsEmailUpdateEnabled', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Account.SmsRegisterTemplateCode'].displayName">
<el-input
v-model="globalSetting['Abp.Account.SmsRegisterTemplateCode'].value"
:placeholder="globalSetting['Abp.Account.SmsRegisterTemplateCode'].description"
@input="(value) => handleSettingValueChanged('Abp.Account.SmsRegisterTemplateCode', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Account.SmsSigninTemplateCode'].displayName">
<el-input
v-model="globalSetting['Abp.Account.SmsSigninTemplateCode'].value"
:placeholder="globalSetting['Abp.Account.SmsSigninTemplateCode'].description"
@input="(value) => handleSettingValueChanged('Abp.Account.SmsSigninTemplateCode', value)"
/>
</el-form-item>
<el-form-item :label="globalSetting['Abp.Account.PhoneVerifyCodeExpiration'].displayName">
<el-input
v-model="globalSetting['Abp.Account.PhoneVerifyCodeExpiration'].value"
:placeholder="globalSetting['Abp.Account.PhoneVerifyCodeExpiration'].description"
@input="(value) => handleSettingValueChanged('Abp.Account.PhoneVerifyCodeExpiration', value)"
/>
</el-form-item>
<el-row>
<el-col :span="8">
<el-form-item :label="globalSetting['Abp.Account.IsSelfRegistrationEnabled'].displayName">
<el-switch
v-model="globalSetting['Abp.Account.IsSelfRegistrationEnabled'].value"
@input="(value) => handleSettingValueChanged('Abp.Account.IsSelfRegistrationEnabled', value)"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item :label="globalSetting['Abp.Account.EnableLocalLogin'].displayName">
<el-switch
v-model="globalSetting['Abp.Account.EnableLocalLogin'].value"
@input="(value) => handleSettingValueChanged('Abp.Account.EnableLocalLogin', value)"
/>
</el-form-item>
</el-col>
</el-row>
</el-tab-pane>
</el-tabs>
<el-form-item>
<el-button
type="primary"
style="width:200px;margin:inherit;"
@click="onSaveGlobalSetting"
>
{{ $t('global.confirm') }}
</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import SettingService, { Setting, SettingUpdate, SettingsUpdate } from '@/api/settings'
const booleanStrings = ['True', 'true', 'False', 'false']
@Component({
name: 'GlobalSettingEditForm'
})
export default class extends Vue {
private globalSettingLoaded = false
private globalSetting: {[key: string]: Setting} = {}
private globalSettingChangeKeys = new Array<string>()
get allowIdentitySetting() {
if (this.globalSetting['Abp.Identity.Password.RequiredLength']) {
return true
}
return false
}
get allowAccountSetting() {
if (this.globalSetting['Abp.Account.EnableLocalLogin']) {
return true
}
return false
}
mounted() {
this.handleGetGlobalSettings()
}
private handleSettingValueChanged(key: string, value: any) {
if (!this.globalSettingChangeKeys.includes(key)) {
this.globalSettingChangeKeys.push(key)
}
this.$set(this.globalSetting[key], 'value', value)
this.$forceUpdate()
}
private handleGetGlobalSettings() {
SettingService.getSettings('G', '').then(settings => {
settings.items.forEach(setting => {
if (setting.value) {
const value = setting.value.toLowerCase()
if (booleanStrings.includes(value)) {
setting.value = value === 'true'
}
} else {
const defaultValue = setting.defaultValue.toLowerCase()
if (booleanStrings.includes(defaultValue)) {
setting.value = defaultValue === 'true'
}
}
this.globalSetting[setting.name] = setting
})
this.globalSettingLoaded = true
})
}
private onSaveGlobalSetting() {
const updateSettings = new SettingsUpdate()
this.globalSettingChangeKeys.forEach(key => {
const updateSetting = new SettingUpdate()
updateSetting.name = key
updateSetting.value = this.globalSetting[key].value
updateSettings.settings.push(updateSetting)
})
if (updateSettings.settings.length > 0) {
SettingService.setSettings('G', '', updateSettings).then(() => {
this.$message.success(this.$t('AbpSettingManagement.SuccessfullySaved').toString())
})
}
}
}
</script>

42
vueJs/src/views/admin/settings/index.vue

@ -1,53 +1,37 @@
<template>
<el-tabs
tab-position="left"
style="height: 200px;"
>
<el-tab-pane
label="系统配置"
:label="$t('settings.globalSetting')"
>
系统配置
<GlobalSettingEditForm />
</el-tab-pane>
<el-tab-pane
label="租户配置"
:label="$t('settings.tenantSetting')"
>
租户配置
{{ $t('settings.tenantSetting') }}
</el-tab-pane>
<el-tab-pane
label="用户配置"
:label="$t('settings.userSetting')"
>
用户配置
{{ $t('settings.userSetting') }}
</el-tab-pane>
</el-tabs>
</template>
<script lang="ts">
import SettingService, { Setting } from '@/api/settings'
import { Component, Vue } from 'vue-property-decorator'
@Component({
name: 'Settings'
})
export default class extends Vue {
private settings: Setting[]
constructor() {
super()
this.settings = new Array<Setting>()
}
import GlobalSettingEditForm from './components/GlobalSettingEditForm.vue'
mounted() {
this.handleGetSettings()
}
private handleGetSettings() {
SettingService.getSettings('G', '').then(settings => {
this.settings = settings.items
console.log(this.settings)
})
@Component({
name: 'Settings',
components: {
GlobalSettingEditForm
}
}
})
export default class extends Vue {}
</script>
<style lang="scss" scoped>

Loading…
Cancel
Save