f
This commit is contained in:
@@ -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
23
src/auto-imports.d.ts
vendored
@@ -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
16
src/components.d.ts
vendored
@@ -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']
|
||||
}
|
||||
}
|
||||
|
||||
94
src/composables/useAppReviewPresentation.ts
Normal file
94
src/composables/useAppReviewPresentation.ts
Normal 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
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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' },
|
||||
])
|
||||
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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(() => {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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="右箭头" />
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user