Explorar el Código

客户端修改语言时刷新页面

Cyrus Zhou hace 9 meses
padre
commit
26ef98a20b

+ 1 - 1
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -356,7 +356,7 @@ public class SysAuthService : IDynamicApiController, ITransient
 
         // 解析Token
         var (isValid, tokenData, validationResult) = JWTEncryption.Validate(accessToken);
-        if (isValid) throw Oops.Oh(ErrorCodeEnum.D1016);
+        if (!isValid) throw Oops.Oh(ErrorCodeEnum.D1016);
 
         // 获取用户Id
         var user = await _sysUserRep.AsQueryable().ClearFilter().FirstAsync(u => u.Id == _userManager.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);

+ 14 - 1
Admin.NET/Admin.NET.Core/Service/User/SysUserService.cs

@@ -209,7 +209,20 @@ public class SysUserService : IDynamicApiController, ITransient
             Input = input
         });
     }
-
+    /// <summary>
+    /// 更新当前用户语言 🔖
+    /// </summary>
+    /// <param name="langCode"></param>
+    /// <returns></returns>
+    [UnitOfWork]
+    [ApiDescriptionSettings(Name = "SetLangCode"), HttpPost]
+    [DisplayName("更新当前用户语言")]
+    public virtual async Task SetLangCode(string langCode)
+    {
+        var user = await _sysUserRep.AsQueryable().ClearFilter().FirstAsync(u => u.Id == _userManager.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);
+        user.LangCode = langCode;
+        await _sysUserRep.AsUpdateable(user).UpdateColumns(it => it.LangCode).ExecuteCommandAsync();
+    }
     /// <summary>
     /// 更新角色和扩展机构
     /// </summary>

+ 77 - 91
Web/src/api-services/apis/sys-user-api.ts

