This commit is contained in:
2025-11-10 00:59:40 +08:00
parent 78c46aed71
commit bac96fcbe6
76 changed files with 8726 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import { useCache } from '@gold/hooks/web/useCache'
import { getToken as getTokenFromManager } from './token-manager'
const { wsCache } = useCache()
const AccessTokenKey = 'ACCESS_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'
// 获取token - 使用统一的 token 管理器
export const getAccessToken = () => {
return getTokenFromManager()
}
// 刷新token
export const getRefreshToken = () => {
try {
// 优先从 wsCache 读取
const refreshToken = wsCache.get(RefreshTokenKey) || wsCache.get('refresh_token')
if (refreshToken) {
return refreshToken
}
} catch (e) {
console.warn('获取 refresh token 失败:', e)
}
return null
}
// 设置token
export const setToken = (token) => {
wsCache.set(RefreshTokenKey, token.refreshToken)
wsCache.set(AccessTokenKey, token.accessToken)
}
// 删除token
export const removeToken = () => {
wsCache.delete(AccessTokenKey)
wsCache.delete(RefreshTokenKey)
}
/** 格式化tokenjwt格式 */
export const formatToken = (token) => {
return 'Bearer ' + token
}

View File

@@ -0,0 +1,20 @@
import MarkdownIt from 'markdown-it'
// 创建 markdown 实例
const md = new MarkdownIt()
/**
* 渲染 markdown 内容为 HTML
* @param {string} content - markdown 内容
* @returns {string} HTML 字符串
*/
export function renderMarkdown(content) {
if (!content) return ''
return md.render(content)
}
/**
* 导出 md 实例,供需要自定义配置的地方使用
*/
export { md }

View File

@@ -0,0 +1,56 @@
import localforage from 'localforage'
// 统一的 IndexedDB 存储封装API 与 localStorage 类似但为异步
// 默认使用一个命名的存储实例,便于后续扩展多命名空间
const store = localforage.createInstance({
name: 'web-gold',
storeName: 'app_store',
description: 'App persistent storage powered by IndexedDB',
})
export async function setJSON(key, value) {
try {
const json = JSON.stringify(value)
await store.setItem(key, json)
return true
} catch (err) {
console.error('[storage.setJSON] failed:', err)
return false
}
}
export async function getJSON(key, fallback = null) {
try {
const raw = await store.getItem(key)
if (raw == null) return fallback
return JSON.parse(raw)
} catch (err) {
console.error('[storage.getJSON] failed:', err)
return fallback
}
}
export async function remove(key) {
try {
await store.removeItem(key)
} catch (err) {
console.error('[storage.remove] failed:', err)
}
}
export async function clearAll() {
try {
await store.clear()
} catch (err) {
console.error('[storage.clearAll] failed:', err)
}
}
export default {
setJSON,
getJSON,
remove,
clearAll,
}

View File

@@ -0,0 +1,100 @@
import { useCache } from '@gold/hooks/web/useCache'
/**
* Token 统一管理模块
*
* 优先级顺序:
* 1. 手动输入的 dev token (sessionStorage)
* 2. 正式登录的 token (wsCache)
* 3. 环境变量 VITE_DEV_TOKEN
*/
// sessionStorage 中的手动 token key
const DEV_MANUAL_TOKEN_KEY = 'DEV_MANUAL_TOKEN'
// 获取缓存实例
let wsCache = null
function getCache() {
if (!wsCache) {
wsCache = useCache().wsCache
}
return wsCache
}
/**
* 获取完整的 Authorization Header 值
* @returns {string} Bearer token 或空字符串
*/
export function getAuthHeader() {
const token = getToken()
return token ? `Bearer ${token}` : ''
}
/**
* 获取 token
* @returns {string} token 字符串
*/
export function getToken() {
// 1. 优先使用手动输入的 dev token
const manualToken = sessionStorage.getItem(DEV_MANUAL_TOKEN_KEY)
if (manualToken) {
return manualToken
}
// 2. 使用正式登录的 token从 wsCache 读取)
try {
const cache = getCache()
const accessToken = cache.get('ACCESS_TOKEN') || cache.get('access_token')
if (accessToken) {
return accessToken
}
} catch (e) {
console.warn('获取 wsCache 失败:', e)
}
// 3. 兜底:环境变量中的 token
const envToken = import.meta?.env?.VITE_DEV_TOKEN
if (envToken) {
return envToken
}
return ''
}
/**
* 设置手动输入的 dev token
* @param {string} token
*/
export function setDevToken(token) {
if (token) {
sessionStorage.setItem(DEV_MANUAL_TOKEN_KEY, token)
} else {
sessionStorage.removeItem(DEV_MANUAL_TOKEN_KEY)
}
}
/**
* 获取手动输入的 dev token用于显示
* @returns {string}
*/
export function getDevToken() {
return sessionStorage.getItem(DEV_MANUAL_TOKEN_KEY) || ''
}
/**
* 清除所有 token
*/
export function clearAllTokens() {
sessionStorage.removeItem(DEV_MANUAL_TOKEN_KEY)
try {
const cache = getCache()
cache.delete('ACCESS_TOKEN')
cache.delete('access_token')
cache.delete('REFRESH_TOKEN')
cache.delete('refresh_token')
} catch (e) {
console.warn('清除 wsCache 失败:', e)
}
}

View File

@@ -0,0 +1,55 @@
import { match as pathMatch } from 'path-to-regexp'
/**
* 安全解析 URL失败返回 null
*/
export function safeParseUrl(input) {
const raw = (input || '').trim()
if (!raw) return null
try {
return new URL(raw)
} catch {
return null
}
}
/**
* 从 URL 对象按顺序读取第一个非空的 query 值
*/
export function getFirstQuery(urlObj, keys = []) {
if (!urlObj || !urlObj.searchParams) return ''
for (const key of keys) {
const v = urlObj.searchParams.get(key)
if (v) return v
}
return ''
}
// 组合解析:优先从 queryKeys 取值,其次按 path-to-regexp 的模式从 pathname 匹配(返回首个命名参数),最后可回退 raw
export function resolveId(input, options = {}) {
const raw = (input || '').trim()
if (!raw) return ''
const { queryKeys = [], pathPatterns = [], fallbackRaw = true } = options
const urlObj = safeParseUrl(raw)
const q = getFirstQuery(urlObj, queryKeys)
if (q) return q
if (urlObj) {
for (const pattern of pathPatterns) {
if (typeof pattern === 'string') {
const m = pathMatch(pattern)(urlObj.pathname)
if (m && m.params) {
const firstKey = Object.keys(m.params)[0]
const val = firstKey ? m.params[firstKey] : ''
if (val) return String(val)
}
} else if (pattern instanceof RegExp) {
const m = urlObj.pathname.match(pattern)
if (m && m[1]) return m[1]
}
}
}
return fallbackRaw ? raw : ''
}