mirror of https://github.com/halo-dev/halo-admin
refactor: request api of user data (#882)
#### What type of PR is this? /kind improvement #### What this PR does / why we need it: 重构获取用户信息的请求方式,无需再请求所有角色即可获取当前用户的角色信息,适配:https://github.com/halo-dev/halo/pull/3372 相关 PR:https://github.com/halo-dev/console/pull/847 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3342 #### Special notes for your reviewer: 测试方式: 1. Halo 需要切换到 https://github.com/halo-dev/halo/pull/3372 分支。 2. Console 需要 `pnpm install && pnpm build:packages` 3. 测试用户列表、登录、检查角色信息是否显示正确。 #### Does this PR introduce a user-facing change? ```release-note 优化 Console 端用户角色标识的显示名称。 ```pull/883/head^2
parent
66a626c916
commit
6244e8b5c0
|
@ -77,6 +77,7 @@ models/counter-request.ts
|
|||
models/counter.ts
|
||||
models/custom-templates.ts
|
||||
models/dashboard-stats.ts
|
||||
models/detailed-user.ts
|
||||
models/excerpt.ts
|
||||
models/extension.ts
|
||||
models/file-reverse-proxy-provider.ts
|
||||
|
@ -96,6 +97,8 @@ models/listed-reply-list.ts
|
|||
models/listed-reply.ts
|
||||
models/listed-single-page-list.ts
|
||||
models/listed-single-page.ts
|
||||
models/listed-user-list.ts
|
||||
models/listed-user.ts
|
||||
models/login-history.ts
|
||||
models/menu-item-list.ts
|
||||
models/menu-item-spec.ts
|
||||
|
|
|
@ -34,11 +34,13 @@ import { BASE_PATH, COLLECTION_FORMATS, RequestArgs, BaseAPI, RequiredError } fr
|
|||
// @ts-ignore
|
||||
import { ChangePasswordRequest } from '../models'
|
||||
// @ts-ignore
|
||||
import { DetailedUser } from '../models'
|
||||
// @ts-ignore
|
||||
import { GrantRequest } from '../models'
|
||||
// @ts-ignore
|
||||
import { User } from '../models'
|
||||
import { ListedUserList } from '../models'
|
||||
// @ts-ignore
|
||||
import { UserList } from '../models'
|
||||
import { User } from '../models'
|
||||
// @ts-ignore
|
||||
import { UserPermission } from '../models'
|
||||
/**
|
||||
|
@ -174,6 +176,47 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi
|
|||
options: localVarRequestOptions,
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Get user detail by name
|
||||
* @param {string} name User name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getUserDetail: async (name: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'name' is not null or undefined
|
||||
assertParamExists('getUserDetail', 'name', name)
|
||||
const localVarPath = `/apis/api.console.halo.run/v1alpha1/users/{name}`.replace(
|
||||
`{${'name'}}`,
|
||||
encodeURIComponent(String(name)),
|
||||
)
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL)
|
||||
let baseOptions
|
||||
if (configuration) {
|
||||
baseOptions = configuration.baseOptions
|
||||
}
|
||||
|
||||
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options }
|
||||
const localVarHeaderParameter = {} as any
|
||||
const localVarQueryParameter = {} as any
|
||||
|
||||
// authentication BasicAuth required
|
||||
// http basic authentication required
|
||||
setBasicAuthToObject(localVarRequestOptions, configuration)
|
||||
|
||||
// authentication BearerAuth required
|
||||
// http bearer authentication required
|
||||
await setBearerAuthToObject(localVarHeaderParameter, configuration)
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter)
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}
|
||||
localVarRequestOptions.headers = { ...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers }
|
||||
|
||||
return {
|
||||
url: toPathString(localVarUrlObj),
|
||||
options: localVarRequestOptions,
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Grant permissions to user
|
||||
* @param {string} name User name
|
||||
|
@ -231,9 +274,9 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi
|
|||
* @param {string} [keyword]
|
||||
* @param {string} [role]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
@ -242,9 +285,9 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi
|
|||
keyword?: string,
|
||||
role?: string,
|
||||
size?: number,
|
||||
page?: number,
|
||||
labelSelector?: Array<string>,
|
||||
fieldSelector?: Array<string>,
|
||||
page?: number,
|
||||
options: AxiosRequestConfig = {},
|
||||
): Promise<RequestArgs> => {
|
||||
const localVarPath = `/apis/api.console.halo.run/v1alpha1/users`
|
||||
|
@ -283,10 +326,6 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi
|
|||
localVarQueryParameter['size'] = size
|
||||
}
|
||||
|
||||
if (page !== undefined) {
|
||||
localVarQueryParameter['page'] = page
|
||||
}
|
||||
|
||||
if (labelSelector) {
|
||||
localVarQueryParameter['labelSelector'] = labelSelector
|
||||
}
|
||||
|
@ -295,6 +334,10 @@ export const ApiConsoleHaloRunV1alpha1UserApiAxiosParamCreator = function (confi
|
|||
localVarQueryParameter['fieldSelector'] = fieldSelector
|
||||
}
|
||||
|
||||
if (page !== undefined) {
|
||||
localVarQueryParameter['page'] = page
|
||||
}
|
||||
|
||||
setSearchParams(localVarUrlObj, localVarQueryParameter)
|
||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}
|
||||
localVarRequestOptions.headers = { ...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers }
|
||||
|
@ -377,7 +420,7 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (configuration?: Conf
|
|||
*/
|
||||
async getCurrentUserDetail(
|
||||
options?: AxiosRequestConfig,
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<User>> {
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DetailedUser>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getCurrentUserDetail(options)
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)
|
||||
},
|
||||
|
@ -394,6 +437,19 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (configuration?: Conf
|
|||
const localVarAxiosArgs = await localVarAxiosParamCreator.getPermissions(name, options)
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)
|
||||
},
|
||||
/**
|
||||
* Get user detail by name
|
||||
* @param {string} name User name
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
async getUserDetail(
|
||||
name: string,
|
||||
options?: AxiosRequestConfig,
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<DetailedUser>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.getUserDetail(name, options)
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)
|
||||
},
|
||||
/**
|
||||
* Grant permissions to user
|
||||
* @param {string} name User name
|
||||
|
@ -415,9 +471,9 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (configuration?: Conf
|
|||
* @param {string} [keyword]
|
||||
* @param {string} [role]
|
||||
* @param {number} [size] Size of one page. Zero indicates no limit.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {Array<string>} [labelSelector] Label selector for filtering.
|
||||
* @param {Array<string>} [fieldSelector] Field selector for filtering.
|
||||
* @param {number} [page] The page number. Zero indicates no page.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
|
@ -426,19 +482,19 @@ export const ApiConsoleHaloRunV1alpha1UserApiFp = function (configuration?: Conf
|
|||
keyword?: string,
|
||||
role?: string,
|
||||
size?: number,
|
||||
page?: number,
|
||||
labelSelector?: Array<string>,
|
||||
fieldSelector?: Array<string>,
|
||||
page?: number,
|
||||
options?: AxiosRequestConfig,
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<UserList>> {
|
||||
): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<ListedUserList>> {
|
||||
const localVarAxiosArgs = await localVarAxiosParamCreator.listUsers(
|
||||
sort,
|
||||
keyword,
|
||||
role,
|
||||
size,
|
||||
page,
|
||||
labelSelector,
|
||||
fieldSelector,
|
||||
page,
|
||||
options,
|
||||
)
|
||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)
|
||||
|
@ -489,7 +545,7 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (
|
|||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getCurrentUserDetail(options?: AxiosRequestConfig): AxiosPromise<User> {
|
||||
getCurrentUserDetail(options?: AxiosRequestConfig): AxiosPromise<DetailedUser> {
|
||||
return localVarFp.getCurrentUserDetail(options).then((request) => request(axios, basePath))
|
||||
},
|
||||
/**
|
||||
|
@ -504,6 +560,18 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (
|
|||
): AxiosPromise<UserPermission> {
|
||||
return localVarFp.getPermissions(requestParameters.name, options).then((request) => request(axios, basePath))
|
||||
},
|
||||
/**
|
||||
* Get user detail by name
|
||||
* @param {ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
*/
|
||||
getUserDetail(
|
||||
requestParameters: ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest,
|
||||
options?: AxiosRequestConfig,
|
||||
): AxiosPromise<DetailedUser> {
|
||||
return localVarFp.getUserDetail(requestParameters.name, options).then((request) => request(axios, basePath))
|
||||
},
|
||||
/**
|
||||
* Grant permissions to user
|
||||
* @param {ApiConsoleHaloRunV1alpha1UserApiGrantPermissionRequest} requestParameters Request parameters.
|
||||
|
@ -527,16 +595,16 @@ export const ApiConsoleHaloRunV1alpha1UserApiFactory = function (
|
|||
listUsers(
|
||||
requestParameters: ApiConsoleHaloRunV1alpha1UserApiListUsersRequest = {},
|
||||
options?: AxiosRequestConfig,
|
||||
): AxiosPromise<UserList> {
|
||||
): AxiosPromise<ListedUserList> {
|
||||
return localVarFp
|
||||
.listUsers(
|
||||
requestParameters.sort,
|
||||
requestParameters.keyword,
|
||||
requestParameters.role,
|
||||
requestParameters.size,
|
||||
requestParameters.page,
|
||||
requestParameters.labelSelector,
|
||||
requestParameters.fieldSelector,
|
||||
requestParameters.page,
|
||||
options,
|
||||
)
|
||||
.then((request) => request(axios, basePath))
|
||||
|
@ -591,6 +659,20 @@ export interface ApiConsoleHaloRunV1alpha1UserApiGetPermissionsRequest {
|
|||
readonly name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for getUserDetail operation in ApiConsoleHaloRunV1alpha1UserApi.
|
||||
* @export
|
||||
* @interface ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest
|
||||
*/
|
||||
export interface ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest {
|
||||
/**
|
||||
* User name
|
||||
* @type {string}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiGetUserDetail
|
||||
*/
|
||||
readonly name: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for grantPermission operation in ApiConsoleHaloRunV1alpha1UserApi.
|
||||
* @export
|
||||
|
@ -646,13 +728,6 @@ export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest {
|
|||
*/
|
||||
readonly size?: number
|
||||
|
||||
/**
|
||||
* The page number. Zero indicates no page.
|
||||
* @type {number}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||
*/
|
||||
readonly page?: number
|
||||
|
||||
/**
|
||||
* Label selector for filtering.
|
||||
* @type {Array<string>}
|
||||
|
@ -666,6 +741,13 @@ export interface ApiConsoleHaloRunV1alpha1UserApiListUsersRequest {
|
|||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||
*/
|
||||
readonly fieldSelector?: Array<string>
|
||||
|
||||
/**
|
||||
* The page number. Zero indicates no page.
|
||||
* @type {number}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1UserApiListUsers
|
||||
*/
|
||||
readonly page?: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -733,6 +815,22 @@ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI {
|
|||
.then((request) => request(this.axios, this.basePath))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user detail by name
|
||||
* @param {ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest} requestParameters Request parameters.
|
||||
* @param {*} [options] Override http request option.
|
||||
* @throws {RequiredError}
|
||||
* @memberof ApiConsoleHaloRunV1alpha1UserApi
|
||||
*/
|
||||
public getUserDetail(
|
||||
requestParameters: ApiConsoleHaloRunV1alpha1UserApiGetUserDetailRequest,
|
||||
options?: AxiosRequestConfig,
|
||||
) {
|
||||
return ApiConsoleHaloRunV1alpha1UserApiFp(this.configuration)
|
||||
.getUserDetail(requestParameters.name, options)
|
||||
.then((request) => request(this.axios, this.basePath))
|
||||
}
|
||||
|
||||
/**
|
||||
* Grant permissions to user
|
||||
* @param {ApiConsoleHaloRunV1alpha1UserApiGrantPermissionRequest} requestParameters Request parameters.
|
||||
|
@ -766,9 +864,9 @@ export class ApiConsoleHaloRunV1alpha1UserApi extends BaseAPI {
|
|||
requestParameters.keyword,
|
||||
requestParameters.role,
|
||||
requestParameters.size,
|
||||
requestParameters.page,
|
||||
requestParameters.labelSelector,
|
||||
requestParameters.fieldSelector,
|
||||
requestParameters.page,
|
||||
options,
|
||||
)
|
||||
.then((request) => request(this.axios, this.basePath))
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import { Role } from './role'
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import { User } from './user'
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface DetailedUser
|
||||
*/
|
||||
export interface DetailedUser {
|
||||
/**
|
||||
*
|
||||
* @type {User}
|
||||
* @memberof DetailedUser
|
||||
*/
|
||||
user: User
|
||||
/**
|
||||
*
|
||||
* @type {Array<Role>}
|
||||
* @memberof DetailedUser
|
||||
*/
|
||||
roles: Array<Role>
|
||||
}
|
|
@ -31,6 +31,7 @@ export * from './counter-list'
|
|||
export * from './counter-request'
|
||||
export * from './custom-templates'
|
||||
export * from './dashboard-stats'
|
||||
export * from './detailed-user'
|
||||
export * from './excerpt'
|
||||
export * from './extension'
|
||||
export * from './file-reverse-proxy-provider'
|
||||
|
@ -49,6 +50,8 @@ export * from './listed-reply'
|
|||
export * from './listed-reply-list'
|
||||
export * from './listed-single-page'
|
||||
export * from './listed-single-page-list'
|
||||
export * from './listed-user'
|
||||
export * from './listed-user-list'
|
||||
export * from './login-history'
|
||||
export * from './menu'
|
||||
export * from './menu-item'
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import { ListedUser } from './listed-user'
|
||||
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ListedUserList
|
||||
*/
|
||||
export interface ListedUserList {
|
||||
/**
|
||||
* Page number, starts from 1. If not set or equal to 0, it means no pagination.
|
||||
* @type {number}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
page: number
|
||||
/**
|
||||
* Size of each page. If not set or equal to 0, it means no pagination.
|
||||
* @type {number}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
size: number
|
||||
/**
|
||||
* Total elements.
|
||||
* @type {number}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
total: number
|
||||
/**
|
||||
* A chunk of items.
|
||||
* @type {Array<ListedUser>}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
items: Array<ListedUser>
|
||||
/**
|
||||
* Indicates whether current page is the first page.
|
||||
* @type {boolean}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
first: boolean
|
||||
/**
|
||||
* Indicates whether current page is the last page.
|
||||
* @type {boolean}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
last: boolean
|
||||
/**
|
||||
* Indicates whether current page has previous page.
|
||||
* @type {boolean}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
hasNext: boolean
|
||||
/**
|
||||
* Indicates whether current page has previous page.
|
||||
* @type {boolean}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
hasPrevious: boolean
|
||||
/**
|
||||
* Indicates total pages.
|
||||
* @type {number}
|
||||
* @memberof ListedUserList
|
||||
*/
|
||||
totalPages: number
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* Halo Next API
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 2.0.0
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import { Role } from './role'
|
||||
// May contain unused imports in some cases
|
||||
// @ts-ignore
|
||||
import { User } from './user'
|
||||
|
||||
/**
|
||||
* A chunk of items.
|
||||
* @export
|
||||
* @interface ListedUser
|
||||
*/
|
||||
export interface ListedUser {
|
||||
/**
|
||||
*
|
||||
* @type {User}
|
||||
* @memberof ListedUser
|
||||
*/
|
||||
user: User
|
||||
/**
|
||||
*
|
||||
* @type {Array<Role>}
|
||||
* @memberof ListedUser
|
||||
*/
|
||||
roles: Array<Role>
|
||||
}
|
|
@ -18,7 +18,7 @@ import {
|
|||
useRouter,
|
||||
type RouteRecordRaw,
|
||||
} from "vue-router";
|
||||
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { nextTick, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import axios from "axios";
|
||||
import GlobalSearchModal from "@/components/global-search/GlobalSearchModal.vue";
|
||||
import LoginModal from "@/components/login/LoginModal.vue";
|
||||
|
@ -29,7 +29,7 @@ import { hasPermission } from "@/utils/permission";
|
|||
import { useUserStore } from "@/stores/user";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { useScroll } from "@vueuse/core";
|
||||
import { defineStore } from "pinia";
|
||||
import { defineStore, storeToRefs } from "pinia";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
|
@ -39,6 +39,8 @@ const moreMenuRootVisible = ref(false);
|
|||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { currentRoles, currentUser } = storeToRefs(userStore);
|
||||
|
||||
const handleLogout = () => {
|
||||
Dialog.warning({
|
||||
title: "确定要退出登录吗?",
|
||||
|
@ -58,19 +60,6 @@ const handleLogout = () => {
|
|||
});
|
||||
};
|
||||
|
||||
const currentRole = computed(() => {
|
||||
const names = JSON.parse(
|
||||
userStore.currentUser?.metadata.annotations?.[rbacAnnotations.ROLE_NAMES] ||
|
||||
"[]"
|
||||
);
|
||||
|
||||
if (names.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return roleStore.getRoleDisplayName(names[0]);
|
||||
});
|
||||
|
||||
// Global Search
|
||||
const globalSearchVisible = ref(false);
|
||||
|
||||
|
@ -249,24 +238,28 @@ onMounted(() => {
|
|||
</div>
|
||||
<div class="profile-placeholder">
|
||||
<div class="current-profile">
|
||||
<div v-if="userStore.currentUser?.spec.avatar" class="profile-avatar">
|
||||
<div v-if="currentUser?.spec.avatar" class="profile-avatar">
|
||||
<VAvatar
|
||||
:src="userStore.currentUser?.spec.avatar"
|
||||
:alt="userStore.currentUser?.spec.displayName"
|
||||
:src="currentUser?.spec.avatar"
|
||||
:alt="currentUser?.spec.displayName"
|
||||
size="md"
|
||||
circle
|
||||
></VAvatar>
|
||||
</div>
|
||||
<div class="profile-name">
|
||||
<div class="flex text-sm font-medium">
|
||||
{{ userStore.currentUser?.spec.displayName }}
|
||||
{{ currentUser?.spec.displayName }}
|
||||
</div>
|
||||
<div v-if="currentRole" class="flex">
|
||||
<div v-if="currentRoles?.[0]" class="flex">
|
||||
<VTag>
|
||||
<template #leftIcon>
|
||||
<IconUserSettings />
|
||||
</template>
|
||||
{{ currentRole }}
|
||||
{{
|
||||
currentRoles[0].metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] || currentRoles[0].metadata.name
|
||||
}}
|
||||
</VTag>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -244,9 +244,6 @@ async function initApp() {
|
|||
|
||||
await loadUserPermissions();
|
||||
|
||||
const roleStore = useRoleStore();
|
||||
await roleStore.fetchRoles();
|
||||
|
||||
try {
|
||||
await loadPluginModules();
|
||||
} catch (e) {
|
||||
|
|
|
@ -36,9 +36,7 @@ import Fuse from "fuse.js";
|
|||
import { usePermission } from "@/utils/permission";
|
||||
import { roleLabels } from "@/constants/labels";
|
||||
import { SUPER_ROLE_NAME } from "@/constants/constants";
|
||||
import { useRoleStore } from "@/stores/role";
|
||||
|
||||
const roleStore = useRoleStore();
|
||||
const { currentUserHasPermission } = usePermission();
|
||||
|
||||
const editingModal = ref<boolean>(false);
|
||||
|
@ -93,7 +91,6 @@ const handleOpenEditingModal = (role: Role) => {
|
|||
const onEditingModalClose = () => {
|
||||
selectedRole.value = undefined;
|
||||
handleFetchRoles();
|
||||
roleStore.fetchRoles();
|
||||
};
|
||||
|
||||
const handleCloneRole = async (role: Role) => {
|
||||
|
@ -143,7 +140,6 @@ const handleDelete = async (role: Role) => {
|
|||
console.error("Failed to delete role", e);
|
||||
} finally {
|
||||
handleFetchRoles();
|
||||
roleStore.fetchRoles();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,26 +1,13 @@
|
|||
<script lang="ts" setup>
|
||||
import { IconUserSettings, VTag } from "@halo-dev/components";
|
||||
import type { Ref } from "vue";
|
||||
import { computed, inject } from "vue";
|
||||
import { inject } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import type { DetailedUser } from "@halo-dev/api-client";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { useRoleStore } from "@/stores/role";
|
||||
|
||||
const user = inject<Ref<User>>("user");
|
||||
|
||||
const roleStore = useRoleStore();
|
||||
|
||||
const roles = computed(() => {
|
||||
const names = JSON.parse(
|
||||
user?.value?.metadata?.annotations?.[rbacAnnotations.ROLE_NAMES] || "[]"
|
||||
);
|
||||
|
||||
return names.map((name: string) => {
|
||||
return roleStore.getRoleDisplayName(name);
|
||||
});
|
||||
});
|
||||
const user = inject<Ref<DetailedUser | undefined>>("user");
|
||||
|
||||
const router = useRouter();
|
||||
</script>
|
||||
|
@ -32,7 +19,7 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">显示名称</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.spec?.displayName }}
|
||||
{{ user?.user.spec?.displayName }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -40,7 +27,7 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">用户名</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.metadata?.name }}
|
||||
{{ user?.user.metadata?.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -48,7 +35,7 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">电子邮箱</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.spec?.email || "未设置" }}
|
||||
{{ user?.user.spec?.email || "未设置" }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -57,14 +44,22 @@ const router = useRouter();
|
|||
<dt class="text-sm font-medium text-gray-900">角色</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
<VTag
|
||||
v-for="(role, index) in roles"
|
||||
v-for="(role, index) in user?.roles"
|
||||
:key="index"
|
||||
@click="router.push({ name: 'RoleDetail', params: { name: role } })"
|
||||
@click="
|
||||
router.push({
|
||||
name: 'RoleDetail',
|
||||
params: { name: role.metadata.name },
|
||||
})
|
||||
"
|
||||
>
|
||||
<template #leftIcon>
|
||||
<IconUserSettings />
|
||||
</template>
|
||||
{{ role }}
|
||||
{{
|
||||
role.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] ||
|
||||
role.metadata.name
|
||||
}}
|
||||
</VTag>
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -73,7 +68,7 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">描述</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.spec?.bio || "无" }}
|
||||
{{ user?.user.spec?.bio || "无" }}
|
||||
</dd>
|
||||
</div>
|
||||
<div
|
||||
|
@ -83,7 +78,7 @@ const router = useRouter();
|
|||
<dd
|
||||
class="mt-1 text-sm tabular-nums text-gray-900 sm:col-span-3 sm:mt-0"
|
||||
>
|
||||
{{ formatDatetime(user?.metadata?.creationTimestamp) }}
|
||||
{{ formatDatetime(user?.user.metadata?.creationTimestamp) }}
|
||||
</dd>
|
||||
</div>
|
||||
<!-- TODO: add display last login time support -->
|
||||
|
@ -93,7 +88,7 @@ const router = useRouter();
|
|||
>
|
||||
<dt class="text-sm font-medium text-gray-900">最近登录时间</dt>
|
||||
<dd class="mt-1 text-sm text-gray-900 sm:col-span-3 sm:mt-0">
|
||||
{{ user?.metadata?.creationTimestamp }}
|
||||
{{ user?.user.metadata?.creationTimestamp }}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
|
|
@ -25,13 +25,12 @@ import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
|||
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
||||
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { Role, User, UserList } from "@halo-dev/api-client";
|
||||
import type { Role, User, ListedUserList } from "@halo-dev/api-client";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { useRoleStore } from "@/stores/role";
|
||||
import { getNode } from "@formkit/core";
|
||||
import FilterTag from "@/components/filter/FilterTag.vue";
|
||||
import { useFetchRole } from "../roles/composables/use-role";
|
||||
|
@ -44,7 +43,7 @@ const editingModal = ref<boolean>(false);
|
|||
const passwordChangeModal = ref<boolean>(false);
|
||||
const grantPermissionModal = ref<boolean>(false);
|
||||
|
||||
const users = ref<UserList>({
|
||||
const users = ref<ListedUserList>({
|
||||
page: 1,
|
||||
size: 20,
|
||||
total: 0,
|
||||
|
@ -62,7 +61,6 @@ const keyword = ref("");
|
|||
const refreshInterval = ref();
|
||||
|
||||
const userStore = useUserStore();
|
||||
const roleStore = useRoleStore();
|
||||
|
||||
const ANONYMOUSUSER_NAME = "anonymousUser";
|
||||
const DELETEDUSER_NAME = "ghost";
|
||||
|
@ -99,7 +97,7 @@ const handleFetchUsers = async (options?: {
|
|||
users.value = data;
|
||||
|
||||
const deletedUsers = users.value.items.filter(
|
||||
(user) => !!user.metadata.deletionTimestamp
|
||||
(user) => !!user.user.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedUsers.length) {
|
||||
|
@ -188,7 +186,7 @@ const handleCheckAllChange = (e: Event) => {
|
|||
if (checked) {
|
||||
selectedUserNames.value =
|
||||
users.value.items.map((user) => {
|
||||
return user.metadata.name;
|
||||
return user.user.metadata.name;
|
||||
}) || [];
|
||||
} else {
|
||||
selectedUserNames.value.length = 0;
|
||||
|
@ -215,16 +213,6 @@ const handleOpenGrantPermissionModal = (user: User) => {
|
|||
grantPermissionModal.value = true;
|
||||
};
|
||||
|
||||
const getRoles = (user: User) => {
|
||||
const names = JSON.parse(
|
||||
user.metadata.annotations?.[rbacAnnotations.ROLE_NAMES] || "[]"
|
||||
);
|
||||
|
||||
return names.map((name: string) => {
|
||||
return roleStore.getRoleDisplayName(name);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleFetchUsers();
|
||||
});
|
||||
|
@ -521,14 +509,14 @@ const hasFilters = computed(() => {
|
|||
role="list"
|
||||
>
|
||||
<li v-for="(user, index) in users.items" :key="index">
|
||||
<VEntity :is-selected="checkSelection(user)">
|
||||
<VEntity :is-selected="checkSelection(user.user)">
|
||||
<template
|
||||
v-if="currentUserHasPermission(['system:users:manage'])"
|
||||
#checkbox
|
||||
>
|
||||
<input
|
||||
v-model="selectedUserNames"
|
||||
:value="user.metadata.name"
|
||||
:value="user.user.metadata.name"
|
||||
class="h-4 w-4 rounded border-gray-300 text-indigo-600"
|
||||
name="post-checkbox"
|
||||
type="checkbox"
|
||||
|
@ -538,18 +526,18 @@ const hasFilters = computed(() => {
|
|||
<VEntityField>
|
||||
<template #description>
|
||||
<VAvatar
|
||||
:alt="user.spec.displayName"
|
||||
:src="user.spec.avatar"
|
||||
:alt="user.user.spec.displayName"
|
||||
:src="user.user.spec.avatar"
|
||||
size="md"
|
||||
></VAvatar>
|
||||
</template>
|
||||
</VEntityField>
|
||||
<VEntityField
|
||||
:title="user.spec.displayName"
|
||||
:description="user.metadata.name"
|
||||
:title="user.user.spec.displayName"
|
||||
:description="user.user.metadata.name"
|
||||
:route="{
|
||||
name: 'UserDetail',
|
||||
params: { name: user.metadata.name },
|
||||
params: { name: user.user.metadata.name },
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
@ -557,17 +545,21 @@ const hasFilters = computed(() => {
|
|||
<VEntityField>
|
||||
<template #description>
|
||||
<div
|
||||
v-for="(role, roleIndex) in getRoles(user)"
|
||||
v-for="(role, roleIndex) in user.roles"
|
||||
:key="roleIndex"
|
||||
class="flex items-center"
|
||||
>
|
||||
<VTag>
|
||||
{{ role }}
|
||||
{{
|
||||
role.metadata.annotations?.[
|
||||
rbacAnnotations.DISPLAY_NAME
|
||||
] || role.metadata.name
|
||||
}}
|
||||
</VTag>
|
||||
</div>
|
||||
</template>
|
||||
</VEntityField>
|
||||
<VEntityField v-if="user.metadata.deletionTimestamp">
|
||||
<VEntityField v-if="user.user.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
|
@ -575,7 +567,7 @@ const hasFilters = computed(() => {
|
|||
<VEntityField>
|
||||
<template #description>
|
||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
||||
{{ formatDatetime(user.metadata.creationTimestamp) }}
|
||||
{{ formatDatetime(user.user.metadata.creationTimestamp) }}
|
||||
</span>
|
||||
</template>
|
||||
</VEntityField>
|
||||
|
@ -588,35 +580,37 @@ const hasFilters = computed(() => {
|
|||
v-close-popper
|
||||
block
|
||||
type="secondary"
|
||||
@click="handleOpenCreateModal(user)"
|
||||
@click="handleOpenCreateModal(user.user)"
|
||||
>
|
||||
修改资料
|
||||
</VButton>
|
||||
<VButton
|
||||
v-close-popper
|
||||
block
|
||||
@click="handleOpenPasswordChangeModal(user)"
|
||||
@click="handleOpenPasswordChangeModal(user.user)"
|
||||
>
|
||||
修改密码
|
||||
</VButton>
|
||||
<VButton
|
||||
v-if="
|
||||
userStore.currentUser?.metadata.name !== user.metadata.name
|
||||
userStore.currentUser?.metadata.name !==
|
||||
user.user.metadata.name
|
||||
"
|
||||
v-close-popper
|
||||
block
|
||||
@click="handleOpenGrantPermissionModal(user)"
|
||||
@click="handleOpenGrantPermissionModal(user.user)"
|
||||
>
|
||||
分配角色
|
||||
</VButton>
|
||||
<VButton
|
||||
v-if="
|
||||
userStore.currentUser?.metadata.name !== user.metadata.name
|
||||
userStore.currentUser?.metadata.name !==
|
||||
user.user.metadata.name
|
||||
"
|
||||
v-close-popper
|
||||
block
|
||||
type="danger"
|
||||
@click="handleDelete(user)"
|
||||
@click="handleDelete(user.user)"
|
||||
>
|
||||
删除
|
||||
</VButton>
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
import BasicLayout from "@/layouts/BasicLayout.vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { VButton, VSpace, VTabbar, VAvatar } from "@halo-dev/components";
|
||||
import { computed, onMounted, provide, ref, watch } from "vue";
|
||||
import { computed, onMounted, provide, ref, watch, type Ref } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import type { DetailedUser } from "@halo-dev/api-client";
|
||||
import UserEditingModal from "../components/UserEditingModal.vue";
|
||||
import UserPasswordChangeModal from "../components/UserPasswordChangeModal.vue";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
|
@ -26,7 +26,7 @@ const tabs = [
|
|||
// },
|
||||
];
|
||||
|
||||
const user = ref<User>();
|
||||
const user = ref<DetailedUser>();
|
||||
const loading = ref();
|
||||
const editingModal = ref(false);
|
||||
const passwordChangeModal = ref(false);
|
||||
|
@ -40,7 +40,7 @@ const handleFetchUser = async () => {
|
|||
const { data } = await apiClient.user.getCurrentUserDetail();
|
||||
user.value = data;
|
||||
} else {
|
||||
const { data } = await apiClient.extension.user.getv1alpha1User({
|
||||
const { data } = await apiClient.user.getUserDetail({
|
||||
name: params.name as string,
|
||||
});
|
||||
user.value = data;
|
||||
|
@ -56,10 +56,12 @@ const isCurrentUser = computed(() => {
|
|||
if (params.name === "-") {
|
||||
return true;
|
||||
}
|
||||
return user.value?.metadata.name === userStore.currentUser?.metadata.name;
|
||||
return (
|
||||
user.value?.user.metadata.name === userStore.currentUser?.metadata.name
|
||||
);
|
||||
});
|
||||
|
||||
provide("user", user);
|
||||
provide<Ref<DetailedUser | undefined>>("user", user);
|
||||
|
||||
const activeTab = ref();
|
||||
|
||||
|
@ -92,12 +94,12 @@ const handleTabChange = (id: string) => {
|
|||
<BasicLayout>
|
||||
<UserEditingModal
|
||||
v-model:visible="editingModal"
|
||||
:user="user"
|
||||
:user="user?.user"
|
||||
@close="handleFetchUser"
|
||||
/>
|
||||
<UserPasswordChangeModal
|
||||
v-model:visible="passwordChangeModal"
|
||||
:user="user"
|
||||
:user="user?.user"
|
||||
@close="handleFetchUser"
|
||||
/>
|
||||
<header class="bg-white">
|
||||
|
@ -107,8 +109,8 @@ const handleTabChange = (id: string) => {
|
|||
<div class="h-20 w-20">
|
||||
<VAvatar
|
||||
v-if="user"
|
||||
:src="user?.spec.avatar"
|
||||
:alt="user?.spec.displayName"
|
||||
:src="user.user.spec.avatar"
|
||||
:alt="user.user.spec.displayName"
|
||||
circle
|
||||
width="100%"
|
||||
height="100%"
|
||||
|
@ -117,10 +119,10 @@ const handleTabChange = (id: string) => {
|
|||
</div>
|
||||
<div class="block">
|
||||
<h1 class="truncate text-lg font-bold text-gray-900">
|
||||
{{ user?.spec.displayName }}
|
||||
{{ user?.user.spec.displayName }}
|
||||
</h1>
|
||||
<span v-if="!loading" class="text-sm text-gray-600">
|
||||
@{{ user?.metadata.name }}
|
||||
@{{ user?.user.metadata.name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,37 +1,12 @@
|
|||
import { defineStore } from "pinia";
|
||||
import type { Role, UserPermission } from "@halo-dev/api-client";
|
||||
import type { UserPermission } from "@halo-dev/api-client";
|
||||
import { ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { roleLabels } from "@/constants/labels";
|
||||
import { rbacAnnotations } from "@/constants/annotations";
|
||||
|
||||
export const useRoleStore = defineStore("role", () => {
|
||||
const roles = ref<Role[]>([]);
|
||||
const permissions = ref<UserPermission>({
|
||||
roles: [],
|
||||
uiPermissions: [],
|
||||
});
|
||||
|
||||
async function fetchRoles() {
|
||||
try {
|
||||
const { data } = await apiClient.extension.role.listv1alpha1Role(
|
||||
{
|
||||
page: 0,
|
||||
size: 0,
|
||||
labelSelector: [`!${roleLabels.TEMPLATE}`],
|
||||
},
|
||||
{ mute: true }
|
||||
);
|
||||
roles.value = data.items;
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch roles", error);
|
||||
}
|
||||
}
|
||||
|
||||
function getRoleDisplayName(name: string) {
|
||||
const role = roles.value.find((role) => role.metadata.name === name);
|
||||
return role?.metadata.annotations?.[rbacAnnotations.DISPLAY_NAME] || name;
|
||||
}
|
||||
|
||||
return { roles, permissions, fetchRoles, getRoleDisplayName };
|
||||
return { permissions };
|
||||
});
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { User } from "@halo-dev/api-client";
|
||||
import type { Role, User } from "@halo-dev/api-client";
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
interface UserStoreState {
|
||||
currentUser?: User;
|
||||
currentRoles?: Role[];
|
||||
isAnonymous: boolean;
|
||||
loginModalVisible: boolean;
|
||||
}
|
||||
|
@ -11,6 +12,7 @@ interface UserStoreState {
|
|||
export const useUserStore = defineStore("user", {
|
||||
state: (): UserStoreState => ({
|
||||
currentUser: undefined,
|
||||
currentRoles: [],
|
||||
isAnonymous: true,
|
||||
loginModalVisible: false,
|
||||
}),
|
||||
|
@ -18,8 +20,9 @@ export const useUserStore = defineStore("user", {
|
|||
async fetchCurrentUser() {
|
||||
try {
|
||||
const { data } = await apiClient.user.getCurrentUserDetail();
|
||||
this.currentUser = data;
|
||||
this.isAnonymous = data.metadata.name === "anonymousUser";
|
||||
this.currentUser = data.user;
|
||||
this.currentRoles = data.roles;
|
||||
this.isAnonymous = data.user.metadata.name === "anonymousUser";
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch current user", e);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue