From 9150a17097ec3088f8c51a662c35fff8ea750475 Mon Sep 17 00:00:00 2001 From: Mplan Date: Fri, 22 May 2026 21:04:49 +0800 Subject: [PATCH] feat: add admin console and account settings Implement the admin dashboard with review, user, and image management workflows. Add profile settings, password reset, pending upload defaults, community placeholder routing, Vercel SPA rewrites, refreshed header styling, and the OpenCloud color-system skill. --- .../skills/opencloud-color-system/SKILL.md | 74 ++ src/components/layout/AppHeader.vue | 56 +- src/composables/useUpload.ts | 2 +- src/main.ts | 2 +- src/router/index.ts | 16 + src/stores/auth.ts | 70 +- src/views/admin/AdminView.vue | 774 +++++++++++++++++- src/views/auth/LoginView.vue | 61 +- src/views/auth/RegisterView.vue | 36 +- src/views/auth/ResetPasswordView.vue | 136 +++ src/views/community/CommunityView.vue | 14 + src/views/profile/ProfileSettingsView.vue | 181 ++++ src/views/profile/ProfileView.vue | 20 +- src/views/upload/UploadView.vue | 10 +- vercel.json | 8 + 15 files changed, 1410 insertions(+), 50 deletions(-) create mode 100644 .agents/skills/opencloud-color-system/SKILL.md create mode 100644 src/views/auth/ResetPasswordView.vue create mode 100644 src/views/community/CommunityView.vue create mode 100644 src/views/profile/ProfileSettingsView.vue create mode 100644 vercel.json diff --git a/.agents/skills/opencloud-color-system/SKILL.md b/.agents/skills/opencloud-color-system/SKILL.md new file mode 100644 index 0000000..4b46ffa --- /dev/null +++ b/.agents/skills/opencloud-color-system/SKILL.md @@ -0,0 +1,74 @@ +--- +name: opencloud-color-system +description: "Use when modifying OpenCloud UI colors, visual hierarchy, Tailwind classes, buttons, cards, headers, gradients, status chips, or page-level visual design. Ensures the project keeps its current fresh sky/teal/white visual language and avoids inconsistent dark or purple defaults." +--- + +# OpenCloud Color System + +Use this skill whenever changing OpenCloud visual design, component styling, or Tailwind color classes. + +## Visual Direction + +OpenCloud should feel like a clean sky atlas: airy, fresh, bright, and observational. + +- Base surfaces: `white`, `slate-50`, `sky-50`, soft translucent white (`bg-white/80`, `bg-white/88`). +- Main accent: teal/cyan for navigation, identity, account surfaces. +- Secondary accent: sky blue for upload and action highlights. +- Supporting accent: amber only for rarity, badges, pending/review states. +- Danger accent: rose/red only for destructive or rejected states. +- Avoid purple as a default accent. +- Avoid black selected states except for text or rare high-contrast badges. + +## Core Palette + +Use these Tailwind families first: + +- `slate`: text, borders, neutral panels. +- `sky`: page gradients, upload/action emphasis, map/cloud atmosphere. +- `teal`: navigation selected states, account identity, calm success-adjacent UI. +- `cyan`: subtle sky gradients and avatar/logo surfaces. +- `emerald`: explicit success/approved state only. +- `amber`: pending/review/uncommon rarity. +- `rose`: rejected/destructive/rare rarity. + +Preferred combinations: + +- Page hero: `bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]` +- Soft app page: `bg-[linear-gradient(180deg,#f0fdfa_0%,#f8fafc_100%)]` +- Brand chip/avatar: `bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)]` +- Selected nav: `bg-teal-100 text-teal-800 ring-1 ring-teal-200` +- Upload button: `border-sky-200 bg-sky-100 text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)]` + +## Component Rules + +- Header navigation selected state should stay teal, not black. +- Upload action should stay visually distinct from nav, preferably sky blue. +- Username/account entry should be light and calm: white/teal, subtle border, subtle shadow. +- Cards should generally use `bg-white`, `border-slate-200`, and light offset shadows. +- Use gradients for page introductions instead of generic rounded white rectangles. +- When adding hover states, prefer light fills (`hover:bg-teal-50`, `hover:bg-sky-50`) over dark inversion. + +## Status Colors + +- Approved/success: `emerald-100`, `emerald-700`. +- Pending/review: `amber-100`, `amber-700`. +- Rejected/destructive: `rose-100`, `rose-700` or Naive UI `type="error"`. +- Hidden/private/neutral: `slate-100`, `slate-600`. + +## Anti-Patterns + +- Do not use purple as a fallback visual direction. +- Do not use `bg-slate-900 text-white` for ordinary selected navigation. +- Do not introduce dark-mode-heavy sections unless the surrounding page already uses that language. +- Do not overuse rounded rectangles; the project has been intentionally moving toward sharper, atlas-like panels. +- Do not mix random accent colors within the same feature. Pick one accent family and keep it consistent. + +## Validation + +After color/style changes, run: + +```bash +npx vue-tsc -b +``` + +Run `npm run build` if the change touches routes, imported components, or package dependencies. diff --git a/src/components/layout/AppHeader.vue b/src/components/layout/AppHeader.vue index bab738b..f50bbce 100644 --- a/src/components/layout/AppHeader.vue +++ b/src/components/layout/AppHeader.vue @@ -1,6 +1,6 @@ diff --git a/src/views/auth/LoginView.vue b/src/views/auth/LoginView.vue index ea671d9..f8efd66 100644 --- a/src/views/auth/LoginView.vue +++ b/src/views/auth/LoginView.vue @@ -11,7 +11,10 @@ const route = useRoute() const email = ref('') const password = ref('') const error = ref('') +const resetMessage = ref('') +const resetMode = ref(false) const loading = ref(false) +const resetLoading = ref(false) async function handleLogin() { error.value = '' @@ -26,6 +29,26 @@ async function handleLogin() { loading.value = false } } + +async function handleSendResetEmail() { + error.value = '' + resetMessage.value = '' + + if (!email.value) { + error.value = '请输入需要重置密码的邮箱。' + return + } + + resetLoading.value = true + try { + await authStore.sendPasswordReset(email.value) + resetMessage.value = '重置密码邮件已发送,请查收邮箱。' + } catch (e: unknown) { + error.value = e instanceof Error ? e.message : '重置邮件发送失败,请稍后重试' + } finally { + resetLoading.value = false + } +}