From 72329baff4752d9675ad1040b1ad6b940d598c90 Mon Sep 17 00:00:00 2001 From: Cccc_ Date: Mon, 4 May 2026 17:52:39 +0800 Subject: [PATCH] feat(new-frontend): use shadcn-vue UI --- apps/new-frontend/package.json | 2 + apps/new-frontend/pnpm-lock.yaml | 162 ++++++++- apps/new-frontend/src/app/theme.ts | 2 +- .../new-frontend/src/components/AppLayout.vue | 122 ++++--- .../src/components/StateBlock.vue | 16 +- .../templates/TemplateConfigEditor.vue | 14 +- .../templates/TemplateFieldNode.vue | 67 ++-- apps/new-frontend/src/components/ui.ts | 18 +- .../src/components/ui/button/Button.vue | 34 ++ .../src/components/ui/button/index.ts | 35 ++ .../src/components/ui/dialog/Dialog.vue | 15 + .../src/components/ui/dialog/DialogClose.vue | 12 + .../components/ui/dialog/DialogContent.vue | 55 +++ .../ui/dialog/DialogDescription.vue | 23 ++ .../src/components/ui/dialog/DialogFooter.vue | 29 ++ .../src/components/ui/dialog/DialogHeader.vue | 17 + .../components/ui/dialog/DialogOverlay.vue | 26 ++ .../ui/dialog/DialogScrollContent.vue | 64 ++++ .../src/components/ui/dialog/DialogTitle.vue | 23 ++ .../components/ui/dialog/DialogTrigger.vue | 12 + .../src/components/ui/dialog/index.ts | 10 + .../src/components/ui/tooltip/Tooltip.vue | 15 + .../components/ui/tooltip/TooltipContent.vue | 45 +++ .../components/ui/tooltip/TooltipProvider.vue | 14 + .../components/ui/tooltip/TooltipTrigger.vue | 12 + .../src/components/ui/tooltip/index.ts | 4 + apps/new-frontend/src/views/DashboardView.vue | 335 +++++++++--------- apps/new-frontend/src/views/LoginView.vue | 49 +-- apps/new-frontend/src/views/RecordsView.vue | 23 +- apps/new-frontend/src/views/SettingsView.vue | 29 +- .../src/views/TaskRecordsView.vue | 24 +- apps/new-frontend/src/views/TasksView.vue | 90 ++--- .../src/views/admin/AdminLogsView.vue | 2 +- .../src/views/admin/AdminRecordsView.vue | 18 +- .../src/views/admin/AdminStatsView.vue | 22 +- .../src/views/admin/AdminTemplatesView.vue | 205 ++++++----- .../src/views/admin/AdminUsersView.vue | 74 ++-- 37 files changed, 1204 insertions(+), 515 deletions(-) create mode 100644 apps/new-frontend/src/components/ui/button/Button.vue create mode 100644 apps/new-frontend/src/components/ui/button/index.ts create mode 100644 apps/new-frontend/src/components/ui/dialog/Dialog.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogClose.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogContent.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogDescription.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogFooter.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogHeader.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogOverlay.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogScrollContent.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogTitle.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/DialogTrigger.vue create mode 100644 apps/new-frontend/src/components/ui/dialog/index.ts create mode 100644 apps/new-frontend/src/components/ui/tooltip/Tooltip.vue create mode 100644 apps/new-frontend/src/components/ui/tooltip/TooltipContent.vue create mode 100644 apps/new-frontend/src/components/ui/tooltip/TooltipProvider.vue create mode 100644 apps/new-frontend/src/components/ui/tooltip/TooltipTrigger.vue create mode 100644 apps/new-frontend/src/components/ui/tooltip/index.ts diff --git a/apps/new-frontend/package.json b/apps/new-frontend/package.json index 056a30d..1577922 100644 --- a/apps/new-frontend/package.json +++ b/apps/new-frontend/package.json @@ -16,9 +16,11 @@ }, "dependencies": { "@tailwindcss/vite": "^4.2.4", + "@vueuse/core": "^14.3.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-vue-next": "^1.0.0", + "reka-ui": "^2.9.6", "tailwind-merge": "^3.5.0", "tailwindcss": "^4.2.4", "vue": "^3.5.33" diff --git a/apps/new-frontend/pnpm-lock.yaml b/apps/new-frontend/pnpm-lock.yaml index 48a120a..0d470d8 100644 --- a/apps/new-frontend/pnpm-lock.yaml +++ b/apps/new-frontend/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@tailwindcss/vite': specifier: ^4.2.4 version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(jiti@2.6.1)) + '@vueuse/core': + specifier: ^14.3.0 + version: 14.3.0(vue@3.5.33(typescript@6.0.3)) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -20,6 +23,9 @@ importers: lucide-vue-next: specifier: ^1.0.0 version: 1.0.0(vue@3.5.33(typescript@6.0.3)) + reka-ui: + specifier: ^2.9.6 + version: 2.9.6(vue@3.5.33(typescript@6.0.3)) tailwind-merge: specifier: ^3.5.0 version: 3.5.0 @@ -139,6 +145,18 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@floating-ui/vue@1.1.11': + resolution: {integrity: sha512-HzHKCNVxnGS35r9fCHBc3+uCnjw9IWIlCPL683cGgM9Kgj2BiAl8x1mS7vtvP6F9S/e/q4O6MApwSHj8hNLGfw==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -159,6 +177,12 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} + '@internationalized/date@3.12.1': + resolution: {integrity: sha512-6IedsVWXyq4P9Tj+TxuU8WGWM70hYLl12nbYU8jkikVpa6WXapFazPUcHUMDMoWftIDE2ILDkFFte6W2nFCkRQ==} + + '@internationalized/number@3.6.6': + resolution: {integrity: sha512-iFgmQaXHE0vytNfpLZWOC2mEJCBRzcUxt53Xf/yCXG93lRvqas237i3r7X4RKMwO3txiyZD4mQjKAByFv6UGSQ==} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -289,6 +313,9 @@ packages: '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + '@swc/helpers@0.5.21': + resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} + '@tailwindcss/node@4.2.4': resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} @@ -383,6 +410,14 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@tanstack/virtual-core@3.14.0': + resolution: {integrity: sha512-JLANqGy/D6k4Ujmh8Tr25lGimuOXNiaVyXaCAZS0W+1390sADdGnyUdSWNIfd49gebtIxGMij4IktRVzrdr12Q==} + + '@tanstack/vue-virtual@3.13.24': + resolution: {integrity: sha512-A0k2qF0zFSUStXSZkGXABouXr2Tw2Ztl/cVIYG9qy84uR8W7UNjAcX3DvzBS3YnDcwvLxab8v7dbmYBZ39itDA==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -398,6 +433,9 @@ packages: '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/web-bluetooth@0.0.21': + resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} + '@typescript-eslint/parser@8.59.1': resolution: {integrity: sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -500,6 +538,19 @@ packages: vue: optional: true + '@vueuse/core@14.3.0': + resolution: {integrity: sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==} + peerDependencies: + vue: ^3.5.0 + + '@vueuse/metadata@14.3.0': + resolution: {integrity: sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==} + + '@vueuse/shared@14.3.0': + resolution: {integrity: sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==} + peerDependencies: + vue: ^3.5.0 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -523,6 +574,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -589,6 +644,9 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -912,6 +970,9 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -971,6 +1032,11 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + reka-ui@2.9.6: + resolution: {integrity: sha512-K6bL457owpvWONc7hsjFxo3HDC9s6IzhRqShW0w9JSKelPGfRbkHD558UQTn/NH1cvrXVHygKyC7fExFmRketg==} + peerDependencies: + vue: '>= 3.4.0' + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -1099,6 +1165,17 @@ packages: vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + vue-demi@0.14.10: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + vue-eslint-parser@10.4.0: resolution: {integrity: sha512-Vxi9pJdbN3ZnVGLODVtZ7y4Y2kzAAE2Cm0CZ3ZDRvydVYxZ6VrnBhLikBsRS+dpwj4Jv4UCv21PTEwF5rQ9WXg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1213,6 +1290,26 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/utils@0.2.11': {} + + '@floating-ui/vue@1.1.11(vue@3.5.33(typescript@6.0.3))': + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/utils': 0.2.11 + vue-demi: 0.14.10(vue@3.5.33(typescript@6.0.3)) + transitivePeerDependencies: + - '@vue/composition-api' + - vue + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -1229,6 +1326,14 @@ snapshots: '@humanwhocodes/retry@0.4.3': {} + '@internationalized/date@3.12.1': + dependencies: + '@swc/helpers': 0.5.21 + + '@internationalized/number@3.6.6': + dependencies: + '@swc/helpers': 0.5.21 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -1312,6 +1417,10 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.17': {} + '@swc/helpers@0.5.21': + dependencies: + tslib: 2.8.1 + '@tailwindcss/node@4.2.4': dependencies: '@jridgewell/remapping': 2.3.5 @@ -1380,6 +1489,13 @@ snapshots: tailwindcss: 4.2.4 vite: 8.0.10(@types/node@25.6.0)(jiti@2.6.1) + '@tanstack/virtual-core@3.14.0': {} + + '@tanstack/vue-virtual@3.13.24(vue@3.5.33(typescript@6.0.3))': + dependencies: + '@tanstack/virtual-core': 3.14.0 + vue: 3.5.33(typescript@6.0.3) + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -1395,6 +1511,8 @@ snapshots: dependencies: undici-types: 7.19.2 + '@types/web-bluetooth@0.0.21': {} + '@typescript-eslint/parser@8.59.1(eslint@9.39.4(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@typescript-eslint/scope-manager': 8.59.1 @@ -1543,6 +1661,19 @@ snapshots: typescript: 6.0.3 vue: 3.5.33(typescript@6.0.3) + '@vueuse/core@14.3.0(vue@3.5.33(typescript@6.0.3))': + dependencies: + '@types/web-bluetooth': 0.0.21 + '@vueuse/metadata': 14.3.0 + '@vueuse/shared': 14.3.0(vue@3.5.33(typescript@6.0.3)) + vue: 3.5.33(typescript@6.0.3) + + '@vueuse/metadata@14.3.0': {} + + '@vueuse/shared@14.3.0(vue@3.5.33(typescript@6.0.3))': + dependencies: + vue: 3.5.33(typescript@6.0.3) + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -1564,6 +1695,10 @@ snapshots: argparse@2.0.1: {} + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + balanced-match@1.0.2: {} balanced-match@4.0.4: {} @@ -1616,6 +1751,8 @@ snapshots: deep-is@0.1.4: {} + defu@6.1.7: {} + detect-libc@2.1.2: {} enhanced-resolve@5.21.0: @@ -1900,6 +2037,8 @@ snapshots: dependencies: boolbase: 1.0.0 + ohash@2.0.11: {} + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -1952,6 +2091,22 @@ snapshots: punycode@2.3.1: {} + reka-ui@2.9.6(vue@3.5.33(typescript@6.0.3)): + dependencies: + '@floating-ui/dom': 1.7.6 + '@floating-ui/vue': 1.1.11(vue@3.5.33(typescript@6.0.3)) + '@internationalized/date': 3.12.1 + '@internationalized/number': 3.6.6 + '@tanstack/vue-virtual': 3.13.24(vue@3.5.33(typescript@6.0.3)) + '@vueuse/core': 14.3.0(vue@3.5.33(typescript@6.0.3)) + '@vueuse/shared': 14.3.0(vue@3.5.33(typescript@6.0.3)) + aria-hidden: 1.2.6 + defu: 6.1.7 + ohash: 2.0.11 + vue: 3.5.33(typescript@6.0.3) + transitivePeerDependencies: + - '@vue/composition-api' + resolve-from@4.0.0: {} rolldown@1.0.0-rc.17: @@ -2010,8 +2165,7 @@ snapshots: dependencies: typescript: 6.0.3 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} tw-animate-css@1.4.0: {} @@ -2043,6 +2197,10 @@ snapshots: vscode-uri@3.1.0: {} + vue-demi@0.14.10(vue@3.5.33(typescript@6.0.3)): + dependencies: + vue: 3.5.33(typescript@6.0.3) + vue-eslint-parser@10.4.0(eslint@9.39.4(jiti@2.6.1)): dependencies: debug: 4.4.3 diff --git a/apps/new-frontend/src/app/theme.ts b/apps/new-frontend/src/app/theme.ts index 4bd48a4..99d9ad4 100644 --- a/apps/new-frontend/src/app/theme.ts +++ b/apps/new-frontend/src/app/theme.ts @@ -108,7 +108,7 @@ export function useTheme() { modeLabel: computed(() => { if (state.mode === 'light') return '亮色' if (state.mode === 'dark') return '暗色' - return state.resolved === 'dark' ? '跟随系统:暗色' : '跟随系统:亮色' + return '设备' }), setThemeMode, cycleThemeMode, diff --git a/apps/new-frontend/src/components/AppLayout.vue b/apps/new-frontend/src/components/AppLayout.vue index 58c1358..d8e3607 100644 --- a/apps/new-frontend/src/components/AppLayout.vue +++ b/apps/new-frontend/src/components/AppLayout.vue @@ -13,6 +13,7 @@ import { ScrollText, Settings, Shield, + Sun, UserRound, Users, X, @@ -20,7 +21,9 @@ import { import { computed, ref } from 'vue' import { useAuth } from '@/app/auth' import { useRouter } from '@/app/router' -import { useTheme } from '@/app/theme' +import { type ThemeMode, useTheme } from '@/app/theme' +import { Button } from '@/components/ui/button' +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' const { state: authState, isAdmin, logout } = useAuth() const router = useRouter() @@ -47,6 +50,18 @@ const isAdminRoute = computed(() => router.state.path.startsWith('/admin')) const approvalLabel = computed(() => (authState.user?.is_approved ? '已审批' : '待审批')) const roleLabel = computed(() => (isAdmin.value ? '管理员' : '普通用户')) const themeLabel = computed(() => theme.modeLabel.value) +const themeModes = [ + { mode: 'light', label: '亮色', icon: Sun }, + { mode: 'dark', label: '暗色', icon: MoonStar }, + { mode: 'system', label: '设备', icon: Monitor }, +] as const + +function themeModeButtonClass(mode: ThemeMode) { + if (theme.state.mode === mode) { + return 'bg-zinc-900 text-white shadow-sm hover:bg-zinc-900 hover:text-white dark:bg-zinc-100 dark:text-zinc-950 dark:hover:bg-zinc-100 dark:hover:text-zinc-950' + } + return 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-950 dark:text-zinc-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-50' +} function go(path: string) { mobileOpen.value = false @@ -64,16 +79,18 @@ function signOut() {
-
+
- +
- - + + + {{ item.label }} + + +
+ + +
-
+
-
+
-
+
管理员
-

+

{{ title }}

-

- {{ - isAdminRoute - ? '管理用户、模板、记录、日志和系统统计。' - : '管理打卡任务、授权状态和系统记录。' - }} -

-
- - {{ approvalLabel }} +
+
+ + {{ approvalLabel }} +
+
+ + 管理员工作区 +
diff --git a/apps/new-frontend/src/components/StateBlock.vue b/apps/new-frontend/src/components/StateBlock.vue index d6bca45..087650e 100644 --- a/apps/new-frontend/src/components/StateBlock.vue +++ b/apps/new-frontend/src/components/StateBlock.vue @@ -15,10 +15,10 @@ defineEmits<{