From fe895bd37c7a7de47451c38bd9df415a2f5d6eb9 Mon Sep 17 00:00:00 2001 From: hongawen <83944980@qq.com> Date: Wed, 21 Aug 2024 14:52:36 +0800 Subject: [PATCH] initHeader --- frontend/.env.development | 4 + frontend/.env.production | 4 + frontend/package.json | 2 + frontend/src/App.vue | 12 +- frontend/src/api/user/index.ts | 2 +- frontend/src/assets/images/logo.png | Bin 0 -> 12670 bytes frontend/src/assets/styles/tailMain.css | 2 +- frontend/src/constants/storeKey.ts | 3 + frontend/src/layouts/CnHeader/index.vue | 92 ++++++ frontend/src/layouts/index.vue | 34 +++ frontend/src/main.ts | 13 +- frontend/src/router/routerMap.ts | 12 + frontend/src/stores/interface/index.ts | 62 ++++ .../src/stores/{ => modules}/user/index.ts | 0 frontend/src/theme/index.scss | 22 ++ frontend/src/types/global.d.ts | 75 +++++ frontend/src/types/utils.d.ts | 17 ++ frontend/src/types/window.d.ts | 8 + frontend/src/utils/http/index.ts | 2 +- frontend/src/utils/index.ts | 288 ++++++++++++++++++ frontend/src/utils/is/index.ts | 125 ++++++++ frontend/src/utils/logout/index.ts | 2 +- frontend/src/views/Login.vue | 14 +- frontend/src/views/dashboard/index.vue | 231 ++++++++++++++ frontend/vite.config.ts | 17 ++ 25 files changed, 1023 insertions(+), 20 deletions(-) create mode 100644 frontend/src/assets/images/logo.png create mode 100644 frontend/src/layouts/CnHeader/index.vue create mode 100644 frontend/src/layouts/index.vue create mode 100644 frontend/src/stores/interface/index.ts rename frontend/src/stores/{ => modules}/user/index.ts (100%) create mode 100644 frontend/src/theme/index.scss create mode 100644 frontend/src/types/utils.d.ts create mode 100644 frontend/src/types/window.d.ts create mode 100644 frontend/src/utils/index.ts create mode 100644 frontend/src/utils/is/index.ts create mode 100644 frontend/src/views/dashboard/index.vue diff --git a/frontend/.env.development b/frontend/.env.development index 072e0f8..5d89297 100644 --- a/frontend/.env.development +++ b/frontend/.env.development @@ -1,2 +1,6 @@ NODE_ENV='development' + VITE_TITLE="" +# 路由模式 +# Optional: hash | history +VITE_ROUTER_MODE = hash \ No newline at end of file diff --git a/frontend/.env.production b/frontend/.env.production index 444ec20..a5993a4 100644 --- a/frontend/.env.production +++ b/frontend/.env.production @@ -1,2 +1,6 @@ NODE_ENV='production' + VITE_TITLE="" +# 路由模式 +# Optional: hash | history +VITE_ROUTER_MODE = hash \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 809d047..dfe4c6c 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -37,6 +37,8 @@ "sass": "^1.77.8", "tailwindcss": "^3.4.7", "typescript": "~5.4.0", + "unplugin-auto-import": "^0.18.2", + "unplugin-vue-components": "^0.27.4", "vite": "^5.3.1", "vite-plugin-node-polyfills": "^0.22.0", "vite-plugin-svg-icons": "^2.0.1", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 6f68e3f..59fa68e 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,13 +1,13 @@ - - + diff --git a/frontend/src/api/user/index.ts b/frontend/src/api/user/index.ts index 15531ec..44fabc7 100644 --- a/frontend/src/api/user/index.ts +++ b/frontend/src/api/user/index.ts @@ -1,5 +1,5 @@ import createAxios from '@/utils/http' -import { useUserInfoStore } from '@/stores/user' +import { useUserInfoStore } from '@/stores/modules/user' import { sm3Digest } from '@/assets/commjs/sm3.js' import { sm2, encrypt } from '@/assets/commjs/sm2.js' diff --git a/frontend/src/assets/images/logo.png b/frontend/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..188979824b57ba90c2e9c60bf44f0d87a69d7d17 GIT binary patch literal 12670 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/styles/tailMain.css b/frontend/src/assets/styles/tailMain.css index 855175a..56c5d07 100644 --- a/frontend/src/assets/styles/tailMain.css +++ b/frontend/src/assets/styles/tailMain.css @@ -3,6 +3,7 @@ @tailwind utilities; + /* 申明字体为东方大楷 */ @font-face { font-family: 'DongFangDaKai'; @@ -16,4 +17,3 @@ font-family: "MFBanHei"; /* Project id 1513211 */ src: url('@/assets/font/MFBanHei.ttf?t=1643094287456') format('truetype'); } - diff --git a/frontend/src/constants/storeKey.ts b/frontend/src/constants/storeKey.ts index a477600..412b47f 100644 --- a/frontend/src/constants/storeKey.ts +++ b/frontend/src/constants/storeKey.ts @@ -5,6 +5,9 @@ // 用户信息 export const USER_INFO = 'userInfo' +// 用户信息 +export const TABS_INFO = 'tabsInfo' + // WEB端布局配置 export const STORE_CONFIG = 'storeConfig' diff --git a/frontend/src/layouts/CnHeader/index.vue b/frontend/src/layouts/CnHeader/index.vue new file mode 100644 index 0000000..21a79c8 --- /dev/null +++ b/frontend/src/layouts/CnHeader/index.vue @@ -0,0 +1,92 @@ + + + + diff --git a/frontend/src/layouts/index.vue b/frontend/src/layouts/index.vue new file mode 100644 index 0000000..bff62b2 --- /dev/null +++ b/frontend/src/layouts/index.vue @@ -0,0 +1,34 @@ + + + diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 9562623..4faec90 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,9 +1,9 @@ import { createApp } from 'vue' import App from './App.vue' -// element-plus -import ElementPlus from 'element-plus' -import 'element-plus/dist/index.css' +// element-plus 全局引入图标 +import * as ElementPlusIconsVue from '@element-plus/icons-vue' + // 使用pinia import pinia from '@/stores' // 导入路由 @@ -18,11 +18,16 @@ import registerGlobComp from '@/components' //创建实例 const app = createApp(App) const setupAll = async () => { + //全局注册图标 + for(const [key, component] of Object.entries(ElementPlusIconsVue)){ + app.component(key, component) + } + app .use(Router) // 使用路由 - .use(ElementPlus) // 使用ele-plus组件 .use(pinia) // 使用pinia .use(registerGlobComp) // 使用全局自定义组件 + .use(ElementPlusIconsVue) // 使用element-plus图标 //待路由初始化完毕后,挂载app diff --git a/frontend/src/router/routerMap.ts b/frontend/src/router/routerMap.ts index 558b8fd..9a6786e 100644 --- a/frontend/src/router/routerMap.ts +++ b/frontend/src/router/routerMap.ts @@ -10,6 +10,18 @@ const constantRouterMap = [ name: 'login', component: Login, }, + { + path: '/home', + name: 'home', + component: import("@/layouts/index.vue"), + children: [ + { + path: '/home', + name: 'home', + component: () => import("@/views/Home.vue"), + }, + ], + }, ] export default constantRouterMap diff --git a/frontend/src/stores/interface/index.ts b/frontend/src/stores/interface/index.ts new file mode 100644 index 0000000..d6b8ef9 --- /dev/null +++ b/frontend/src/stores/interface/index.ts @@ -0,0 +1,62 @@ +export type LayoutType = "vertical" | "classic" | "transverse" | "columns"; + +export type AssemblySizeType = "large" | "default" | "small"; + +export type LanguageType = "zh" | "en" | null; + +/* GlobalState */ +export interface GlobalState { + layout: LayoutType; + assemblySize: AssemblySizeType; + language: LanguageType; + maximize: boolean; + primary: string; + isDark: boolean; + isGrey: boolean; + isWeak: boolean; + asideInverted: boolean; + headerInverted: boolean; + isCollapse: boolean; + accordion: boolean; + watermark: boolean; + breadcrumb: boolean; + breadcrumbIcon: boolean; + tabs: boolean; + tabsIcon: boolean; + footer: boolean; +} + +/* UserState */ +export interface UserState { + token: string; + userInfo: { name: string }; +} + +/* tabsMenuProps */ +export interface TabsMenuProps { + icon: string; + title: string; + path: string; + name: string; + close: boolean; + isKeepAlive: boolean; +} + +/* TabsState */ +export interface TabsState { + tabsMenuList: TabsMenuProps[]; +} + +/* AuthState */ +export interface AuthState { + routeName: string; + authButtonList: { + [key: string]: string[]; + }; + authMenuList: Menu.MenuOptions[]; +} + +/* KeepAliveState */ +export interface KeepAliveState { + keepAliveName: string[]; +} diff --git a/frontend/src/stores/user/index.ts b/frontend/src/stores/modules/user/index.ts similarity index 100% rename from frontend/src/stores/user/index.ts rename to frontend/src/stores/modules/user/index.ts diff --git a/frontend/src/theme/index.scss b/frontend/src/theme/index.scss new file mode 100644 index 0000000..22a98cf --- /dev/null +++ b/frontend/src/theme/index.scss @@ -0,0 +1,22 @@ +@forward "element-plus/theme-chalk/src/common/var.scss" with ( + $colors: ( + "primary": (//主题色 + "base": #003078, + ), + "success": (//成功色 + "base": #67C23A, + ), + "warning": (//警告色 + "base": #E6A23C, + ), + "danger": (//危险色 + "base": #F56C6C, + ), + "error": (//错误色 + "base": #FF4949, + ), + "info": (//信息色 + "base": #409EFF, + ), + ), +); diff --git a/frontend/src/types/global.d.ts b/frontend/src/types/global.d.ts index 7bd63d6..f7b0abe 100644 --- a/frontend/src/types/global.d.ts +++ b/frontend/src/types/global.d.ts @@ -31,3 +31,78 @@ interface ApiResponse { } type ApiPromise = Promise> + +/* Menu */ +declare namespace Menu { + interface MenuOptions { + path: string; + name: string; + component?: string | (() => Promise); + redirect?: string; + meta: MetaProps; + children?: MenuOptions[]; + } + interface MetaProps { + icon: string; + title: string; + activeMenu?: string; + isLink?: string; + isHide: boolean; + isFull: boolean; + isAffix: boolean; + isKeepAlive: boolean; + } +} + +/* FileType */ +declare namespace File { + type ImageMimeType = + | "image/apng" + | "image/bmp" + | "image/gif" + | "image/jpeg" + | "image/pjpeg" + | "image/png" + | "image/svg+xml" + | "image/tiff" + | "image/webp" + | "image/x-icon"; + + type ExcelMimeType = "application/vnd.ms-excel" | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; +} + +/* Vite */ +declare type Recordable = Record; + +declare interface ViteEnv { + VITE_USER_NODE_ENV: "development" | "production" | "test"; + VITE_GLOB_APP_TITLE: string; + VITE_PORT: number; + VITE_OPEN: boolean; + VITE_REPORT: boolean; + VITE_ROUTER_MODE: "hash" | "history"; + VITE_BUILD_COMPRESS: "gzip" | "brotli" | "gzip,brotli" | "none"; + VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean; + VITE_DROP_CONSOLE: boolean; + VITE_PWA: boolean; + VITE_DEVTOOLS: boolean; + VITE_PUBLIC_PATH: string; + VITE_API_URL: string; + VITE_PROXY: [string, string][]; +} + +interface ImportMetaEnv extends ViteEnv { + __: unknown; +} + +/* __APP_INFO__ */ +declare const __APP_INFO__: { + pkg: { + name: string; + version: string; + dependencies: Recordable; + devDependencies: Recordable; + }; + lastBuildTime: string; +}; + diff --git a/frontend/src/types/utils.d.ts b/frontend/src/types/utils.d.ts new file mode 100644 index 0000000..8476216 --- /dev/null +++ b/frontend/src/types/utils.d.ts @@ -0,0 +1,17 @@ +type ObjToKeyValUnion = { + [K in keyof T]: { key: K; value: T[K] }; +}[keyof T]; + +type ObjToKeyValArray = { + [K in keyof T]: [K, T[K]]; +}[keyof T]; + +type ObjToSelectedValueUnion = { + [K in keyof T]: T[K]; +}[keyof T]; + +type Optional = Omit & Partial>; + +type GetOptional = { + [P in keyof T as T[P] extends Required[P] ? never : P]: T[P]; +}; diff --git a/frontend/src/types/window.d.ts b/frontend/src/types/window.d.ts new file mode 100644 index 0000000..1582726 --- /dev/null +++ b/frontend/src/types/window.d.ts @@ -0,0 +1,8 @@ +declare global { + interface Navigator { + msSaveOrOpenBlob: (blob: Blob, fileName: string) => void; + browserLanguage: string; + } +} + +export {}; diff --git a/frontend/src/utils/http/index.ts b/frontend/src/utils/http/index.ts index c8bcf59..2e969c9 100644 --- a/frontend/src/utils/http/index.ts +++ b/frontend/src/utils/http/index.ts @@ -3,7 +3,7 @@ import axios from 'axios' import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus' import { refreshToken } from '@/api/user' import router from '@/router/index' -import { useUserInfoStore } from '@/stores/user' +import { useUserInfoStore } from '@/stores/modules/user' window.requests = [] window.tokenRefreshing = false diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts new file mode 100644 index 0000000..e1eb997 --- /dev/null +++ b/frontend/src/utils/index.ts @@ -0,0 +1,288 @@ +import { isArray } from "@/utils/is"; + +const mode = import.meta.env.VITE_ROUTER_MODE; + +/** + * @description 获取localStorage + * @param {String} key Storage名称 + * @returns {String} + */ +export function localGet(key: string) { + const value = window.localStorage.getItem(key); + try { + return JSON.parse(window.localStorage.getItem(key) as string); + } catch (error) { + return value; + } +} + +/** + * @description 存储localStorage + * @param {String} key Storage名称 + * @param {*} value Storage值 + * @returns {void} + */ +export function localSet(key: string, value: any) { + window.localStorage.setItem(key, JSON.stringify(value)); +} + +/** + * @description 清除localStorage + * @param {String} key Storage名称 + * @returns {void} + */ +export function localRemove(key: string) { + window.localStorage.removeItem(key); +} + +/** + * @description 清除所有localStorage + * @returns {void} + */ +export function localClear() { + window.localStorage.clear(); +} + +/** + * @description 判断数据类型 + * @param {*} val 需要判断类型的数据 + * @returns {String} + */ +export function isType(val: any) { + if (val === null) return "null"; + if (typeof val !== "object") return typeof val; + else return Object.prototype.toString.call(val).slice(8, -1).toLocaleLowerCase(); +} + +/** + * @description 生成唯一 uuid + * @returns {String} + */ +export function generateUUID() { + let uuid = ""; + for (let i = 0; i < 32; i++) { + let random = (Math.random() * 16) | 0; + if (i === 8 || i === 12 || i === 16 || i === 20) uuid += "-"; + uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16); + } + return uuid; +} + +/** + * 判断两个对象是否相同 + * @param {Object} a 要比较的对象一 + * @param {Object} b 要比较的对象二 + * @returns {Boolean} 相同返回 true,反之 false + */ +export function isObjectValueEqual(a: { [key: string]: any }, b: { [key: string]: any }) { + if (!a || !b) return false; + let aProps = Object.getOwnPropertyNames(a); + let bProps = Object.getOwnPropertyNames(b); + if (aProps.length != bProps.length) return false; + for (let i = 0; i < aProps.length; i++) { + let propName = aProps[i]; + let propA = a[propName]; + let propB = b[propName]; + if (!b.hasOwnProperty(propName)) return false; + if (propA instanceof Object) { + if (!isObjectValueEqual(propA, propB)) return false; + } else if (propA !== propB) { + return false; + } + } + return true; +} + +/** + * @description 生成随机数 + * @param {Number} min 最小值 + * @param {Number} max 最大值 + * @returns {Number} + */ +export function randomNum(min: number, max: number): number { + let num = Math.floor(Math.random() * (min - max) + max); + return num; +} + +/** + * @description 获取当前时间对应的提示语 + * @returns {String} + */ +export function getTimeState() { + let timeNow = new Date(); + let hours = timeNow.getHours(); + if (hours >= 6 && hours <= 10) return `早上好 ⛅`; + if (hours >= 10 && hours <= 14) return `中午好 🌞`; + if (hours >= 14 && hours <= 18) return `下午好 🌞`; + if (hours >= 18 && hours <= 24) return `晚上好 🌛`; + if (hours >= 0 && hours <= 6) return `凌晨好 🌛`; +} + +/** + * @description 获取浏览器默认语言 + * @returns {String} + */ +export function getBrowserLang() { + let browserLang = navigator.language ? navigator.language : navigator.browserLanguage; + let defaultBrowserLang = ""; + if (["cn", "zh", "zh-cn"].includes(browserLang.toLowerCase())) { + defaultBrowserLang = "zh"; + } else { + defaultBrowserLang = "en"; + } + return defaultBrowserLang; +} + +/** + * @description 获取不同路由模式所对应的 url + params + * @returns {String} + */ +export function getUrlWithParams() { + const url = { + hash: location.hash.substring(1), + history: location.pathname + location.search + }; + return url[mode]; +} + +/** + * @description 使用递归扁平化菜单,方便添加动态路由 + * @param {Array} menuList 菜单列表 + * @returns {Array} + */ +export function getFlatMenuList(menuList: Menu.MenuOptions[]): Menu.MenuOptions[] { + let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)); + return newMenuList.flatMap(item => [item, ...(item.children ? getFlatMenuList(item.children) : [])]); +} + +/** + * @description 使用递归过滤出需要渲染在左侧菜单的列表 (需剔除 isHide == true 的菜单) + * @param {Array} menuList 菜单列表 + * @returns {Array} + * */ +export function getShowMenuList(menuList: Menu.MenuOptions[]) { + let newMenuList: Menu.MenuOptions[] = JSON.parse(JSON.stringify(menuList)); + return newMenuList.filter(item => { + item.children?.length && (item.children = getShowMenuList(item.children)); + return !item.meta?.isHide; + }); +} + +/** + * @description 使用递归找出所有面包屑存储到 pinia/vuex 中 + * @param {Array} menuList 菜单列表 + * @param {Array} parent 父级菜单 + * @param {Object} result 处理后的结果 + * @returns {Object} + */ +export const getAllBreadcrumbList = (menuList: Menu.MenuOptions[], parent = [], result: { [key: string]: any } = {}) => { + for (const item of menuList) { + result[item.path] = [...parent, item]; + if (item.children) getAllBreadcrumbList(item.children, result[item.path], result); + } + return result; +}; + +/** + * @description 使用递归处理路由菜单 path,生成一维数组 (第一版本地路由鉴权会用到,该函数暂未使用) + * @param {Array} menuList 所有菜单列表 + * @param {Array} menuPathArr 菜单地址的一维数组 ['**','**'] + * @returns {Array} + */ +export function getMenuListPath(menuList: Menu.MenuOptions[], menuPathArr: string[] = []): string[] { + for (const item of menuList) { + if (typeof item === "object" && item.path) menuPathArr.push(item.path); + if (item.children?.length) getMenuListPath(item.children, menuPathArr); + } + return menuPathArr; +} + +/** + * @description 递归查询当前 path 所对应的菜单对象 (该函数暂未使用) + * @param {Array} menuList 菜单列表 + * @param {String} path 当前访问地址 + * @returns {Object | null} + */ +export function findMenuByPath(menuList: Menu.MenuOptions[], path: string): Menu.MenuOptions | null { + for (const item of menuList) { + if (item.path === path) return item; + if (item.children) { + const res = findMenuByPath(item.children, path); + if (res) return res; + } + } + return null; +} + +/** + * @description 使用递归过滤需要缓存的菜单 name (该函数暂未使用) + * @param {Array} menuList 所有菜单列表 + * @param {Array} keepAliveNameArr 缓存的菜单 name ['**','**'] + * @returns {Array} + * */ +export function getKeepAliveRouterName(menuList: Menu.MenuOptions[], keepAliveNameArr: string[] = []) { + menuList.forEach(item => { + item.meta.isKeepAlive && item.name && keepAliveNameArr.push(item.name); + item.children?.length && getKeepAliveRouterName(item.children, keepAliveNameArr); + }); + return keepAliveNameArr; +} + +/** + * @description 格式化表格单元格默认值 (el-table-column) + * @param {Number} row 行 + * @param {Number} col 列 + * @param {*} callValue 当前单元格值 + * @returns {String} + * */ +export function formatTableColumn(row: number, col: number, callValue: any) { + // 如果当前值为数组,使用 / 拼接(根据需求自定义) + if (isArray(callValue)) return callValue.length ? callValue.join(" / ") : "--"; + return callValue ?? "--"; +} + +/** + * @description 处理 ProTable 值为数组 || 无数据 + * @param {*} callValue 需要处理的值 + * @returns {String} + * */ +export function formatValue(callValue: any) { + // 如果当前值为数组,使用 / 拼接(根据需求自定义) + if (isArray(callValue)) return callValue.length ? callValue.join(" / ") : "--"; + return callValue ?? "--"; +} + +/** + * @description 处理 prop 为多级嵌套的情况,返回的数据 (列如: prop: user.name) + * @param {Object} row 当前行数据 + * @param {String} prop 当前 prop + * @returns {*} + * */ +export function handleRowAccordingToProp(row: { [key: string]: any }, prop: string) { + if (!prop.includes(".")) return row[prop] ?? "--"; + prop.split(".").forEach(item => (row = row[item] ?? "--")); + return row; +} + +/** + * @description 处理 prop,当 prop 为多级嵌套时 ==> 返回最后一级 prop + * @param {String} prop 当前 prop + * @returns {String} + * */ +export function handleProp(prop: string) { + const propArr = prop.split("."); + if (propArr.length == 1) return prop; + return propArr[propArr.length - 1]; +} + + +/** + * @description 递归查找 callValue 对应的 enum 值 + * */ +export function findItemNested(enumData: any, callValue: any, value: string, children: string) { + return enumData.reduce((accumulator: any, current: any) => { + if (accumulator) return accumulator; + if (current[value] === callValue) return current; + if (current[children]) return findItemNested(current[children], callValue, value, children); + }, null); +} diff --git a/frontend/src/utils/is/index.ts b/frontend/src/utils/is/index.ts new file mode 100644 index 0000000..5678491 --- /dev/null +++ b/frontend/src/utils/is/index.ts @@ -0,0 +1,125 @@ +/** + * @description: 判断值是否未某个类型 + */ +export function is(val: unknown, type: string) { + return Object.prototype.toString.call(val) === `[object ${type}]`; +} + +/** + * @description: 是否为函数 + */ +export function isFunction(val: unknown): val is T { + return is(val, "Function"); +} + +/** + * @description: 是否已定义 + */ +export const isDef = (val?: T): val is T => { + return typeof val !== "undefined"; +}; + +/** + * @description: 是否未定义 + */ +export const isUnDef = (val?: T): val is T => { + return !isDef(val); +}; + +/** + * @description: 是否为对象 + */ +export const isObject = (val: any): val is Record => { + return val !== null && is(val, "Object"); +}; + +/** + * @description: 是否为时间 + */ +export function isDate(val: unknown): val is Date { + return is(val, "Date"); +} + +/** + * @description: 是否为数值 + */ +export function isNumber(val: unknown): val is number { + return is(val, "Number"); +} + +/** + * @description: 是否为AsyncFunction + */ +export function isAsyncFunction(val: unknown): val is Promise { + return is(val, "AsyncFunction"); +} + +/** + * @description: 是否为promise + */ +export function isPromise(val: unknown): val is Promise { + return is(val, "Promise") && isObject(val) && isFunction(val.then) && isFunction(val.catch); +} + +/** + * @description: 是否为字符串 + */ +export function isString(val: unknown): val is string { + return is(val, "String"); +} + +/** + * @description: 是否为boolean类型 + */ +export function isBoolean(val: unknown): val is boolean { + return is(val, "Boolean"); +} + +/** + * @description: 是否为数组 + */ +export function isArray(val: any): val is Array { + return val && Array.isArray(val); +} + +/** + * @description: 是否客户端 + */ +export const isClient = () => { + return typeof window !== "undefined"; +}; + +/** + * @description: 是否为浏览器 + */ +export const isWindow = (val: any): val is Window => { + return typeof window !== "undefined" && is(val, "Window"); +}; + +/** + * @description: 是否为 element 元素 + */ +export const isElement = (val: unknown): val is Element => { + return isObject(val) && !!val.tagName; +}; + +/** + * @description: 是否为 null + */ +export function isNull(val: unknown): val is null { + return val === null; +} + +/** + * @description: 是否为 null || undefined + */ +export function isNullOrUnDef(val: unknown): val is null | undefined { + return isUnDef(val) || isNull(val); +} + +/** + * @description: 是否为 16 进制颜色 + */ +export const isHexColor = (str: string) => { + return /^#?([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(str); +}; diff --git a/frontend/src/utils/logout/index.ts b/frontend/src/utils/logout/index.ts index ddd2c64..256342a 100644 --- a/frontend/src/utils/logout/index.ts +++ b/frontend/src/utils/logout/index.ts @@ -1,4 +1,4 @@ -import { useUserInfoStore } from '@/stores/user' +import { useUserInfoStore } from '@/stores/modules/user' import { USER_INFO } from '@/constants/storeKey' export function clearUserInfo() { diff --git a/frontend/src/views/Login.vue b/frontend/src/views/Login.vue index b3fe48b..f42c6c4 100644 --- a/frontend/src/views/Login.vue +++ b/frontend/src/views/Login.vue @@ -38,7 +38,7 @@ import { ref, onMounted } from "vue"; const router = useRouter(); import { useRouter } from "vue-router"; import { Avatar, Lock } from "@element-plus/icons-vue"; -import { useUserInfoStore } from "@/stores/user"; +import { useUserInfoStore } from "@/stores/modules/user"; const userInfoStore = useUserInfoStore(); @@ -61,12 +61,12 @@ const handleLogin = () => { loginLoading.value = true; if (LoginForm.value.loginUserName && LoginForm.value.loginUserPassword) { setTimeout(() => { - // router.push({ - // path: "/admin", - // query: { - // name: LoginForm.value.loginUserName, - // }, - // }); + router.push({ + path: "/home", + query: { + name: LoginForm.value.loginUserName, + }, + }); userInfoStore.dataFill({ loginName: LoginForm.value.loginUserName }); console.log(userInfoStore.loginName) }, 1500); diff --git a/frontend/src/views/dashboard/index.vue b/frontend/src/views/dashboard/index.vue new file mode 100644 index 0000000..9928094 --- /dev/null +++ b/frontend/src/views/dashboard/index.vue @@ -0,0 +1,231 @@ + + + diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index fd178d6..200c659 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -3,6 +3,9 @@ import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' import vue from '@vitejs/plugin-vue' import path from 'path' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' export default defineConfig((config) => { return { @@ -13,6 +16,16 @@ export default defineConfig((config) => { iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')], symbolId: 'icon-[dir]-[name]', }), + AutoImport({ + resolvers: [ElementPlusResolver({ + importStyle: "sass", + })] + }), + Components({ + resolvers: [ElementPlusResolver({ + importStyle: "sass", + })] + }), ], // 基础配置 base: './', @@ -30,6 +43,10 @@ export default defineConfig((config) => { }, javascriptEnabled: true, }, + scss: { + // 引入index.scss覆盖文件 + additionalData: `@use "@/theme/index.scss" as *;`, + } }, }, build: {