@@ -60,13 +60,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -107,13 +100,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             const query = new URLSearchParams(localVarUrlObj.search);
             for (const key in localVarQueryParameter) {
@@ -151,13 +137,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -199,13 +178,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -247,13 +219,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -295,13 +260,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -348,13 +306,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             const query = new URLSearchParams(localVarUrlObj.search);
             for (const key in localVarQueryParameter) {
@@ -397,13 +348,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             const query = new URLSearchParams(localVarUrlObj.search);
             for (const key in localVarQueryParameter) {
@@ -441,13 +385,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -489,13 +426,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -517,6 +447,48 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
                 options: localVarRequestOptions,
             };
         },
+        /**
+         * 
+         * @summary 更新用户语言 🔖
+         * @param {string} langCode 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        apiSysUserSetLangCodeLangCodePost: async (langCode: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
+            // verify required parameter 'langCode' is not null or undefined
+            if (langCode === null || langCode === undefined) {
+                throw new RequiredError('langCode','Required parameter langCode was null or undefined when calling apiSysUserSetLangCodeLangCodePost.');
+            }
+            const localVarPath = `/api/sysUser/setLangCode/{langCode}`
+                .replace(`{${"langCode"}}`, encodeURIComponent(String(langCode)));
+            // use dummy base URL string because the URL constructor only accepts absolute URLs.
+            const localVarUrlObj = new URL(localVarPath, 'https://example.com');
+            let baseOptions;
+            if (configuration) {
+                baseOptions = configuration.baseOptions;
+            }
+            const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
+            const localVarHeaderParameter = {} as any;
+            const localVarQueryParameter = {} as any;
+
+            // authentication Bearer required
+
+            const query = new URLSearchParams(localVarUrlObj.search);
+            for (const key in localVarQueryParameter) {
+                query.set(key, localVarQueryParameter[key]);
+            }
+            for (const key in options.params) {
+                query.set(key, options.params[key]);
+            }
+            localVarUrlObj.search = (new URLSearchParams(query)).toString();
+            let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
+            localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+
+            return {
+                url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
+                options: localVarRequestOptions,
+            };
+        },
         /**
          * 
          * @summary 设置用户状态 🔖
@@ -537,13 +509,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -585,13 +550,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -633,13 +591,6 @@ export const SysUserApiAxiosParamCreator = function (configuration?: Configurati
             const localVarQueryParameter = {} as any;
 
             // authentication Bearer required
-            // http bearer authentication required
-            if (configuration && configuration.accessToken) {
-                const accessToken = typeof configuration.accessToken === 'function'
-                    ? await configuration.accessToken()
-                    : await configuration.accessToken;
-                localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
-            }
 
             localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
 
@@ -809,6 +760,20 @@ export const SysUserApiFp = function(configuration?: Configuration) {
                 return axios.request(axiosRequestArgs);
             };
         },
+        /**
+         * 
+         * @summary 更新用户语言 🔖
+         * @param {string} langCode 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysUserSetLangCodeLangCodePost(langCode: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
+            const localVarAxiosArgs = await SysUserApiAxiosParamCreator(configuration).apiSysUserSetLangCodeLangCodePost(langCode, options);
+            return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
+                const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
+                return axios.request(axiosRequestArgs);
+            };
+        },
         /**
          * 
          * @summary 设置用户状态 🔖
@@ -959,6 +924,16 @@ export const SysUserApiFactory = function (configuration?: Configuration, basePa
         async apiSysUserResetPwdPost(body?: ResetPwdUserInput, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminResultString>> {
             return SysUserApiFp(configuration).apiSysUserResetPwdPost(body, options).then((request) => request(axios, basePath));
         },
+        /**
+         * 
+         * @summary 更新用户语言 🔖
+         * @param {string} langCode 
+         * @param {*} [options] Override http request option.
+         * @throws {RequiredError}
+         */
+        async apiSysUserSetLangCodeLangCodePost(langCode: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
+            return SysUserApiFp(configuration).apiSysUserSetLangCodeLangCodePost(langCode, options).then((request) => request(axios, basePath));
+        },
         /**
          * 
          * @summary 设置用户状态 🔖
@@ -1108,6 +1083,17 @@ export class SysUserApi extends BaseAPI {
     public async apiSysUserResetPwdPost(body?: ResetPwdUserInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminResultString>> {
         return SysUserApiFp(this.configuration).apiSysUserResetPwdPost(body, options).then((request) => request(this.axios, this.basePath));
     }
+    /**
+     * 
+     * @summary 更新用户语言 🔖
+     * @param {string} langCode 
+     * @param {*} [options] Override http request option.
+     * @throws {RequiredError}
+     * @memberof SysUserApi
+     */
+    public async apiSysUserSetLangCodeLangCodePost(langCode: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
+        return SysUserApiFp(this.configuration).apiSysUserSetLangCodeLangCodePost(langCode, options).then((request) => request(this.axios, this.basePath));
+    }
     /**
      * 
      * @summary 设置用户状态 🔖

+ 6 - 0
Web/src/api-services/models/sys-user.ts

@@ -405,4 +405,10 @@ export interface SysUser {
      * @memberof SysUser
      */
     signature?: string | null;
+    /**
+     * 语言代码(如 zh_CN)
+     * @type {string}
+     * @memberof SysUser
+     */
+    langCode?: string | null;
 }

+ 41 - 15
Web/src/layout/navBars/topBar/user.vue

@@ -6,15 +6,19 @@
 			</div>
 			<template #dropdown>
 				<el-dropdown-menu>
-					<el-dropdown-item command="large" :disabled="state.disabledSize === 'large'">{{ $t('message.user.dropdownLarge') }}</el-dropdown-item>
-					<el-dropdown-item command="default" :disabled="state.disabledSize === 'default'">{{ $t('message.user.dropdownDefault') }}</el-dropdown-item>
-					<el-dropdown-item command="small" :disabled="state.disabledSize === 'small'">{{ $t('message.user.dropdownSmall') }}</el-dropdown-item>
+					<el-dropdown-item command="large" :disabled="state.disabledSize === 'large'">{{
+						$t('message.user.dropdownLarge') }}</el-dropdown-item>
+					<el-dropdown-item command="default" :disabled="state.disabledSize === 'default'">{{
+						$t('message.user.dropdownDefault') }}</el-dropdown-item>
+					<el-dropdown-item command="small" :disabled="state.disabledSize === 'small'">{{
+						$t('message.user.dropdownSmall') }}</el-dropdown-item>
 				</el-dropdown-menu>
 			</template>
 		</el-dropdown>
 		<el-dropdown :show-timeout="70" :hide-timeout="50" trigger="click" @command="onLanguageChange">
 			<div class="layout-navbars-breadcrumb-user-icon">
