+
+ 站点首页
+
登录
diff --git a/app/pages/index/index.vue b/app/pages/index/index.vue
index 060a00b..974a4da 100644
--- a/app/pages/index/index.vue
+++ b/app/pages/index/index.vue
@@ -7,6 +7,33 @@ const { allowRegister } = useGlobalConfig()
const logoutLoading = ref(false)
+const features = [
+ {
+ title: '个人资料',
+ desc: '生平叙事、头像、社交链接与公开主页 slug,支持分块可见性。',
+ icon: 'i-lucide-user-round',
+ to: '/me/profile',
+ },
+ {
+ title: 'Markdown 文章',
+ desc: '自写内容、slug、摘要与封面,每条可公开、私密或仅链接分享。',
+ icon: 'i-lucide-file-text',
+ to: '/me/posts',
+ },
+ {
+ title: '时光机',
+ desc: '按时间轴记录里程碑事件,与文章、阅读流在同一叙事里呈现。',
+ icon: 'i-lucide-history',
+ to: '/me/timeline',
+ },
+ {
+ title: 'RSS 收件箱',
+ desc: '订阅源仅自己可见;定时拉取、去重,条目默认可再设为公开展示。',
+ icon: 'i-lucide-rss',
+ to: '/me/rss',
+ },
+] as const
+
async function logout() {
logoutLoading.value = true
try {
@@ -20,72 +47,208 @@ async function logout() {
-
-
-
-
-
-
欢迎回来,{{ user?.username }}
-
你已登录,可访问站内受保护内容。
+
+
+
+
+
+
+
+ 个人数据中心
+
+
+ 把你的故事、文章与阅读,收进一个地方
+
+
+ Person Panel 面向「多用户、邀请制」场景:每位用户独立资料与订阅;公开主页可只展示你愿意公开的部分;RSS 在后台静默同步。
+
+
+
+
+ 进入控制台
+
+
+ 预览公开主页
+
+
+ 设置公开链接
+
+
+
+
+ 登录使用
+
+
+ 注册账号
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 当前用户
+
+
+ {{ user.nickname?.trim() || user.username }}
+
+
+ @{{ user.username }} · {{ user.role === 'admin' ? '管理员' : '用户' }}
+
-
已登录
-
+
+
+
+ 公开主页
+
+
+ {{ user.publicSlug ? `/@${user.publicSlug}` : '尚未设置' }}
+
+
+ 去资料页配置
+
+
+
+
+ 快捷入口
+
+
+
+ 文章
+
+
+ 时光机
+
+
+ RSS
+
+
+ 资料
+
+
+ 用户管理
+
+
+
+
-
-
- 状态
- 会话有效
-
-
- 入口
- 首页 / 配置 / API
-
-
- 建议
- 可继续扩展个人中心
+
+
+
+
+
+
+ 你能做什么
+
+
+ 四大模块覆盖展示、创作与阅读输入;权限与可见性按条目细粒度控制。
+
+
+
+
+
+
+
+
+
+
+ {{ item.title }}
+
+
+ {{ item.desc }}
+
+
+ 打开
+
+
+
+
-
-
- 进入控制台
+
+
+
+ 访客说明
+
+
+ 本站默认需登录后使用控制台。若你已有账号,请点击「登录」;新账号由管理员在后台创建(邀请制)。
+
+
+
+ 登录
-
- 退出登录
-
-
- 配置 API
+
+ 注册
-
-
-
-
-
-
-
欢迎来到本站
-
当前为访客模式,仅开放首页与认证页面。
-
-
未登录
-
-
+
-
-
- 访问策略
- 登录优先,白名单放行
-
-
- 安全能力
- API 默认鉴权 + 401 统一处理
-
-
-
-
-
去登录
-
去注册
+
+
+
+ 需要退出当前会话?
+
+
+
+ 配置 API(调试)
+
+
+ 退出登录
+
-
+
-
\ No newline at end of file
+
diff --git a/server/api/auth/me.get.ts b/server/api/auth/me.get.ts
index 3ace9e9..32af168 100644
--- a/server/api/auth/me.get.ts
+++ b/server/api/auth/me.get.ts
@@ -1,5 +1,8 @@
+import { dbGlobal } from "drizzle-pkg/lib/db";
+import { users } from "drizzle-pkg/lib/schema/auth";
+import { eq } from "drizzle-orm";
import { UNAUTHORIZED_MESSAGE } from "#server/constants/auth";
-import { clearSessionCookie, getSessionId } from "#server/service/auth/cookie";
+import { clearSessionCookie } from "#server/service/auth/cookie";
import { toPublicAuthError } from "#server/service/auth/errors";
export default defineWrappedResponseHandler(async (event) => {
@@ -13,8 +16,21 @@ export default defineWrappedResponseHandler(async (event) => {
});
}
+ const [row] = await dbGlobal
+ .select({
+ nickname: users.nickname,
+ avatar: users.avatar,
+ })
+ .from(users)
+ .where(eq(users.id, user.id))
+ .limit(1);
+
return R.success({
- user,
+ user: {
+ ...user,
+ nickname: row?.nickname ?? null,
+ avatar: row?.avatar ?? null,
+ },
});
} catch (err) {
throw toPublicAuthError(err);
diff --git a/server/api/config/me.get.ts b/server/api/config/me.get.ts
index 645d137..b5e0d8b 100644
--- a/server/api/config/me.get.ts
+++ b/server/api/config/me.get.ts
@@ -1,3 +1,6 @@
+import { dbGlobal } from "drizzle-pkg/lib/db";
+import { users } from "drizzle-pkg/lib/schema/auth";
+import { eq } from "drizzle-orm";
import { KNOWN_CONFIG_KEYS } from "#server/service/config/registry";
export default defineWrappedResponseHandler(async (event) => {
@@ -10,12 +13,23 @@ export default defineWrappedResponseHandler(async (event) => {
}),
);
+ const [row] = await dbGlobal
+ .select({
+ nickname: users.nickname,
+ avatar: users.avatar,
+ })
+ .from(users)
+ .where(eq(users.id, user.id))
+ .limit(1);
+
return R.success({
user: {
id: user.id,
username: user.username,
role: user.role,
publicSlug: user.publicSlug,
+ nickname: row?.nickname ?? null,
+ avatar: row?.avatar ?? null,
},
config: Object.fromEntries(entries),
});
diff --git a/server/service/auth/index.ts b/server/service/auth/index.ts
index 4c2f9a0..d25929f 100644
--- a/server/service/auth/index.ts
+++ b/server/service/auth/index.ts
@@ -22,6 +22,8 @@ export type MinimalUser = {
username: string;
role: string;
publicSlug: string | null;
+ nickname: string | null;
+ avatar: string | null;
};
export class AuthValidationError extends Error {
@@ -110,6 +112,8 @@ async function insertUserWithRetry(
username: users.username,
role: users.role,
publicSlug: users.publicSlug,
+ nickname: users.nickname,
+ avatar: users.avatar,
});
return newUser as MinimalUser;
} catch (err) {
@@ -161,6 +165,8 @@ export async function loginUser(payload: AuthPayload) {
status: users.status,
role: users.role,
publicSlug: users.publicSlug,
+ nickname: users.nickname,
+ avatar: users.avatar,
})
.from(users)
.where(eq(users.username, username));
@@ -187,6 +193,8 @@ export async function loginUser(payload: AuthPayload) {
username: user.username,
role: user.role,
publicSlug: user.publicSlug,
+ nickname: user.nickname,
+ avatar: user.avatar,
} satisfies MinimalUser,
sessionId,
expiresAt,
@@ -207,6 +215,8 @@ export async function getCurrentUser(sessionId: string): Promise