This commit is contained in:
2026-07-17 15:58:25 +08:00
parent fb9a55229f
commit 89207dcf81
16 changed files with 227 additions and 164 deletions

View File

@@ -6,7 +6,7 @@ export default defineUniPages({
{ path: 'pages/privacy-consent', style: { navigationStyle: 'custom', navigationBarTitleText: '隐私政策授权' } },
{ path: 'pages/launch', style: { navigationStyle: 'custom', navigationBarTitleText: '' } },
{ path: 'pages/index', style: { navigationBarTitleText: '首页' } },
{ path: 'pages/agent', style: { navigationBarTitleText: '代理中心' } },
{ path: 'pages/agent', style: { navigationBarTitleText: '推广收益' } },
{ path: 'pages/agent-manage-agreement', style: { navigationBarTitleText: '代理管理协议', navigationStyle: 'default' } },
{ path: 'pages/agent-promote-details', auth: true, style: { navigationBarTitleText: '收益明细' } },
{ path: 'pages/agent-rewards-details', auth: true, style: { navigationBarTitleText: '奖励明细' } },
@@ -17,7 +17,7 @@ export default defineUniPages({
{ path: 'pages/help', style: { navigationBarTitleText: '帮助中心' } },
{ path: 'pages/help-detail', style: { navigationBarTitleText: '帮助详情' } },
{ path: 'pages/help-guide', style: { navigationBarTitleText: '引导指南' } },
{ path: 'pages/invitation', auth: true, style: { navigationBarTitleText: '邀请下级' } },
{ path: 'pages/invitation', auth: true, style: { navigationBarTitleText: '邀请好友' } },
{ path: 'pages/invitation-agent-apply', auth: true, style: { navigationBarTitleText: '代理申请' } },
{ path: 'pages/login', style: { navigationBarTitleText: '登录' } },
{ path: 'pages/me', style: { navigationBarTitleText: '我的' } },

23
src/auto-imports.d.ts vendored
View File

@@ -7,7 +7,6 @@
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const ZoomAdapter: typeof import('./utils/zoomAdapter.js')['ZoomAdapter']
const aesDecrypt: typeof import('./utils/crypto.js')['aesDecrypt']
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
const appendAppAuthQueryParams: typeof import('./composables/useReportWebview')['appendAppAuthQueryParams']
@@ -15,8 +14,6 @@ declare global {
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const buildAgentVipApplyH5Url: typeof import('./composables/useAgentVipH5')['buildAgentVipApplyH5Url']
const calculatePromotionPricing: typeof import('./utils/promotionPricing.js')['calculatePromotionPricing']
const chatCrypto: typeof import('./utils/chatCrypto.js')['default']
const chatEncrypt: typeof import('./utils/chatEncrypt.js')['default']
const clearAuthStorage: typeof import('./utils/storage')['clearAuthStorage']
const clearToken: typeof import('./utils/storage')['clearToken']
const computed: typeof import('vue')['computed']
@@ -44,6 +41,7 @@ declare global {
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const ensureCurrentPageAccess: typeof import('./composables/useNavigationAuthGuard')['ensureCurrentPageAccess']
const ensureCurrentPageAppReviewAllowed: typeof import('./composables/useAppReviewPresentation')['ensureCurrentPageAppReviewAllowed']
const ensurePageAccessByUrl: typeof import('./composables/useNavigationAuthGuard')['ensurePageAccessByUrl']
const ensurePrivacyConsentIfNeeded: typeof import('./composables/usePrivacyConsent')['ensurePrivacyConsentIfNeeded']
const extendRef: typeof import('@vueuse/core')['extendRef']
@@ -128,6 +126,7 @@ declare global {
const openAgentVipApplyInExternalBrowser: typeof import('./composables/useAgentVipH5')['openAgentVipApplyInExternalBrowser']
const openCustomerService: typeof import('./composables/useCustomerService')['openCustomerService']
const openExternalUrl: typeof import('./composables/openExternalUrl')['openExternalUrl']
const parseQueryFromUrl: typeof import('./composables/useAppReviewPresentation')['parseQueryFromUrl']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
@@ -139,6 +138,7 @@ declare global {
const reactivePick: typeof import('@vueuse/core')['reactivePick']
const readLocalFileAsBase64: typeof import('./utils/appLocalFile')['readLocalFileAsBase64']
const readonly: typeof import('vue')['readonly']
const redirectIfAppReviewRouteBlocked: typeof import('./composables/useAppReviewPresentation')['redirectIfAppReviewRouteBlocked']
const ref: typeof import('vue')['ref']
const refAutoReset: typeof import('@vueuse/core')['refAutoReset']
const refDebounced: typeof import('@vueuse/core')['refDebounced']
@@ -161,6 +161,8 @@ declare global {
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const shouldBlockAppReviewRoute: typeof import('./composables/useAppReviewPresentation')['shouldBlockAppReviewRoute']
const shouldHideDownlineMlmUi: typeof import('./composables/useAppReviewPresentation')['shouldHideDownlineMlmUi']
const shouldSilencePrivacyBlockedRequest: typeof import('./composables/usePrivacyConsent')['shouldSilencePrivacyBlockedRequest']
const syncRef: typeof import('@vueuse/core')['syncRef']
const syncRefs: typeof import('@vueuse/core')['syncRefs']
@@ -202,7 +204,6 @@ declare global {
const useAsyncQueue: typeof import('@vueuse/core')['useAsyncQueue']
const useAsyncState: typeof import('@vueuse/core')['useAsyncState']
const useAttrs: typeof import('vue')['useAttrs']
const useAuthGuard: typeof import('./composables/useAuthGuard')['useAuthGuard']
const useAuthStore: typeof import('./stores/auth')['useAuthStore']
const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery']
@@ -216,7 +217,6 @@ declare global {
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useCount: typeof import('./composables/useCount')['useCount']
const useCountdown: typeof import('@vueuse/core')['useCountdown']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
@@ -243,7 +243,6 @@ declare global {
const useElementHover: typeof import('@vueuse/core')['useElementHover']
const useElementSize: typeof import('@vueuse/core')['useElementSize']
const useElementVisibility: typeof import('@vueuse/core')['useElementVisibility']
const useEnv: typeof import('./composables/useEnv.js')['useEnv']
const useEventBus: typeof import('@vueuse/core')['useEventBus']
const useEventListener: typeof import('@vueuse/core')['useEventListener']
const useEventSource: typeof import('@vueuse/core')['useEventSource']
@@ -260,7 +259,6 @@ declare global {
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
const useGlobalNotification: typeof import('./composables/useGlobalNotification.js')['useGlobalNotification']
const useHotUpdate: typeof import('./composables/useHotUpdate')['useHotUpdate']
const useHttp: typeof import('./composables/useHttp.js')['useHttp']
const useId: typeof import('vue')['useId']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
@@ -304,12 +302,10 @@ declare global {
const usePreferredReducedMotion: typeof import('@vueuse/core')['usePreferredReducedMotion']
const usePreferredReducedTransparency: typeof import('@vueuse/core')['usePreferredReducedTransparency']
const usePrevious: typeof import('@vueuse/core')['usePrevious']
const useQuery: typeof import('./composables/useQuery')['useQuery']
const useRafFn: typeof import('@vueuse/core')['useRafFn']
const useRefHistory: typeof import('@vueuse/core')['useRefHistory']
const useReportWebview: typeof import('./composables/useReportWebview')['useReportWebview']
const useResizeObserver: typeof import('@vueuse/core')['useResizeObserver']
const useRiskNotifier: typeof import('./composables/useRiskNotifier.js')['useRiskNotifier']
const useRoute: typeof import('./composables/uni-router')['useRoute']
const useRouter: typeof import('./composables/uni-router')['useRouter']
const useSEO: typeof import('./composables/useSEO.js')['useSEO']
@@ -360,14 +356,11 @@ declare global {
const useWakeLock: typeof import('@vueuse/core')['useWakeLock']
const useWebNotification: typeof import('@vueuse/core')['useWebNotification']
const useWebSocket: typeof import('@vueuse/core')['useWebSocket']
const useWebView: typeof import('./composables/useWebView.js')['useWebView']
const useWebWorker: typeof import('@vueuse/core')['useWebWorker']
const useWebWorkerFn: typeof import('@vueuse/core')['useWebWorkerFn']
const useWeixinShare: typeof import('./composables/useWeixinShare.js')['useWeixinShare']
const useWindowFocus: typeof import('@vueuse/core')['useWindowFocus']
const useWindowScroll: typeof import('@vueuse/core')['useWindowScroll']
const useWindowSize: typeof import('@vueuse/core')['useWindowSize']
const useZoomAdapter: typeof import('./composables/useZoomAdapter.js')['useZoomAdapter']
const watch: typeof import('vue')['watch']
const watchArray: typeof import('@vueuse/core')['watchArray']
const watchAtMost: typeof import('@vueuse/core')['watchAtMost']
@@ -385,7 +378,6 @@ declare global {
const watchWithFilter: typeof import('@vueuse/core')['watchWithFilter']
const whenever: typeof import('@vueuse/core')['whenever']
const writePngBase64ToLocal: typeof import('./utils/appLocalFile')['writePngBase64ToLocal']
const zoomAdapter: typeof import('./utils/zoomAdapter.js')['default']
}
// for type re-export
declare global {
@@ -446,6 +438,7 @@ declare module 'vue' {
readonly eagerComputed: UnwrapRef<typeof import('@vueuse/core')['eagerComputed']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly ensureCurrentPageAccess: UnwrapRef<typeof import('./composables/useNavigationAuthGuard')['ensureCurrentPageAccess']>
readonly ensureCurrentPageAppReviewAllowed: UnwrapRef<typeof import('./composables/useAppReviewPresentation')['ensureCurrentPageAppReviewAllowed']>
readonly ensurePageAccessByUrl: UnwrapRef<typeof import('./composables/useNavigationAuthGuard')['ensurePageAccessByUrl']>
readonly ensurePrivacyConsentIfNeeded: UnwrapRef<typeof import('./composables/usePrivacyConsent')['ensurePrivacyConsentIfNeeded']>
readonly extendRef: UnwrapRef<typeof import('@vueuse/core')['extendRef']>
@@ -530,6 +523,7 @@ declare module 'vue' {
readonly openAgentVipApplyInExternalBrowser: UnwrapRef<typeof import('./composables/useAgentVipH5')['openAgentVipApplyInExternalBrowser']>
readonly openCustomerService: UnwrapRef<typeof import('./composables/useCustomerService')['openCustomerService']>
readonly openExternalUrl: UnwrapRef<typeof import('./composables/openExternalUrl')['openExternalUrl']>
readonly parseQueryFromUrl: UnwrapRef<typeof import('./composables/useAppReviewPresentation')['parseQueryFromUrl']>
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
@@ -541,6 +535,7 @@ declare module 'vue' {
readonly reactivePick: UnwrapRef<typeof import('@vueuse/core')['reactivePick']>
readonly readLocalFileAsBase64: UnwrapRef<typeof import('./utils/appLocalFile')['readLocalFileAsBase64']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly redirectIfAppReviewRouteBlocked: UnwrapRef<typeof import('./composables/useAppReviewPresentation')['redirectIfAppReviewRouteBlocked']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly refAutoReset: UnwrapRef<typeof import('@vueuse/core')['refAutoReset']>
readonly refDebounced: UnwrapRef<typeof import('@vueuse/core')['refDebounced']>
@@ -563,6 +558,8 @@ declare module 'vue' {
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly shouldBlockAppReviewRoute: UnwrapRef<typeof import('./composables/useAppReviewPresentation')['shouldBlockAppReviewRoute']>
readonly shouldHideDownlineMlmUi: UnwrapRef<typeof import('./composables/useAppReviewPresentation')['shouldHideDownlineMlmUi']>
readonly shouldSilencePrivacyBlockedRequest: UnwrapRef<typeof import('./composables/usePrivacyConsent')['shouldSilencePrivacyBlockedRequest']>
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>

16
src/components.d.ts vendored
View File

@@ -19,5 +19,21 @@ declare module 'vue' {
RealNameAuthDialog: typeof import('./components/RealNameAuthDialog.vue')['default']
SectionTitle: typeof import('./components/SectionTitle.vue')['default']
VipBanner: typeof import('./components/VipBanner.vue')['default']
WdButton: typeof import('wot-design-uni/components/wd-button/wd-button.vue')['default']
WdCell: typeof import('wot-design-uni/components/wd-cell/wd-cell.vue')['default']
WdCellGroup: typeof import('wot-design-uni/components/wd-cell-group/wd-cell-group.vue')['default']
WdCheckbox: typeof import('wot-design-uni/components/wd-checkbox/wd-checkbox.vue')['default']
WdColPicker: typeof import('wot-design-uni/components/wd-col-picker/wd-col-picker.vue')['default']
WdDivider: typeof import('wot-design-uni/components/wd-divider/wd-divider.vue')['default']
WdForm: typeof import('wot-design-uni/components/wd-form/wd-form.vue')['default']
WdFormItem: typeof import('wot-design-uni/components/wd-form-item/wd-form-item.vue')['default']
WdIcon: typeof import('wot-design-uni/components/wd-icon/wd-icon.vue')['default']
WdInput: typeof import('wot-design-uni/components/wd-input/wd-input.vue')['default']
WdLoadmore: typeof import('wot-design-uni/components/wd-loadmore/wd-loadmore.vue')['default']
WdNavbar: typeof import('wot-design-uni/components/wd-navbar/wd-navbar.vue')['default']
WdPicker: typeof import('wot-design-uni/components/wd-picker/wd-picker.vue')['default']
WdPopup: typeof import('wot-design-uni/components/wd-popup/wd-popup.vue')['default']
WdTabbar: typeof import('wot-design-uni/components/wd-tabbar/wd-tabbar.vue')['default']
WdTabbarItem: typeof import('wot-design-uni/components/wd-tabbar-item/wd-tabbar-item.vue')['default']
}
}

View File

@@ -0,0 +1,94 @@
/**
* App Store 展示策略:保留「邀请好友」,不在 App 内呈现「下级 / 团队 / 层级返利」相关能力。
* 后端逻辑不变,仅影响 bdrp-app 前端入口与文案。
*/
const BLOCKED_PAGE_ROUTES = new Set([
'pages/subordinate-list',
'pages/subordinate-detail',
'pages/agent-rewards-details',
'pages/agent-vip-config',
'pages/agent-vip',
])
const BLOCKED_HELP_DETAIL_IDS = new Set([
'invite_earnings',
'vip_guide',
'direct_earnings',
])
const BLOCKED_HELP_GUIDE_IDS = new Set<string>([
// 邀请好友引导保留展示
])
let cachedHideDownline: boolean | null = null
/** 是否在 App 内隐藏下级/团队返利相关 UI当前 App 以 iOS 上架为主) */
export function shouldHideDownlineMlmUi(): boolean {
if (cachedHideDownline !== null)
return cachedHideDownline
try {
const sys = uni.getSystemInfoSync()
cachedHideDownline = sys.uniPlatform === 'app' || sys.platform === 'ios'
}
catch {
cachedHideDownline = true
}
return cachedHideDownline
}
export function shouldBlockAppReviewRoute(route: string, query: Record<string, string> = {}): boolean {
if (!shouldHideDownlineMlmUi())
return false
const normalized = route.replace(/^\//, '').split('?')[0]
if (BLOCKED_PAGE_ROUTES.has(normalized))
return true
const helpId = String(query.id || query.ID || '').trim()
if (normalized === 'pages/help-detail' && BLOCKED_HELP_DETAIL_IDS.has(helpId))
return true
if (normalized === 'pages/help-guide' && BLOCKED_HELP_GUIDE_IDS.has(helpId))
return true
return false
}
export function parseQueryFromUrl(url = ''): Record<string, string> {
const qIndex = url.indexOf('?')
if (qIndex === -1)
return {}
const query: Record<string, string> = {}
const search = url.slice(qIndex + 1)
for (const part of search.split('&')) {
if (!part)
continue
const eq = part.indexOf('=')
const key = eq === -1 ? part : part.slice(0, eq)
const value = eq === -1 ? '' : part.slice(eq + 1)
if (key)
query[decodeURIComponent(key)] = decodeURIComponent(value)
}
return query
}
const HOME_URL = '/pages/index'
export function redirectIfAppReviewRouteBlocked(route: string, query: Record<string, string> = {}) {
if (!shouldBlockAppReviewRoute(route, query))
return false
uni.redirectTo({ url: HOME_URL })
return true
}
/** 当前页若为审核屏蔽页则跳回首页 */
export function ensureCurrentPageAppReviewAllowed(): boolean {
const stack = getCurrentPages()
const page = stack[stack.length - 1] as { route?: string, options?: Record<string, string> }
if (!page?.route)
return true
const route = page.route.replace(/^\//, '')
const query = page.options || {}
if (shouldBlockAppReviewRoute(route, query)) {
uni.redirectTo({ url: HOME_URL })
return false
}
return true
}

View File

@@ -1,4 +1,5 @@
import { pages } from 'virtual:uni-pages'
import { parseQueryFromUrl, shouldBlockAppReviewRoute } from '@/composables/useAppReviewPresentation'
import { useAgentStore } from '@/stores/agentStore'
import { getAgentInfo, getToken } from '@/utils/storage'
@@ -85,11 +86,24 @@ function goAgentApply(mode: GuardMode) {
uni.navigateTo({ url: AGENT_APPLY_URL })
}
function blockAppReviewRoute(mode: GuardMode) {
if (mode === 'redirect')
uni.redirectTo({ url: HOME_URL })
else
uni.redirectTo({ url: HOME_URL })
}
export function ensurePageAccessByUrl(url = '', mode: GuardMode = 'navigate') {
const route = parseRouteFromUrl(url)
if (!route || route === LOGIN_ROUTE)
return false
const query = parseQueryFromUrl(url)
if (shouldBlockAppReviewRoute(route, query)) {
blockAppReviewRoute(mode)
return true
}
const permission = getPermission(route)
if (!permission.requiresAuth)
return false

View File

@@ -20,7 +20,7 @@ const tabbar = ref('index')
const safeAreaTop = ref(0)
const menu = reactive([
{ title: '首页', icon: 'home', name: 'index' },
{ title: '资产', icon: 'cart', name: 'agent' },
{ title: '收益', icon: 'cart', name: 'agent' },
{ title: '我的', icon: 'user', name: 'me' },
])

View File

@@ -1,6 +1,13 @@
<script setup>
definePage({ layout: 'default', auth: true })
import { ref } from 'vue'
import { onReachBottom } from '@dcloudio/uni-app'
import { ensureCurrentPageAppReviewAllowed } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default', auth: true })
onShow(() => {
ensureCurrentPageAppReviewAllowed()
})
// 类型映射配置
const typeConfig = {
descendant_promotion: {

View File

@@ -130,8 +130,13 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { ensureCurrentPageAppReviewAllowed } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default', auth: true })
onShow(() => {
ensureCurrentPageAppReviewAllowed()
})
// 报告类型选项:由后端动态返回
const reportOptions = ref([])
const reportOptionsByValue = computed(() => {

View File

@@ -1,8 +1,11 @@
<script setup>
import { storeToRefs } from 'pinia'
import { computed, ref } from 'vue'
import { shouldHideDownlineMlmUi } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'home' })
const hideDownlineMlmUi = shouldHideDownlineMlmUi()
const agentStore = useAgentStore()
const { isAgent } = storeToRefs(agentStore)
const data = ref(null)
@@ -175,7 +178,7 @@ function toSubordinateList() {
</view>
</view>
<view class="rounded-xl from-green-50/40 to-cyan-50/30 bg-gradient-to-r p-6 shadow-lg">
<view v-if="!hideDownlineMlmUi" class="rounded-xl from-green-50/40 to-cyan-50/30 bg-gradient-to-r p-6 shadow-lg">
<view class="mb-4 flex items-center justify-between">
<view>
<text class="text-lg text-gray-800 font-bold">

View File

@@ -1,6 +1,7 @@
<script setup>
import { onMounted, ref } from 'vue'
import { useRoute } from '@/composables/uni-router'
import { redirectIfAppReviewRouteBlocked } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default' })
const route = useRoute()
@@ -31,13 +32,15 @@ const titleMap = {
report_types: '赤眉有哪些大数据报告类型',
report_push: '如何推广报告',
report_secret: '报告推广秘籍大公开',
invite_earnings: '如何邀请下级成为代理',
invite_earnings: '如何邀请好友使用服务',
direct_earnings: '如何成为赤眉代理',
vip_guide: '如何成为VIP代理和SVIP代理?',
}
onMounted(() => {
const id = route.query.id
const id = String(route.query.id || '').trim()
if (redirectIfAppReviewRouteBlocked('pages/help-detail', { id }))
return
if (id && titleMap[id]) {
currentHelp.value = {
title: titleMap[id],

View File

@@ -1,12 +1,18 @@
<script setup>
import { computed, onMounted, ref } from 'vue'
import { useRoute, useRouter } from '@/composables/uni-router'
import { redirectIfAppReviewRouteBlocked } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default' })
const route = useRoute()
const router = useRouter()
const currentStepIndex = ref(0)
onMounted(() => {
const id = String(route.query.id || '').trim()
redirectIfAppReviewRouteBlocked('pages/help-guide', { id })
})
// 引导步骤数据
const guideSteps = {
report_guide: [

View File

@@ -1,18 +1,20 @@
<script setup>
import { computed, ref } from 'vue'
import { useRouter } from '@/composables/uni-router'
import { shouldHideDownlineMlmUi } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default' })
const router = useRouter()
const activeTab = ref('report')
const hideDownlineMlmUi = shouldHideDownlineMlmUi()
const categories = [
const allCategories = [
{
title: '推广报告',
name: 'report',
items: [
{ id: 'report_guide', title: '直推报告页面引导', type: 'guide' },
{ id: 'invite_guide', title: '邀请下级页面引导', type: 'guide' },
{ id: 'invite_guide', title: '邀请好友页面引导', type: 'guide' },
{ id: 'direct_earnings', title: '如何成为赤眉代理' },
{ id: 'report_push', title: '如何推广报告' },
{ id: 'report_calculation', title: '推广报告的收益是如何计算的?' },
@@ -23,10 +25,10 @@ const categories = [
],
},
{
title: '邀请下级',
title: '邀请好友',
name: 'invite',
items: [
{ id: 'invite_earnings', title: '邀请下级赚取收益' },
{ id: 'invite_earnings', title: '邀请好友使用服务' },
],
},
{
@@ -38,8 +40,32 @@ const categories = [
},
]
const categories = computed(() => {
if (!hideDownlineMlmUi)
return allCategories
const reportItems = allCategories[0].items.filter((item) => {
if (item.id === 'invite_guide')
return true
if (item.id === 'direct_earnings')
return false
return true
}).map((item) => {
if (item.id === 'invite_guide')
return { ...item, title: '邀请好友页面引导' }
return item
})
return [
{
...allCategories[0],
items: reportItems,
},
]
})
const currentCategory = computed(() => {
return categories.find(item => item.name === activeTab.value) || categories[0]
return categories.value.find(item => item.name === activeTab.value) || categories.value[0]
})
function goToDetail(id, type) {
@@ -57,105 +83,3 @@ function goToDetail(id, type) {
}
}
</script>
<template>
<view class="help-center">
<view class="tab-bar">
<view
v-for="(category, index) in categories"
:key="index"
class="tab-item"
:class="{ active: activeTab === category.name }"
@click="activeTab = category.name"
>
{{ category.title }}
</view>
</view>
<wd-cell-group border class="help-list">
<wd-cell
v-for="item in currentCategory.items"
:key="item.id"
:title="item.title"
clickable
class="help-item"
@click="goToDetail(item.id, item.type)"
>
<template v-if="item.type === 'guide'" #label>
<text class="guide-tag">
引导指南
</text>
</template>
</wd-cell>
</wd-cell-group>
</view>
</template>
<style lang="scss" scoped>
.help-center {
min-height: 100vh;
background-color: #f7f8fa;
padding: 12px;
.tab-bar {
display: flex;
background: #fff;
border-radius: 10px;
padding: 4px;
gap: 6px;
}
.tab-item {
flex: 1;
text-align: center;
padding: 8px 0;
border-radius: 8px;
color: #666;
font-size: 14px;
}
.tab-item.active {
background: #2563eb;
color: #fff;
font-weight: 600;
}
.help-list {
margin-top: 12px;
border-radius: 12px;
overflow: hidden;
.guide-tag {
margin-top: 4px;
display: inline-flex;
padding: 2px 8px;
font-size: 12px;
border-radius: 10px;
color: #fff;
background-color: #2563eb;
}
}
}
.help-detail {
padding: 20px;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
h3 {
margin: 0;
font-size: 18px;
}
}
&-content {
white-space: pre-line;
line-height: 1.6;
color: #666;
}
}
</style>

View File

@@ -4,7 +4,6 @@ import bannerImg2 from '/static/images/index/banner_2.png'
import bannerImg3 from '/static/images/index/banner_3.png'
import honestyBanner from '/static/images/index/banner_B.png'
import indexPromoteIcon from '/static/images/index/tgbg.png'
import indexInvitationIcon from '/static/images/index/yqhy.png'
import { ensurePrivacyConsentIfNeeded } from '@/composables/usePrivacyConsent'
definePage({ layout: 'home' })
@@ -15,10 +14,6 @@ onShow(() => {
const banners = [bannerImg, bannerImg2, bannerImg3]
function toInvitation() {
uni.navigateTo({ url: '/pages/invitation' })
}
function toPromote() {
uni.navigateTo({ url: '/pages/promote' })
}
@@ -44,46 +39,30 @@ function toPromote() {
<view class="mt-2 px-4">
<view class="mb-2 text-base text-gray-800 font-bold">
即刻赚佣金
推广服务
</view>
<view
class="card-gradient-1 mb-4 flex items-center rounded-2xl p-0 shadow-xl"
@click="toPromote"
>
<view class="flex flex-1 flex-col items-start justify-center py-4 pl-4">
<view class="min-w-0 flex flex-1 flex-col items-start justify-center py-4 pl-4 pr-3">
<view class="mb-1 text-[20px] text-blue-700 font-bold">
直推报告
</view>
<view class="mb-4 text-xs text-gray-700">
选择所需报告类型灵活定价一键分享客户客户下单即结算佣金实时到账
<view class="mb-4 text-xs text-gray-700 leading-5">
选择所需报告类型灵活定价一键分享客户客户下单即结算收益实时到账
</view>
<wd-button plain>
立即推广
</wd-button>
</view>
<image class="mx-4 my-4 h-20 w-20" :src="indexPromoteIcon" mode="aspectFit" />
</view>
<view
class="card-gradient-2 flex items-center rounded-2xl p-0 shadow-xl"
@click="toInvitation"
>
<view class="flex flex-1 flex-col items-start justify-center py-4 pl-4">
<view class="mb-1 text-[20px] text-teal-700 font-bold">
邀请下级代理
</view>
<view class="mb-4 text-xs text-gray-700">
邀请好友成为代理好友推广获客客户支付即返佣团队收益轻松到手
</view>
<wd-button plain>
立即邀请
</wd-button>
<view class="card-icon-wrap mr-4 w-[88px] flex shrink-0 items-center justify-center self-stretch">
<image class="card-icon my-4" :src="indexPromoteIcon" mode="aspectFit" />
</view>
<image class="mx-4 my-4 h-20 w-20" :src="indexInvitationIcon" mode="aspectFit" />
</view>
<view class="relative mt-4 h-[120px] overflow-hidden rounded-2xl shadow-xl">
<view class="relative h-[120px] overflow-hidden rounded-2xl shadow-xl">
<image class="absolute inset-0 h-full w-full" :src="honestyBanner" mode="aspectFill" />
<view class="absolute inset-0 bg-black/5" />
</view>
@@ -103,10 +82,13 @@ function toPromote() {
0 1.5px 4px 0 rgba(60, 120, 255, 0.08);
}
.card-gradient-2 {
background: linear-gradient(135deg, #e6f7fa 0%, #fafdff 100%);
box-shadow:
0 6px 24px 0 rgba(0, 200, 180, 0.1),
0 1.5px 4px 0 rgba(0, 200, 180, 0.08);
.card-icon-wrap {
max-width: 88px;
}
.card-icon {
width: 100%;
max-width: 80px;
max-height: 80px;
}
</style>

View File

@@ -3,6 +3,7 @@ import { storeToRefs } from 'pinia'
import { computed, onBeforeMount, ref, watch } from 'vue'
import { openCustomerService } from '@/composables/useCustomerService'
import { openAgentVipApplyInExternalBrowser } from '@/composables/useAgentVipH5'
import { shouldHideDownlineMlmUi } from '@/composables/useAppReviewPresentation'
import { useAgentStore } from '@/stores/agentStore'
import { useDialogStore } from '@/stores/dialogStore'
import { useUserStore } from '@/stores/userStore'
@@ -16,6 +17,7 @@ const dialogStore = useDialogStore()
const { isAgent, level, ExpiryTime } = storeToRefs(agentStore)
const { userAvatar, isLoggedIn, mobile } = storeToRefs(userStore)
const isWeChat = ref(false)
const hideDownlineMlmUi = shouldHideDownlineMlmUi()
const normalizedLevel = computed(() => {
const raw = String(level.value || '').trim()
@@ -242,11 +244,11 @@ onBeforeMount(() => {
</view>
</view>
</view>
<VipBanner v-if="isAgent && normalizedLevel === 'NORMAL'" />
<VipBanner v-if="isAgent && normalizedLevel === 'NORMAL' && !hideDownlineMlmUi" />
<!-- 功能菜单 -->
<view>
<view class="overflow-hidden rounded-xl bg-white shadow-sm">
<template v-if="isAgent && ['VIP', 'SVIP'].includes(normalizedLevel)">
<template v-if="isAgent && ['VIP', 'SVIP'].includes(normalizedLevel) && !hideDownlineMlmUi">
<view
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-purple-50"
@click="toVipConfig">
@@ -290,9 +292,9 @@ onBeforeMount(() => {
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
@click="toInvitation">
<view class="flex items-center gap-3">
<image src="/static/images/index/yqhy.png" class="h-6 w-6" alt="邀请下级" />
<image src="/static/images/index/yqhy.png" class="h-6 w-6" alt="邀请好友" />
<text class="text-gray-700 font-medium">
邀请下级
邀请好友
</text>
</view>
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />

View File

@@ -3,9 +3,14 @@ import { onMounted, ref } from 'vue'
import { onReachBottom } from '@dcloudio/uni-app'
import { useRoute } from '@/composables/uni-router'
import useApiFetch from '@/composables/useApiFetch'
import { ensureCurrentPageAppReviewAllowed } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default', auth: true })
onShow(() => {
ensureCurrentPageAppReviewAllowed()
})
const route = useRoute()
const loading = ref(false)
const page = ref(1)

View File

@@ -2,9 +2,14 @@
import { onMounted, ref } from 'vue'
import { onReachBottom } from '@dcloudio/uni-app'
import useApiFetch from '@/composables/useApiFetch'
import { ensureCurrentPageAppReviewAllowed } from '@/composables/useAppReviewPresentation'
definePage({ layout: 'default', auth: true })
onShow(() => {
ensureCurrentPageAppReviewAllowed()
})
const subordinates = ref([])
const loading = ref(false)
const page = ref(1)