From 42cee4913ae42c3b1fbd743d67f0b20cd1f5ef43 Mon Sep 17 00:00:00 2001
From: tianfeng <769204422@qq.com>
Date: Fri, 22 Aug 2025 14:41:35 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=8A=9F=E8=83=BD?=
=?UTF-8?q?=E4=BC=98=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/utils/appBridge.js | 24 +-
src/utils/pageConfig.js | 82 ++++++
src/utils/permissionManager.js | 22 +-
src/utils/usePageInitialization.js | 392 +++++++++++++++++++++++++++++
src/views/AgencyCenterView.vue | 148 ++---------
src/views/CoinSellerView.vue | 46 ++--
src/views/HostCenterView.vue | 258 +------------------
7 files changed, 553 insertions(+), 419 deletions(-)
create mode 100644 src/utils/pageConfig.js
create mode 100644 src/utils/usePageInitialization.js
diff --git a/src/utils/appBridge.js b/src/utils/appBridge.js
index c1cf56f..3bc418b 100644
--- a/src/utils/appBridge.js
+++ b/src/utils/appBridge.js
@@ -94,15 +94,7 @@ export function connectApplication(renderFun) {
window.getIosAccessOriginParam = renderFun
try {
- if (ios()) {
- console.debug('ios access detected')
- // iOS可能需要特殊处理,这里先使用通用方法
- if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessOrigin) {
- window.webkit.messageHandlers.getAccessOrigin.postMessage({})
- } else if (window.app && window.app.getAccessOrigin) {
- renderFun(window.app.getAccessOrigin())
- }
- } else if (android()) {
+ if (android()) {
console.debug('Flutter Android WebView 检测')
console.debug('window.app 对象:', window.app)
@@ -177,7 +169,19 @@ export function connectApplication(renderFun) {
}
checkApp()
}
- } else {
+ }
+
+ /*else if (ios()) {
+ console.debug('ios access detected')
+ // iOS可能需要特殊处理,这里先使用通用方法
+ if (window.webkit && window.webkit.messageHandlers && window.webkit.messageHandlers.getAccessOrigin) {
+ window.webkit.messageHandlers.getAccessOrigin.postMessage({})
+ } else if (window.app && window.app.getAccessOrigin) {
+ renderFun(window.app.getAccessOrigin())
+ }
+ }*/
+
+ else {
console.debug('非移动设备环境')
// 非APP环境,可能是浏览器调试
console.warn('Not in APP environment, using mock data for development')
diff --git a/src/utils/pageConfig.js b/src/utils/pageConfig.js
new file mode 100644
index 0000000..63c3bdb
--- /dev/null
+++ b/src/utils/pageConfig.js
@@ -0,0 +1,82 @@
+// src/config/pageConfigs.js
+/**
+ * 各页面的初始化配置
+ * 统一管理不同页面对 usePageInitialization 的配置需求
+ */
+export const PageConfig = {
+ HOST_CENTER: {
+ needsBankBalance: true,
+ needsWorkStatistics: true,
+ needsRouteGuard: true,
+ title: 'Host Center',
+ userTag: '👑 Host'
+ },
+
+ COIN_SELLER: {
+ needsBankBalance: true,
+ needsWorkStatistics: false, // Coin Seller 不需要工作统计
+ needsRouteGuard: true,
+ title: 'Coin Seller',
+ userTag: '💰 Coin Seller'
+ },
+
+ AGENCY_CENTER: {
+ needsBankBalance: true,
+ needsWorkStatistics: true,
+ needsRouteGuard: true,
+ title: 'Agency Center',
+ userTag: '🏢 Agency'
+ },
+
+ BD_CENTER: {
+ needsBankBalance: true,
+ needsWorkStatistics: false, // BD 可能不需要日常工作统计
+ needsRouteGuard: true,
+ title: 'BD Center',
+ userTag: '📈 BD'
+ },
+
+ APPLY: {
+ needsBankBalance: false, // 申请页面不需要余额
+ needsWorkStatistics: false, // 申请页面不需要工作统计
+ needsRouteGuard: false, // 申请页面不需要身份检查
+ title: 'Apply',
+ userTag: null // 申请页面可能没有身份标签
+ }
+}
+
+/**
+ * 获取页面配置的工具函数
+ * @param {string} pageType 页面类型
+ * @returns {Object} 页面配置对象
+ */
+export function getPageConfig(pageType) {
+ const config = PageConfig[pageType]
+ if (!config) {
+ console.warn(`未找到页面配置: ${pageType}`)
+ return PageConfig.HOST_CENTER // 默认使用 HOST_CENTER 配置
+ }
+ return config
+}
+
+// ==========================================
+import { usePageInitialization } from './usePageInitialization.js'
+
+/**
+ * 使用预配置的页面初始化函数
+ * @param {string} pageType 页面类型 (HOST_CENTER, COIN_SELLER, etc.)
+ * @param {Object} customOptions 自定义选项,会覆盖默认配置
+ * @returns {Object} usePageInitialization 的返回值
+ */
+export function usePageInitializationWithConfig(pageType, customOptions = {}) {
+ const pageConfig = getPageConfig(pageType)
+
+ // 合并默认配置和自定义选项
+ const options = {
+ ...pageConfig,
+ ...customOptions
+ }
+
+ return usePageInitialization(options)
+}
+
diff --git a/src/utils/permissionManager.js b/src/utils/permissionManager.js
index 213be28..afc534d 100644
--- a/src/utils/permissionManager.js
+++ b/src/utils/permissionManager.js
@@ -6,7 +6,7 @@
// 用户身份类型
export const USER_ROLES = {
FREIGHT_AGENT: 'freightAgent',
- AGENT: 'agent',
+ AGENT: 'agent',
BD: 'bd',
ANCHOR: 'anchor',
GUEST: 'guest'
@@ -16,7 +16,7 @@ export const USER_ROLES = {
export const PAGES = {
COIN_SELLER: '/coin-seller',
AGENCY_CENTER: '/agency-center',
- BD_CENTER: '/bd-center',
+ BD_CENTER: '/bd-center',
HOST_CENTER: '/host-center',
APPLY: '/apply',
MESSAGE: '/message',
@@ -30,7 +30,7 @@ export const PAGE_PERMISSIONS = {
[PAGES.COIN_SELLER]: [USER_ROLES.FREIGHT_AGENT],
[PAGES.AGENCY_CENTER]: [USER_ROLES.AGENT],
[PAGES.BD_CENTER]: [USER_ROLES.BD],
- [PAGES.HOST_CENTER]: [USER_ROLES.AGENT, USER_ROLES.ANCHOR],
+ [PAGES.HOST_CENTER]: [USER_ROLES.ANCHOR],
[PAGES.APPLY]: [USER_ROLES.GUEST],
[PAGES.MESSAGE]: [USER_ROLES.AGENT],
[PAGES.TRANSFER]: [USER_ROLES.AGENT, USER_ROLES.BD, USER_ROLES.ANCHOR],
@@ -76,7 +76,7 @@ class PermissionManager {
this.primaryRole = this.calculatePrimaryRole(identity)
this.allowedPages = this.calculateAllowedPages(this.primaryRole)
this.isIdentityLoaded = true
-
+
console.debug('🔐 User identity updated:', {
identity: this.userIdentity,
primaryRole: this.primaryRole,
@@ -97,7 +97,7 @@ class PermissionManager {
if (identity.agent) return USER_ROLES.AGENT
if (identity.bd) return USER_ROLES.BD
if (identity.anchor) return USER_ROLES.ANCHOR
-
+
return USER_ROLES.GUEST
}
@@ -108,13 +108,13 @@ class PermissionManager {
*/
calculateAllowedPages(primaryRole) {
const allowedPages = []
-
+
Object.entries(PAGE_PERMISSIONS).forEach(([page, roles]) => {
if (roles.length === 0 || roles.includes(primaryRole)) {
allowedPages.push(page)
}
})
-
+
return allowedPages
}
@@ -131,13 +131,13 @@ class PermissionManager {
// 检查是否在允许列表中
const hasPermission = this.allowedPages.includes(page)
-
+
console.debug('🔍 Permission check:', {
page,
primaryRole: this.primaryRole,
hasPermission
})
-
+
return hasPermission
}
@@ -179,13 +179,13 @@ class PermissionManager {
*/
getAllRoles() {
if (!this.userIdentity) return [USER_ROLES.GUEST]
-
+
const roles = []
if (this.userIdentity.freightAgent) roles.push(USER_ROLES.FREIGHT_AGENT)
if (this.userIdentity.agent) roles.push(USER_ROLES.AGENT)
if (this.userIdentity.bd) roles.push(USER_ROLES.BD)
if (this.userIdentity.anchor) roles.push(USER_ROLES.ANCHOR)
-
+
return roles.length > 0 ? roles : [USER_ROLES.GUEST]
}
diff --git a/src/utils/usePageInitialization.js b/src/utils/usePageInitialization.js
new file mode 100644
index 0000000..f905300
--- /dev/null
+++ b/src/utils/usePageInitialization.js
@@ -0,0 +1,392 @@
+// src/composables/usePageInitialization.js
+import { ref, reactive, onMounted } from 'vue'
+import { useRouter } from 'vue-router'
+import { getBankBalance, getTeamEntry, getTeamMemberWorkStatistics } from '../api/wallet.js'
+import { connectApplication, parseAccessOrigin, parseHeader, setHttpHeaders, isInApp } from '../utils/appBridge.js'
+import { appConnectionManager, isAppConnected, getAppHeaderInfo } from '../utils/appConnectionManager.js'
+import { checkAndRedirect } from '../utils/routeGuard.js'
+import { getUserId, setUserInfo } from '../utils/userStore.js'
+import { showError } from '../utils/toast.js'
+
+/**
+ * 页面初始化公共组合式函数
+ * 适用于: HOST_CENTER, COIN_SELLER, AGENCY_CENTER, BD_CENTER, APPLY 等页面
+ *
+ * @param {Object} options 配置选项
+ * @param {boolean} options.needsBankBalance 是否需要获取银行余额 (默认: true)
+ * @param {boolean} options.needsWorkStatistics 是否需要获取工作统计 (默认: true)
+ * @param {boolean} options.needsRouteGuard 是否需要路由守卫检查 (默认: true)
+ * @param {Function} options.onDataLoaded 数据加载完成后的回调函数
+ * @param {Function} options.onConnectionSuccess APP连接成功后的回调函数
+ * @param {Function} options.onConnectionFailed APP连接失败后的回调函数
+ */
+export function usePageInitialization(options = {}) {
+ const {
+ needsBankBalance = true,
+ needsWorkStatistics = true,
+ needsRouteGuard = true,
+ onDataLoaded,
+ onConnectionSuccess,
+ onConnectionFailed
+ } = options
+
+ const router = useRouter()
+
+ // 响应式状态
+ const loading = ref(false)
+ const appConnected = ref(false)
+ const headerInfo = ref({})
+ const userProfile = ref(null)
+
+ // 用户信息
+ const userInfo = reactive({
+ name: 'user',
+ id: '1001',
+ userAvatar: '',
+ userNickname: 'user',
+ account: '1234567890'
+ })
+
+ // 收入信息
+ const salaryInfo = reactive({
+ hostSalary: 0.00,
+ currentSalary: 0.00
+ })
+
+ // 任务信息
+ const taskInfo = reactive({
+ anchorType: 'Chat',
+ minutesProgress: 0,
+ minutesTotal: 120,
+ giftTask: 0
+ })
+
+ /**
+ * 连接APP并获取认证信息(优化版 - 仅专注连接)
+ */
+ const connectToApp = async () => {
+ console.group('🔗 APP Connection Process')
+ console.debug('🚀 Starting APP connection...')
+
+ try {
+ // 检查是否在APP环境中
+ if (!isInApp()) {
+ console.debug('🌐 Browser environment detected')
+ appConnected.value = true
+ console.groupEnd()
+
+ // 触发连接成功回调
+ if (onConnectionSuccess) {
+ onConnectionSuccess({ environment: 'browser' })
+ }
+
+ return { success: true, environment: 'browser' }
+ }
+
+ // 检查是否已经连接且未过期
+ if (isAppConnected()) {
+ console.debug('✅ APP already connected and valid')
+ appConnected.value = true
+
+ // 使用缓存的头部信息
+ const cachedHeaderInfo = getAppHeaderInfo()
+ if (cachedHeaderInfo) {
+ headerInfo.value = cachedHeaderInfo
+ console.debug('🔧 Using cached HTTP headers')
+ }
+
+ console.groupEnd()
+
+ // 触发连接成功回调
+ if (onConnectionSuccess) {
+ onConnectionSuccess({ environment: 'app', fromCache: true })
+ }
+
+ return { success: true, environment: 'app', fromCache: true }
+ }
+
+ // 检查是否有正在进行的连接
+ if (appConnectionManager.isConnecting()) {
+ console.debug('⏳ Connection already in progress, waiting...')
+ await appConnectionManager.getConnectionPromise()
+ appConnected.value = true
+ console.debug('✅ Connected via existing process')
+ console.groupEnd()
+
+ // 触发连接成功回调
+ if (onConnectionSuccess) {
+ onConnectionSuccess({ environment: 'app', fromCache: true })
+ }
+
+ return { success: true, environment: 'app', fromCache: true }
+ }
+
+ // 建立新的APP连接
+ console.debug('📱 Establishing new APP connection...')
+
+ const connectionResult = await new Promise((resolve, reject) => {
+ const connectionPromise = new Promise((connectResolve, connectReject) => {
+ connectApplication(async (access) => {
+ try {
+ const result = parseAccessOrigin(access)
+
+ if (result.success) {
+ // 解析头部信息
+ headerInfo.value = parseHeader(result.data)
+
+ // 设置HTTP请求头
+ console.debug('🔧 Setting HTTP headers...')
+ await setHttpHeaders(headerInfo.value)
+
+ // 标记连接成功
+ appConnected.value = true
+ appConnectionManager.setConnected(headerInfo.value)
+
+ console.debug('🎉 APP connection established successfully')
+ connectResolve({ success: true, environment: 'app', fromCache: false })
+ } else {
+ console.error('❌ Failed to parse access origin:', result.error)
+ appConnectionManager.reset()
+ connectReject(new Error(result.error))
+ }
+ } catch (error) {
+ console.error('❌ Connection process failed:', error)
+ appConnectionManager.reset()
+ connectReject(error)
+ }
+ })
+ })
+
+ // 设置连接状态
+ appConnectionManager.setConnecting(connectionPromise)
+
+ connectionPromise
+ .then(resolve)
+ .catch(reject)
+ })
+
+ console.debug('✅ Connection completed successfully')
+ console.groupEnd()
+
+ // 触发连接成功回调
+ if (onConnectionSuccess) {
+ onConnectionSuccess(connectionResult)
+ }
+
+ return connectionResult
+
+ } catch (error) {
+ console.error('❌ Connection failed:', error)
+ appConnected.value = false
+ console.groupEnd()
+
+ // 触发连接失败回调
+ if (onConnectionFailed) {
+ onConnectionFailed(error)
+ }
+
+ // 连接失败的特殊处理
+ if (error.message && error.message.includes('parse access')) {
+ router.push({ path: '/not_app', query: { message: error.message }})
+ }
+
+ return { success: false, error: error.message }
+ }
+ }
+
+ /**
+ * 获取银行余额
+ */
+ const fetchBankBalance = async () => {
+ if (!needsBankBalance) return
+
+ loading.value = true
+
+ try {
+ const response = await getBankBalance()
+
+ if (response.status && typeof response.body === 'number') {
+ // 格式化余额显示,保留2位小数
+ salaryInfo.currentSalary = response.body.toFixed(2)
+ } else {
+ salaryInfo.currentSalary = 0.00
+ }
+ } catch (error) {
+ console.error('Failed to fetch bank balance:', error)
+ salaryInfo.currentSalary = 0.00
+ // 可以显示错误提示
+ showError('Failed to load balance. Please try again.')
+ } finally {
+ loading.value = false
+ }
+ }
+
+ /**
+ * 获取工作统计数据
+ */
+ const fetchWorkStatistics = async () => {
+ if (!needsWorkStatistics) return
+
+ try {
+ const response = await getTeamMemberWorkStatistics('DAILY', getUserId())
+ if (response.status && response.body) {
+ // 更新任务信息
+ taskInfo.anchorType = 'Chat' // 固定值
+ taskInfo.minutesProgress = response.body.ownTime
+ taskInfo.giftTask = response.body.acceptGiftValue || 0 // acceptGiftValue
+ }
+
+ } catch (error) {
+ console.error('获取工作统计失败:', error)
+ }
+ }
+
+ /**
+ * 获取团队入口信息
+ */
+ const fetchTeamEntry = async () => {
+ try {
+ const response = await getTeamEntry()
+
+ if (response && response.status && response.body) {
+ userProfile.value = response.body
+
+ // 缓存用户信息
+ if (response.body.memberProfile) {
+ setUserInfo(response.body.memberProfile, response.body.teamProfile)
+
+ // 更新用户信息显示
+ userInfo.userNickname = response.body.memberProfile.userNickname
+ userInfo.id = response.body.memberProfile.account
+ userInfo.userAvatar = response.body.memberProfile.userAvatar
+ }
+
+ return response.body.memberProfile?.id
+ }
+ } catch (error) {
+ console.error('获取团队信息失败:', error)
+ if (error.message && error.message.includes('401')) {
+ await router.push({
+ path: '/not_app',
+ query: { message: error.message }
+ })
+ return
+ }
+ }
+ return null
+ }
+
+ /**
+ * 数据初始化函数
+ */
+ const initializePageData = async () => {
+ console.debug('📊 Starting data initialization...')
+
+ try {
+ // 获取团队信息
+ const teamEntryResult = await fetchTeamEntry()
+ if (teamEntryResult != null) {
+ // 并行获取银行余额和工作统计(提高性能)
+ const dataPromises = []
+
+ if (needsBankBalance) {
+ dataPromises.push(fetchBankBalance())
+ }
+
+ if (needsWorkStatistics) {
+ dataPromises.push(fetchWorkStatistics())
+ }
+
+ // 等待所有数据加载完成
+ await Promise.all(dataPromises)
+
+ // 使用路由守卫进行身份检查和重定向
+ if (needsRouteGuard) {
+ await checkAndRedirect(router, teamEntryResult)
+ }
+
+ // 触发数据加载完成回调
+ if (onDataLoaded) {
+ onDataLoaded({
+ userProfile: userProfile.value,
+ userInfo: userInfo,
+ salaryInfo: salaryInfo,
+ taskInfo: taskInfo
+ })
+ }
+
+ console.debug('✅ Data initialization completed')
+ }
+ } catch (error) {
+ console.error('❌ Data initialization failed:', error)
+ }
+ }
+
+ /**
+ * 处理头像图片加载失败
+ */
+ const handleImageError = () => {
+ // 图片加载失败时,清空userAvatar,显示占位符
+ userInfo.userAvatar = ''
+ }
+
+ /**
+ * 获取头像占位符(用户名首字母)
+ */
+ const getAvatarPlaceholder = () => {
+ if (userInfo.name && userInfo.name.length > 0) {
+ return userInfo.name.charAt(0).toUpperCase()
+ }
+ return 'U' // 默认显示 'U'
+ }
+
+ /**
+ * 页面挂载时的初始化逻辑
+ */
+ const initializePage = async () => {
+ console.debug('📄 Page initialization started')
+
+ try {
+ // 第一步:仅进行APP连接
+ const connectionResult = await connectToApp()
+
+ // 第二步:根据连接结果决定是否初始化数据
+ if (connectionResult.success) {
+ console.debug('🔗 Connection successful, initializing data...')
+ await initializePageData()
+ } else {
+ console.warn('⚠️ Connection failed, skipping data initialization')
+ }
+ } catch (error) {
+ console.error('❌ Page initialization failed:', error)
+ }
+ }
+
+ // 自动在 onMounted 时初始化
+ onMounted(initializePage)
+
+ // 返回所有需要的状态和方法
+ return {
+ // 状态
+ loading,
+ appConnected,
+ headerInfo,
+ userProfile,
+ userInfo,
+ salaryInfo,
+ taskInfo,
+
+ // 方法
+ connectToApp,
+ initializePageData,
+ fetchBankBalance,
+ fetchWorkStatistics,
+ fetchTeamEntry,
+ handleImageError,
+ getAvatarPlaceholder,
+ initializePage,
+
+ // 手动初始化方法(如果需要重新初始化)
+ reinitialize: initializePage
+ }
+}
diff --git a/src/views/AgencyCenterView.vue b/src/views/AgencyCenterView.vue
index 889c6f0..01795e4 100644
--- a/src/views/AgencyCenterView.vue
+++ b/src/views/AgencyCenterView.vue
@@ -10,13 +10,13 @@
{{ getAvatarPlaceholder() }}
ID: {{ userInfo.id }}