From 79ebad0aa1f4519df7570363f3f07a7a8aa99841 Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Sat, 18 Apr 2026 00:08:06 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E4=BB=A3=E7=A0=81=E6=A0=BC=E5=BC=8F?= =?UTF-8?q?=E5=8C=96=E4=B8=8E=E7=BB=9F=E4=B8=80=E6=A0=B7=E5=BC=8F=E5=8F=98?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/auth.ts | 4 +- src/components/custom-tree/index.vue | 2 - src/composables/useLoading.ts | 66 ++++---- src/composables/useNavbar.ts | 2 +- src/composables/useRequest.ts | 198 ++++++++++++------------ src/composables/useTabbar.ts | 56 +++---- src/pages/index/index.vue | 37 +---- src/pages/login/index.vue | 162 ++++++++++--------- src/pages/mine/about/index.vue | 3 - src/pages/mine/account/index.vue | 17 +- src/pages/mine/index.vue | 83 ++++------ src/pages/mine/official/index.vue | 6 +- src/pages/mine/settings/index.vue | 12 +- src/pages/mine/settings/theme/index.vue | 6 +- src/pages/work/dept/index.vue | 33 +++- src/pages/work/dict/index.vue | 24 +-- src/pages/work/dict/item/index.vue | 19 ++- src/pages/work/index.vue | 14 +- src/pages/work/menu/index.vue | 5 +- src/pages/work/notice/index.vue | 116 +++++++++++--- src/pages/work/role/assign-perm.vue | 2 +- src/pages/work/role/index.vue | 88 +++++++++-- src/pages/work/user/index.vue | 135 +++++++++++++--- src/router/index.ts | 4 +- src/store/modules/theme.ts | 50 +++--- src/store/modules/user.ts | 94 +++++------ src/styles/theme.scss | 28 ++++ unocss.config.ts | 10 +- 28 files changed, 744 insertions(+), 532 deletions(-) diff --git a/src/api/auth.ts b/src/api/auth.ts index d17d113..40a4e8b 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -80,7 +80,7 @@ const AuthAPI = { */ sendSmsLoginCode(mobile: string): Promise { const mobileSafe = encodeURIComponent(mobile); - return request({ + return request({ url: `${AUTH_BASE_URL}/sms/code?mobile=${mobileSafe}`, method: "POST", }); @@ -153,7 +153,7 @@ const AuthAPI = { * 登出 */ logout() { - return request({ + return request({ url: `${AUTH_BASE_URL}/logout`, method: "DELETE", }); diff --git a/src/components/custom-tree/index.vue b/src/components/custom-tree/index.vue index 6e339bc..e4332ce 100644 --- a/src/components/custom-tree/index.vue +++ b/src/components/custom-tree/index.vue @@ -211,8 +211,6 @@ function handleNodeAction(node: FlatNode) { emit("action", node.raw); } -// ===== 多选相关 ===== - /** 判断节点是否选中(多选模式) */ function isChecked(value: string) { return internalCheckedKeys.value.has(value); diff --git a/src/composables/useLoading.ts b/src/composables/useLoading.ts index 1801801..e953fdd 100644 --- a/src/composables/useLoading.ts +++ b/src/composables/useLoading.ts @@ -1,4 +1,4 @@ -import { ref, computed } from "vue" +import { ref, computed } from "vue"; /** * 加载状态管理 @@ -26,63 +26,63 @@ import { ref, computed } from "vue" export interface UseLoadingOptions { /** 是否使用全局单例,默认 true */ - singleton?: boolean + singleton?: boolean; /** 初始加载状态,默认 false */ - initial?: boolean + initial?: boolean; /** 加载提示消息 */ - message?: string + message?: string; } export interface UseLoadingReturn { /** 是否处于加载状态 */ - isLoading: ReturnType> + isLoading: ReturnType>; /** 加载计数(支持并发) */ - loadingCount: ReturnType> + loadingCount: ReturnType>; /** 当前加载消息 */ - message: ReturnType> + message: ReturnType>; /** 开始加载 */ - start: (msg?: string) => void + start: (msg?: string) => void; /** 结束加载 */ - stop: () => void + stop: () => void; /** 包装异步函数,自动管理加载状态 */ - wrap: (promise: Promise) => Promise + wrap: (promise: Promise) => Promise; /** 设置加载消息 */ - setMessage: (msg: string) => void + setMessage: (msg: string) => void; } /** * 创建加载状态实例 */ function createLoadingState(options: UseLoadingOptions = {}) { - const { initial = false, message: initialMessage = "" } = options + const { message: initialMessage = "" } = options; - const loadingCount = ref(0) - const message = ref(initialMessage) + const loadingCount = ref(0); + const message = ref(initialMessage); - const isLoading = computed(() => loadingCount.value > 0) + const isLoading = computed(() => loadingCount.value > 0); /** * 开始加载 * @param msg 加载提示消息 */ const start = (msg?: string): void => { - loadingCount.value++ + loadingCount.value++; if (msg) { - message.value = msg + message.value = msg; } - } + }; /** * 结束加载 */ const stop = (): void => { if (loadingCount.value > 0) { - loadingCount.value-- + loadingCount.value--; } if (loadingCount.value === 0) { - message.value = "" + message.value = ""; } - } + }; /** * 包装异步函数,自动管理加载状态 @@ -90,20 +90,20 @@ function createLoadingState(options: UseLoadingOptions = {}) { */ const wrap = async (promise: Promise): Promise => { try { - start() - return await promise + start(); + return await promise; } finally { - stop() + stop(); } - } + }; /** * 设置加载消息 * @param msg 消息内容 */ const setMessage = (msg: string): void => { - message.value = msg - } + message.value = msg; + }; return { isLoading, @@ -113,11 +113,11 @@ function createLoadingState(options: UseLoadingOptions = {}) { stop, wrap, setMessage, - } + }; } /** 全局单例实例 */ -let loadingInstance: UseLoadingReturn | null = null +let loadingInstance: UseLoadingReturn | null = null; /** * 加载状态管理 Hook @@ -128,14 +128,14 @@ let loadingInstance: UseLoadingReturn | null = null * @param options 配置选项 */ export function useLoading(options?: UseLoadingOptions): UseLoadingReturn { - const { singleton = true } = options ?? {} + const { singleton = true } = options ?? {}; if (singleton) { if (!loadingInstance) { - loadingInstance = createLoadingState(options) + loadingInstance = createLoadingState(options); } - return loadingInstance + return loadingInstance; } - return createLoadingState(options) + return createLoadingState(options); } diff --git a/src/composables/useNavbar.ts b/src/composables/useNavbar.ts index d16e264..57ea93f 100644 --- a/src/composables/useNavbar.ts +++ b/src/composables/useNavbar.ts @@ -72,7 +72,7 @@ export interface UseNavbarReturn { * @param options 配置选项 */ export function useNavbar(options: UseNavbarOptions = {}): UseNavbarReturn { - const { navBarHeight = 44, hasTabbar = false } = options; + const { navBarHeight = 44 } = options; // 状态栏高度 const statusBarHeight = ref(0); diff --git a/src/composables/useRequest.ts b/src/composables/useRequest.ts index 066a550..08edaf8 100644 --- a/src/composables/useRequest.ts +++ b/src/composables/useRequest.ts @@ -1,4 +1,4 @@ -import { ref, computed, shallowRef, type Ref, type ComputedRef } from "vue" +import { ref, computed, shallowRef, type Ref, type ComputedRef } from "vue"; /** * 请求状态管理 @@ -24,36 +24,36 @@ import { ref, computed, shallowRef, type Ref, type ComputedRef } from "vue" export interface UseRequestOptions { /** 是否立即执行,默认 false */ - immediate?: boolean + immediate?: boolean; /** 初始数据 */ - initialData?: T | null + initialData?: T | null; /** 请求前的回调 */ - onBefore?: () => void + onBefore?: () => void; /** 请求成功的回调 */ - onSuccess?: (data: T) => void + onSuccess?: (data: T) => void; /** 请求失败的回调 */ - onError?: (error: Error) => void + onError?: (error: Error) => void; /** 请求完成的回调(无论成功失败) */ - onFinally?: () => void + onFinally?: () => void; /** 是否重置数据在重新请求时,默认 false */ - resetOnExecute?: boolean + resetOnExecute?: boolean; } export interface UseRequestReturn { /** 响应数据 */ - data: Ref + data: Ref; /** 是否正在加载 */ - loading: ComputedRef + loading: ComputedRef; /** 错误信息 */ - error: Ref + error: Ref; /** 是否已请求过(用于区分初始状态和请求后状态) */ - hasExecuted: Ref + hasExecuted: Ref; /** 执行请求 */ - execute: () => Promise + execute: () => Promise; /** 刷新数据(重新执行请求) */ - refresh: () => Promise + refresh: () => Promise; /** 重置状态 */ - reset: () => void + reset: () => void; } /** @@ -74,15 +74,15 @@ export function useRequest( onError, onFinally, resetOnExecute = false, - } = options + } = options; // 使用 shallowRef 避免深层响应式,提升性能 - const data = shallowRef(initialData) as Ref - const error = ref(null) - const loadingCount = ref(0) - const hasExecuted = ref(false) + const data = shallowRef(initialData) as Ref; + const error = ref(null); + const loadingCount = ref(0); + const hasExecuted = ref(false); - const loading = computed(() => loadingCount.value > 0) + const loading = computed(() => loadingCount.value > 0); /** * 执行请求 @@ -90,51 +90,51 @@ export function useRequest( const execute = async (): Promise => { // 重置状态 if (resetOnExecute) { - data.value = initialData - error.value = null + data.value = initialData; + error.value = null; } - loadingCount.value++ - hasExecuted.value = true + loadingCount.value++; + hasExecuted.value = true; try { - onBefore?.() - const result = await requestFn() - data.value = result - error.value = null - onSuccess?.(result) - return result + onBefore?.(); + const result = await requestFn(); + data.value = result; + error.value = null; + onSuccess?.(result); + return result; } catch (e) { - const err = e instanceof Error ? e : new Error(String(e)) - error.value = err - onError?.(err) - return null + const err = e instanceof Error ? e : new Error(String(e)); + error.value = err; + onError?.(err); + return null; } finally { - loadingCount.value-- - onFinally?.() + loadingCount.value--; + onFinally?.(); } - } + }; /** * 刷新数据 */ const refresh = async (): Promise => { - return execute() - } + return execute(); + }; /** * 重置状态 */ const reset = (): void => { - data.value = initialData - error.value = null - loadingCount.value = 0 - hasExecuted.value = false - } + data.value = initialData; + error.value = null; + loadingCount.value = 0; + hasExecuted.value = false; + }; // 立即执行 if (immediate) { - execute() + execute(); } return { @@ -145,7 +145,7 @@ export function useRequest( execute, refresh, reset, - } + }; } /** @@ -167,42 +167,42 @@ export function useRequest( */ export interface PaginationParams { - pageNum: number - pageSize: number + pageNum: number; + pageSize: number; } export interface UsePaginationOptions { /** 每页条数,默认 10 */ - pageSize?: number + pageSize?: number; /** 初始数据 */ - initialData?: T[] + initialData?: T[]; /** 请求成功的回调 */ - onSuccess?: (list: T[], total: number) => void + onSuccess?: (list: T[], total: number) => void; /** 请求失败的回调 */ - onError?: (error: Error) => void + onError?: (error: Error) => void; } export interface UsePaginationReturn { /** 数据列表 */ - list: Ref + list: Ref; /** 是否正在加载 */ - loading: ComputedRef + loading: ComputedRef; /** 错误信息 */ - error: Ref + error: Ref; /** 是否还有更多数据 */ - hasMore: ComputedRef + hasMore: ComputedRef; /** 当前页码 */ - pageNum: Ref + pageNum: Ref; /** 总条数 */ - total: Ref + total: Ref; /** 是否为空 */ - isEmpty: ComputedRef + isEmpty: ComputedRef; /** 加载更多 */ - loadMore: () => Promise + loadMore: () => Promise; /** 刷新(从第一页开始) */ - refresh: () => Promise + refresh: () => Promise; /** 重置 */ - reset: () => void + reset: () => void; } /** @@ -215,17 +215,17 @@ export function usePagination( requestFn: (params: PaginationParams) => Promise>, options: UsePaginationOptions = {} ): UsePaginationReturn { - const { pageSize = 10, initialData = [], onSuccess, onError } = options + const { pageSize = 10, initialData = [], onSuccess, onError } = options; - const list = ref(initialData) as Ref - const loadingCount = ref(0) - const error = ref(null) - const pageNum = ref(1) - const total = ref(0) + const list = ref(initialData) as Ref; + const loadingCount = ref(0); + const error = ref(null); + const pageNum = ref(1); + const total = ref(0); - const loading = computed(() => loadingCount.value > 0) - const hasMore = computed(() => list.value.length < total.value) - const isEmpty = computed(() => list.value.length === 0 && !loading.value) + const loading = computed(() => loadingCount.value > 0); + const hasMore = computed(() => list.value.length < total.value); + const isEmpty = computed(() => list.value.length === 0 && !loading.value); /** * 加载更多 @@ -233,59 +233,59 @@ export function usePagination( const loadMore = async (): Promise => { // 如果正在加载或没有更多数据,直接返回 if (loading.value || !hasMore.value) { - return list.value + return list.value; } - loadingCount.value++ + loadingCount.value++; try { const result = await requestFn({ pageNum: pageNum.value, pageSize, - }) + }); // 如果是第一页,替换数据;否则追加数据 if (pageNum.value === 1) { - list.value = result.list + list.value = result.list; } else { - list.value = [...list.value, ...result.list] + list.value = [...list.value, ...result.list]; } - total.value = result.total - pageNum.value++ - onSuccess?.(result.list, result.total) + total.value = result.total; + pageNum.value++; + onSuccess?.(result.list, result.total); - return result.list + return result.list; } catch (e) { - const err = e instanceof Error ? e : new Error(String(e)) - error.value = err - onError?.(err) - return [] + const err = e instanceof Error ? e : new Error(String(e)); + error.value = err; + onError?.(err); + return []; } finally { - loadingCount.value-- + loadingCount.value--; } - } + }; /** * 刷新(从第一页开始) */ const refresh = async (): Promise => { - pageNum.value = 1 - total.value = 0 - list.value = [] - return loadMore() - } + pageNum.value = 1; + total.value = 0; + list.value = []; + return loadMore(); + }; /** * 重置 */ const reset = (): void => { - list.value = initialData - loadingCount.value = 0 - error.value = null - pageNum.value = 1 - total.value = 0 - } + list.value = initialData; + loadingCount.value = 0; + error.value = null; + pageNum.value = 1; + total.value = 0; + }; return { list, @@ -298,5 +298,5 @@ export function usePagination( loadMore, refresh, reset, - } + }; } diff --git a/src/composables/useTabbar.ts b/src/composables/useTabbar.ts index f0442b5..99e4f5f 100644 --- a/src/composables/useTabbar.ts +++ b/src/composables/useTabbar.ts @@ -1,4 +1,4 @@ -import { ref, computed } from "vue" +import { ref, computed } from "vue"; /** * TabBar 状态管理 @@ -19,15 +19,15 @@ export interface TabbarItem { /** 唯一标识 */ - name: string + name: string; /** 徽标数字,null 表示不显示 */ - value: number | null + value: number | null; /** 是否激活 */ - active: boolean + active: boolean; /** 显示标题 */ - title: string + title: string; /** 图标名称 */ - icon: string + icon: string; } /** 默认 TabBar 配置 */ @@ -35,7 +35,7 @@ const DEFAULT_TABBAR_ITEMS: Omit[] = [ { name: "home", value: null, title: "首页", icon: "home" }, { name: "work", value: null, title: "工作台", icon: "laptop" }, { name: "mine", value: null, title: "我的", icon: "user" }, -] +]; /** * 创建 TabBar 状态实例 @@ -49,24 +49,24 @@ function createTabbarState() { ...item, active: index === 0, })) - ) + ); /** TabBar 列表 */ - const tabbarList = computed(() => items.value) + const tabbarList = computed(() => items.value); /** 当前激活的 TabBar 项 */ const activeTabbar = computed(() => { - return items.value.find((item) => item.active) || items.value[0] - }) + return items.value.find((item) => item.active) || items.value[0]; + }); /** * 获取指定 TabBar 项的徽标数字 * @param name TabBar 项名称 */ const getTabbarItemValue = (name: string): number | null => { - const item = items.value.find((item) => item.name === name) - return item?.value ?? null - } + const item = items.value.find((item) => item.name === name); + return item?.value ?? null; + }; /** * 设置 TabBar 项的徽标数字 @@ -74,11 +74,11 @@ function createTabbarState() { * @param value 徽标数字 */ const setTabbarItem = (name: string, value: number): void => { - const item = items.value.find((item) => item.name === name) + const item = items.value.find((item) => item.name === name); if (item) { - item.value = value + item.value = value; } - } + }; /** * 设置激活的 TabBar 项 @@ -86,9 +86,9 @@ function createTabbarState() { */ const setTabbarItemActive = (name: string): void => { items.value.forEach((item) => { - item.active = item.name === name - }) - } + item.active = item.name === name; + }); + }; /** * 重置 TabBar 状态 @@ -97,8 +97,8 @@ function createTabbarState() { items.value = DEFAULT_TABBAR_ITEMS.map((item, index) => ({ ...item, active: index === 0, - })) - } + })); + }; return { tabbarList, @@ -107,11 +107,11 @@ function createTabbarState() { setTabbarItem, setTabbarItemActive, resetTabbar, - } + }; } /** 全局单例实例 */ -let tabbarInstance: ReturnType | null = null +let tabbarInstance: ReturnType | null = null; /** * TabBar 状态管理 Hook @@ -123,14 +123,14 @@ let tabbarInstance: ReturnType | null = null * @param options.singleton 是否使用单例模式,默认 true */ export function useTabbar(options?: { singleton?: boolean }) { - const { singleton = true } = options ?? {} + const { singleton = true } = options ?? {}; if (singleton) { if (!tabbarInstance) { - tabbarInstance = createTabbarState() + tabbarInstance = createTabbarState(); } - return tabbarInstance + return tabbarInstance; } - return createTabbarState() + return createTabbarState(); } diff --git a/src/pages/index/index.vue b/src/pages/index/index.vue index b70c4bf..27b328a 100644 --- a/src/pages/index/index.vue +++ b/src/pages/index/index.vue @@ -105,10 +105,6 @@ import { checkLogin, isLoggedIn } from "@/utils/auth"; import LogAPI, { type VisitOverview as ApiVisitOverview, type VisitTrend } from "@/api/log"; import NoticeAPI, { type NoticeItem } from "@/api/notice"; -// ============================================================================ -// 类型定义 -// ============================================================================ - type VisitOverviewVO = ApiVisitOverview; interface NavItem { @@ -118,22 +114,17 @@ interface NavItem { perm: string; } -// ============================================================================ -// Hooks -// ============================================================================ - const router = useRouter(); const userStore = useUserStore(); // custom-navbar 组件内部已处理导航栏高度与胶囊避让 -// ============================================================================ -// 响应式数据 -// ============================================================================ - const current = ref(0); const recentDaysRange = ref(7); -const swiperList = ref(["https://www.youlai.tech/storage/youlai/bg02.png" ,"https://www.youlai.tech/storage/blog/banner9.png" ]); +const swiperList = ref([ + "https://www.youlai.tech/storage/youlai/bg02.png", + "https://www.youlai.tech/storage/blog/banner9.png", +]); const visitOverviewData = ref({ todayUvCount: 0, @@ -228,10 +219,6 @@ const chartOpts = ref({ }, }); -// ============================================================================ -// 数据加载 -// ============================================================================ - function loadAppVersion() { try { const p: any = (globalThis as any).plus; @@ -287,10 +274,6 @@ async function loadVisitTrendData() { } } -// ============================================================================ -// 事件处理 -// ============================================================================ - function handleNavClick(item: NavItem) { // 未登录 / 无权限时:展示默认导航,但点击统一跳登录 if (!isLogged.value || !hasAnyPerm.value) { @@ -332,10 +315,6 @@ function handleDataRangeChange({ value }: { value: number }) { loadVisitTrendData(); } -// ============================================================================ -// 生命周期 -// ============================================================================ - onReady(() => { loadAppVersion(); loadNoticeData(); @@ -491,13 +470,13 @@ onShow(() => { &--uv, &--green { - background: #34d19d; + background: var(--color-success); box-shadow: 0 0 10rpx rgba(52, 209, 157, 0.35); } &--pv, &--blue { - background: #4d80f0; + background: var(--color-primary); box-shadow: 0 0 10rpx rgba(77, 128, 240, 0.3); } } @@ -512,12 +491,12 @@ onShow(() => { &--uv, &--green { - color: #34d19d; + color: var(--color-success); } &--pv, &--blue { - color: #4d80f0; + color: var(--color-primary); } } diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue index 932d926..f148cc6 100644 --- a/src/pages/login/index.vue +++ b/src/pages/login/index.vue @@ -214,7 +214,9 @@ />