feat: support roles management

Signed-off-by: Ryan Wang <i@ryanc.cc>
pull/588/head
Ryan Wang 2022-06-28 13:54:45 +08:00
parent e54faab91e
commit f825047eb5
6 changed files with 71 additions and 76 deletions

View File

@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
const token = const token =
"eyJhbGciOiJSUzUxMiJ9.eyJpc3MiOiJIYWxvIE93bmVyIiwic3ViIjoiYWRtaW4iLCJleHAiOjE2NTYzODYyODYsImlhdCI6MTY1NjI5OTg4Niwic2NvcGUiOlsiUk9MRV9zdXBlci1yb2xlIl19.uiBxplxctL3a8G_pNWJzEKEMD-a11VPygHh-yUmm3jaZadt5KWIonkuMl3bSASC96NJn3Lmo1OtSagWIkRWUrWqM4r4_sj3NDOiDpcjxy2msrpe8v9sp_BA4yGjAoaoMBEvdjZ3sQ7L9gJKHhL9bTNsXiSkjS5b7OJLujuF5VFJMp-fmzUDz8-EC5u43wz8MUF88bMk4gUg3nOJYnSTRlrU6759IggEM_0SjZu9wewcLxxa4Vhson_mN6hTObsOyWYjMjTbMlSBQiDfN9IXZ2cRZTnE2me0pT6J0AyP33qBp69B-K0cTaUO2Tcx5_BuWHGUCFUAFwE5FKchGgr6NuA" "eyJhbGciOiJSUzUxMiJ9.eyJpc3MiOiJIYWxvIE93bmVyIiwic3ViIjoiYWRtaW4iLCJleHAiOjE2NTY0NzM3NTMsImlhdCI6MTY1NjM4NzM1Mywic2NvcGUiOlsiUk9MRV9zdXBlci1yb2xlIl19.vJ7l6jo3CJv7h4XTDvqjY70qngpaiiYhJL7_vXNPRY2Rz2NdmosMzy-BIRYPRuJnhU33uQ5LjXY5K2YwyQinrIsT66JsfckuYi6slAQY2rUC3929wC3gBcMJp9Z--VGRA701vDoecGWnGh68XR-RCK_uGcMnNhC4A1bCsb-nrn4TYdUndM0Aa2OsGP6G0IjzuyvXwwoAGB2JojBdGzXVz2KujHsaELziAZ2Kx78wsEIREN0pZGXnapB1-0nqgjLQ9VuGl62bRAkyzirwbasgB6Tk8njz-TR_uIL-smyWt_LUwX5I97lrM5VCtMmBlT999_Zi8MgzWTHeEUobzbI4ng";
const axiosInstance = axios.create({ const axiosInstance = axios.create({
headers: { headers: {
Authorization: `Bearer ${token}`, Authorization: `Bearer ${token}`,

View File

@ -10,29 +10,39 @@ import {
VTag, VTag,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { roles } from "@/modules/system/roles/roles-mock"; import { onMounted, ref } from "vue";
import { ref } from "vue";
import { users } from "@/modules/system/users/users-mock"; import { users } from "@/modules/system/users/users-mock";
import { axiosInstance } from "@halo-dev/admin-shared";
import type { Role } from "@/types/extension";
const route = useRoute(); const route = useRoute();
const role = ref(); const role = ref<Role>();
const roleActiveId = ref("detail"); const roleActiveId = ref("detail");
if (route.params.id) { const handleFetchRole = async () => {
role.value = roles.find((r) => r.id === Number(route.params.id)); try {
} else { const response = await axiosInstance.get(
role.value = roles[0]; `/api/v1alpha1/roles/${route.params.name}`
} );
role.value = response.data;
} catch (error) {
console.error(error);
}
};
const router = useRouter(); const router = useRouter();
const handleRouteToUser = (username: string) => { const handleRouteToUser = (username: string) => {
router.push({ name: "UserDetail", params: { username } }); router.push({ name: "UserDetail", params: { username } });
}; };
onMounted(() => {
handleFetchRole();
});
</script> </script>
<template> <template>
<VPageHeader :title="`角色:${role.name}`"> <VPageHeader :title="`角色:${role?.metadata?.name}`">
<template #icon> <template #icon>
<IconShieldUser class="mr-2 self-center" /> <IconShieldUser class="mr-2 self-center" />
</template> </template>
@ -64,7 +74,7 @@ const handleRouteToUser = (username: string) => {
<p <p
class="mt-1 flex max-w-2xl items-center gap-2 text-sm text-gray-500" class="mt-1 flex max-w-2xl items-center gap-2 text-sm text-gray-500"
> >
<span>包含 {{ role.permissions }} 个权限</span> <span>包含 {{ role?.rules?.length }} 个权限</span>
</p> </p>
</div> </div>
<div class="border-t border-gray-200"> <div class="border-t border-gray-200">
@ -74,7 +84,7 @@ const handleRouteToUser = (username: string) => {
> >
<dt class="text-sm font-medium text-gray-900">名称</dt> <dt class="text-sm font-medium text-gray-900">名称</dt>
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0"> <dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
{{ role.name }} {{ role?.metadata?.name }}
</dd> </dd>
</div> </div>
<div <div
@ -82,7 +92,7 @@ const handleRouteToUser = (username: string) => {
> >
<dt class="text-sm font-medium text-gray-900">别名</dt> <dt class="text-sm font-medium text-gray-900">别名</dt>
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0"> <dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
{{ role.slug }} {{ role?.metadata?.name }}
</dd> </dd>
</div> </div>
<div <div
@ -106,7 +116,7 @@ const handleRouteToUser = (username: string) => {
> >
<dt class="text-sm font-medium text-gray-900">创建时间</dt> <dt class="text-sm font-medium text-gray-900">创建时间</dt>
<dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0"> <dd class="mt-1 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
2020-01-01 {{ role?.metadata?.creationTimestamp }}
</dd> </dd>
</div> </div>
<div <div

View File

@ -12,17 +12,31 @@ import {
VSpace, VSpace,
VTag, VTag,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { roles } from "./roles-mock";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { ref } from "vue"; import { onMounted, ref } from "vue";
import type { Role } from "@/types/extension";
import { axiosInstance } from "@halo-dev/admin-shared";
const createVisible = ref(false); const createVisible = ref(false);
const roles = ref<Role[]>([]);
const router = useRouter(); const router = useRouter();
const handleRouteToDetail = (id: number) => { const handleFetchRoles = async () => {
router.push({ name: "RoleDetail", params: { id } }); try {
const { data } = await axiosInstance.get("/api/v1alpha1/roles");
roles.value = data;
} catch (e) {
console.error(e);
}
}; };
const handleRouteToDetail = (name: string) => {
router.push({ name: "RoleDetail", params: { name } });
};
onMounted(() => {
handleFetchRoles();
});
</script> </script>
<template> <template>
<VModal v-model:visible="createVisible" title="新建角色"></VModal> <VModal v-model:visible="createVisible" title="新建角色"></VModal>
@ -140,7 +154,7 @@ const handleRouteToDetail = (id: number) => {
<li <li
v-for="(role, index) in roles" v-for="(role, index) in roles"
:key="index" :key="index"
@click="handleRouteToDetail(role.id)" @click="handleRouteToDetail(role.metadata.name)"
> >
<div <div
class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50" class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50"
@ -149,12 +163,12 @@ const handleRouteToDetail = (id: number) => {
<div class="flex-1"> <div class="flex-1">
<div class="flex flex-row items-center"> <div class="flex flex-row items-center">
<span class="mr-2 truncate text-sm font-medium text-gray-900"> <span class="mr-2 truncate text-sm font-medium text-gray-900">
{{ role.name }} {{ role.metadata.name }}
</span> </span>
</div> </div>
<div class="mt-2 flex"> <div class="mt-2 flex">
<span class="text-xs text-gray-500"> <span class="text-xs text-gray-500">
包含 {{ role.permissions }} 个权限 包含 {{ role.rules?.length }} 个权限
</span> </span>
</div> </div>
</div> </div>
@ -166,7 +180,7 @@ const handleRouteToDetail = (id: number) => {
class="hidden text-sm text-gray-500 hover:text-gray-900 sm:block" class="hidden text-sm text-gray-500 hover:text-gray-900 sm:block"
target="_blank" target="_blank"
> >
{{ role.users }} 个用户 0 个用户
</a> </a>
<VTag> 系统保留</VTag> <VTag> 系统保留</VTag>
<time class="text-sm text-gray-500" datetime="2020-01-07"> <time class="text-sm text-gray-500" datetime="2020-01-07">

View File

@ -16,7 +16,7 @@ export default definePlugin({
component: RoleList, component: RoleList,
}, },
{ {
path: "roles/:id", path: "roles/:name",
name: "RoleDetail", name: "RoleDetail",
component: RoleDetail, component: RoleDetail,
}, },

View File

@ -1,30 +0,0 @@
export const roles = [
{
id: 1,
name: "Super Administrator",
slug: "super-administrator",
permissions: 100,
users: 10,
},
{
id: 2,
name: "Administrator",
slug: "administrator",
permissions: 32,
users: 5,
},
{
id: 3,
name: "Editor",
slug: "editor",
permissions: 10,
users: 3,
},
{
id: 4,
name: "Guest",
slug: "guest",
permissions: 5,
users: 10232,
},
];

View File

@ -10,28 +10,29 @@ import {
VTabItem, VTabItem,
VTabs, VTabs,
} from "@halo-dev/components"; } from "@halo-dev/components";
import { ref } from "vue"; import { onMounted, ref } from "vue";
import type { PersonalAccessToken } from "@/types/extension";
import { axiosInstance } from "@halo-dev/admin-shared";
const createVisible = ref(false); const createVisible = ref(false);
const createActiveId = ref("general"); const createActiveId = ref("general");
const tokens = ref([ const personalAccessTokens = ref<PersonalAccessToken[]>([]);
{
id: 1, const handleFetchPersonalAccessTokens = async () => {
name: "小程序", try {
token: "...SlR6vi_BkwqjYcVgHrhA", const response = await axiosInstance.get(
}, "/api/v1alpha1/personalaccesstokens"
{ );
id: 2, personalAccessTokens.value = response.data;
name: "App", } catch (e) {
token: "...SlR6vi_BkwqjYcVgHrhA", console.error(e);
}, }
{ };
id: 3,
name: "Raycast", onMounted(() => {
token: "...SlR6vi_BkwqjYcVgHrhA", handleFetchPersonalAccessTokens();
}, });
]);
</script> </script>
<template> <template>
<VModal v-model:visible="createVisible" :width="720" title="创建个人令牌"> <VModal v-model:visible="createVisible" :width="720" title="创建个人令牌">
@ -269,7 +270,7 @@ const tokens = ref([
class="mt-5 box-border h-full w-full divide-y divide-gray-100" class="mt-5 box-border h-full w-full divide-y divide-gray-100"
role="list" role="list"
> >
<li v-for="(token, index) in tokens" :key="index"> <li v-for="(token, index) in personalAccessTokens" :key="index">
<div <div
class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50" class="relative block cursor-pointer px-4 py-3 transition-all hover:bg-gray-50"
> >
@ -277,12 +278,12 @@ const tokens = ref([
<div class="flex-1"> <div class="flex-1">
<div class="flex flex-row items-center"> <div class="flex flex-row items-center">
<span class="mr-2 truncate text-sm font-medium text-gray-900"> <span class="mr-2 truncate text-sm font-medium text-gray-900">
{{ token.name }} {{ token.spec?.displayName }}
</span> </span>
</div> </div>
<div class="mt-2 flex"> <div class="mt-2 flex">
<span class="text-xs text-gray-500"> <span class="text-xs text-gray-500">
{{ token.token }} {{ token.spec?.tokenDigest }}
</span> </span>
</div> </div>
</div> </div>
@ -292,10 +293,10 @@ const tokens = ref([
> >
<div class="flex flex-col gap-1"> <div class="flex flex-col gap-1">
<time class="text-xs text-gray-500" datetime="2020-01-07"> <time class="text-xs text-gray-500" datetime="2020-01-07">
创建日期2020-01-07 12:00:00 创建日期{{ token.metadata?.creationTimestamp }}
</time> </time>
<time class="text-xs text-gray-500" datetime="2020-01-07"> <time class="text-xs text-gray-500" datetime="2020-01-07">
失效日期永久 失效日期{{ token.spec?.expiresAt }}
</time> </time>
</div> </div>
<span class="cursor-pointer hover:text-red-600"> <span class="cursor-pointer hover:text-red-600">