-				<i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'" :title="$t('message.user.title1')"></i>
+				<i class="iconfont" :class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"
+					:title="$t('message.user.title1')"></i>
 			</div>
 			<template #dropdown>
 				<el-dropdown-menu>
@@ -46,7 +50,8 @@
 			</el-popover>
 		</div>
 		<div class="layout-navbars-breadcrumb-user-icon" @click="onScreenfullClick">
-			<i class="iconfont" :title="state.isScreenfull ? $t('message.user.title6') : $t('message.user.title5')" :class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
+			<i class="iconfont" :title="state.isScreenfull ? $t('message.user.title6') : $t('message.user.title5')"
+				:class="!state.isScreenfull ? 'icon-fullscreen' : 'icon-tuichuquanping'"></i>
 		</div>
 		<div class="layout-navbars-breadcrumb-user-icon mr10" @click="onOnlineUserClick">
 			<el-icon title="在线用户">
@@ -74,11 +79,16 @@
 			<template #dropdown>
 				<el-dropdown-menu>
 					<!-- <el-dropdown-item command="/dashboard/home">{{ $t('message.user.dropdown1') }}</el-dropdown-item> -->
-					<el-dropdown-item :icon="Avatar" command="/system/userCenter">{{ $t('message.user.dropdown2') }}</el-dropdown-item>
-					<el-dropdown-item :icon="Loading" command="clearCache">{{ $t('message.user.dropdown3') }}</el-dropdown-item>
-					<el-dropdown-item :icon="Switch" divided command="changeTenant" v-if="auth('sysTenant:changeTenant')">{{ $t('message.layout.changeTenant') }}</el-dropdown-item>
-					<el-dropdown-item :icon="Lock" divided command="lockScreen">{{ $t('message.layout.threeIsLockScreen') }}</el-dropdown-item>
-					<el-dropdown-item :icon="CircleCloseFilled" divided command="logOut">{{ $t('message.user.dropdown5') }}</el-dropdown-item>
+					<el-dropdown-item :icon="Avatar" command="/system/userCenter">{{ $t('message.user.dropdown2')
+					}}</el-dropdown-item>
+					<el-dropdown-item :icon="Loading" command="clearCache">{{ $t('message.user.dropdown3')
+					}}</el-dropdown-item>
+					<el-dropdown-item :icon="Switch" divided command="changeTenant"
+						v-if="auth('sysTenant:changeTenant')">{{ $t('message.layout.changeTenant') }}</el-dropdown-item>
+					<el-dropdown-item :icon="Lock" divided command="lockScreen">{{
+						$t('message.layout.threeIsLockScreen') }}</el-dropdown-item>
+					<el-dropdown-item :icon="CircleCloseFilled" divided command="logOut">{{ $t('message.user.dropdown5')
+					}}</el-dropdown-item>
 				</el-dropdown-menu>
 			</template>
 		</el-dropdown>
@@ -103,8 +113,8 @@ import { Local, Session } from '/@/utils/storage';
 import Push from 'push.js';
 import { signalR } from '/@/views/system/onlineUser/signalR';
 import { Avatar, CircleCloseFilled, Loading, Lock, Switch } from '@element-plus/icons-vue';
-import { clearAccessAfterReload, getAPI } from '/@/utils/axios-utils';
-import { SysAuthApi, SysNoticeApi, SysLangApi } from '/@/api-services/api';
+import { accessTokenKey, clearAccessAfterReload, getAPI } from '/@/utils/axios-utils';
+import { SysAuthApi, SysNoticeApi, SysUserApi } from '/@/api-services/api';
 import { auth } from '/@/utils/authFunction';
 import { useLangStore } from '/@/stores/useLangStore';
 
@@ -226,7 +236,14 @@ const onComponentSizeChange = (size: string) => {
 	window.location.reload();
 };
 // 语言切换
