- 后台全面引入 Naive UI 组件库,统一 UI 规范 - 前台 usePublicApi 切换到 API 调用(GET /api/content/[key]) - 前后台数据源统一(site_content 表) - 产品线统一管理(tour/camp/course 三套编辑器) - 产品数据归一化(itinerary/faq/pricing 格式统一) - 表单提交 API 改写入 submissions 表 - 新增 submissions 标记已读 API - site-content PUT 支持 upsert - 修复前台 bug(stories 路由冲突、占位符警告、selector breadcrumb) - 消除 PageHero 类型警告(useSEO reactive 修复) - 25 个前台页面全部 HTTP 200,展示效果不变 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
48 行
1.1 KiB
JavaScript
48 行
1.1 KiB
JavaScript
/**
|
|
* 管理后台认证 composable
|
|
*/
|
|
export function useAdmin() {
|
|
const token = useState('admin_token', () => '')
|
|
|
|
// 客户端刷新时从 localStorage 恢复 token
|
|
if (import.meta.client && !token.value) {
|
|
token.value = localStorage.getItem('admin_token') || ''
|
|
}
|
|
|
|
const isLoggedIn = computed(() => !!token.value)
|
|
|
|
async function login(username, password) {
|
|
const data = await $fetch('/api/admin/login', {
|
|
method: 'POST',
|
|
body: { username, password },
|
|
})
|
|
token.value = data.token
|
|
localStorage.setItem('admin_token', data.token)
|
|
return data
|
|
}
|
|
|
|
function logout() {
|
|
token.value = ''
|
|
localStorage.removeItem('admin_token')
|
|
navigateTo('/admin/login')
|
|
}
|
|
|
|
// 带认证的请求封装
|
|
function adminFetch(url, options = {}) {
|
|
return $fetch(url, {
|
|
...options,
|
|
headers: {
|
|
...options.headers,
|
|
Authorization: `Bearer ${token.value}`,
|
|
},
|
|
onResponseError({ response }) {
|
|
if (response.status === 401) {
|
|
logout()
|
|
}
|
|
},
|
|
})
|
|
}
|
|
|
|
return { token, isLoggedIn, login, logout, adminFetch }
|
|
}
|