七、项目搭建-权限管理,首页,暗黑模式

248 阅读3分钟

权限管理

1、用户管理
1.1 功能展示

image-20230902231658039.png

image-20230902231749762.png

image-20230902231822783.png

1.2 代码实现

1、定义数据类型project\src\api\acl\user\type.ts

//账号信息的ts类型
export interface ResponseData {
    code: number,
    message: string,
    ok: boolean
}
//代表一个账号信息的ts类型
export interface User {
    id?: number,
    "createTime"?: string,
    "updateTime"?: string,
    "username"?: string,
    "password"?: string,
    "name"?: string,
    "phone"?: null,
    "roleName"?: string
}
//数组包含全部的用户信息
export type Records = User[];
//获取全部用户信息接口返回的数据ts类型
export interface UserResponseData extends ResponseData {
    data: {
        records: Records,
        "total": number,
        "size": number,
        "current": number,
        "pages": number
    }
}
​
//代表一个职位的ts类型
export interface RoleData {
    "id"?: number,
    "createTime"?: string,
    "updateTime"?: string,
    "roleName": string,
    "remark": null
}
//全部职位的列表
export type AllRole = RoleData[];
//获取全部职位的接口返回的数据ts类型
export interface AllRoleResponseData extends ResponseData {
    data: {
        assignRoles: AllRole,
        allRolesList: AllRole
    }
}
​
//给用户分配职位接口携带参数的ts类型
export interface SetRoleData {
    "roleIdList": number[],
    "userId": number
}
  1. 定义接口api: project\src\api\acl\user\index.ts

    //用户管理模块的接口
    import request from "@/utils/request";
    import type { UserResponseData, User, AllRoleResponseData, SetRoleData } from "./type";
    //枚举地址
    enum API {
        //获取全部已有用户账号信息
        ALLUSER_URL = '/admin/acl/user/',
        //添加一个新的用户账号
        ADDUSER_URL = "/admin/acl/user/save",
        //更新已有的用户账号
        UPDATEUSER_URL = '/admin/acl/user/update',
        //获取全部职位,当前账号拥有的职位接口
        ALLROLEURL = '/admin/acl/user/toAssign/',
        //给已有的用户分配角色接口
        SETROLE_URL = '/admin/acl/user/doAssignRole',
        //删除某一个账号
        DELETEUSER_URL = '/admin/acl/user/remove/',
        //批量删除的接口
        DELETEALLUSER_URL = '/admin/acl/user/batchRemove'
    ​
    }
    //获取用户账号信息的接口
    export const reqUserInfo = (page: number, limit: number, username: string) => request.get<any, UserResponseData>(API.ALLUSER_URL + `${page}/${limit}/?username=${username}`);
    //添加用户与更新已有用户的接口
    export const reqAddOrUpdateUser = (data: User) => {
        //携带参数有ID更新
        if (data.id) {
            return request.put<any, any>(API.UPDATEUSER_URL, data);
        } else {
            return request.post<any, any>(API.ADDUSER_URL, data);
        }
    }
    //获取全部职位以及包含当前用户的已有的职位
    export const reqAllRole = (userId: number) => request.get<any, AllRoleResponseData>(API.ALLROLEURL + userId);
    //分配职位
    export const reqSetUserRole = (data: SetRoleData) => request.post<any, any>(API.SETROLE_URL, data);
    //删除某一个账号的信息
    export const reqRemoveUser = (userId: number) => request.delete<any, any>(API.DELETEUSER_URL + userId);
    //批量删除的接口
    export const reqSelectUser = (idList: number[]) => request.delete(API.DELETEALLUSER_URL, { data: idList });
    
2、角色管理
2.1 功能展示

image-20230902231941946.png

image-20230902232003959.png

image-20230902232031172.png

