[积分商城]PlayX对接中心

This commit is contained in:
2026-03-20 18:10:23 +08:00
parent 0b0821c5c7
commit 0d62c915bd
3 changed files with 119 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
export default {
title: 'PlayX Integration Center',
desc: 'Manage orders, daily push, claim logs and user assets in one place.',
orders: 'Orders',
dailyPush: 'Daily Push',
claimLog: 'Claim Log',
userAsset: 'User Asset',
}

View File

@@ -0,0 +1,9 @@
export default {
title: 'PlayX 对接中心',
desc: '集中管理积分商城与 PlayX 的订单、推送、领取与资产数据。建议优先处理“发放子状态=失败可重试”的订单。',
orders: '统一订单',
dailyPush: '每日推送',
claimLog: '领取记录',
userAsset: '用户资产',
}

View File

@@ -0,0 +1,102 @@
<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>