Files
admin/www/app/stores/site.ts
T

114 lines
2.9 KiB
TypeScript
Raw Normal View History

2026-07-31 19:02:00 +08:00
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
};
});