2.2 代码实现
  1. project\src\api\acl\role\type.ts

    export interface ResponseData {
        code: number,
        message: string,
        ok: boolean
    }
    //职位数据类型
    export interface RoleData {
        "id"?: number,
        "createTime"?: string,
        "updateTime"?: string,
        "roleName": string,
        "remark"?: null
    }
    ​
    //全部职位的数组的ts类型
    export type Records = RoleData[];
    //全部职位数据的相应的ts类型
    export interface RoleResponseData extends ResponseData {
        data: {
            records: Records,
            "total": number,
            "size": number,
            "current": number,
            "orders": [],
            "optimizeCountSql": boolean,
            "hitCount": boolean,
            "countId": null,
            "maxLimit": null,
            "searchCount": boolean,
            "pages": number
        }
    }
    ​
    ​
    //菜单与按钮数据的ts类型
    export interface MunuData {
        "id": number,
        "createTime": string,
        "updateTime": string,
        "pid": number,
        "name": string,
        "code": string,
        "toCode": string,
        "type": number,
        "status": null,
        "level": number,
        "children"?: MenuList,
        "select": boolean
    }
    export type MenuList = MunuData[];
    ​
    //菜单权限与按钮权限数据的ts类型
    export interface MenuResponseData extends ResponseData {
        data: MenuList
    }
    
  2. project\src\api\acl\role\index.ts

    //角色管理模块的的接口
    import request from "@/utils/request";
    import type { RoleResponseData, RoleData, MenuResponseData } from './type'
    //枚举地址
    enum API {
        //获取全部的职位接口
        ALLROLE_URL = '/admin/acl/role/',
        //新增岗位的接口地址
        ADDROLE_URL = '/admin/acl/role/save',
        //更新已有的职位
        UPDATEROLE_URL = '/admin/acl/role/update',
        //获取全部的菜单与按钮的数据
        ALLPERMISSTION = "/admin/acl/permission/toAssign/",
        //给相应的职位分配权限
        SETPERMISTION_URL = '/admin/acl/permission/doAssign/?',
        //删除已有的职位
        REMOVEROLE_URL = '/admin/acl/role/remove/'
    }
    //获取全部的角色
    export const reqAllRoleList = (page: number, limit: number, roleName: string) => request.get<any, RoleResponseData>(API.ALLROLE_URL + `${page}/${limit}/?roleName=${roleName}`);
    //添加职位与更新已有职位接口
    export const reqAddOrUpdateRole = (data: RoleData) => {
        if (data.id) {
            return request.put<any, any>(API.UPDATEROLE_URL, data);
        } else {
            return request.post<any, any>(API.ADDROLE_URL, data);
        }
    }
    ​
    //获取全部菜单与按钮权限数据
    export const reqAllMenuList = (roleId: number) => request.get<any, MenuResponseData>(API.ALLPERMISSTION + roleId);
    //给相应的职位下发权限
    export const reqSetPermisstion = (roleId: number, permissionId: number[]) => request.post(API.SETPERMISTION_URL + `roleId=${roleId}&permissionId=${permissionId}`);
    //删除已有的职位
    export const reqRemoveRole = (roleId: number) => request.delete<any, any>(API.REMOVEROLE_URL + roleId)
    
  3. project\src\views\acl\role\index.vue

