103 lines
3.7 KiB
Vue
103 lines
3.7 KiB
Vue
<template>
|
||
<div class="default-main">
|
||
<!-- 语言包注入是异步的:把 t() 调用和子组件渲染都延后到注入完成后,避免 intlify Not found -->
|
||
<template v-if="langReady">
|
||
<el-card shadow="never" class="mb-4">
|
||
<template #header>
|
||
<div class="card-header">{{ t('mall.playxCenter.title') }}</div>
|
||
</template>
|
||
<div class="desc">{{ t('mall.playxCenter.desc') }}</div>
|
||
</el-card>
|
||
|
||
<el-tabs v-model="activeName" type="border-card">
|
||
<el-tab-pane :label="t('mall.playxCenter.orders')" name="orders">
|
||
<PlayxOrderIndex />
|
||
</el-tab-pane>
|
||
<el-tab-pane :label="t('mall.playxCenter.dailyPush')" name="dailyPush">
|
||
<PlayxDailyPushIndex />
|
||
</el-tab-pane>
|
||
<el-tab-pane :label="t('mall.playxCenter.claimLog')" name="claimLog">
|
||
<PlayxClaimLogIndex />
|
||
</el-tab-pane>
|
||
<el-tab-pane :label="t('mall.playxCenter.userAsset')" name="userAsset">
|
||
<PlayxUserAssetIndex />
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
</template>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { onMounted, ref } from 'vue'
|
||
import { useI18n } from 'vue-i18n'
|
||
import PlayxOrderIndex from '/@/views/backend/mall/playxOrder/index.vue'
|
||
import PlayxDailyPushIndex from '/@/views/backend/mall/playxDailyPush/index.vue'
|
||
import PlayxClaimLogIndex from '/@/views/backend/mall/playxClaimLog/index.vue'
|
||
import PlayxUserAssetIndex from '/@/views/backend/mall/playxUserAsset/index.vue'
|
||
import { useConfig } from '/@/stores/config'
|
||
import { mergeMessage } from '/@/lang/index'
|
||
|
||
defineOptions({
|
||
name: 'mall/playxCenter',
|
||
})
|
||
|
||
const { t } = useI18n()
|
||
const activeName = ref('orders')
|
||
const langReady = ref(false)
|
||
|
||
/**
|
||
* 由于语言包是按“路由”懒加载的:
|
||
* playxCenter 内部直接渲染了多个子页面组件(订单/推送/领取/资产),
|
||
* 如果对应菜单被禁用,子页面路由可能不会触发语言包加载,导致 t('mall.playx*') 显示为 key。
|
||
* 关键点:子页面组件在首次渲染阶段就会执行 t()。
|
||
* 因此语言包需要在首次渲染前(而不是 onMounted)完成 merge。
|
||
*/
|
||
async function ensurePlayxCenterLang() {
|
||
const config = useConfig()
|
||
const locale = config.lang.defaultLang
|
||
const prefix = `./backend/${locale}`
|
||
|
||
const loadPaths = [
|
||
`${prefix}/mall/playxCenter.ts`,
|
||
`${prefix}/mall/playxOrder.ts`,
|
||
`${prefix}/mall/playxDailyPush.ts`,
|
||
`${prefix}/mall/playxClaimLog.ts`,
|
||
`${prefix}/mall/playxUserAsset.ts`,
|
||
]
|
||
|
||
// 某些场景下 i18n 初始化可能晚于组件创建,这里做一次最小等待。
|
||
// 不会阻塞很久:通常 window.loadLangHandle 会在应用启动阶段就准备好。
|
||
while (!window.loadLangHandle) {
|
||
await new Promise((r) => setTimeout(r, 0))
|
||
}
|
||
|
||
const handleMap = window.loadLangHandle
|
||
for (const p of loadPaths) {
|
||
const loader = handleMap[p]
|
||
if (!loader) continue
|
||
const mod = await loader()
|
||
// 与 getLangFileMessage 的命名规则一致:namespace 应为 `mall/playxOrder` 这类路径
|
||
const pathName = p.slice(p.lastIndexOf(prefix) + (prefix.length + 1), p.lastIndexOf('.'))
|
||
mergeMessage(mod?.default ?? {}, pathName)
|
||
}
|
||
}
|
||
|
||
onMounted(async () => {
|
||
await ensurePlayxCenterLang()
|
||
langReady.value = true
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.mb-4 {
|
||
margin-bottom: 16px;
|
||
}
|
||
.card-header {
|
||
font-weight: 600;
|
||
}
|
||
.desc {
|
||
color: var(--el-text-color-secondary);
|
||
}
|
||
</style>
|
||
|