diff --git a/app/components/TopNav.vue b/app/components/TopNav.vue index 91a4341..3f38b7a 100644 --- a/app/components/TopNav.vue +++ b/app/components/TopNav.vue @@ -61,17 +61,17 @@ watch(() => route.path, () => {
  • - 登录 - 注册 + 登录 + 注册
  • -
    +
  • {{ user?.username }} -
  • +
    {{ user?.username }} diff --git a/app/pages/auth/index.vue b/app/pages/auth/index.vue deleted file mode 100644 index 18e8c4f..0000000 --- a/app/pages/auth/index.vue +++ /dev/null @@ -1,807 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/pages/auth/login.vue b/app/pages/auth/login.vue new file mode 100644 index 0000000..f24e460 --- /dev/null +++ b/app/pages/auth/login.vue @@ -0,0 +1,582 @@ + + + + + \ No newline at end of file diff --git a/app/pages/auth/register.vue b/app/pages/auth/register.vue new file mode 100644 index 0000000..33fdc56 --- /dev/null +++ b/app/pages/auth/register.vue @@ -0,0 +1,510 @@ + + + + + \ No newline at end of file diff --git a/app/utils/auth-routes.ts b/app/utils/auth-routes.ts index 4a8f032..8924aa4 100644 --- a/app/utils/auth-routes.ts +++ b/app/utils/auth-routes.ts @@ -1,5 +1,5 @@ -const PUBLIC_ROUTE_EXACT = new Set(["/", "/auth"]); -const GUEST_ONLY_ROUTE_EXACT = new Set(["/auth"]); +const PUBLIC_ROUTE_EXACT = new Set(["/", "/auth/login", "/auth/register"]); +const GUEST_ONLY_ROUTE_EXACT = new Set(["/auth/login", "/auth/register"]); /** 公开主页 /@slug 与仅链接分享 /p/slug/t/token */ const PUBLIC_ROUTE_PREFIXES: string[] = ["/@", "/p/"]; diff --git a/docs/superpowers/specs/2026-05-25-admin-users-management-design.md b/docs/superpowers/specs/2026-05-25-admin-users-management-design.md new file mode 100644 index 0000000..49c23a3 --- /dev/null +++ b/docs/superpowers/specs/2026-05-25-admin-users-management-design.md @@ -0,0 +1,99 @@ +# Admin Users Management — Design Spec + +## 概述 + +后台管理系统的用户管理模块,提供管理员增删改查用户的能力。 + +## 路由与布局 + +- **布局**:`app/layouts/admin.vue` — 左侧边栏 + 右侧 `` 内容区 +- **边栏菜单**:用户管理、Scheduled Tasks +- **访问控制**:所有 `/admin/*` 路由需要 admin 角色(`requireAdmin`) +- **边栏宽度**:240px 固定,内容区 flex-1 + +## 页面:用户列表 `/admin/users` + +### 路由 +- `app/pages/admin/users/index.vue` + +### 顶部操作栏 +- 搜索框(按 username / email 过滤,客户端筛选) +- 新建用户按钮(coral CTA) + +### 表格列 +| 列 | 来源 | +|----|------| +| ID | `users.id` | +| Username | `users.username` | +| Email | `users.email` | +| Role | `users.role`(badge 显示:user=蓝/ admin=珊瑚色) | +| Status | `users.status`(badge 显示:active=绿 / inactive=灰) | +| Created | `users.createdAt`(格式化日期) | + +### 行操作 +- 编辑(打开编辑弹窗) +- 删除(确认对话框后执行) + +### 分页 +- 每页 20 条,支持 prev/next + +## 弹窗:新建用户 + +### 字段 +| 字段 | 类型 | 校验 | +|------|------|------| +| Username | text | 必填,唯一 | +| Email | text | 必填,Email 格式 | +| Role | select | user / admin,默认 user | +| Status | select | active / inactive,默认 active | + +### 提交 +- POST `/api/admin/users` +- 成功后关闭弹窗,刷新列表 + +## 弹窗:编辑用户 + +### 字段(均只读展示) +| 字段 | 行为 | +|------|------| +| Username | 只读文本 | +| Email | 只读文本 | +| Role | select — user / admin | +| Status | select — active / inactive | + +### 提交 +- PATCH `/api/admin/users/:id` +- 成功后关闭弹窗,刷新列表 + +## API 设计 + +### `GET /api/admin/users` +- 调用 `requireAdmin` +- 返回用户列表(排除 password 字段) +- Query: `page`, `limit` + +### `POST /api/admin/users` +- 调用 `requireAdmin` +- Body: `{ username, email, role, status }` +- 创建用户(初始 password 可随机生成或留空由管理员重置) + +### `PATCH /api/admin/users/:id` +- 调用 `requireAdmin` +- Body: `{ role, status }` + +### `DELETE /api/admin/users/:id` +- 调用 `requireAdmin` +- 删除用户(级联删除 sessions) + +## 视觉风格 + +遵循 DESIGN.md: +- 页面底色:`#faf9f5`(canvas) +- 按钮:coral `#cc785c` +- 表格:白色底 + hairline 边框 +- Badge:role 和 status 用小药丸标签 + +## 依赖 + +- 复用 `server/utils/admin-guard.ts` 的 `requireAdmin` +- 用户 schema 已有(`packages/drizzle-pkg/lib/schema/auth.ts`) diff --git a/docs/superpowers/specs/2026-05-25-auth-pages-redesign-design.md b/docs/superpowers/specs/2026-05-25-auth-pages-redesign-design.md new file mode 100644 index 0000000..c80bbe0 --- /dev/null +++ b/docs/superpowers/specs/2026-05-25-auth-pages-redesign-design.md @@ -0,0 +1,91 @@ +# 登录注册页面重写设计 + +## 日期 +2026-05-25 + +## 目标 +重写 `/auth/login` 和 `/auth/register` 页面为独立的极简居中卡片表单,不依赖其他页面信息。 + +## 设计风格 +方案一:极简居中卡片 + +## 结构 + +### 页面结构 +- 全屏 `{colors.canvas}` = #faf9f5 背景 +- 居中单卡片,`{rounded.lg}`(12px),白底 + 微妙阴影 +- 卡片最大宽度 420px,内边距 40px + +### 背景装饰 +- 32px 圆点网格纹理(`{colors.hairline}` 色,opacity 0.5) +- 右上角 + 左下角各一模糊光晕(coral + amber,opacity ~10-12%) + +### 表单内容(login) +- 标题:"欢迎回来" +- 副标题:"继续您的探索之旅" +- 用户名/邮箱输入框(浮动 label) +- 密码输入框 + 忘记密码链接 +- 验证码输入框 + 验证码图片 +- 记住我复选框 +- 提交按钮 +- 分割线 + 社交登录按钮 +- 底部链接:"还没有账户?立即注册" + +### 表单内容(register) +- 标题:"创建账户" +- 副标题:"加入我们开始策展" +- 用户名输入框 +- 密码输入框 +- 确认密码输入框 +- 验证码输入框 + 验证码图片 +- 提交按钮 +- 分割线 + 社交登录按钮 +- 底部链接:"已有账户?立即登录" + +## 交互细节 +- 提交按钮 hover 光泽扫过动效 +- 输入框 focus 边框变 coral + 外发光(4px coral 10% alpha) +- 验证码点击刷新 + +## 组件样式 + +### 卡片 +``` +background: {colors.canvas} +border-radius: 12px +box-shadow: 0 2px 12px rgba(20,20,19,0.06) +padding: 40px +max-width: 420px +``` + +### 输入框 +``` +background: {colors.canvas} +border: 1.5px solid {colors.hairline} +border-radius: 8px +padding: 20px 16px 8px +font-size: 16px +transition: border-color 0.2s ease, box-shadow 0.2s ease +focus: border-color = {colors.primary}, box-shadow = 0 0 0 4px rgba(204, 120, 92, 0.1) +``` + +### 提交按钮 +``` +background: {colors.primary} +color: {colors.on-primary} +border-radius: 8px +padding: 18px 24px +hover: {colors.primary-active} +active: scale(0.98) +``` + +### 背景光晕 +``` +光晕1(右上): background: {colors.primary}, top: -150px, right: 10%, opacity: 0.12, blur: 80px, 尺寸: 500px +光晕2(左下): background: {colors.accent-amber}, bottom: -100px, left: 20%, opacity: 0.08, blur: 80px, 尺寸: 400px +网格纹理: radial-gradient, 32px 间隔, opacity 0.5 +``` + +## 实现文件 +- `app/pages/auth/login.vue` +- `app/pages/auth/register.vue` \ No newline at end of file diff --git a/packages/drizzle-pkg/db.sqlite b/packages/drizzle-pkg/db.sqlite index f0d8f9f..504a985 100644 Binary files a/packages/drizzle-pkg/db.sqlite and b/packages/drizzle-pkg/db.sqlite differ