feat: 登录会话持久化 + Caddy 反代部署方案

This commit is contained in:
root
2026-10-16 11:27:15 +08:00
parent de3add8881
commit 2660dc6fa9
7 changed files with 79 additions and 34 deletions
+4 -18
View File
@@ -21,24 +21,12 @@ import { categoryLabel, type Attendance, type LogItem, type Memo } from './db/sc
const toasts = useToasts()
// ---- 用户会话 ----
// ---- 用户会话(持久化登录,退出走顶栏按钮)----
const session = ref<Session | null>(getSession())
const IDLE_LOGOUT_MS = 30 * 60 * 1000
let sessionIdleTimer: number | null = null
function armSessionTimer() {
if (sessionIdleTimer !== null) window.clearTimeout(sessionIdleTimer)
if (!session.value) return
sessionIdleTimer = window.setTimeout(() => { doLogout(true) }, IDLE_LOGOUT_MS)
}
function onActivity() {
if (session.value) armSessionTimer()
}
async function onLogin(s: Session) {
session.value = s
location.hash = '#/calendar'
route.value = 'calendar'
armSessionTimer()
await refreshClock()
await refreshTip()
startSyncTimer()
@@ -49,12 +37,12 @@ async function onLogin(s: Session) {
showToast('已迁移原有数据 ' + mt + ' 条')
}
}
async function doLogout(auto: boolean) {
async function doLogout() {
await logoutUser()
session.value = null
route.value = 'calendar'
location.hash = '#/calendar'
showToast(auto ? '长时间未操作已自动退出' : '已退出登录')
showToast('已退出登录')
}
// ---- 自动同步:登录后与每 5 分钟,静默执行 ----
@@ -212,10 +200,8 @@ async function refreshTip() {
onMounted(async () => {
window.addEventListener('keydown', onGlobalKey)
window.addEventListener('click', onActivity)
if (session.value) {
openUserDatabase(session.value.userId)
armSessionTimer()
await refreshClock()
await refreshTip()
startSyncTimer()
@@ -268,7 +254,7 @@ onMounted(async () => {
填写本周周记
</button>
<span class="user-chip num">{{ session?.username }}</span>
<button class="btn btn-sm" @click="doLogout(false)">退出</button>
<button class="btn btn-sm" @click="doLogout">退出</button>
<button class="btn btn-primary btn-sm" :disabled="clockDone" @click="doClock">
<Icon :name="clockDone ? 'check-circle' : 'clock'" :size="14" />
<span class="num">{{ clockLabel }}</span>
+5 -4
View File
@@ -31,10 +31,11 @@ export interface Session {
username: string
}
// 会话存 sessionStorage:关闭标签页即退出,刷新页面保持登录
// 会话持久化到 localStorage:关闭浏览器后仍保持登录,无需每次使用都登录
// 安全边界:密码库主密码不随会话保存,每次启动仍需解锁
export function getSession(): Session | null {
try {
const raw = sessionStorage.getItem(SESSION_KEY)
const raw = localStorage.getItem(SESSION_KEY)
if (!raw) return null
const s = JSON.parse(raw)
if (s && s.userId && s.username) return s as Session
@@ -42,10 +43,10 @@ export function getSession(): Session | null {
return null
}
function setSession(s: Session): void {
sessionStorage.setItem(SESSION_KEY, JSON.stringify(s))
localStorage.setItem(SESSION_KEY, JSON.stringify(s))
}
function clearSession(): void {
sessionStorage.removeItem(SESSION_KEY)
localStorage.removeItem(SESSION_KEY)
}
export function openUserDatabase(userId: string): void {
+1 -1
View File
@@ -347,7 +347,7 @@ async function doImport() {
<div class="ai-grid">
<div class="rule-item">
<label>同步服务地址</label>
<input class="input" v-model="syncBase" placeholder="如 http://124.221.192.176:3780" />
<input class="input" v-model="syncBase" placeholder="如 https://sync.linyux.cn 或 https://gitea.linyux.cn/sync-api" />
</div>
<div class="rule-item">
<label>云端用户名</label>