diff --git a/web/.env.development b/web/.env.development index 6a1e227..d618ebf 100644 --- a/web/.env.development +++ b/web/.env.development @@ -13,6 +13,7 @@ VITE_DROP_CONSOLE=true #VITE_PROXY = [["/appApi","http://localhost:8001"],["/upload","http://localhost:8001/upload"]] VITE_PROXY=[["/admin","http://localhost:8000/admin"]] + # API 接口地址 VITE_GLOB_API_URL= @@ -24,3 +25,10 @@ VITE_GLOB_IMG_URL= # 接口前缀 VITE_GLOB_API_URL_PREFIX=/admin + +# 快速登录账号密码配置,没有配置则不开启快速登录 +## 格式为 [["账号名称","账号密码","角色名称"],["账号名称","账号密码"],["账号名称"]] +## 帐号名称不能为空,密码为空则和帐号名称相同 +## 角色名称可选,如果不填写则默认使用账号名称作为角色名称 +## 账号名称和角色名称可以重复,账号名称和密码可以重复 +VITE_APP_DEMO_ACCOUNT=[["admin","123456","超管"],["test","123456","管理员"],["ameng","123456","租户"],["abai","123456","商户"],["asong","123456","用户"]] \ No newline at end of file diff --git a/web/build/utils.ts b/web/build/utils.ts index b319538..9653cea 100644 --- a/web/build/utils.ts +++ b/web/build/utils.ts @@ -34,7 +34,7 @@ export function wrapperEnv(envConf: Recordable): ViteEnv { } catch (error) {} } ret[envName] = realName; - process.env[envName] = realName; + // process.env[envName] = realName; } return ret; } diff --git a/web/src/debug/account.ts b/web/src/debug/account.ts new file mode 100644 index 0000000..df545ee --- /dev/null +++ b/web/src/debug/account.ts @@ -0,0 +1,43 @@ +import { isArray } from "@/utils/is"; + +interface Account { + /** + * 账号名称 + */ + name: string; + /** + * 用户名 + */ + username: string; + /** + * 密码 + */ + password: string; +} +/** + * 获取配置的账号信息 + * @returns {[]Account} 返回账号信息数组 + */ +export function getDemoAccounts() { + + let envConf = import.meta.env.VITE_APP_DEMO_ACCOUNT || ""; + // 帐号密码一样 + // [["username"],["username","password"],["username","password","name"]] + try { + let accounts = JSON.parse(envConf); + if (accounts && isArray(accounts)) { + return accounts.map((item: String[]) => { + let [username = "", password = "", name = ""] = item; + username = username; + password = password || username; + name = name || username; + return { + name, + username, + password, + } as Account; + }); + } + } catch (error) {} + return [] as Account[]; +} diff --git a/web/src/hooks/useBoolean.ts b/web/src/hooks/useBoolean.ts new file mode 100644 index 0000000..1646ffa --- /dev/null +++ b/web/src/hooks/useBoolean.ts @@ -0,0 +1,49 @@ +import { ref, Ref } from "vue"; + +type Resettable = + /** + * 基础形式为一个元组,包含: + * 1. `Ref`:状态引用,可以直接访问和修改状态值 + * 2. `() => void`:切换真假 + * 3. `(value: boolean) => void`:设置状态 + * 4.`() => void`:设置为`true`方法 + * 5.`() => void`:设置为`false`方法 + */ + [Ref, () => void, () => void] & /** + * 同时扩展为一个对象形式,提供以下属性和方法: + * - `loading: Ref`:状态引用,与元组中的第一个元素相同 + * - `startLoading: () => void`:开始加载方法,与元组中的第二个元素相同 + * - `endLoading: () => void`:结束加载方法,与元组中的第三个元素相同 + */ { + /** 加载状态引用 */ + bool: Ref; + toggle: () => void; + setBool: (value: boolean) => void; + setTrue: () => void; + setFalse: () => void; + }; +export default function useBoolean(initValue = false): Resettable { + const bool = ref(initValue); + + function setBool(value: boolean) { + bool.value = value; + } + function setTrue() { + setBool(true); + } + function setFalse() { + setBool(false); + } + function toggle() { + setBool(!bool.value); + } + + // 返回带加载状态引用、开始加载和结束加载方法的扩展数组 + return (Object.assign([bool, toggle, setBool, setTrue, setFalse], { + bool, + toggle, + setBool, + setTrue, + setFalse, + }) as unknown) as Resettable; +} diff --git a/web/src/layout/components/Header/Search.vue b/web/src/layout/components/Header/Search.vue new file mode 100644 index 0000000..05cdee1 --- /dev/null +++ b/web/src/layout/components/Header/Search.vue @@ -0,0 +1,241 @@ + + + diff --git a/web/src/layout/components/Header/index.vue b/web/src/layout/components/Header/index.vue index 3e91bcb..8756836 100644 --- a/web/src/layout/components/Header/index.vue +++ b/web/src/layout/components/Header/index.vue @@ -69,6 +69,7 @@
+ @@ -200,6 +201,8 @@ import { notificationStoreWidthOut } from '@/store/modules/notification'; import { getIcon } from '@/enums/systemMessageEnum'; + import Search from './Search.vue'; + export default defineComponent({ name: 'PageHeader', components: { @@ -208,6 +211,7 @@ ProjectSetting, AsideMenu, SystemMessage, + Search, }, props: { collapsed: { diff --git a/web/src/utils/tree.ts b/web/src/utils/tree.ts new file mode 100644 index 0000000..b67e076 --- /dev/null +++ b/web/src/utils/tree.ts @@ -0,0 +1,97 @@ +/** + * 树形数组转平级 + * @date 2023-01-09 + * @returns {array} + */ +export const tree2FlatArray = (tree: any[], childrenKey: string = "children") => { + return tree.reduce((arr, item) => { + var children = item?.[childrenKey] ?? []; + var obj = item; + delete obj[childrenKey]; + //解构赋值+默认值 + return arr.concat([obj], tree2FlatArray(children)); //children部分进行递归 + }, []); +}; +/** + * 树形数组转对象 + * @date 2023-01-09 + * @returns {object} + */ +export const tree2Objects = ( + tree: any[], + key: string = "id", + childrenKey: string = "children" +) => { + let rows = tree2FlatArray(tree, childrenKey); + let objects = {}; + rows.forEach((item) => { + objects[item[key]] = item; + }); + return objects; +}; + +/** + * 树形菜单数据输出 + * @date 2022-04-20 + * @param {object} data - 数据 + * @param {string} pid="parent_id" - 父类名称 + * @param {string} children="children" - 子类名称 + * @returns {object} + */ +export const treesBy = ( + data: any[], + pid: string = "parent_id", + children: string = "children" +) => { + let map = {}, + val = []; + data.forEach((item) => { + item[children] = []; + map[item.id] = item; + }); + data.forEach((item) => { + const parent = map[item[pid]]; + if (!!parent) { + parent[children].push(item); + } else { + val.push(item); + } + }); + return val; +}; +/** + * 格式化树形菜单,省市区 + * @param {object} org + * @returns {object} + */ +export const mapTree = (org: any, keyId = "v", keyChild = "s", keyName = "n") => { + const haveChildren = + org[keyChild] && Array.isArray(org[keyChild]) && org[keyChild].length > 0; + return { + key: org[keyId], + value: String(org[keyId]), + label: org[keyName], + isLeaf: true, + children: haveChildren ? org[keyChild].map((i) => mapTree(i)) : [], + }; +}; + +/** + * 格式化树形菜单,省市区 + * @param {object} org + * @returns {object} + */ +export const toFlatArray = ( + tree: any[], + parentId: string | number, + keyId: string | number = "key" +) => { + return tree.reduce((t, _) => { + const child = _["children"]; + return [ + ...t, + { [keyId]: _[keyId], parentId }, + ...(child && child.length ? toFlatArray(child, _[keyId]) : []), + ]; + }, []); +}; diff --git a/web/src/views/login/login/demo-account.vue b/web/src/views/login/login/demo-account.vue index 7a725c1..5dda468 100644 --- a/web/src/views/login/login/demo-account.vue +++ b/web/src/views/login/login/demo-account.vue @@ -1,60 +1,37 @@