114 lines
2.9 KiB
TypeScript
114 lines
2.9 KiB
TypeScript
import { defineStore } from 'pinia';
|
||
import type {
|
||
SiteSettings,
|
||
FooterSettings,
|
||
SocialLink,
|
||
SeoDefaults,
|
||
NavItem,
|
||
NavAppearance,
|
||
ProductSeries,
|
||
I18nEntry
|
||
} from '~/types/site';
|
||
|
||
/**
|
||
* 官网全局站点状态
|
||
*
|
||
* 在应用启动时一次性拉取全局配置、导航、产品(Mega Menu)与 i18n 词条,
|
||
* 供 AppHeader / AppFooter 及各页面共享使用。
|
||
*/
|
||
export const useSiteStore = defineStore('site', () => {
|
||
const { getGlobal, getNav, getI18n, getProducts } = useSiteApi();
|
||
const { locale } = useI18n();
|
||
|
||
// ===== 全局配置 =====
|
||
const site = ref<SiteSettings | null>(null);
|
||
const footer = ref<FooterSettings | null>(null);
|
||
const social = ref<SocialLink[]>([]);
|
||
const seo = ref<SeoDefaults | null>(null);
|
||
|
||
// ===== 导航 =====
|
||
const navItems = ref<NavItem[]>([]);
|
||
const navAppearance = ref<NavAppearance | null>(null);
|
||
|
||
// ===== 产品(导航 Mega Menu) =====
|
||
const productSeries = ref<ProductSeries[]>([]);
|
||
|
||
// ===== i18n 词条(dict_key -> entry) =====
|
||
const i18nMap = ref<Record<string, I18nEntry>>({});
|
||
|
||
const loaded = ref(false);
|
||
const loading = ref(false);
|
||
|
||
/** 应用启动时调用,并行拉取全局数据 */
|
||
async function init() {
|
||
if (loaded.value || loading.value) return;
|
||
loading.value = true;
|
||
try {
|
||
const [globalRes, navRes, i18nRes, productsRes] = await Promise.all([
|
||
getGlobal(),
|
||
getNav(),
|
||
getI18n(),
|
||
getProducts()
|
||
]);
|
||
|
||
if (globalRes) {
|
||
site.value = globalRes.site;
|
||
footer.value = globalRes.footer;
|
||
social.value = globalRes.social ?? [];
|
||
seo.value = globalRes.seo;
|
||
}
|
||
if (navRes) {
|
||
navItems.value = navRes.items ?? [];
|
||
navAppearance.value = navRes.appearance;
|
||
}
|
||
if (i18nRes) {
|
||
const map: Record<string, I18nEntry> = {};
|
||
for (const entry of i18nRes.items ?? []) {
|
||
map[entry.dict_key] = entry;
|
||
}
|
||
i18nMap.value = map;
|
||
}
|
||
if (productsRes) {
|
||
productSeries.value = productsRes.series ?? [];
|
||
}
|
||
|
||
loaded.value = true;
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 翻译 CMS 动态词条(www_i18n_entries)
|
||
* @param key 词条 key,如 'btn.learn_more'
|
||
* @param fallback 词条缺失时的回退文案
|
||
*/
|
||
function td(key: string, fallback = ''): string {
|
||
const entry = i18nMap.value[key];
|
||
if (!entry) return fallback || key;
|
||
const value = locale.value === 'en' ? entry.value_en : entry.value_zh;
|
||
return value || fallback || key;
|
||
}
|
||
|
||
/** 根据当前语言取导航入口名称 */
|
||
function navLabel(item: NavItem): string {
|
||
return locale.value === 'en' ? item.name_en : item.name_zh;
|
||
}
|
||
|
||
return {
|
||
site,
|
||
footer,
|
||
social,
|
||
seo,
|
||
navItems,
|
||
navAppearance,
|
||
productSeries,
|
||
i18nMap,
|
||
loaded,
|
||
loading,
|
||
init,
|
||
td,
|
||
navLabel
|
||
};
|
||
});
|