<template>
    <el-card>
        <el-form :inline="true" class="form">
            <el-form-item label="职位搜索">
                <el-input placeholder="请你输入搜索职位关键字" v-model="keyword"></el-input>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" size="default" :disabled="keyword ? false : true" @click="search">搜索</el-button>
                <el-button type="primary" size="default" @click="reset">重置</el-button>
            </el-form-item>
        </el-form>
    </el-card>
    <el-card style="margin: 10px 0px;">
        <el-button type="primary" size="default" icon="Plus" @click="addRole">添加职位</el-button>
        <el-table border style="margin: 10px 0px;" :data="allRole">
            <el-table-column type="index" align="center" label="#"></el-table-column>
            <el-table-column label="ID" align="center" prop="id"></el-table-column>
            <el-table-column label="职位名称" align="center" prop="roleName" show-overflow-tooltip></el-table-column>
            <el-table-column label="创建世间" align="center" show-overflow-tooltip prop="createTime"></el-table-column>
            <el-table-column label="更新时间" align="center" show-overflow-tooltip prop="updateTime"></el-table-column>
            <el-table-column label="操作" width="280px" align="center">
                <!-- row:已有的职位对象 -->
                <template #="{ row, $index }">
                    <el-button type="primary" size="small" icon="User" @click="setPermisstion(row)">分配权限</el-button>
                    <el-button type="primary" size="small" icon="Edit" @click="updateRole(row)">编辑</el-button>
                    <el-popconfirm :title="`你确定要删除${row.roleName}?`" width="260px" @confirm="removeRole(row.id)">
                        <template #reference>
                            <el-button type="primary" size="small" icon="Delete">删除</el-button>
                        </template>
                    </el-popconfirm>
                </template>
            </el-table-column>
        </el-table>
        <el-pagination v-model:current-page="pageNo" v-model:page-size="pageSize" :page-sizes="[10, 20, 30, 40]"
            :background="true" layout="prev, pager, next, jumper,->,sizes,total" :total="total" @current-change="getHasRole"
            @size-change="sizeChange" />
    </el-card>
    <!-- 添加职位与更新已有职位的结构:对话框 -->
    <el-dialog v-model="dialogVisite" :title="RoleParams.id ? '更新职位' : '添加职位'">
        <el-form :model="RoleParams" :rules="rules" ref="form">
            <el-form-item label="职位名称" prop="roleName">
                <el-input placeholder="请你输入职位名称" v-model="RoleParams.roleName"></el-input>
            </el-form-item>
        </el-form>
        <template #footer>
            <el-button type="primary" size="default" @click="dialogVisite = false">取消</el-button>
            <el-button type="primary" size="default" @click="save">确定</el-button>
        </template>
    </el-dialog>
    <!-- 抽屉组件:分配职位的菜单权限与按钮的权限 -->
    <el-drawer v-model="drawer">
        <template #header>
            <h4>分配菜单与按钮的权限</h4>
        </template>
        <template #default>
            <!-- 树形控件 -->
            <el-tree ref="tree" :data="menuArr" show-checkbox node-key="id" default-expand-all
                :default-checked-keys="selectArr" :props="defaultProps" />
        </template>
        <template #footer>
            <div style="flex: auto">
                <el-button @click="drawer = false">取消</el-button>
                <el-button type="primary" @click="handler">确定</el-button>
            </div>
        </template>
    </el-drawer>
