192 lines
5.8 KiB
JavaScript
192 lines
5.8 KiB
JavaScript
import { getCache, setCache } from '@/utils/cache'
|
|
import { getThemeApi } from '@/api/page/theme.js'
|
|
|
|
/**
|
|
* 主题运行时:缓存 css_vars + tokens + layout
|
|
* 页面通过 mixin / Theme* 组件消费,禁止按 template.code 特判
|
|
*/
|
|
|
|
const STORAGE_KEY = 'theme_tokens'
|
|
const STORAGE_VARS_KEY = 'theme_css_vars'
|
|
const STORAGE_LAYOUT_KEY = 'theme_layout'
|
|
const STORAGE_META_KEY = 'theme_meta'
|
|
const STORAGE_SCHEMES_KEY = 'theme_card_schemes'
|
|
const STORAGE_FEATURES_KEY = 'theme_features'
|
|
|
|
export const FALLBACK_VARS = {
|
|
'--color-primary': '#B08D57',
|
|
'--color-primary-soft': '#d9b97f',
|
|
'--color-accent': '#8C6A3F',
|
|
'--color-bg': '#FAF7F2',
|
|
'--color-bg-soft': '#f5f2ec',
|
|
'--color-surface': '#ffffff',
|
|
'--color-surface-soft': '#fafafa',
|
|
'--color-text': '#1C1917',
|
|
'--color-text-soft': '#666666',
|
|
'--color-text-muted': '#999999',
|
|
'--color-border': '#E7DFD3',
|
|
'--color-price': '#B08D57',
|
|
'--radius-md': '16rpx',
|
|
'--radius-lg': '20rpx',
|
|
'--shadow-md': '0 8rpx 24rpx rgba(0,0,0,0.06)',
|
|
'--motion-base': '320ms',
|
|
'--motion-easing': 'cubic-bezier(0.22,1,0.36,1)',
|
|
}
|
|
|
|
export const FALLBACK_LAYOUT = {
|
|
home: { hero: 'carousel', category: 'grid', product: 'grid' },
|
|
product: { gallery: 'swiper', price: 'inline', action: 'fixed' },
|
|
list: { style: 'card' },
|
|
mine: { header: 'gradient', menu: 'list' },
|
|
package: { list: 'card' },
|
|
effect: {
|
|
transition: 'fade',
|
|
skeleton: 'shimmer',
|
|
card: 'elevated',
|
|
icon: 'line',
|
|
},
|
|
card_scheme: 'champagne-foil',
|
|
chrome: { tabbar: 'plain', navbar: 'solid', tabbar_anim: 'slide' },
|
|
page_presets: {},
|
|
pages: {},
|
|
}
|
|
|
|
/** 拉取并落地主题 */
|
|
export async function loadAndApplyTheme() {
|
|
let theme = null
|
|
try {
|
|
// eslint-disable-next-line no-console
|
|
console.log('[theme] GET theme …')
|
|
theme = await getThemeApi()
|
|
// eslint-disable-next-line no-console
|
|
console.log('[theme] ok', theme && theme.code, theme && theme.fallback)
|
|
} catch (e) {
|
|
// eslint-disable-next-line no-console
|
|
console.warn('[theme] request failed', e)
|
|
}
|
|
if (!theme || !theme.css_vars) {
|
|
theme = {
|
|
code: '',
|
|
name: '',
|
|
css_vars: getCache(STORAGE_VARS_KEY) || FALLBACK_VARS,
|
|
tokens: getCache(STORAGE_KEY) || {},
|
|
layout: getCache(STORAGE_LAYOUT_KEY) || FALLBACK_LAYOUT,
|
|
card_schemes: getCache(STORAGE_SCHEMES_KEY) || {},
|
|
features: getThemeFeatures(),
|
|
fallback: true,
|
|
}
|
|
}
|
|
applyTheme(theme)
|
|
return theme
|
|
}
|
|
|
|
export function applyTheme(theme) {
|
|
if (!theme) return
|
|
const vars = { ...FALLBACK_VARS, ...(theme.css_vars || {}) }
|
|
const layout = mergeLayout(theme.layout)
|
|
setCache(STORAGE_VARS_KEY, vars)
|
|
setCache(STORAGE_LAYOUT_KEY, layout)
|
|
if (theme.tokens) {
|
|
setCache(STORAGE_KEY, theme.tokens)
|
|
}
|
|
setCache(STORAGE_META_KEY, {
|
|
code: theme.code || '',
|
|
name: theme.name || '',
|
|
style_tag: theme.style_tag || '',
|
|
fallback: !!theme.fallback,
|
|
})
|
|
setCache(STORAGE_SCHEMES_KEY, theme.card_schemes || {})
|
|
setCache(STORAGE_FEATURES_KEY, {
|
|
package_enabled: !!(theme.features && theme.features.package_enabled),
|
|
subscribe_pay_tpl: (theme.features && theme.features.subscribe_pay_tpl) || '',
|
|
subscribe_ship_tpl: (theme.features && theme.features.subscribe_ship_tpl) || '',
|
|
})
|
|
applyVarsToDom(vars)
|
|
}
|
|
|
|
function mergeLayout(layout) {
|
|
const src = layout && typeof layout === 'object' ? layout : {}
|
|
const chrome = src.chrome && typeof src.chrome === 'object' ? src.chrome : {}
|
|
return {
|
|
home: { ...FALLBACK_LAYOUT.home, ...(src.home || {}) },
|
|
product: { ...FALLBACK_LAYOUT.product, ...(src.product || {}) },
|
|
list: { ...FALLBACK_LAYOUT.list, ...(src.list || {}) },
|
|
mine: { ...FALLBACK_LAYOUT.mine, ...(src.mine || {}) },
|
|
package: { ...FALLBACK_LAYOUT.package, ...(src.package || {}) },
|
|
effect: { ...FALLBACK_LAYOUT.effect, ...(src.effect || {}) },
|
|
card_scheme: src.card_scheme || FALLBACK_LAYOUT.card_scheme,
|
|
chrome: {
|
|
tabbar: chrome.tabbar || 'plain',
|
|
navbar: chrome.navbar || 'solid',
|
|
tabbar_anim: chrome.tabbar_anim || 'slide',
|
|
tabbar_color: chrome.tabbar_color || '',
|
|
tabbar_color_on: chrome.tabbar_color_on || '',
|
|
},
|
|
page_presets: src.page_presets && typeof src.page_presets === 'object' ? src.page_presets : {},
|
|
pages: src.pages && typeof src.pages === 'object' ? src.pages : {},
|
|
}
|
|
}
|
|
|
|
export function applyVarsToDom(vars) {
|
|
if (!vars) return
|
|
// #ifdef H5
|
|
try {
|
|
const root = document.documentElement
|
|
Object.entries(vars).forEach(([k, v]) => {
|
|
root.style.setProperty(k, String(v))
|
|
})
|
|
} catch (e) {
|
|
// ignore
|
|
}
|
|
// #endif
|
|
}
|
|
|
|
export function getActiveVars() {
|
|
return getCache(STORAGE_VARS_KEY) || FALLBACK_VARS
|
|
}
|
|
|
|
export function getActiveLayout() {
|
|
return mergeLayout(getCache(STORAGE_LAYOUT_KEY) || FALLBACK_LAYOUT)
|
|
}
|
|
|
|
export function getActiveTokens() {
|
|
return getCache(STORAGE_KEY) || {}
|
|
}
|
|
|
|
export function getThemeMeta() {
|
|
return getCache(STORAGE_META_KEY) || { code: '', name: '', style_tag: '', fallback: true }
|
|
}
|
|
|
|
/** 完整主题快照(页面调试 / 组件用) */
|
|
export function getActiveSchemes() {
|
|
return getCache(STORAGE_SCHEMES_KEY) || {}
|
|
}
|
|
|
|
/** 应用级开关,跟主题一起缓存,底栏/首页热门套餐都读这里 */
|
|
export function getThemeFeatures() {
|
|
const cached = getCache(STORAGE_FEATURES_KEY) || {}
|
|
return {
|
|
package_enabled: !!cached.package_enabled,
|
|
subscribe_pay_tpl: cached.subscribe_pay_tpl || '',
|
|
subscribe_ship_tpl: cached.subscribe_ship_tpl || '',
|
|
}
|
|
}
|
|
|
|
export function getTheme() {
|
|
return {
|
|
...getThemeMeta(),
|
|
css_vars: getActiveVars(),
|
|
tokens: getActiveTokens(),
|
|
layout: getActiveLayout(),
|
|
card_schemes: getActiveSchemes(),
|
|
features: getThemeFeatures(),
|
|
}
|
|
}
|
|
|
|
export function varsToStyleString(vars) {
|
|
const obj = vars || getActiveVars()
|
|
return Object.entries(obj)
|
|
.map(([k, v]) => `${k}: ${v}`)
|
|
.join('; ')
|
|
}
|