-const onLanguageChange = (lang: string) => {
+const onLanguageChange = async (lang: string) => {
+	const langItem = state.languages.find((item: { value: string }) => item.value === lang);
+	if (langItem) {
+		await getAPI(SysUserApi).apiSysUserSetLangCodeLangCodePost(langItem.code);
+		const accessToken = Local.get(accessTokenKey);
+		await getAPI(SysAuthApi).apiSysAuthRefreshTokenGet(`${accessToken}`);
+		window.location.reload();
+	}
 	Local.remove('themeConfig');
 	themeConfig.value.globalI18n = lang;
 	Local.set('themeConfig', themeConfig.value);
@@ -240,9 +257,19 @@ const initI18nOrSize = (value: string, attr: string) => {
 };
 // 页面加载时
 onMounted(async () => {
+	state.languages = langStore.languages;
 	if (Local.get('themeConfig')) {
 		initI18nOrSize('globalComponentSize', 'disabledSize');
-		initI18nOrSize('globalI18n', 'disabledI18n');
+		const userLangCode = userInfos.value.langCode;
+		const langItem = state.languages.find((item: { code: string }) => item.code === userLangCode);
+		if (langItem) {
+			const themeConfig = Local.get('themeConfig');
+			themeConfig.globalI18n = langItem.value;
+			Local.set('themeConfig', themeConfig);
+			initI18nOrSize('globalI18n', 'disabledI18n');
+		} else {
+			initI18nOrSize('globalI18n', 'disabledI18n');
+		}
 	}
 	// 手动获取用户桌面通知权限
 	if (Push.Permission.GRANTED) {
@@ -256,7 +283,6 @@ onMounted(async () => {
 			Push.clear();
 		}
 	});
-	state.languages = langStore.languages;
 	// 加载未读的站内信
 	var res = await getAPI(SysNoticeApi).apiSysNoticeUnReadListGet();
 	state.noticeList = res.data.result ?? [];

+ 1 - 0
Web/src/stores/userInfo.ts

@@ -82,6 +82,7 @@ export const useUserInfo = defineStore('userInfo', {
 							authBtnList: d.buttons,
 							tenantId: d.tenantId,
 							currentTenantId: d.currentTenantId,
+							langCode: d.langCode,
 							time: new Date().getTime(),
 						};
 

+ 1 - 0
Web/src/types/pinia.d.ts

@@ -23,6 +23,7 @@ declare interface UserInfos<T = any> {
 	orgId:string;
 	orgName:string;
 	tenantId:string;
+	langCode:string;
 	currentTenantId:string;
 
 	[key: string]: T;

+ 6 - 2
Web/src/views/system/user/component/userCenter.vue

@@ -177,10 +177,11 @@ import OrgTree from '/@/views/system/user/component/orgTree.vue';
 import CropperDialog from '/@/components/cropper/index.vue';
 import VueGridLayout from 'vue-grid-layout';
 import { sm2 } from 'sm-crypto-v2';
-import { clearAccessAfterReload, getAPI } from '/@/utils/axios-utils';
-import { SysFileApi, SysUserApi } from '/@/api-services/api';
+import { accessTokenKey, clearAccessAfterReload, getAPI } from '/@/utils/axios-utils';
+import { SysAuthApi, SysFileApi, SysUserApi } from '/@/api-services/api';
 import { ChangePwdInput, SysUser, SysFile } from '/@/api-services/models';
 import { useLangStore } from '/@/stores/useLangStore';
+import { Local } from '/@/utils/storage';
 const langStore = useLangStore();
 const stores = useUserInfo();
 const { userInfos } = storeToRefs(stores);
@@ -284,6 +285,9 @@ const submitUserBase = () => {
 			type: 'warning',
 		}).then(async () => {
 			await getAPI(SysUserApi).apiSysUserBaseInfoPost(state.ruleFormBase);
+			const accessToken = Local.get(accessTokenKey);
+			await getAPI(SysAuthApi).apiSysAuthRefreshTokenGet(`${accessToken}`);
+			window.location.reload();
 		});
 	});
 };