</template><script setup lang="ts">
import { ref, onMounted, reactive, nextTick } from 'vue';
//请求方法
import { reqRemoveRole, reqAllRoleList, reqAddOrUpdateRole, reqAllMenuList, reqSetPermisstion } from '@/api/acl/role';
import type { RoleResponseData, Records, RoleData, MenuResponseData, MenuList } from '@/api/acl/role/type'
//引入骨架的仓库
import useLayOutSettingStore from '@/store/modules/setting';
import { ElMessage } from 'element-plus';
let settingStore = useLayOutSettingStore();
//当前页码
let pageNo = ref<number>(1);
//一页展示几条数据
let pageSize = ref<number>(10);
//搜索职位关键字
let keyword = ref<string>('');
//存储全部已有的职位
let allRole = ref<Records>([]);
//职位总个数
let total = ref<number>(0);
//控制对话框的显示与隐藏
let dialogVisite = ref<boolean>(false);
//获取form组件实例
let form = ref<any>();
//控制抽屉显示与隐藏
let drawer = ref<boolean>(false);
//收集新增岗位数据
let RoleParams = reactive<RoleData>({
    roleName: ''
})
//准备一个数组:数组用于存储勾选的节点的ID(四级的)
let selectArr = ref<number[]>([]);
//定义数组存储用户权限的数据
let menuArr = ref<MenuList>([]);
//获取tree组件实例
let tree = ref<any>();
//组件挂载完毕
onMounted(() => {
    //获取职位请求
    getHasRole();
});
//获取全部用户信息的方法|分页器当前页码发生变化的回调
const getHasRole = async (pager = 1) => {
    //修改当前页码
    pageNo.value = pager;
    let result: RoleResponseData = await reqAllRoleList(pageNo.value, pageSize.value, keyword.value);
    if (result.code == 200) {
        total.value = result.data.total;
        allRole.value = result.data.records;
    }
}
//下拉菜单的回调
const sizeChange = () => {
    getHasRole();
}
//搜索按钮的回调
const search = () => {
    //再次发请求根据关键字
    getHasRole();
    keyword.value = '';
}
//重置按钮的回调
const reset = () => {
    settingStore.refsh = !settingStore.refsh;
}
//添加职位按钮的回调
const addRole = () => {
    //对话框显示出来
    dialogVisite.value = true;
    //清空数据
    Object.assign(RoleParams, {
        roleName: '',
        id: 0
    });
    //清空上一次表单校验错误结果
    nextTick(() => {
        form.value.clearValidate('roleName');
    })
​
}
//更新已有的职位按钮的回调
const updateRole = (row: RoleData) => {
    //显示出对话框
    dialogVisite.value = true;
    //存储已有的职位----带有ID的
    Object.assign(RoleParams, row);
    //清空上一次表单校验错误结果
    nextTick(() => {
        form.value.clearValidate('roleName');
    })
}
//自定义校验规则的回调
const validatorRoleName = (rule: any, value: any, callBack: any) => {
    if (value.trim().length >= 2) {
        callBack();
    } else {
        callBack(new Error('职位名称至少两位'))
    }
}
//职位校验规则
const rules = {
    roleName: [
        { required: true, trigger: 'blur', validator: validatorRoleName }
    ]
}
​
//确定按钮的回调
const save = async () => {
    //表单校验结果,结果通过在发请求、结果没有通过不应该在发生请求
    await form.value.validate();
    //添加职位|更新职位的请求
    let result: any = await reqAddOrUpdateRole(RoleParams);
    if (result.code == 200) {
        //提示文字
        ElMessage({ type: 'success', message: RoleParams.id ? '更新成功' : '添加成功' });
        //对话框显示
        dialogVisite.value = false;
        //再次获取全部的已有的职位
        getHasRole(RoleParams.id ? pageNo.value : 1);
    }
}
​
//分配权限按钮的回调
//已有的职位的数据
const setPermisstion = async (row: RoleData) => {
    //抽屉显示出来
    drawer.value = true;
    //收集当前要分类权限的职位的数据
    Object.assign(RoleParams, row);
    //根据职位获取权限的数据
    let result: MenuResponseData = await reqAllMenuList((RoleParams.id as number));
    if (result.code == 200) {
        menuArr.value = result.data;
        selectArr.value = filterSelectArr(menuArr.value, []);
    }
}
//树形控件的测试数据
const defaultProps = {
    children: 'children',
    label: 'name',
}
​
const filterSelectArr = (allData: any, initArr: any) => {
    allData.forEach((item: any) => {
        if (item.select && item.level == 4) {
            initArr.push(item.id);
        }
        if (item.children && item.children.length > 0) {
            filterSelectArr(item.children, initArr);
        }
    })
​
    return initArr;
}
​
//抽屉确定按钮的回调
const handler = async () => {
    //职位的ID
    const roleId = (RoleParams.id as number);
    //选中节点的ID
    let arr = tree.value.getCheckedKeys();
    //半选的ID
    let arr1 = tree.value.getHalfCheckedKeys();
    let permissionId = arr.concat(arr1);
    //下发权限
    let result: any = await reqSetPermisstion(roleId, permissionId);
    if (result.code == 200) {
        //抽屉关闭
        drawer.value = false;
        //提示信息
        ElMessage({ type: 'success', message: '分配权限成功' });
        //页面刷新
        window.location.reload();
    }
}
​
//删除已有的职位
const removeRole = async (id: number) => {
    let result: any = await reqRemoveRole(id);
    if (result.code == 200) {
        //提示信息
        ElMessage({ type: 'success', message: '删除成功' });
        getHasRole(allRole.value.length > 1 ? pageNo.value : pageNo.value - 1);
    }
}
</script><style scoped>
.form {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 50px;
}
</style>
3、菜单管理
3.1 功能展示

image-20230902232430935.png

image-20230902232458238.png

image-20230902232558769.png

3.2 代码实现
  1. project\src\api\acl\menu\type.ts

    //数据类型定义
    export interface ResponseData {
        code: number,
        message: string,
        ok: boolean
    }
    //菜单数据与按钮数据的ts类型
    export interface Permisstion {
        "id"?: number,
        "createTime": string,
        "updateTime": string,
        "pid": number,
        "name": string,
        "code": null,
        "toCode": null,
        "type": number,
        "status": null,
        "level": number,
        "children"?: PermisstionList,
        "select": boolean
    }
    export type PermisstionList = Permisstion[];
    //菜单接口返回的数据类型
    export interface PermisstionResponseData extends ResponseData {
        data: PermisstionList
    }
    ​
    //添加与修改菜单携带的参数的ts类型
    export interface MenuParams {
        id?: number,//ID
        "code": string,//权限数值
        "level": number,//几级菜单
        "name": string,//菜单的名字
        "pid": number,//菜单的ID
    }
    
  2. project\src\api\acl\menu\index.ts

    import request from "@/utils/request";
    import type { PermisstionResponseData, MenuParams } from './type';
    //枚举地址
    enum API {
        //获取全部菜单与按钮的标识数据
        ALLPERMISSTION_URL = '/admin/acl/permission',
        //给某一级菜单新增一个子菜单
        ADDMENU_URL = '/admin/acl/permission/save',
        //更新某一个已有的菜单
        UPDATE_URL = '/admin/acl/permission/update',
        //删除已有的菜单
        DELETEMENU_URL = '/admin/acl/permission/remove/'
    }
    //获取菜单数据
    export const reqAllPermisstion = () => request.get<any, PermisstionResponseData>(API.ALLPERMISSTION_URL);
    //添加与更新菜单的方法
    export const reqAddOrUpdateMenu = (data: MenuParams) => {
        if (data.id) {
            return request.put<any, any>(API.UPDATE_URL, data);
        } else {
            return request.post<any, any>(API.ADDMENU_URL, data);
        }
    }
    ​
    //删除某一个已有的菜单
    export const reqRemoveMenu = (id: number) => request.delete<any, any>(API.DELETEMENU_URL + id);
    ​
    
  3. project\src\views\acl\permission\index.vue

<template>
    <el-table :data="PermisstionArr" style="width: 100%; margin-bottom: 20px" row-key="id" border>
        <el-table-column label="名称" prop="name"></el-table-column>
        <el-table-column label="权限值" prop="code"></el-table-column>
        <el-table-column label="修改时间" prop="updateTime"></el-table-column>
        <el-table-column label="操作">
            <!-- row:即为已有的菜单对象|按钮的对象的数据 -->
            <template #="{ row, $index }">
                <el-button type="primary" @click="addPermisstion(row)" size="small"
                    :disabled="row.level == 4 ? true : false">{{
                        row.level == 3 ? '添加功能'
                        : '添加菜单' }}</el-button>
                <el-button type="primary" @click="updatePermisstion(row)" size="small"
                    :disabled="row.level == 1 ? true : false">编辑</el-button>
                <el-popconfirm :title="`你确定要删除${row.name}?`" width="260px" @confirm="removeMenu(row.id)">
                    <template #reference>
                        <el-button type="primary" size="small" :disabled="row.level == 1 ? true : false">删除</el-button>
                    </template>
                </el-popconfirm>
​
            </template>
        </el-table-column>
    </el-table>
    <!-- 对话框组件:添加或者更新已有的菜单的数据结构 -->
    <el-dialog v-model="dialogVisible" :title="menuData.id ? '更新菜单' : '添加菜单'">
        <!-- 表单组件:收集新增与已有的菜单的数据 -->
        <el-form>
            <el-form-item label="名称">
                <el-input placeholder="请你输入菜单名称" v-model="menuData.name"></el-input>
            </el-form-item>
            <el-form-item label="权限">
                <el-input placeholder="请你输入权限数值" v-model="menuData.code"></el-input>
            </el-form-item>
        </el-form>
        <template #footer>
            <span class="dialog-footer">
                <el-button @click="dialogVisible = false">取消</el-button>
                <el-button type="primary" @click="save">
                    确定
                </el-button>
            </span>
        </template>
    </el-dialog>
</template><script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
//引入获取菜单请求API
import { reqAllPermisstion, reqAddOrUpdateMenu, reqRemoveMenu } from '@/api/acl/menu';
//引入ts类型
import type { MenuParams, PermisstionResponseData, PermisstionList, Permisstion } from '@/api/acl/menu/type';
import { ElMessage } from "element-plus";
//存储菜单的数据
let PermisstionArr = ref<PermisstionList>([]);
//控制对话框的显示与隐藏
let dialogVisible = ref<boolean>(false);
//携带的参数
let menuData = reactive<MenuParams>({
    "code": "",
    "level": 0,
    "name": "",
    "pid": 0,
})
//组件挂载完毕
onMounted(() => {
    getHasPermisstion();
});
//获取菜单数据的方法
const getHasPermisstion = async () => {
    let result: PermisstionResponseData = await reqAllPermisstion();
    if (result.code == 200) {
        PermisstionArr.value = result.data;
    }
}
​
//添加菜单按钮的回调
const addPermisstion = (row: Permisstion) => {
    //清空数据
    Object.assign(menuData, {
        id: 0,
        "code": "",
        "level": 0,
        "name": "",
        "pid": 0,
    })
    //对话框显示出来
    dialogVisible.value = true;
    //收集新增的菜单的level数值
    menuData.level = row.level + 1;
    //给谁新增子菜单
    menuData.pid = (row.id as number);
​
}
//编辑已有的菜单
const updatePermisstion = (row: Permisstion) => {
    dialogVisible.value = true;
    //点击修改按钮:收集已有的菜单的数据进行更新
    Object.assign(menuData, row);
}
​
//确定按钮的回调
const save = async () => {
    //发请求:新增子菜单|更新某一个已有的菜单的数据
    let result: any = await reqAddOrUpdateMenu(menuData);
    if (result.code == 200) {
        //对话框隐藏
        dialogVisible.value = false;
        //提示信息
        ElMessage({ type: 'success', message: menuData.id ? '更新成功' : '添加成功' })
        //再次获取全部最新的菜单的数据
        getHasPermisstion();
    }
}
​
//删除按钮回调
const removeMenu = async (id: number) => {
    let result = await reqRemoveMenu(id);
    if (result.code == 200) {
        ElMessage({ type: 'success', message: '删除成功' });
        getHasPermisstion();
​
    }
}
​
​
</script><style scoped></style>

首页

功能展示

image-20230902232723187.png

代码实现

  1. project\src\views\home\index.vue
<template>
  <el-card>
    <div class="box">
      <img :src="userStore.avatar" alt="" class="avatar">
      <div class="bottom">
        <h3 class="title">{{ getTime() }}好呀{{ userStore.username }}</h3>
        <p class="subtitle">硅谷甄选运营平台</p>
      </div>
    </div>
  </el-card>
  <div class="bottoms">
    <svg-icon name="welcome" width="600px" height="300px"></svg-icon>
  </div>
</template><script setup lang="ts">
import { getTime } from '@/utils/time'
//引入用户相关的仓库,获取当前用户的头像、昵称
import useUserStore from '@/store/modules/user';
//获取存储用户信息的仓库对象
let userStore = useUserStore();
​
</script><style scoped lang="scss">
.box {
  display: flex;
​
  .avatar {
    width: 100px;
    height: 100px;
    border-radius: 50%;
  }
​
  .bottom {
    margin-left: 20px;
​
    .title {
      font-size: 30px;
      font-weight: 900;
      margin-bottom: 30px;
    }
​
    .subtitle {
      font-style: italic;
      color: skyblue;
    }
  }
}
.bottoms{
  margin-top: 10px;
  display: flex;
  justify-content: center;
}
</style>

暗黑模式和自定义模式

功能展示

image-20230902232844194.png

image-20230902232829593.png

image-20230902232907620.png

代码实现

暗黑模式和自定义模式都是利用element-ui 提供的组件来实现的

  1. 在入口文件 main.ts 中引入

    import { createApp } from 'vue'
    import App from './App.vue'
    // 引入 element-plus 插件与样式
    import ElementPlus from 'element-plus';
    import 'element-plus/dist/index.css'
    //@ts-ignore忽略当前文件ts类型的检测否则有红色提示(打包会失败)
    import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
    // svg 插件需要引入的配置代码
    import 'virtual:svg-icons-register'
    // 引入自定义插件对象:注册整个项目的全局组件
    import gloablComponent from '@/components/index';
    // 引入模板的全局样式
    import '@/styles/index.scss'
    //暗黑模式需要的样式 +++++++++++++++++++
    import 'element-plus/theme-chalk/dark/css-vars.css'
    .........
    ​
    
  2. project\src\layout\tabbar\setting\index.vue

    <template>
        <el-button size="small" icon="Refresh" circle @click="updateRefsh"></el-button>
        <el-button size="small" icon="FullScreen" circle @click="fullScreen"></el-button>
    ​
        <el-popover placement="bottom" title="主题设置" :width="300" trigger="hover">
            <!-- 表单元素 -->
            <el-form>
                <el-form-item label="主题颜色">
                    <el-color-picker @change="setColor" v-model="color" size="small" show-alpha :predefine="predefineColors" />
                </el-form-item>
                <el-form-item label="暗黑模式">
                    <el-switch @change="changeDark" v-model="dark" class="mt-2" style="margin-left: 24px" inline-prompt
                        active-icon="MoonNight" inactive-icon="Sunny" />
                </el-form-item>
            </el-form>
            <template #reference>
                <el-button size="small" icon="Setting" circle></el-button>
            </template>
        </el-popover>
        <img :src="userStore.avatar" style="width: 24px;height: 24px;margin:0px 10px;border-radius: 50%;">
        <!-- 下拉菜单 -->
        <el-dropdown>
            <span class="el-dropdown-link">
                {{ userStore.username }}
                <el-icon class="el-icon--right">
                    <arrow-down />
                </el-icon>
            </span>
            <template #dropdown>
                <el-dropdown-menu>
                    <el-dropdown-item @click="logout">退出登录</el-dropdown-item>
                </el-dropdown-menu>
            </template>
        </el-dropdown>
    </template><script setup lang="ts">
    import { ref } from 'vue'
    import { useRouter, useRoute } from 'vue-router';
    //获取用户相关的小仓库
    import useUserStore from '@/store/modules/user';
    //获取骨架的小仓库
    import useLayOutSettingStore from '@/store/modules/setting';
    let layoutSettingStore = useLayOutSettingStore();
    let userStore = useUserStore();
    //获取路由器对象
    let $router = useRouter();
    //获取路由对向
    let $route = useRoute();
    //收集开关的数据
    let dark = ref<boolean>(false);
    //刷新按钮点击回调
    const updateRefsh = () => {
        layoutSettingStore.refsh = !layoutSettingStore.refsh;
    };
    //全屏按钮点击的回调
    const fullScreen = () => {
        //DOM对象的一个属性:可以用来判断当前是不是全屏模式[全屏:true,不是全屏:false]
        let full = document.fullscreenElement;
        //切换为全屏模式
        if (!full) {
            //文档根节点的方法requestFullscreen,实现全屏模式
            document.documentElement.requestFullscreen();
        } else {
            //变为不是全屏模式->退出全屏模式
            document.exitFullscreen();
        }
    }
    //退出登录点击回调
    const logout = async () => {
        //第一件事情:需要向服务器发请求[退出登录接口]******
        //第二件事情:仓库当中关于用于相关的数据清空[token|username|avatar]
        //第三件事情:跳转到登录页面
        await userStore.userLogout();
        //跳转到登录页面
        $router.push({ path: '/login', query: { redirect: $route.path } });
    ​
    }
    ​
    //颜色组件组件的数据
    const color = ref('rgba(255, 69, 0, 0.68)')
    const predefineColors = ref([
        '#ff4500',
        '#ff8c00',
        '#ffd700',
        '#90ee90',
        '#00ced1',
        '#1e90ff',
        '#c71585',
        'rgba(255, 69, 0, 0.68)',
        'rgb(255, 120, 0)',
        'hsv(51, 100, 98)',
        'hsva(120, 40, 94, 0.5)',
        'hsl(181, 100%, 37%)',
        'hsla(209, 100%, 56%, 0.73)',
        '#c7158577',
    ])
    ​
    //switch开关的chang事件进行暗黑模式的切换
    const changeDark = () => {
        //获取HTML根节点
        let html = document.documentElement;
        //判断HTML标签是否有类名dark
        dark.value ? html.className = 'dark' : html.className = '';
    }
    ​
    //主题颜色的设置
    const setColor = ()=>{
       //通知js修改根节点的样式对象的属性与属性值
       const html = document.documentElement;
       html.style.setProperty('--el-color-primary',color.value);
    }
    </script><script lang="ts">
    export default {
        name: "Setting"
    }
    </script>
    <style scoped></style>