f
This commit is contained in:
3
.env
3
.env
@@ -33,6 +33,9 @@ VITE_SITE_ORIGIN=https://chimei.ronsafe.cn
|
|||||||
# 报告 H5 根地址(可选,优先与 VITE_SITE_ORIGIN 配合使用)
|
# 报告 H5 根地址(可选,优先与 VITE_SITE_ORIGIN 配合使用)
|
||||||
VITE_REPORT_BASE_URL=https://chimei.ronsafe.cn
|
VITE_REPORT_BASE_URL=https://chimei.ronsafe.cn
|
||||||
|
|
||||||
|
# 与 bdrp-webview `.env` 中 VITE_TOKEN_VERSION 保持一致(外部浏览器带参登录)
|
||||||
|
VITE_TOKEN_VERSION=1.0
|
||||||
|
|
||||||
# `src/pages/not-found.vue` 必需
|
# `src/pages/not-found.vue` 必需
|
||||||
VITE_SEO_SITE_NAME=赤眉
|
VITE_SEO_SITE_NAME=赤眉
|
||||||
|
|
||||||
|
|||||||
32
_backup/pages/agent-vip-apply.vue
Normal file
32
_backup/pages/agent-vip-apply.vue
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { buildAgentVipApplyH5Url } from '@/composables/useAgentVipH5'
|
||||||
|
import { ensureCurrentPageAccess } from '@/composables/useNavigationAuthGuard'
|
||||||
|
|
||||||
|
definePage({ layout: false, auth: true })
|
||||||
|
|
||||||
|
const src = ref('')
|
||||||
|
|
||||||
|
onLoad((query) => {
|
||||||
|
const params: Record<string, string> = {}
|
||||||
|
const type = query?.type
|
||||||
|
if (type) {
|
||||||
|
const normalized = String(type).toLowerCase()
|
||||||
|
if (normalized === 'vip' || normalized === 'svip')
|
||||||
|
params.type = normalized
|
||||||
|
}
|
||||||
|
src.value = buildAgentVipApplyH5Url(params)
|
||||||
|
if (!src.value)
|
||||||
|
uni.showToast({ title: '未配置 H5 站点地址', icon: 'none' })
|
||||||
|
})
|
||||||
|
|
||||||
|
onShow(() => {
|
||||||
|
ensureCurrentPageAccess('redirect')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<web-view v-if="src" :src="src" />
|
||||||
|
<view v-else class="flex min-h-screen items-center justify-center bg-gray-50 px-6 text-center text-sm text-gray-500">
|
||||||
|
无法打开会员升级页面,请检查 VITE_SITE_ORIGIN 配置
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import InquireForm from '@/components/InquireForm.vue'
|
import InquireForm from './components/InquireForm.vue'
|
||||||
|
|
||||||
definePage({ layout: 'default' })
|
definePage({ layout: 'default' })
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
|
import { defineManifestConfig } from '@uni-helper/vite-plugin-uni-manifest'
|
||||||
|
|
||||||
export default defineManifestConfig({
|
export default defineManifestConfig({
|
||||||
'name': '赤眉',
|
'name': '戎行赤眉',
|
||||||
'appid': 'H5A4E639E',
|
'appid': 'H5A4E639E',
|
||||||
'description': '',
|
'description': '',
|
||||||
'versionName': '1.0.0',
|
'versionName': '1.0.0',
|
||||||
@@ -36,19 +36,40 @@ export default defineManifestConfig({
|
|||||||
},
|
},
|
||||||
"Payment": {},
|
"Payment": {},
|
||||||
"UIWebview": {},
|
"UIWebview": {},
|
||||||
"Camera": {}
|
|
||||||
},
|
},
|
||||||
/* 应用发布信息 */
|
/* 应用发布信息 */
|
||||||
distribute: {
|
distribute: {
|
||||||
/* android打包配置 */
|
/* android打包配置 */
|
||||||
android: {
|
android: {
|
||||||
permissions: [
|
permissionExternalStorage: {
|
||||||
'<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>',
|
request: 'none',
|
||||||
'<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>',
|
},
|
||||||
'<uses-feature android:name="android.hardware.camera.autofocus"/>',
|
permissionPhoneState: {
|
||||||
|
request: 'none',
|
||||||
|
},
|
||||||
|
// 云打包默认已含 INTERNET / 网络状态 / 读写存储等,此处只配置「强制移除」与启动申请策略,避免 permissions 重复合并失败
|
||||||
|
excludePermissions: [
|
||||||
'<uses-permission android:name="android.permission.CAMERA"/>',
|
'<uses-permission android:name="android.permission.CAMERA"/>',
|
||||||
'<uses-feature android:name="android.hardware.camera"/>',
|
'<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_PHONE_STATE"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_PHONE_NUMBERS"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_BASIC_PHONE_STATE"/>',
|
||||||
|
'<uses-permission android:name="android.permission.CALL_PHONE"/>',
|
||||||
|
'<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_CALL_LOG"/>',
|
||||||
|
'<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>',
|
||||||
|
'<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>',
|
||||||
|
'<uses-permission android:name="android.permission.CALL_PRIVILEGED"/>',
|
||||||
|
'<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>',
|
||||||
|
'<uses-permission android:name="android.permission.READ_VOICEMAIL"/>',
|
||||||
|
'<uses-permission android:name="android.permission.WRITE_VOICEMAIL"/>',
|
||||||
|
'<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>',
|
||||||
|
'<uses-permission android:name="android.permission.USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER"/>',
|
||||||
],
|
],
|
||||||
|
"targetSdkVersion": 30
|
||||||
},
|
},
|
||||||
/* ios打包配置 */
|
/* ios打包配置 */
|
||||||
"ios": {
|
"ios": {
|
||||||
|
|||||||
@@ -12,14 +12,11 @@ export default defineUniPages({
|
|||||||
{ path: 'pages/agent-rewards-details', auth: true, style: { navigationBarTitleText: '奖励明细' } },
|
{ path: 'pages/agent-rewards-details', auth: true, style: { navigationBarTitleText: '奖励明细' } },
|
||||||
{ path: 'pages/agent-service-agreement', style: { navigationBarTitleText: '信息技术服务合同', navigationStyle: 'default' } },
|
{ path: 'pages/agent-service-agreement', style: { navigationBarTitleText: '信息技术服务合同', navigationStyle: 'default' } },
|
||||||
{ path: 'pages/agent-vip', auth: true, style: { navigationBarTitleText: '代理会员' } },
|
{ path: 'pages/agent-vip', auth: true, style: { navigationBarTitleText: '代理会员' } },
|
||||||
{ path: 'pages/agent-vip-apply', auth: true, style: { navigationBarTitleText: 'VIP代理申请' } },
|
|
||||||
{ path: 'pages/agent-vip-config', auth: true, style: { navigationBarTitleText: '代理报告配置' } },
|
{ path: 'pages/agent-vip-config', auth: true, style: { navigationBarTitleText: '代理报告配置' } },
|
||||||
{ path: 'pages/authorization', style: { navigationBarTitleText: '授权书', navigationStyle: 'default' } },
|
{ path: 'pages/authorization', style: { navigationBarTitleText: '授权书', navigationStyle: 'default' } },
|
||||||
{ path: 'pages/help', style: { navigationBarTitleText: '帮助中心' } },
|
{ path: 'pages/help', style: { navigationBarTitleText: '帮助中心' } },
|
||||||
{ path: 'pages/help-detail', style: { navigationBarTitleText: '帮助详情' } },
|
{ path: 'pages/help-detail', style: { navigationBarTitleText: '帮助详情' } },
|
||||||
{ path: 'pages/help-guide', style: { navigationBarTitleText: '引导指南' } },
|
{ path: 'pages/help-guide', style: { navigationBarTitleText: '引导指南' } },
|
||||||
{ path: 'pages/history-query', auth: true, style: { navigationBarTitleText: '历史报告' } },
|
|
||||||
{ path: 'pages/inquire', 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/invitation-agent-apply', auth: true, style: { navigationBarTitleText: '代理申请' } },
|
||||||
{ path: 'pages/login', style: { navigationBarTitleText: '登录' } },
|
{ path: 'pages/login', style: { navigationBarTitleText: '登录' } },
|
||||||
|
|||||||
12
src/auto-imports.d.ts
vendored
12
src/auto-imports.d.ts
vendored
@@ -10,8 +10,10 @@ declare global {
|
|||||||
const ZoomAdapter: typeof import('./utils/zoomAdapter.js')['ZoomAdapter']
|
const ZoomAdapter: typeof import('./utils/zoomAdapter.js')['ZoomAdapter']
|
||||||
const aesDecrypt: typeof import('./utils/crypto.js')['aesDecrypt']
|
const aesDecrypt: typeof import('./utils/crypto.js')['aesDecrypt']
|
||||||
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
|
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
|
||||||
|
const appendAppAuthQueryParams: typeof import('./composables/useReportWebview')['appendAppAuthQueryParams']
|
||||||
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
|
||||||
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
|
||||||
|
const buildAgentVipApplyH5Url: typeof import('./composables/useAgentVipH5')['buildAgentVipApplyH5Url']
|
||||||
const calculatePromotionPricing: typeof import('./utils/promotionPricing.js')['calculatePromotionPricing']
|
const calculatePromotionPricing: typeof import('./utils/promotionPricing.js')['calculatePromotionPricing']
|
||||||
const chatCrypto: typeof import('./utils/chatCrypto.js')['default']
|
const chatCrypto: typeof import('./utils/chatCrypto.js')['default']
|
||||||
const chatEncrypt: typeof import('./utils/chatEncrypt.js')['default']
|
const chatEncrypt: typeof import('./utils/chatEncrypt.js')['default']
|
||||||
@@ -78,6 +80,7 @@ declare global {
|
|||||||
const markRaw: typeof import('vue')['markRaw']
|
const markRaw: typeof import('vue')['markRaw']
|
||||||
const navigateLogin: typeof import('./utils/navigate')['navigateLogin']
|
const navigateLogin: typeof import('./utils/navigate')['navigateLogin']
|
||||||
const navigateTo: typeof import('./utils/navigate')['navigateTo']
|
const navigateTo: typeof import('./utils/navigate')['navigateTo']
|
||||||
|
const navigateToAgentVipApplyH5: typeof import('./composables/useAgentVipH5')['navigateToAgentVipApplyH5']
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
const nextTick: typeof import('vue')['nextTick']
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
const onActivated: typeof import('vue')['onActivated']
|
||||||
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
|
const onAddToFavorites: typeof import('@dcloudio/uni-app')['onAddToFavorites']
|
||||||
@@ -122,7 +125,9 @@ declare global {
|
|||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
const onUpdated: typeof import('vue')['onUpdated']
|
||||||
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
|
||||||
|
const openAgentVipApplyInExternalBrowser: typeof import('./composables/useAgentVipH5')['openAgentVipApplyInExternalBrowser']
|
||||||
const openCustomerService: typeof import('./composables/useCustomerService')['openCustomerService']
|
const openCustomerService: typeof import('./composables/useCustomerService')['openCustomerService']
|
||||||
|
const openExternalUrl: typeof import('./composables/openExternalUrl')['openExternalUrl']
|
||||||
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
|
||||||
const provide: typeof import('vue')['provide']
|
const provide: typeof import('vue')['provide']
|
||||||
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
const provideLocal: typeof import('@vueuse/core')['provideLocal']
|
||||||
@@ -156,6 +161,7 @@ declare global {
|
|||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
const shallowRef: typeof import('vue')['shallowRef']
|
||||||
|
const shouldSilencePrivacyBlockedRequest: typeof import('./composables/usePrivacyConsent')['shouldSilencePrivacyBlockedRequest']
|
||||||
const syncRef: typeof import('@vueuse/core')['syncRef']
|
const syncRef: typeof import('@vueuse/core')['syncRef']
|
||||||
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
const syncRefs: typeof import('@vueuse/core')['syncRefs']
|
||||||
const templateRef: typeof import('@vueuse/core')['templateRef']
|
const templateRef: typeof import('@vueuse/core')['templateRef']
|
||||||
@@ -408,8 +414,10 @@ declare module 'vue' {
|
|||||||
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
||||||
readonly aesDecrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesDecrypt']>
|
readonly aesDecrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesDecrypt']>
|
||||||
readonly aesEncrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesEncrypt']>
|
readonly aesEncrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesEncrypt']>
|
||||||
|
readonly appendAppAuthQueryParams: UnwrapRef<typeof import('./composables/useReportWebview')['appendAppAuthQueryParams']>
|
||||||
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
|
||||||
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
|
||||||
|
readonly buildAgentVipApplyH5Url: UnwrapRef<typeof import('./composables/useAgentVipH5')['buildAgentVipApplyH5Url']>
|
||||||
readonly calculatePromotionPricing: UnwrapRef<typeof import('./utils/promotionPricing.js')['calculatePromotionPricing']>
|
readonly calculatePromotionPricing: UnwrapRef<typeof import('./utils/promotionPricing.js')['calculatePromotionPricing']>
|
||||||
readonly clearAuthStorage: UnwrapRef<typeof import('./utils/storage')['clearAuthStorage']>
|
readonly clearAuthStorage: UnwrapRef<typeof import('./utils/storage')['clearAuthStorage']>
|
||||||
readonly clearToken: UnwrapRef<typeof import('./utils/storage')['clearToken']>
|
readonly clearToken: UnwrapRef<typeof import('./utils/storage')['clearToken']>
|
||||||
@@ -474,6 +482,7 @@ declare module 'vue' {
|
|||||||
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
|
||||||
readonly navigateLogin: UnwrapRef<typeof import('./utils/navigate')['navigateLogin']>
|
readonly navigateLogin: UnwrapRef<typeof import('./utils/navigate')['navigateLogin']>
|
||||||
readonly navigateTo: UnwrapRef<typeof import('./utils/navigate')['navigateTo']>
|
readonly navigateTo: UnwrapRef<typeof import('./utils/navigate')['navigateTo']>
|
||||||
|
readonly navigateToAgentVipApplyH5: UnwrapRef<typeof import('./composables/useAgentVipH5')['navigateToAgentVipApplyH5']>
|
||||||
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
|
||||||
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
|
||||||
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
|
readonly onAddToFavorites: UnwrapRef<typeof import('@dcloudio/uni-app')['onAddToFavorites']>
|
||||||
@@ -518,7 +527,9 @@ declare module 'vue' {
|
|||||||
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
|
||||||
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
|
||||||
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
|
||||||
|
readonly openAgentVipApplyInExternalBrowser: UnwrapRef<typeof import('./composables/useAgentVipH5')['openAgentVipApplyInExternalBrowser']>
|
||||||
readonly openCustomerService: UnwrapRef<typeof import('./composables/useCustomerService')['openCustomerService']>
|
readonly openCustomerService: UnwrapRef<typeof import('./composables/useCustomerService')['openCustomerService']>
|
||||||
|
readonly openExternalUrl: UnwrapRef<typeof import('./composables/openExternalUrl')['openExternalUrl']>
|
||||||
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
readonly pausableWatch: UnwrapRef<typeof import('@vueuse/core')['pausableWatch']>
|
||||||
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
readonly provide: UnwrapRef<typeof import('vue')['provide']>
|
||||||
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
readonly provideLocal: UnwrapRef<typeof import('@vueuse/core')['provideLocal']>
|
||||||
@@ -552,6 +563,7 @@ declare module 'vue' {
|
|||||||
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
|
||||||
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
|
||||||
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
|
||||||
|
readonly shouldSilencePrivacyBlockedRequest: UnwrapRef<typeof import('./composables/usePrivacyConsent')['shouldSilencePrivacyBlockedRequest']>
|
||||||
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
readonly syncRef: UnwrapRef<typeof import('@vueuse/core')['syncRef']>
|
||||||
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
readonly syncRefs: UnwrapRef<typeof import('@vueuse/core')['syncRefs']>
|
||||||
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
|
readonly templateRef: UnwrapRef<typeof import('@vueuse/core')['templateRef']>
|
||||||
|
|||||||
1
src/components.d.ts
vendored
1
src/components.d.ts
vendored
@@ -12,7 +12,6 @@ declare module 'vue' {
|
|||||||
BindPhoneDialog: typeof import('./components/BindPhoneDialog.vue')['default']
|
BindPhoneDialog: typeof import('./components/BindPhoneDialog.vue')['default']
|
||||||
EmptyState: typeof import('./components/EmptyState.vue')['default']
|
EmptyState: typeof import('./components/EmptyState.vue')['default']
|
||||||
ImageSaveGuide: typeof import('./components/ImageSaveGuide.vue')['default']
|
ImageSaveGuide: typeof import('./components/ImageSaveGuide.vue')['default']
|
||||||
InquireForm: typeof import('./components/InquireForm.vue')['default']
|
|
||||||
LoginDialog: typeof import('./components/LoginDialog.vue')['default']
|
LoginDialog: typeof import('./components/LoginDialog.vue')['default']
|
||||||
Payment: typeof import('./components/Payment.vue')['default']
|
Payment: typeof import('./components/Payment.vue')['default']
|
||||||
PriceInputPopup: typeof import('./components/PriceInputPopup.vue')['default']
|
PriceInputPopup: typeof import('./components/PriceInputPopup.vue')['default']
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { openAgentVipApplyInExternalBrowser } from '@/composables/useAgentVipH5'
|
||||||
|
|
||||||
function toAgentVip() {
|
function toAgentVip() {
|
||||||
uni.navigateTo({ url: '/pages/agent-vip-apply' })
|
openAgentVipApplyInExternalBrowser()
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
46
src/composables/openExternalUrl.ts
Normal file
46
src/composables/openExternalUrl.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/** 在系统默认浏览器中打开链接(App 用 plus,H5 开发调试用 window.open) */
|
||||||
|
function redactUrlForLog(url: string): string {
|
||||||
|
try {
|
||||||
|
const u = new URL(url)
|
||||||
|
for (const key of ['token', 'refreshAfter', 'accessExpire']) {
|
||||||
|
if (u.searchParams.has(key))
|
||||||
|
u.searchParams.set(key, '***')
|
||||||
|
}
|
||||||
|
return u.toString()
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return '[invalid-url]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function openExternalUrl(url: string): boolean {
|
||||||
|
if (!url)
|
||||||
|
return false
|
||||||
|
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
try {
|
||||||
|
if (typeof plus !== 'undefined' && plus.runtime?.openURL) {
|
||||||
|
plus.runtime.openURL(url, (err: unknown) => {
|
||||||
|
console.error('[openExternalUrl] 打开失败', err, redactUrlForLog(url))
|
||||||
|
uni.showToast({ title: '无法打开浏览器', icon: 'none' })
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error('[openExternalUrl] 异常', e)
|
||||||
|
}
|
||||||
|
uni.showToast({ title: '当前环境无法打开外部浏览器', icon: 'none' })
|
||||||
|
return false
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef H5
|
||||||
|
window.open(url, '_blank')
|
||||||
|
return true
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef APP-PLUS || H5
|
||||||
|
uni.showToast({ title: '请使用 App 打开', icon: 'none' })
|
||||||
|
return false
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import { pages } from 'virtual:uni-pages'
|
|||||||
const pathToPage: Record<string, string> = {
|
const pathToPage: Record<string, string> = {
|
||||||
'/': '/pages/index',
|
'/': '/pages/index',
|
||||||
'/login': '/pages/login',
|
'/login': '/pages/login',
|
||||||
'/historyQuery': '/pages/history-query',
|
'/historyQuery': '/pages/index',
|
||||||
'/help': '/pages/help',
|
'/help': '/pages/help',
|
||||||
'/help/detail': '/pages/help-detail',
|
'/help/detail': '/pages/help-detail',
|
||||||
'/help/guide': '/pages/help-guide',
|
'/help/guide': '/pages/help-guide',
|
||||||
@@ -35,7 +35,7 @@ const nameToPage: Record<string, string> = {
|
|||||||
invitation: '/pages/invitation',
|
invitation: '/pages/invitation',
|
||||||
promote: '/pages/promote',
|
promote: '/pages/promote',
|
||||||
agent: '/pages/agent',
|
agent: '/pages/agent',
|
||||||
history: '/pages/history-query',
|
history: '/pages/index',
|
||||||
help: '/pages/help',
|
help: '/pages/help',
|
||||||
helpDetail: '/pages/help-detail',
|
helpDetail: '/pages/help-detail',
|
||||||
helpGuide: '/pages/help-guide',
|
helpGuide: '/pages/help-guide',
|
||||||
@@ -70,7 +70,7 @@ export function resolveWebToUni(to: string | { name?: string, path?: string, que
|
|||||||
|
|
||||||
if (pathOnly.startsWith('/inquire/')) {
|
if (pathOnly.startsWith('/inquire/')) {
|
||||||
const feature = pathOnly.replace(/^\/inquire\//, '')
|
const feature = pathOnly.replace(/^\/inquire\//, '')
|
||||||
const base = `/pages/inquire?feature=${encodeURIComponent(feature)}`
|
const base = `/pages/promote?feature=${encodeURIComponent(feature)}`
|
||||||
return queryPart ? `${base}&${queryPart}` : base
|
return queryPart ? `${base}&${queryPart}` : base
|
||||||
}
|
}
|
||||||
if (pathOnly.startsWith('/agent/invitationAgentApply/')) {
|
if (pathOnly.startsWith('/agent/invitationAgentApply/')) {
|
||||||
@@ -142,12 +142,31 @@ const pageMetaByRoute = new Map(
|
|||||||
(pages as UniPageMeta[]).map(page => [normalizeUniRoute(page.path), page]),
|
(pages as UniPageMeta[]).map(page => [normalizeUniRoute(page.path), page]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function resolvePageMetaByRoute(route: string): UniPageMeta | undefined {
|
||||||
|
const normalized = normalizeUniRoute(route)
|
||||||
|
const candidates = [
|
||||||
|
normalized,
|
||||||
|
normalized.startsWith('pages/') ? normalized.slice('pages/'.length) : `pages/${normalized}`,
|
||||||
|
]
|
||||||
|
for (const key of candidates) {
|
||||||
|
const meta = pageMetaByRoute.get(key)
|
||||||
|
if (meta)
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
export function getCurrentPageMeta(): UniPageMeta | undefined {
|
export function getCurrentPageMeta(): UniPageMeta | undefined {
|
||||||
return pageMetaByRoute.get(getCurrentUniRoute())
|
return resolvePageMetaByRoute(getCurrentUniRoute())
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPageTitleByRoute(route = getCurrentUniRoute()): string {
|
export function getPageTitleByRoute(route = getCurrentUniRoute()): string {
|
||||||
return pageMetaByRoute.get(normalizeUniRoute(route))?.style?.navigationBarTitleText || 'BDRP'
|
const meta = resolvePageMetaByRoute(route)
|
||||||
|
const raw = meta?.style?.navigationBarTitleText
|
||||||
|
if (typeof raw === 'string' && raw.trim())
|
||||||
|
return raw.trim()
|
||||||
|
const appName = import.meta.env.VITE_APP_NAME
|
||||||
|
return (typeof appName === 'string' && appName.trim()) ? appName.trim() : 'BDRP'
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLayoutPageTitle(): string {
|
export function getLayoutPageTitle(): string {
|
||||||
@@ -163,7 +182,6 @@ const UNI_TO_WEB_NOTIFY_PATHS: Record<string, string[]> = {
|
|||||||
'pages/agent': ['/agent'],
|
'pages/agent': ['/agent'],
|
||||||
'pages/me': ['/me'],
|
'pages/me': ['/me'],
|
||||||
'pages/promote': ['/agent/promote'],
|
'pages/promote': ['/agent/promote'],
|
||||||
'pages/history-query': ['/historyQuery'],
|
|
||||||
'pages/help': ['/help'],
|
'pages/help': ['/help'],
|
||||||
'pages/help-detail': ['/help/detail'],
|
'pages/help-detail': ['/help/detail'],
|
||||||
'pages/help-guide': ['/help/guide'],
|
'pages/help-guide': ['/help/guide'],
|
||||||
@@ -176,7 +194,6 @@ const UNI_TO_WEB_NOTIFY_PATHS: Record<string, string[]> = {
|
|||||||
'pages/agent-service-agreement': ['/agentSerivceAgreement'],
|
'pages/agent-service-agreement': ['/agentSerivceAgreement'],
|
||||||
'pages/authorization': ['/authorization'],
|
'pages/authorization': ['/authorization'],
|
||||||
'pages/payment-result': ['/payment/result'],
|
'pages/payment-result': ['/payment/result'],
|
||||||
'pages/inquire': ['/inquire'],
|
|
||||||
'pages/login': ['/login'],
|
'pages/login': ['/login'],
|
||||||
'pages/invitation': ['/agent/invitation'],
|
'pages/invitation': ['/agent/invitation'],
|
||||||
'pages/agent-promote-details': ['/agent/promoteDetails'],
|
'pages/agent-promote-details': ['/agent/promoteDetails'],
|
||||||
@@ -202,8 +219,8 @@ export function getWebPathsForNotification(): string[] {
|
|||||||
const q: Record<string, string> = { ...(page?.options || {}) }
|
const q: Record<string, string> = { ...(page?.options || {}) }
|
||||||
|
|
||||||
// 动态路由:带参数的路径
|
// 动态路由:带参数的路径
|
||||||
if (r === 'pages/inquire' && q.feature)
|
if (r === 'pages/promote' && q.feature)
|
||||||
return [`/inquire/${q.feature}`]
|
return [`/inquire/${q.feature}`, '/agent/promote']
|
||||||
if (r === 'pages/subordinate-detail' && q.id)
|
if (r === 'pages/subordinate-detail' && q.id)
|
||||||
return [`/agent/subordinateDetail/${q.id}`]
|
return [`/agent/subordinateDetail/${q.id}`]
|
||||||
if (r === 'pages/invitation-agent-apply' && q.linkIdentifier)
|
if (r === 'pages/invitation-agent-apply' && q.linkIdentifier)
|
||||||
|
|||||||
58
src/composables/useAgentVipH5.ts
Normal file
58
src/composables/useAgentVipH5.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { openExternalUrl } from '@/composables/openExternalUrl'
|
||||||
|
import { useReportWebview } from '@/composables/useReportWebview'
|
||||||
|
import { getToken } from '@/utils/storage'
|
||||||
|
|
||||||
|
const VIP_APPLY_H5_PATH = '/agent/vipApply'
|
||||||
|
|
||||||
|
const CONFIRM_TITLE = '前往浏览器完成升级'
|
||||||
|
const CONFIRM_CONTENT = '代理会员开通/续费将在系统浏览器中完成,与 App 支付完全分离。是否继续打开?'
|
||||||
|
|
||||||
|
export function buildAgentVipApplyH5Url(params: Record<string, string> = {}) {
|
||||||
|
const { buildSitePathUrl } = useReportWebview()
|
||||||
|
return buildSitePathUrl(VIP_APPLY_H5_PATH, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTypeQuery(options?: { type?: 'vip' | 'svip' | 'VIP' | 'SVIP' }) {
|
||||||
|
const query: Record<string, string> = {}
|
||||||
|
const rawType = options?.type
|
||||||
|
if (rawType) {
|
||||||
|
const normalized = String(rawType).toUpperCase()
|
||||||
|
if (normalized === 'VIP' || normalized === 'SVIP')
|
||||||
|
query.type = normalized.toLowerCase()
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在系统浏览器打开 H5 会员页(带 App 登录态),打开前需用户确认。
|
||||||
|
*/
|
||||||
|
export function openAgentVipApplyInExternalBrowser(options?: { type?: 'vip' | 'svip' | 'VIP' | 'SVIP' }) {
|
||||||
|
if (!getToken()) {
|
||||||
|
uni.showToast({ title: '请先登录', icon: 'none' })
|
||||||
|
uni.navigateTo({ url: '/pages/login' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const h5Url = buildAgentVipApplyH5Url(buildTypeQuery(options))
|
||||||
|
if (!h5Url) {
|
||||||
|
uni.showToast({ title: '未配置 H5 站点地址', icon: 'none' })
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showModal({
|
||||||
|
title: CONFIRM_TITLE,
|
||||||
|
content: CONFIRM_CONTENT,
|
||||||
|
confirmText: '继续',
|
||||||
|
cancelText: '取消',
|
||||||
|
success: (res) => {
|
||||||
|
if (res.confirm)
|
||||||
|
openExternalUrl(h5Url)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @deprecated 请使用 openAgentVipApplyInExternalBrowser */
|
||||||
|
export function navigateToAgentVipApplyH5(options?: { type?: 'vip' | 'svip' | 'VIP' | 'SVIP' }) {
|
||||||
|
return openAgentVipApplyInExternalBrowser(options)
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ const HOME_URL = '/pages/index'
|
|||||||
*/
|
*/
|
||||||
const ROUTE_PERMISSION_MAP: Record<string, PagePermission> = {
|
const ROUTE_PERMISSION_MAP: Record<string, PagePermission> = {
|
||||||
'pages/promote': { requiresAuth: true, requiresAgent: true },
|
'pages/promote': { requiresAuth: true, requiresAgent: true },
|
||||||
'pages/history-query': { requiresAuth: true },
|
|
||||||
'pages/withdraw': { requiresAuth: true, requiresAgent: true },
|
'pages/withdraw': { requiresAuth: true, requiresAgent: true },
|
||||||
'pages/payment-result': { requiresAuth: true },
|
'pages/payment-result': { requiresAuth: true },
|
||||||
'pages/report-result-webview': { requiresAuth: true },
|
'pages/report-result-webview': { requiresAuth: true },
|
||||||
|
|||||||
@@ -3,6 +3,27 @@ import { getToken } from '@/utils/storage'
|
|||||||
|
|
||||||
declare function getCurrentPages(): any[]
|
declare function getCurrentPages(): any[]
|
||||||
|
|
||||||
|
/** 与 bdrp-webview `VITE_TOKEN_VERSION` 保持一致,供外部浏览器 / WebView 带参登录 */
|
||||||
|
function getAppTokenVersionForH5(): string {
|
||||||
|
return String(import.meta.env.VITE_TOKEN_VERSION || '1.0')
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 外部浏览器打开 H5 时携带 App 登录态(须与 webview `applyAppWebViewTokenFromRoute` 对齐) */
|
||||||
|
export function appendAppAuthQueryParams(params: Record<string, string> = {}): Record<string, string> {
|
||||||
|
const merged: Record<string, string> = { ...params, source: 'app' }
|
||||||
|
const token = getToken()
|
||||||
|
if (token)
|
||||||
|
merged.token = token
|
||||||
|
const refreshAfter = uni.getStorageSync('refreshAfter')
|
||||||
|
const accessExpire = uni.getStorageSync('accessExpire')
|
||||||
|
if (refreshAfter != null && refreshAfter !== '')
|
||||||
|
merged.refreshAfter = String(refreshAfter)
|
||||||
|
if (accessExpire != null && accessExpire !== '')
|
||||||
|
merged.accessExpire = String(accessExpire)
|
||||||
|
merged.tokenVersion = getAppTokenVersionForH5()
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
/** App 端部分 WebView 无 URLSearchParams,用手动编码保证兼容 */
|
/** App 端部分 WebView 无 URLSearchParams,用手动编码保证兼容 */
|
||||||
function buildQueryString(params: Record<string, string>): string {
|
function buildQueryString(params: Record<string, string>): string {
|
||||||
const parts: string[] = []
|
const parts: string[] = []
|
||||||
@@ -20,46 +41,37 @@ export function useReportWebview() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const buildReportUrl = (page: 'example' | 'report', params: Record<string, string> = {}) => {
|
const buildReportUrl = (page: 'example' | 'report', params: Record<string, string> = {}) => {
|
||||||
const token = getToken() || ''
|
|
||||||
const base = resolveBase()
|
const base = resolveBase()
|
||||||
if (!base) {
|
if (!base) {
|
||||||
console.warn('[report webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
console.warn('[report webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
const merged: Record<string, string> = { source: 'app', ...params }
|
const merged = appendAppAuthQueryParams(params)
|
||||||
if (token)
|
|
||||||
merged.token = token
|
|
||||||
const search = buildQueryString(merged)
|
const search = buildQueryString(merged)
|
||||||
/** 使用 H5 无顶栏的 App 专用路由,避免 PageLayout 与 App 原生导航栏重复 */
|
/** 使用 H5 无顶栏的 App 专用路由,避免 PageLayout 与 App 原生导航栏重复 */
|
||||||
return `${base}/app/${page === 'example' ? 'example' : 'report'}?${search}`
|
return `${base}/app/${page === 'example' ? 'example' : 'report'}?${search}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildReportShareUrl = (linkIdentifier: string, params: Record<string, string> = {}) => {
|
const buildReportShareUrl = (linkIdentifier: string, params: Record<string, string> = {}) => {
|
||||||
const token = getToken() || ''
|
|
||||||
const base = resolveBase()
|
const base = resolveBase()
|
||||||
if (!base) {
|
if (!base) {
|
||||||
console.warn('[report webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
console.warn('[report webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
const merged: Record<string, string> = { source: 'app', ...params }
|
const merged = appendAppAuthQueryParams(params)
|
||||||
if (token)
|
|
||||||
merged.token = token
|
|
||||||
const search = buildQueryString(merged)
|
const search = buildQueryString(merged)
|
||||||
const encodedLink = encodeURIComponent(linkIdentifier)
|
const encodedLink = encodeURIComponent(linkIdentifier)
|
||||||
return `${base}/report/share/${encodedLink}${search ? `?${search}` : ''}`
|
return `${base}/report/share/${encodedLink}${search ? `?${search}` : ''}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildSitePathUrl = (path: string, params: Record<string, string> = {}) => {
|
const buildSitePathUrl = (path: string, params: Record<string, string> = {}) => {
|
||||||
const token = getToken() || ''
|
|
||||||
const base = resolveBase()
|
const base = resolveBase()
|
||||||
if (!base) {
|
if (!base) {
|
||||||
console.warn('[site webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
console.warn('[site webview] 请配置 VITE_SITE_ORIGIN 或 VITE_REPORT_BASE_URL')
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
||||||
const merged: Record<string, string> = { source: 'app', ...params }
|
const merged = appendAppAuthQueryParams(params)
|
||||||
if (token)
|
|
||||||
merged.token = token
|
|
||||||
const search = buildQueryString(merged)
|
const search = buildQueryString(merged)
|
||||||
return `${base}${normalizedPath}${search ? `?${search}` : ''}`
|
return `${base}${normalizedPath}${search ? `?${search}` : ''}`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onShow } from '@dcloudio/uni-app'
|
import { onShow } from '@dcloudio/uni-app'
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
import { computed, nextTick, onMounted, ref } from 'vue'
|
||||||
import {
|
import {
|
||||||
getCurrentUniRoute,
|
getCurrentUniRoute,
|
||||||
getLayoutPageTitle,
|
getLayoutPageTitle,
|
||||||
@@ -11,10 +11,13 @@ import { ensurePrivacyConsentIfNeeded } from '@/composables/usePrivacyConsent'
|
|||||||
import { useGlobalNotification } from '@/composables/useGlobalNotification'
|
import { useGlobalNotification } from '@/composables/useGlobalNotification'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pageTitle = ref('赤眉')
|
/** 用于在 onShow 时触发标题 computed 重新读取页面栈 */
|
||||||
const currentRoute = ref('')
|
const routeRevision = ref(0)
|
||||||
const safeAreaTop = ref(0)
|
const currentRoute = computed(() => {
|
||||||
const immersiveNavbarSolid = ref(false)
|
routeRevision.value
|
||||||
|
return getCurrentUniRoute()
|
||||||
|
})
|
||||||
|
const pageTitle = computed(() => getLayoutPageTitle())
|
||||||
|
|
||||||
const {
|
const {
|
||||||
showPopup,
|
showPopup,
|
||||||
@@ -25,24 +28,10 @@ const {
|
|||||||
onClosePopup,
|
onClosePopup,
|
||||||
} = useGlobalNotification()
|
} = useGlobalNotification()
|
||||||
|
|
||||||
const immersiveRoutes = new Set([
|
|
||||||
'pages/inquire',
|
|
||||||
])
|
|
||||||
|
|
||||||
const isImmersivePage = computed(() => immersiveRoutes.has(currentRoute.value))
|
|
||||||
const immersiveNavbarClass = computed(() => (
|
|
||||||
immersiveNavbarSolid.value ? 'immersive-wd-navbar is-solid' : 'immersive-wd-navbar'
|
|
||||||
))
|
|
||||||
const immersiveNavbarStyle = computed(() => (
|
|
||||||
immersiveNavbarSolid.value
|
|
||||||
? 'background: rgba(255,255,255,0.96); box-shadow: 0 2px 12px rgba(15, 23, 42, 0.08);'
|
|
||||||
: 'background: transparent; box-shadow: none;'
|
|
||||||
))
|
|
||||||
|
|
||||||
function syncTitle() {
|
function syncTitle() {
|
||||||
currentRoute.value = getCurrentUniRoute()
|
nextTick(() => {
|
||||||
pageTitle.value = getLayoutPageTitle()
|
routeRevision.value += 1
|
||||||
immersiveNavbarSolid.value = false
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildCurrentPageUrl() {
|
function buildCurrentPageUrl() {
|
||||||
@@ -60,15 +49,6 @@ function ensureAuthIfNeeded() {
|
|||||||
ensurePageAccessByUrl(buildCurrentPageUrl(), 'redirect')
|
ensurePageAccessByUrl(buildCurrentPageUrl(), 'redirect')
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSafeAreaTop() {
|
|
||||||
uni.getSystemInfo({
|
|
||||||
success: (res) => {
|
|
||||||
if (res.safeArea)
|
|
||||||
safeAreaTop.value = res.safeArea.top
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function onClickOverlay() {
|
function onClickOverlay() {
|
||||||
onClosePopup()
|
onClosePopup()
|
||||||
}
|
}
|
||||||
@@ -77,17 +57,9 @@ function onClickLeft() {
|
|||||||
router.back()
|
router.back()
|
||||||
}
|
}
|
||||||
|
|
||||||
function onImmersiveNavbarChange(payload) {
|
|
||||||
if (!payload || payload.route !== currentRoute.value || !immersiveRoutes.has(payload.route))
|
|
||||||
return
|
|
||||||
immersiveNavbarSolid.value = Boolean(payload.solid)
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getSafeAreaTop()
|
|
||||||
syncTitle()
|
syncTitle()
|
||||||
loadShownNotificationKeys()
|
loadShownNotificationKeys()
|
||||||
console.log('[通知DEBUG] default layout onMounted, 即将请求通知')
|
|
||||||
getGlobalNotify()
|
getGlobalNotify()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -95,35 +67,29 @@ onShow(() => {
|
|||||||
ensurePrivacyConsentIfNeeded()
|
ensurePrivacyConsentIfNeeded()
|
||||||
syncTitle()
|
syncTitle()
|
||||||
ensureAuthIfNeeded()
|
ensureAuthIfNeeded()
|
||||||
console.log('[通知DEBUG] default layout onShow')
|
|
||||||
checkNotification()
|
checkNotification()
|
||||||
})
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onReady(() => {
|
||||||
uni.$on('immersive-navbar-change', onImmersiveNavbarChange)
|
syncTitle()
|
||||||
})
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
uni.$off('immersive-navbar-change', onImmersiveNavbarChange)
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view
|
<view class="page-layout min-h-screen from-sky-100/20 to-white bg-gradient-to-b">
|
||||||
class="page-layout min-h-screen from-sky-100/20 to-white bg-gradient-to-b"
|
|
||||||
:class="{ 'transparent-layout': isImmersivePage }"
|
|
||||||
>
|
|
||||||
<wd-navbar
|
<wd-navbar
|
||||||
v-if="isImmersivePage"
|
:key="currentRoute"
|
||||||
:class="immersiveNavbarClass"
|
|
||||||
:title="pageTitle"
|
|
||||||
:custom-style="immersiveNavbarStyle"
|
|
||||||
safe-area-inset-top
|
safe-area-inset-top
|
||||||
left-arrow
|
left-arrow
|
||||||
|
placeholder
|
||||||
fixed
|
fixed
|
||||||
|
bordered
|
||||||
@click-left="onClickLeft"
|
@click-left="onClickLeft"
|
||||||
/>
|
>
|
||||||
<wd-navbar v-else :title="pageTitle" safe-area-inset-top left-arrow placeholder fixed @click-left="onClickLeft" />
|
<template #title>
|
||||||
|
<text class="layout-navbar-title">{{ pageTitle }}</text>
|
||||||
|
</template>
|
||||||
|
</wd-navbar>
|
||||||
<slot />
|
<slot />
|
||||||
<wd-popup v-model="showPopup" round :close-on-click-modal="true" @close="onClickOverlay">
|
<wd-popup v-model="showPopup" round :close-on-click-modal="true" @close="onClickOverlay">
|
||||||
<view class="popup-content p-8 text-center" style="width: 85vw;">
|
<view class="popup-content p-8 text-center" style="width: 85vw;">
|
||||||
@@ -142,28 +108,16 @@ onUnmounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.transparent-layout {
|
:deep(.layout-navbar-title) {
|
||||||
background: transparent;
|
display: block;
|
||||||
}
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
:deep(.immersive-wd-navbar) {
|
text-overflow: ellipsis;
|
||||||
z-index: 1000;
|
white-space: nowrap;
|
||||||
transition: background-color 0.2s ease, box-shadow 0.2s ease;
|
color: #111827;
|
||||||
}
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
:deep(.immersive-wd-navbar .wd-navbar__title),
|
line-height: 1.2;
|
||||||
:deep(.immersive-wd-navbar .wd-navbar__left),
|
|
||||||
:deep(.immersive-wd-navbar .wd-navbar__left .wd-icon) {
|
|
||||||
color: #fff !important;
|
|
||||||
text-shadow: 0 1px 6px rgba(0, 0, 0, 0.22);
|
|
||||||
transition: color 0.2s ease, text-shadow 0.2s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.immersive-wd-navbar.is-solid .wd-navbar__title),
|
|
||||||
:deep(.immersive-wd-navbar.is-solid .wd-navbar__left),
|
|
||||||
:deep(.immersive-wd-navbar.is-solid .wd-navbar__left .wd-icon) {
|
|
||||||
color: #111827 !important;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-content {
|
.popup-content {
|
||||||
|
|||||||
@@ -1,986 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { computed, onMounted, reactive, ref } from 'vue'
|
|
||||||
import { openCustomerService } from '@/composables/useCustomerService'
|
|
||||||
import { useAgentStore } from '@/stores/agentStore'
|
|
||||||
|
|
||||||
definePage({ layout: 'default', auth: true })
|
|
||||||
|
|
||||||
/** API 与初始状态可能为 undefined/字符串,避免参与运算出现 NaN */
|
|
||||||
function toFiniteNumber(v, fallback = 0) {
|
|
||||||
if (v === null || v === undefined || v === '')
|
|
||||||
return fallback
|
|
||||||
const n = typeof v === 'number' ? v : Number(String(v).replace(/,/g, ''))
|
|
||||||
return Number.isFinite(n) ? n : fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取代理状态
|
|
||||||
const agentStore = useAgentStore()
|
|
||||||
const { level, ExpiryTime } = storeToRefs(agentStore)
|
|
||||||
|
|
||||||
const selectedType = ref('vip') // 默认选择 VIP(供下方 computed 使用)
|
|
||||||
|
|
||||||
// 计算是否已经是VIP或SVIP
|
|
||||||
const isVipOrSvip = computed(() => ['VIP', 'SVIP'].includes(level.value))
|
|
||||||
const isVip = computed(() => level.value === 'VIP')
|
|
||||||
const isSvip = computed(() => level.value === 'SVIP')
|
|
||||||
|
|
||||||
// 计算续费后的到期时间
|
|
||||||
const renewalExpiryTime = computed(() => {
|
|
||||||
if (!ExpiryTime.value)
|
|
||||||
return '未知'
|
|
||||||
|
|
||||||
// 从格式化字符串中提取日期部分
|
|
||||||
const dateStr = ExpiryTime.value.split(' ')[0] // 假设格式是 "YYYY-MM-DD HH:MM:SS"
|
|
||||||
const parts = dateStr.split('-').map(p => Number.parseInt(p, 10))
|
|
||||||
const [year, month, day] = parts
|
|
||||||
if (parts.length < 3 || [year, month, day].some(n => !Number.isFinite(n)))
|
|
||||||
return '未知'
|
|
||||||
|
|
||||||
// 创建日期对象并加一年
|
|
||||||
const expiryDate = new Date(year, month - 1, day) // 月份从0开始,所以要-1
|
|
||||||
expiryDate.setFullYear(expiryDate.getFullYear() + 1)
|
|
||||||
|
|
||||||
// 返回格式化的日期字符串
|
|
||||||
return `${expiryDate.getFullYear()}-${String(expiryDate.getMonth() + 1).padStart(2, '0')}-${String(expiryDate.getDate()).padStart(2, '0')}`
|
|
||||||
})
|
|
||||||
|
|
||||||
// 按钮文字 - 根据当前状态显示不同文案
|
|
||||||
const buttonText = computed(() => {
|
|
||||||
if (!isVipOrSvip.value)
|
|
||||||
return '立即开通' // 非会员状态
|
|
||||||
|
|
||||||
if (selectedType.value === 'vip') {
|
|
||||||
if (isVip.value)
|
|
||||||
return '续费VIP代理' // VIP续费VIP
|
|
||||||
return '降级不可用' // SVIP不能降级到VIP
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (isSvip.value)
|
|
||||||
return '续费SVIP代理' // SVIP续费SVIP
|
|
||||||
return '升级SVIP代理' // VIP升级SVIP
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 是否可以操作按钮
|
|
||||||
const canPerformAction = computed(() => {
|
|
||||||
// 非会员可以开通任何会员
|
|
||||||
if (!isVipOrSvip.value)
|
|
||||||
return true
|
|
||||||
|
|
||||||
// VIP不能降级到普通会员
|
|
||||||
if (isVip.value && selectedType.value === '')
|
|
||||||
return false
|
|
||||||
|
|
||||||
// SVIP不能降级到VIP
|
|
||||||
if (isSvip.value && selectedType.value === 'vip')
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
// 计算按钮类名
|
|
||||||
const buttonClass = computed(() => {
|
|
||||||
const baseClass
|
|
||||||
= 'w-full py-4 rounded-lg font-bold text-lg shadow-lg transform transition-transform active:scale-98 relative overflow-hidden'
|
|
||||||
|
|
||||||
if (!canPerformAction.value) {
|
|
||||||
return `${baseClass} bg-gray-400 text-white cursor-not-allowed`
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVip.value && selectedType.value === 'svip') {
|
|
||||||
return `${baseClass} bg-gradient-to-r from-purple-500 to-indigo-600 text-white`
|
|
||||||
}
|
|
||||||
|
|
||||||
return `${baseClass} bg-gradient-to-r from-amber-500 to-amber-600 active:from-amber-600 active:to-amber-700 text-white`
|
|
||||||
})
|
|
||||||
|
|
||||||
// VIP价格配置(展示用单位;数值在拉取 API 后写入)
|
|
||||||
const vipConfig = reactive({ priceUnit: '元' })
|
|
||||||
|
|
||||||
// 计算得出的收益数据
|
|
||||||
const revenueData = computed(() => {
|
|
||||||
const price = toFiniteNumber(vipConfig.price)
|
|
||||||
const svipPrice = toFiniteNumber(vipConfig.svipPrice)
|
|
||||||
const vipCommission = toFiniteNumber(vipConfig.vipCommission)
|
|
||||||
const svipCommission = toFiniteNumber(vipConfig.svipCommission)
|
|
||||||
const vipFloatingRate = toFiniteNumber(vipConfig.vipFloatingRate)
|
|
||||||
const svipFloatingRate = toFiniteNumber(vipConfig.svipFloatingRate)
|
|
||||||
const vipConversionBonus = toFiniteNumber(vipConfig.vipConversionBonus)
|
|
||||||
const svipConversionBonus = toFiniteNumber(vipConfig.svipConversionBonus)
|
|
||||||
const withdrawRatio = toFiniteNumber(vipConfig.withdrawRatio)
|
|
||||||
|
|
||||||
const baseOrders = 300 // 基础订单数
|
|
||||||
const pricePerOrder = 50 // 每单价格
|
|
||||||
const baseRevenue = baseOrders * pricePerOrder // 基础推广收益
|
|
||||||
|
|
||||||
const vipCommissionRevenue = baseOrders * vipCommission // VIP下级贡献收益
|
|
||||||
const svipCommissionRevenue = baseOrders * svipCommission // SVIP下级贡献收益
|
|
||||||
|
|
||||||
const vipFloatingRevenue = 100 * 100 * (vipFloatingRate / 100) // VIP浮动收益
|
|
||||||
const svipFloatingRevenue = 200 * 100 * (svipFloatingRate / 100) // SVIP浮动收益
|
|
||||||
|
|
||||||
const vipConversionRevenue = vipConversionBonus * 2 // VIP转化奖励
|
|
||||||
const svipConversionRevenue = svipConversionBonus * 2 // SVIP转化奖励
|
|
||||||
|
|
||||||
const vipExtraRevenue = 3000 // VIP额外收益估计
|
|
||||||
const svipExtraRevenue = 6000 // SVIP额外收益估计
|
|
||||||
|
|
||||||
// 平级提现奖励(只有SVIP才有)
|
|
||||||
const withdrawReward = 20000 * (withdrawRatio / 100)
|
|
||||||
|
|
||||||
// 计算月总收益
|
|
||||||
const vipMonthlyTotal
|
|
||||||
= baseRevenue
|
|
||||||
+ vipCommissionRevenue
|
|
||||||
+ vipFloatingRevenue
|
|
||||||
+ vipConversionRevenue
|
|
||||||
+ vipExtraRevenue
|
|
||||||
|
|
||||||
const svipMonthlyTotal
|
|
||||||
= baseRevenue
|
|
||||||
+ svipCommissionRevenue
|
|
||||||
+ svipFloatingRevenue
|
|
||||||
+ withdrawReward
|
|
||||||
+ svipConversionRevenue
|
|
||||||
+ svipExtraRevenue
|
|
||||||
|
|
||||||
// 计算VIP和SVIP之间的差额
|
|
||||||
const monthlyDifference = svipMonthlyTotal - vipMonthlyTotal
|
|
||||||
const priceDifference = svipPrice - price
|
|
||||||
|
|
||||||
const vipRate = price > 0 ? Math.round(vipMonthlyTotal / price) : 0
|
|
||||||
const svipRate = svipPrice > 0 ? Math.round(svipMonthlyTotal / svipPrice) : 0
|
|
||||||
|
|
||||||
// 月增收对应到「多少天回本」:避免除 0 或月差为 0 时出现 Infinity / NaN
|
|
||||||
let recoverDays = 0
|
|
||||||
if (priceDifference > 0 && monthlyDifference > 0) {
|
|
||||||
const perDay = monthlyDifference / 30
|
|
||||||
if (perDay > 0)
|
|
||||||
recoverDays = Math.ceil(priceDifference / perDay)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
vipMonthly: Math.round(toFiniteNumber(vipMonthlyTotal)),
|
|
||||||
svipMonthly: Math.round(toFiniteNumber(svipMonthlyTotal)),
|
|
||||||
vipYearly: Math.round(toFiniteNumber(vipMonthlyTotal) * 12),
|
|
||||||
svipYearly: Math.round(toFiniteNumber(svipMonthlyTotal) * 12),
|
|
||||||
monthlyDifference: Math.round(toFiniteNumber(monthlyDifference)),
|
|
||||||
yearlyDifference: Math.round(toFiniteNumber(monthlyDifference) * 12),
|
|
||||||
vipRate,
|
|
||||||
svipRate,
|
|
||||||
priceDifference: Math.round(toFiniteNumber(priceDifference)),
|
|
||||||
recoverDays,
|
|
||||||
withdrawReward: Math.round(toFiniteNumber(withdrawReward)),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 加载价格配置
|
|
||||||
onMounted(async () => {
|
|
||||||
// 从API获取会员配置信息
|
|
||||||
try {
|
|
||||||
const { data, error } = await useApiFetch('/agent/membership/info', { silent: true }).get().json()
|
|
||||||
|
|
||||||
if (data.value && !error.value && data.value.code === 200) {
|
|
||||||
const configData = data.value.data
|
|
||||||
|
|
||||||
// 更新VIP配置
|
|
||||||
if (configData.vip_config) {
|
|
||||||
const vipData = configData.vip_config
|
|
||||||
vipConfig.price = toFiniteNumber(vipData.price)
|
|
||||||
vipConfig.vipCommission = toFiniteNumber(vipData.report_commission) // 直接显示,就是几元/单
|
|
||||||
vipConfig.vipFloatingRate = toFiniteNumber(vipData.price_ratio) * 100 // 转换为百分比
|
|
||||||
vipConfig.vipConversionBonus = toFiniteNumber(vipData.lower_convert_vip_reward)
|
|
||||||
vipConfig.vipWithdrawalLimit = toFiniteNumber(vipData.exemption_amount)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新SVIP配置
|
|
||||||
if (configData.svip_config) {
|
|
||||||
const svipData = configData.svip_config
|
|
||||||
vipConfig.svipPrice = toFiniteNumber(svipData.price)
|
|
||||||
vipConfig.svipCommission = toFiniteNumber(svipData.report_commission) // 直接显示,就是几元/单
|
|
||||||
vipConfig.svipFloatingRate = toFiniteNumber(svipData.price_ratio) * 100 // 转换为百分比
|
|
||||||
vipConfig.withdrawRatio = toFiniteNumber(svipData.lower_withdraw_reward_ratio) * 100 // 转换为百分比
|
|
||||||
vipConfig.svipConversionBonus = toFiniteNumber(svipData.lower_convert_svip_reward)
|
|
||||||
vipConfig.svipWithdrawalLimit = toFiniteNumber(svipData.exemption_amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.error('获取会员配置信息失败', data.value?.msg || '未知错误')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('加载会员配置信息失败', error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const showPayment = ref(false)
|
|
||||||
const payID = ref('')
|
|
||||||
const payData = computed(() => ({
|
|
||||||
product_name: `${selectedType.value === 'vip' ? 'VIP' : 'SVIP'}代理`,
|
|
||||||
sell_price: selectedType.value === 'vip'
|
|
||||||
? toFiniteNumber(vipConfig.price)
|
|
||||||
: toFiniteNumber(vipConfig.svipPrice),
|
|
||||||
}))
|
|
||||||
|
|
||||||
function showToast(message) {
|
|
||||||
if (!message)
|
|
||||||
return
|
|
||||||
uni.showToast({
|
|
||||||
title: message,
|
|
||||||
icon: 'none',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择代理类型
|
|
||||||
function selectType(type) {
|
|
||||||
selectedType.value = type
|
|
||||||
}
|
|
||||||
|
|
||||||
// 申请VIP或SVIP
|
|
||||||
async function applyVip() {
|
|
||||||
// 如果是SVIP要降级到VIP,提示不能降级
|
|
||||||
if (isSvip.value && selectedType.value === 'vip') {
|
|
||||||
showToast('SVIP会员不能降级到VIP会员')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toFiniteNumber(payData.value.sell_price) <= 0) {
|
|
||||||
showToast('会员价格加载中,请稍后重试')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, error } = await useApiFetch('/agent/membership/activate')
|
|
||||||
.post({
|
|
||||||
type: selectedType.value.toUpperCase(),
|
|
||||||
})
|
|
||||||
.json()
|
|
||||||
|
|
||||||
if (data.value && !error.value) {
|
|
||||||
if (data.value.code === 200) {
|
|
||||||
if (data.value.data.id) {
|
|
||||||
payID.value = data.value.data.id
|
|
||||||
showPayment.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 联系客服
|
|
||||||
function contactService() {
|
|
||||||
openCustomerService()
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatExpiryTime(expiryTimeStr) {
|
|
||||||
if (!expiryTimeStr)
|
|
||||||
return '未知'
|
|
||||||
// 从格式化字符串中提取日期部分
|
|
||||||
return expiryTimeStr.split(' ')[0] // 假设格式是 "YYYY-MM-DD HH:MM:SS"
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="agent-VIP-apply min-h-screen w-full from-amber-50 via-amber-100 to-amber-50 bg-gradient-to-b pb-24">
|
|
||||||
<!-- 装饰元素 -->
|
|
||||||
<view
|
|
||||||
class="absolute right-0 top-0 h-32 w-32 rounded-bl-full from-amber-300 to-amber-500 bg-gradient-to-br opacity-20" />
|
|
||||||
<view
|
|
||||||
class="absolute left-0 top-40 h-16 w-16 rounded-tr-full from-amber-400 to-amber-600 bg-gradient-to-tr opacity-20" />
|
|
||||||
<view
|
|
||||||
class="absolute bottom-60 right-0 h-24 w-24 rounded-tl-full from-amber-300 to-amber-500 bg-gradient-to-bl opacity-20" />
|
|
||||||
|
|
||||||
<!-- 顶部标题区域 -->
|
|
||||||
<view class="header relative px-4 pb-6 pt-8 text-center">
|
|
||||||
<view
|
|
||||||
class="absolute left-1/2 h-1 w-24 animate-pulse rounded-full from-amber-300 via-amber-500 to-amber-300 bg-gradient-to-r -top-2 -translate-x-1/2" />
|
|
||||||
<view class="mb-1 text-3xl text-amber-800 font-bold">
|
|
||||||
{{ isVipOrSvip ? '代理会员续费' : 'VIP代理申请' }}
|
|
||||||
</view>
|
|
||||||
<view class="mx-auto mt-2 max-w-xs text-sm text-amber-700">
|
|
||||||
<template v-if="isVipOrSvip">
|
|
||||||
您的会员有效期至 {{ formatExpiryTime(ExpiryTime) }},续费后有效期至
|
|
||||||
{{ renewalExpiryTime }}
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
平台为疯狂推广者定制的赚买计划,助您收益<text class="text-red-500 font-bold">翻倍增升</text>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 装饰性金币图标 -->
|
|
||||||
<view class="absolute left-4 top-6 transform -rotate-12">
|
|
||||||
<view
|
|
||||||
class="h-8 w-8 flex items-center justify-center rounded-full from-yellow-300 to-yellow-500 bg-gradient-to-br shadow-lg">
|
|
||||||
<text class="text-xs text-white font-bold">¥</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="absolute right-6 top-10 rotate-12 transform">
|
|
||||||
<view
|
|
||||||
class="h-6 w-6 flex items-center justify-center rounded-full from-yellow-400 to-yellow-600 bg-gradient-to-br shadow-lg">
|
|
||||||
<text class="text-xs text-white font-bold">¥</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 选择代理类型 -->
|
|
||||||
<view class="card-container mb-8 px-4">
|
|
||||||
<view class="transform overflow-hidden border border-amber-100 rounded-xl bg-white shadow-lg transition-all">
|
|
||||||
<view
|
|
||||||
class="relative overflow-hidden from-amber-500 to-amber-600 bg-gradient-to-r px-4 py-3 text-center text-white font-bold">
|
|
||||||
<view class="relative z-10">选择代理类型</view>
|
|
||||||
<view class="absolute inset-0 bg-amber-500 opacity-30">
|
|
||||||
<view
|
|
||||||
class="animate-shimmer absolute left-0 top-0 h-full w-full translate-x-full transform from-transparent via-white to-transparent bg-gradient-to-r opacity-20 -skew-x-30" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="flex gap-4 p-6">
|
|
||||||
<view
|
|
||||||
class="relative flex-1 transform cursor-pointer border-2 rounded-lg p-4 text-center transition-all duration-300 hover:-translate-y-1"
|
|
||||||
:class="[
|
|
||||||
selectedType === 'vip'
|
|
||||||
? 'border-amber-500 bg-amber-50 shadow-md'
|
|
||||||
: 'border-gray-200 hover:border-amber-300',
|
|
||||||
]" @click="selectType('vip')">
|
|
||||||
<view class="text-xl text-amber-700 font-bold">
|
|
||||||
VIP代理
|
|
||||||
</view>
|
|
||||||
<view class="mt-1 text-lg text-amber-600 font-bold">
|
|
||||||
{{ vipConfig.price }}{{ vipConfig.priceUnit }}
|
|
||||||
</view>
|
|
||||||
<view class="mt-2 text-sm text-gray-600">
|
|
||||||
标准VIP权益
|
|
||||||
</view>
|
|
||||||
<view v-if="selectedType === 'vip'"
|
|
||||||
class="absolute h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br shadow-md -right-2 -top-2">
|
|
||||||
<wd-icon name="check" custom-style="color:#fff;font-size:14px;" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view
|
|
||||||
class="relative flex-1 transform cursor-pointer border-2 rounded-lg p-4 text-center transition-all duration-300 hover:-translate-y-1"
|
|
||||||
:class="[
|
|
||||||
selectedType === 'svip'
|
|
||||||
? 'border-amber-500 bg-amber-50 shadow-md'
|
|
||||||
: 'border-gray-200 hover:border-amber-300',
|
|
||||||
]" @click="selectType('svip')">
|
|
||||||
<view class="text-xl text-amber-700 font-bold">
|
|
||||||
SVIP代理
|
|
||||||
</view>
|
|
||||||
<view class="mt-1 text-lg text-amber-600 font-bold">
|
|
||||||
{{ vipConfig.svipPrice }}{{ vipConfig.priceUnit }}
|
|
||||||
</view>
|
|
||||||
<view class="mt-2 text-sm text-gray-600">
|
|
||||||
超级VIP权益
|
|
||||||
</view>
|
|
||||||
<view v-if="selectedType === 'svip'"
|
|
||||||
class="absolute h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br shadow-md -right-2 -top-2">
|
|
||||||
<wd-icon name="check" custom-style="color:#fff;font-size:14px;" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 六大超值权益 -->
|
|
||||||
<view class="card-container mb-8 px-4">
|
|
||||||
<view class="overflow-hidden border border-amber-100 rounded-xl bg-white shadow-lg">
|
|
||||||
<view
|
|
||||||
class="relative overflow-hidden from-amber-500 to-amber-600 bg-gradient-to-r px-4 py-3 text-center text-white font-bold">
|
|
||||||
<view class="relative z-10">六大超值权益</view>
|
|
||||||
<view class="absolute inset-0 bg-amber-500 opacity-30">
|
|
||||||
<view
|
|
||||||
class="animate-shimmer absolute left-0 top-0 h-full w-full translate-x-full transform from-transparent via-white to-transparent bg-gradient-to-r opacity-20 -skew-x-30" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="grid grid-cols-2 gap-4 p-4">
|
|
||||||
<!-- 权益1 -->
|
|
||||||
<view
|
|
||||||
class="border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-br p-3 transition-all duration-300 hover:border-amber-300 hover:shadow-md">
|
|
||||||
<view class="mb-2 flex items-center text-amber-800 font-bold">
|
|
||||||
<text
|
|
||||||
class="mr-2 h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br text-xs text-white">1</text>
|
|
||||||
下级贡献收益
|
|
||||||
</view>
|
|
||||||
<text class="text-sm text-gray-600">
|
|
||||||
下级完全收益您来定,涨多少赚多少,一单最高收益<text class="text-red-500 font-bold">10元</text>
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 权益2 -->
|
|
||||||
<view
|
|
||||||
class="border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-br p-3 transition-all duration-300 hover:border-amber-300 hover:shadow-md">
|
|
||||||
<view class="mb-2 flex items-center text-amber-800 font-bold">
|
|
||||||
<text
|
|
||||||
class="mr-2 h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br text-xs text-white">2</text>
|
|
||||||
下级提现收益
|
|
||||||
</view>
|
|
||||||
<text class="text-sm text-gray-600">
|
|
||||||
下级定价标准由您定,超过标准部分收益更丰厚,一单最高多赚<text class="text-red-500 font-bold">10元</text>
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 权益3 -->
|
|
||||||
<view
|
|
||||||
class="border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-br p-3 transition-all duration-300 hover:border-amber-300 hover:shadow-md">
|
|
||||||
<view class="mb-2 flex items-center text-amber-800 font-bold">
|
|
||||||
<text
|
|
||||||
class="mr-2 h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br text-xs text-white">3</text>
|
|
||||||
转换高额奖励
|
|
||||||
</view>
|
|
||||||
<text class="text-sm text-gray-600">
|
|
||||||
下级成为VIP、SVIP,高额奖励立马发放,<text class="text-red-500 font-bold">399元</text>
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 权益4 -->
|
|
||||||
<view
|
|
||||||
class="border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-br p-3 transition-all duration-300 hover:border-amber-300 hover:shadow-md">
|
|
||||||
<view class="mb-2 flex items-center text-amber-800 font-bold">
|
|
||||||
<text
|
|
||||||
class="mr-2 h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br text-xs text-white">4</text>
|
|
||||||
下级提现奖励
|
|
||||||
</view>
|
|
||||||
<text class="text-sm text-gray-600">
|
|
||||||
下级成为SVIP,每次提现都奖励1%,坐享被动收入
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 权益6 -->
|
|
||||||
<view
|
|
||||||
class="border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-br p-3 transition-all duration-300 hover:border-amber-300 hover:shadow-md">
|
|
||||||
<view class="mb-2 flex items-center text-amber-800 font-bold">
|
|
||||||
<text
|
|
||||||
class="mr-2 h-6 w-6 flex items-center justify-center rounded-full from-amber-500 to-amber-600 bg-gradient-to-br text-xs text-white">6</text>
|
|
||||||
平台专项扶持
|
|
||||||
</view>
|
|
||||||
<text class="text-sm text-gray-600">
|
|
||||||
一对一专属客服服务,为合作伙伴提供全方位成长赋能
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 权益对比表 -->
|
|
||||||
<view v-if="selectedType" class="card-container mb-8 px-4">
|
|
||||||
<view class="overflow-hidden border border-amber-100 rounded-xl bg-white shadow-lg">
|
|
||||||
<view
|
|
||||||
class="relative overflow-hidden from-amber-500 to-amber-600 bg-gradient-to-r px-4 py-3 text-center text-white font-bold">
|
|
||||||
<view class="relative z-10">{{ selectedType === 'vip' ? 'VIP' : 'SVIP' }}代理权益对比</view>
|
|
||||||
<view class="absolute inset-0 bg-amber-500 opacity-30">
|
|
||||||
<view
|
|
||||||
class="animate-shimmer absolute left-0 top-0 h-full w-full translate-x-full transform from-transparent via-white to-transparent bg-gradient-to-r opacity-20 -skew-x-30" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="overflow-x-auto p-4">
|
|
||||||
<table class="w-full border-collapse">
|
|
||||||
<thead>
|
|
||||||
<tr class="from-amber-100 to-amber-200 bg-gradient-to-r">
|
|
||||||
<th class="border border-amber-200 p-2 text-left text-amber-800">
|
|
||||||
权益项目
|
|
||||||
</th>
|
|
||||||
<th class="border border-amber-200 p-2 text-center text-amber-800">
|
|
||||||
普通代理
|
|
||||||
</th>
|
|
||||||
<th class="border border-amber-200 p-2 text-center text-amber-800"
|
|
||||||
:class="{ 'bg-amber-200': selectedType === 'vip' }">
|
|
||||||
VIP代理
|
|
||||||
</th>
|
|
||||||
<th class="border border-amber-200 p-2 text-center text-amber-800"
|
|
||||||
:class="{ 'bg-amber-200': selectedType === 'svip' }">
|
|
||||||
SVIP代理
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
会员权益
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
普通代理<br>免费
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center font-bold" :class="{
|
|
||||||
'text-amber-700 bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.price }}{{ vipConfig.priceUnit }}
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center font-bold" :class="{
|
|
||||||
'text-amber-700 bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.svipPrice }}{{ vipConfig.priceUnit }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级贡献收益
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
1元/单
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.vipCommission }}元/单
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.svipCommission }}元/单
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
自定义设置下级成本
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
❌
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
✓
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
✓
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级价格浮动收益
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
❌
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
最高{{ vipConfig.vipFloatingRate }}%
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
最高{{ vipConfig.svipFloatingRate }}%
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级提现奖励
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
❌
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
❌
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.withdrawRatio }}%
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级转化奖励
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
❌
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.vipConversionBonus }}元*10个
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.svipConversionBonus }}元*10个
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
提现次数额度
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
800元/次
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.vipWithdrawalLimit }}元/次
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.svipWithdrawalLimit }}元/次
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
提现次数
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center">
|
|
||||||
1次/日
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
1次/日
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-bold bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
2次/日
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 收益预估 -->
|
|
||||||
<view v-if="selectedType" class="card-container mb-8 px-4">
|
|
||||||
<view class="overflow-hidden border border-amber-100 rounded-xl bg-white shadow-lg">
|
|
||||||
<view
|
|
||||||
class="relative overflow-hidden from-amber-500 to-amber-600 bg-gradient-to-r px-4 py-3 text-center text-white font-bold">
|
|
||||||
<view class="relative z-10">收益预估对比</view>
|
|
||||||
<view class="absolute inset-0 bg-amber-500 opacity-30">
|
|
||||||
<view
|
|
||||||
class="animate-shimmer absolute left-0 top-0 h-full w-full translate-x-full transform from-transparent via-white to-transparent bg-gradient-to-r opacity-20 -skew-x-30" />
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="p-4">
|
|
||||||
<!-- 顶部收益概览 -->
|
|
||||||
<view class="mb-6 overflow-hidden border border-amber-200 rounded-lg">
|
|
||||||
<view class="from-amber-100 to-amber-200 bg-gradient-to-r px-4 py-2 text-center text-amber-800 font-bold">
|
|
||||||
VIP与SVIP代理收益对比
|
|
||||||
</view>
|
|
||||||
<view class="grid grid-cols-2 divide-x divide-amber-200">
|
|
||||||
<view class="p-4 text-center" :class="{ 'bg-amber-50': selectedType === 'vip' }">
|
|
||||||
<view class="mb-1 text-sm text-gray-600">
|
|
||||||
VIP月预计收益
|
|
||||||
</view>
|
|
||||||
<view class="text-xl text-amber-600 font-bold">
|
|
||||||
{{ revenueData.vipMonthly }}元
|
|
||||||
</view>
|
|
||||||
<view class="mt-1 text-xs text-gray-500">
|
|
||||||
年收益:{{ revenueData.vipYearly }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="p-4 text-center" :class="{ 'bg-amber-50': selectedType === 'svip' }">
|
|
||||||
<view class="mb-1 text-sm text-gray-600">
|
|
||||||
SVIP月预计收益
|
|
||||||
</view>
|
|
||||||
<view class="text-xl text-red-500 font-bold">
|
|
||||||
{{ revenueData.svipMonthly }}元
|
|
||||||
</view>
|
|
||||||
<view class="mt-1 text-xs text-gray-500">
|
|
||||||
年收益:{{ revenueData.svipYearly }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="from-red-50 to-red-100 bg-gradient-to-r px-4 py-2 text-center text-red-600 font-medium">
|
|
||||||
选择SVIP,相比VIP月增收益:<text class="font-bold">{{ revenueData.monthlyDifference }}元</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 详细收益表格 -->
|
|
||||||
<view class="overflow-x-auto">
|
|
||||||
<table class="w-full border-collapse">
|
|
||||||
<thead>
|
|
||||||
<tr class="from-amber-100 to-amber-200 bg-gradient-to-r">
|
|
||||||
<th class="border border-amber-200 p-2 text-left text-amber-800">
|
|
||||||
收益来源
|
|
||||||
</th>
|
|
||||||
<th class="w-1/3 border border-amber-200 p-2 text-center text-amber-800"
|
|
||||||
:class="{ 'bg-amber-200': selectedType === 'vip' }">
|
|
||||||
VIP代理
|
|
||||||
</th>
|
|
||||||
<th class="w-1/3 border border-amber-200 p-2 text-center text-amber-800"
|
|
||||||
:class="{ 'bg-amber-200': selectedType === 'svip' }">
|
|
||||||
SVIP代理
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
推广收益(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
300单×50元=15,000元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
300单×50元=15,000元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级贡献收益(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
300单×{{ vipConfig.vipCommission }}元=360元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
300单×{{ vipConfig.svipCommission }}元=450元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级价格浮动收益(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
100单×100元×{{ vipConfig.vipFloatingRate }}%=500元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
200单×100元×{{ vipConfig.svipFloatingRate }}%=2,000元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级提现奖励(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
-
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ revenueData.withdrawReward }}元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
下级转化奖励(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.vipConversionBonus }}元×2个=598元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ vipConfig.svipConversionBonus }}元×2个=798元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="transition-colors hover:bg-amber-50">
|
|
||||||
<td class="border border-amber-200 p-2 font-medium">
|
|
||||||
额外业务收益(月)
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
约3,000元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-2 text-center" :class="{
|
|
||||||
'text-amber-700 font-medium bg-amber-50': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
约6,000元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="from-amber-50 to-amber-100 bg-gradient-to-r font-bold">
|
|
||||||
<td class="border border-amber-200 p-3">
|
|
||||||
月计收益
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-3 text-center text-amber-700" :class="{
|
|
||||||
'bg-amber-50 border-amber-300': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ revenueData.vipMonthly }}元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-3 text-center text-red-500" :class="{
|
|
||||||
'bg-amber-50 border-amber-300': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ revenueData.svipMonthly }}元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="from-amber-50 to-amber-100 bg-gradient-to-r font-bold">
|
|
||||||
<td class="border border-amber-200 p-3">
|
|
||||||
年计收益
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-3 text-center text-amber-700" :class="{
|
|
||||||
'bg-amber-50 border-amber-300': selectedType === 'vip',
|
|
||||||
}">
|
|
||||||
{{ revenueData.vipYearly }}元
|
|
||||||
</td>
|
|
||||||
<td class="border border-amber-200 p-3 text-center text-red-500" :class="{
|
|
||||||
'bg-amber-50 border-amber-300': selectedType === 'svip',
|
|
||||||
}">
|
|
||||||
{{ revenueData.svipYearly }}元
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 投资回报率 -->
|
|
||||||
<view class="mt-6 border border-amber-200 rounded-lg from-amber-50 to-amber-100 bg-gradient-to-r p-4">
|
|
||||||
<view class="mb-3 text-center text-amber-800 font-bold">
|
|
||||||
投资收益分析
|
|
||||||
</view>
|
|
||||||
<view class="grid grid-cols-1 gap-4">
|
|
||||||
<view class="rounded-lg bg-white p-3 shadow-sm">
|
|
||||||
<view class="flex items-center justify-between">
|
|
||||||
<view class="flex-1 border-r border-amber-100 pr-3">
|
|
||||||
<view class="mb-1 text-center text-amber-700 font-medium">
|
|
||||||
VIP方案
|
|
||||||
</view>
|
|
||||||
<view class="text-center">
|
|
||||||
<view class="text-sm text-amber-600">
|
|
||||||
投资{{ vipConfig.price }}元
|
|
||||||
</view>
|
|
||||||
<view class="text-sm text-gray-600">
|
|
||||||
月收益{{ revenueData.vipMonthly }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="flex-1 pl-3">
|
|
||||||
<view class="mb-1 text-center text-red-500 font-medium">
|
|
||||||
SVIP方案
|
|
||||||
</view>
|
|
||||||
<view class="text-center">
|
|
||||||
<view class="text-sm text-red-500">
|
|
||||||
投资{{ vipConfig.svipPrice }}元
|
|
||||||
</view>
|
|
||||||
<view class="text-sm text-gray-600">
|
|
||||||
月收益{{ revenueData.svipMonthly }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 升级收益对比 -->
|
|
||||||
<view class="rounded-lg from-red-50 to-amber-50 bg-gradient-to-r p-3 shadow-sm">
|
|
||||||
<view class="mb-2 text-center text-red-700 font-medium">
|
|
||||||
SVIP升级优势分析
|
|
||||||
</view>
|
|
||||||
<view class="flex items-center justify-center gap-3">
|
|
||||||
<view class="text-center">
|
|
||||||
<view class="text-sm text-gray-600">
|
|
||||||
额外投资
|
|
||||||
</view>
|
|
||||||
<view class="text-red-600 font-bold">
|
|
||||||
{{ revenueData.priceDifference }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="h-6 w-6 flex flex-shrink-0 items-center justify-center rounded-full bg-red-500 text-white">
|
|
||||||
<view class="transform -translate-y-px">
|
|
||||||
→
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="text-center">
|
|
||||||
<view class="text-sm text-gray-600">
|
|
||||||
每月额外收益
|
|
||||||
</view>
|
|
||||||
<view class="text-red-600 font-bold">
|
|
||||||
{{ revenueData.monthlyDifference }}元
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="h-6 w-6 flex flex-shrink-0 items-center justify-center rounded-full bg-red-500 text-white">
|
|
||||||
<text class="transform -translate-y-px">→</text>
|
|
||||||
</view>
|
|
||||||
<view class="text-center">
|
|
||||||
<view class="text-sm text-gray-600">
|
|
||||||
投资回收时间
|
|
||||||
</view>
|
|
||||||
<view class="text-red-600 font-bold">
|
|
||||||
{{ revenueData.recoverDays }}天
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="mt-3 text-center text-red-500 font-medium">
|
|
||||||
额外投资{{ revenueData.priceDifference }}元,<text class="text-red-600 font-bold">年多赚{{
|
|
||||||
revenueData.yearlyDifference }}元</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 申请按钮(固定在底部) -->
|
|
||||||
<view
|
|
||||||
class="fixed bottom-0 left-0 right-0 z-30 from-amber-100 to-transparent bg-gradient-to-t px-4 py-3 backdrop-blur-sm">
|
|
||||||
<view class="flex flex-col gap-2">
|
|
||||||
<wd-button :class="buttonClass" block :disabled="!canPerformAction" @click="applyVip">
|
|
||||||
<text class="relative z-10">{{ buttonText }}</text>
|
|
||||||
<view
|
|
||||||
class="animate-shimmer absolute left-0 top-0 h-full w-full translate-x-full transform from-transparent via-white to-transparent bg-gradient-to-r opacity-20 -skew-x-30" />
|
|
||||||
</wd-button>
|
|
||||||
<wd-button custom-class="contact-wd-btn" block plain @click="contactService">
|
|
||||||
<view class="flex items-center justify-center text-amber-700 font-medium">
|
|
||||||
<wd-icon name="service" custom-class="mr-1" />
|
|
||||||
<text>联系客服咨询</text>
|
|
||||||
</view>
|
|
||||||
</wd-button>
|
|
||||||
<!-- 最终解释权声明 -->
|
|
||||||
<view class="py-1 text-center text-xs text-gray-400">
|
|
||||||
最终解释权归戎行技术有限公司所有
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<Payment :id="payID" v-model="showPayment" :data="payData" type="agent_vip" @close="showPayment = false" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.agent-VIP-apply {
|
|
||||||
font-family:
|
|
||||||
system-ui,
|
|
||||||
-apple-system,
|
|
||||||
BlinkMacSystemFont,
|
|
||||||
'Segoe UI',
|
|
||||||
Roboto,
|
|
||||||
sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes shimmer {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%) skewX(-30deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
100% {
|
|
||||||
transform: translateX(200%) skewX(-30deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.animate-shimmer {
|
|
||||||
animation: shimmer 3s infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active\:scale-98:active {
|
|
||||||
transform: scale(0.98);
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.contact-wd-btn.wd-button) {
|
|
||||||
border-color: #fbbf24;
|
|
||||||
background-color: #fff;
|
|
||||||
box-shadow: 0 4px 10px rgba(120, 53, 15, 0.08);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { openCustomerService } from '@/composables/useCustomerService'
|
import { openCustomerService } from '@/composables/useCustomerService'
|
||||||
|
import { openAgentVipApplyInExternalBrowser } from '@/composables/useAgentVipH5'
|
||||||
|
|
||||||
definePage({ layout: 'default', auth: true })
|
definePage({ layout: 'default', auth: true })
|
||||||
function toVipApply() {
|
function toVipApply() {
|
||||||
uni.navigateTo({ url: '/pages/agent-vip-apply' })
|
openAgentVipApplyInExternalBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
function toService() {
|
function toService() {
|
||||||
|
|||||||
@@ -1,22 +1,10 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
|
||||||
import bgIcon from '/static/images/bg_icon.png'
|
|
||||||
import bannerImg from '/static/images/index/banner_1.png'
|
import bannerImg from '/static/images/index/banner_1.png'
|
||||||
import bannerImg2 from '/static/images/index/banner_2.png'
|
import bannerImg2 from '/static/images/index/banner_2.png'
|
||||||
import bannerImg3 from '/static/images/index/banner_3.png'
|
import bannerImg3 from '/static/images/index/banner_3.png'
|
||||||
import honestyBanner from '/static/images/index/banner_B.png'
|
import honestyBanner from '/static/images/index/banner_B.png'
|
||||||
import companyIcon from '/static/images/index/company_bg.png'
|
|
||||||
import housekeepingRiskIcon from '/static/images/index/housekeeping_risk_bg.png'
|
|
||||||
import loanCheckIcon from '/static/images/index/loan_check_bg.png'
|
|
||||||
import marriageRiskIcon from '/static/images/index/marriage_risk_bg.png'
|
|
||||||
import personalDataIcon from '/static/images/index/personal_data_bg.png'
|
|
||||||
import preLoanRiskIcon from '/static/images/index/preloan_risk_bg.png'
|
|
||||||
import rentalInfoBg from '/static/images/index/rentalinfo_bg.png'
|
|
||||||
import rightIcon from '/static/images/index/right.png'
|
|
||||||
import indexPromoteIcon from '/static/images/index/tgbg.png'
|
import indexPromoteIcon from '/static/images/index/tgbg.png'
|
||||||
import indexMyReportIcon from '/static/images/index/wdbg.png'
|
|
||||||
import indexInvitationIcon from '/static/images/index/yqhy.png'
|
import indexInvitationIcon from '/static/images/index/yqhy.png'
|
||||||
import { useAppConfig } from '@/composables/useAppConfig'
|
|
||||||
import { ensurePrivacyConsentIfNeeded } from '@/composables/usePrivacyConsent'
|
import { ensurePrivacyConsentIfNeeded } from '@/composables/usePrivacyConsent'
|
||||||
|
|
||||||
definePage({ layout: 'home' })
|
definePage({ layout: 'home' })
|
||||||
@@ -27,28 +15,6 @@ onShow(() => {
|
|||||||
|
|
||||||
const banners = [bannerImg, bannerImg2, bannerImg3]
|
const banners = [bannerImg, bannerImg2, bannerImg3]
|
||||||
|
|
||||||
const services = [
|
|
||||||
{ title: '个人大数据', name: 'personalData', bg: personalDataIcon },
|
|
||||||
{ title: '婚恋风险', name: 'marriage', bg: marriageRiskIcon },
|
|
||||||
{ title: '入职背调', name: 'backgroundcheck', bg: preLoanRiskIcon },
|
|
||||||
]
|
|
||||||
|
|
||||||
const riskServices = [
|
|
||||||
{ title: '小微', name: 'companyinfo', bg: companyIcon },
|
|
||||||
{ title: '家政', name: 'homeservice', bg: housekeepingRiskIcon },
|
|
||||||
{ title: '贷前', name: 'preloanbackgroundcheck', bg: loanCheckIcon },
|
|
||||||
{ title: '诚信租赁', name: 'rentalinfo', bg: rentalInfoBg },
|
|
||||||
]
|
|
||||||
const { appConfig, loadAppConfig } = useAppConfig()
|
|
||||||
const queryRetentionDaysText = computed(() => `${appConfig.value.query.retention_days}天`)
|
|
||||||
void loadAppConfig()
|
|
||||||
|
|
||||||
function toInquire(name) {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: `/pages/inquire?feature=${encodeURIComponent(name)}`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function toInvitation() {
|
function toInvitation() {
|
||||||
uni.navigateTo({ url: '/pages/invitation' })
|
uni.navigateTo({ url: '/pages/invitation' })
|
||||||
}
|
}
|
||||||
@@ -56,112 +22,70 @@ function toInvitation() {
|
|||||||
function toPromote() {
|
function toPromote() {
|
||||||
uni.navigateTo({ url: '/pages/promote' })
|
uni.navigateTo({ url: '/pages/promote' })
|
||||||
}
|
}
|
||||||
|
|
||||||
function toHistory() {
|
|
||||||
uni.navigateTo({ url: '/pages/history-query' })
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="box-border min-h-screen">
|
<view class="box-border min-h-screen bg-[#f5faff] pb-4">
|
||||||
<view class="relative p-4">
|
<view class="m-4 overflow-hidden rounded-2xl">
|
||||||
<swiper class="banner-swiper overflow-hidden rounded-xl" circular autoplay :interval="3000" indicator-dots
|
<swiper
|
||||||
indicator-color="rgba(255,255,255,0.5)" indicator-active-color="#ffffff">
|
class="banner-swiper w-full"
|
||||||
<swiper-item v-for="(item, index) in banners" :key="index">
|
circular
|
||||||
|
autoplay
|
||||||
|
:interval="3000"
|
||||||
|
indicator-dots
|
||||||
|
indicator-color="rgba(255,255,255,0.45)"
|
||||||
|
indicator-active-color="#ffffff"
|
||||||
|
>
|
||||||
|
<swiper-item v-for="(item, index) in banners" :key="index" class="h-full w-full">
|
||||||
<image :src="item" class="h-full w-full" mode="aspectFill" />
|
<image :src="item" class="h-full w-full" mode="aspectFill" />
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="px-6">
|
<view class="mt-2 px-4">
|
||||||
<view class="grid grid-cols-3 gap-3">
|
<view class="mb-2 text-base text-gray-800 font-bold">
|
||||||
<view class="flex flex-col items-center justify-center text-center" @click="toPromote">
|
即刻赚佣金
|
||||||
|
</view>
|
||||||
|
|
||||||
<view
|
<view
|
||||||
class="box-content h-16 w-16 flex items-center justify-center rounded-full from-white to-blue-100/10 bg-gradient-to-b p-1 shadow-lg">
|
class="card-gradient-1 mb-4 flex items-center rounded-2xl p-0 shadow-xl"
|
||||||
<image :src="indexPromoteIcon" class="h-12 w-12" mode="aspectFit" />
|
@click="toPromote"
|
||||||
|
>
|
||||||
|
<view class="flex flex-1 flex-col items-start justify-center py-4 pl-4">
|
||||||
|
<view class="mb-1 text-[20px] text-blue-700 font-bold">
|
||||||
|
直推报告
|
||||||
</view>
|
</view>
|
||||||
<text class="mt-1 text-center font-bold">
|
<view class="mb-4 text-xs text-gray-700">
|
||||||
推广报告
|
选择所需报告类型,灵活定价,一键分享客户,客户下单即结算,佣金实时到账
|
||||||
</text>
|
</view>
|
||||||
|
<wd-button plain>
|
||||||
|
立即推广
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
<image class="mx-4 my-4 h-20 w-20" :src="indexPromoteIcon" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="flex flex-col items-center justify-center text-center" @click="toInvitation">
|
|
||||||
<view
|
<view
|
||||||
class="box-content h-16 w-16 flex items-center justify-center rounded-full from-white to-blue-100/10 bg-gradient-to-b p-1 shadow-lg">
|
class="card-gradient-2 flex items-center rounded-2xl p-0 shadow-xl"
|
||||||
<image :src="indexInvitationIcon" class="h-12 w-12" mode="aspectFit" />
|
@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>
|
||||||
<text class="mt-1 text-center font-bold">
|
<view class="mb-4 text-xs text-gray-700">
|
||||||
邀请下级
|
邀请好友成为代理,好友推广获客,客户支付即返佣,团队收益轻松到手
|
||||||
</text>
|
</view>
|
||||||
|
<wd-button plain>
|
||||||
|
立即邀请
|
||||||
|
</wd-button>
|
||||||
|
</view>
|
||||||
|
<image class="mx-4 my-4 h-20 w-20" :src="indexInvitationIcon" mode="aspectFit" />
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="flex flex-col items-center justify-center text-center" @click="toHistory">
|
<view class="relative mt-4 h-[120px] overflow-hidden rounded-2xl shadow-xl">
|
||||||
<view
|
<image class="absolute inset-0 h-full w-full" :src="honestyBanner" mode="aspectFill" />
|
||||||
class="box-content h-16 w-16 flex items-center justify-center rounded-full from-white to-blue-100/10 bg-gradient-to-b p-1 shadow-lg">
|
<view class="absolute inset-0 bg-black/5" />
|
||||||
<image :src="indexMyReportIcon" class="h-12 w-12" mode="aspectFit" />
|
|
||||||
</view>
|
|
||||||
<text class="mt-1 text-center font-bold">
|
|
||||||
我的报告
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="relative p-4 pt-0">
|
|
||||||
<view class="grid grid-cols-2 my-4 gap-4" style="grid-template-rows: repeat(2, 1fr);">
|
|
||||||
<view v-for="(service, index) in services" :key="index"
|
|
||||||
class="relative min-h-18 flex flex-col rounded-xl px-4 py-2 shadow-lg"
|
|
||||||
:class="index === 0 ? 'row-span-2' : ''"
|
|
||||||
:style="`background: url(${service.bg}) no-repeat; background-size: 100% 100%; background-position: center;`"
|
|
||||||
@click="toInquire(service.name)">
|
|
||||||
<view class="min-h-18 flex items-end">
|
|
||||||
<!-- <text class="text-base text-gray-700 font-semibold">
|
|
||||||
{{ service.title }}
|
|
||||||
</text> -->
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<scroll-view scroll-x class="risk-scroll my-4 px-1 pb-4 pt-2 -mx-1">
|
|
||||||
<view class="inline-flex gap-2">
|
|
||||||
<view v-for="(service, index) in riskServices" :key="index"
|
|
||||||
class="relative h-24 w-[107px] flex-shrink-0 rounded-xl shadow-lg"
|
|
||||||
:style="`background: url(${service.bg}) no-repeat; background-size: 100% 100%; background-position: center;`"
|
|
||||||
@click="toInquire(service.name)">
|
|
||||||
<view class="h-full flex items-end px-2 py-2">
|
|
||||||
<!-- <text class="text-sm text-gray-700 font-semibold">
|
|
||||||
{{ service.title }}
|
|
||||||
</text> -->
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
|
|
||||||
<view class="mb-3 mt-6 flex items-center">
|
|
||||||
<view class="bg-primary h-5 w-1.5 rounded-xl" />
|
|
||||||
<text class="ml-2 text-lg text-gray-800">
|
|
||||||
诚信专栏
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="mt-4 overflow-hidden rounded-xl bg-white shadow-xl">
|
|
||||||
<image :src="honestyBanner" class="block w-full" mode="widthFix" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="mt-4 box-border h-14 w-full flex items-center rounded-lg bg-white px-4 text-gray-700 shadow-lg"
|
|
||||||
@click="toHistory">
|
|
||||||
<view class="mr-4 h-full flex items-center justify-center">
|
|
||||||
<image class="h-10 w-10" :src="bgIcon" mode="aspectFit" />
|
|
||||||
</view>
|
|
||||||
<view class="flex-1">
|
|
||||||
<view class="text-gray-800">
|
|
||||||
我的历史查询记录
|
|
||||||
</view>
|
|
||||||
<view class="text-xs text-gray-500">
|
|
||||||
查询记录有效期为{{ queryRetentionDaysText }}
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<image :src="rightIcon" class="h-6 w-6" mode="aspectFit" />
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -172,7 +96,17 @@ function toHistory() {
|
|||||||
height: 160px;
|
height: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.risk-scroll {
|
.card-gradient-1 {
|
||||||
white-space: nowrap;
|
background: linear-gradient(135deg, #e3f0ff 0%, #fafdff 100%);
|
||||||
|
box-shadow:
|
||||||
|
0 6px 24px 0 rgba(60, 120, 255, 0.1),
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { computed, onBeforeMount, ref, watch } from 'vue'
|
import { computed, onBeforeMount, ref, watch } from 'vue'
|
||||||
import { openCustomerService } from '@/composables/useCustomerService'
|
import { openCustomerService } from '@/composables/useCustomerService'
|
||||||
|
import { openAgentVipApplyInExternalBrowser } from '@/composables/useAgentVipH5'
|
||||||
import { useAgentStore } from '@/stores/agentStore'
|
import { useAgentStore } from '@/stores/agentStore'
|
||||||
import { useDialogStore } from '@/stores/dialogStore'
|
import { useDialogStore } from '@/stores/dialogStore'
|
||||||
import { useUserStore } from '@/stores/userStore'
|
import { useUserStore } from '@/stores/userStore'
|
||||||
@@ -75,9 +76,7 @@ function maskName(name) {
|
|||||||
return `${name.substring(0, 3)}****${name.substring(7)}`
|
return `${name.substring(0, 3)}****${name.substring(7)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function toHistory() {
|
|
||||||
uni.navigateTo({ url: '/pages/history-query' })
|
|
||||||
}
|
|
||||||
function toPromote() {
|
function toPromote() {
|
||||||
uni.navigateTo({ url: '/pages/promote' })
|
uni.navigateTo({ url: '/pages/promote' })
|
||||||
}
|
}
|
||||||
@@ -127,7 +126,7 @@ function toVipConfig() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function toVipRenewal() {
|
function toVipRenewal() {
|
||||||
uni.navigateTo({ url: '/pages/agent-vip-apply' })
|
openAgentVipApplyInExternalBrowser()
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatExpiryTime(expiryTimeStr) {
|
function formatExpiryTime(expiryTimeStr) {
|
||||||
@@ -298,17 +297,6 @@ onBeforeMount(() => {
|
|||||||
</view>
|
</view>
|
||||||
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
|
<image src="/static/images/me/right.png" class="h-4 w-4" alt="右箭头" />
|
||||||
</view>
|
</view>
|
||||||
<view
|
|
||||||
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
|
|
||||||
@click="toHistory">
|
|
||||||
<view class="flex items-center gap-3">
|
|
||||||
<image src="/static/images/index/wdbg.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>
|
|
||||||
<view
|
<view
|
||||||
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
|
class="w-full flex items-center justify-between border-b border-gray-100 px-6 py-4 transition-colors hover:bg-blue-50"
|
||||||
@click="toUserAgreement">
|
@click="toUserAgreement">
|
||||||
|
|||||||
@@ -105,13 +105,13 @@ onShow(() => {
|
|||||||
</view>
|
</view>
|
||||||
<view class="permissions">
|
<view class="permissions">
|
||||||
<view class="permission-item">
|
<view class="permission-item">
|
||||||
1. 网络权限:用于连接服务、加载业务数据与提交操作请求。
|
1. 网络权限:用于连接服务、加载页面与提交查询、支付等操作。
|
||||||
</view>
|
</view>
|
||||||
<view class="permission-item">
|
<view class="permission-item">
|
||||||
2. 存储权限:用于缓存页面数据、保存登录状态与图片文件。
|
2. 相册/存储写入:仅在您点击保存推广海报或二维码图片时,将应用内生成的图片保存到手机相册。
|
||||||
</view>
|
</view>
|
||||||
<view class="permission-item">
|
<view class="permission-item">
|
||||||
3. 设备信息权限:用于运行稳定性、安全风控与异常排查。
|
3. 支付相关能力:在您主动发起支付宝支付时,由支付服务完成交易(具体权限以支付 SDK 为准)。
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="hint">
|
<view class="hint">
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ const formData = ref({
|
|||||||
clientPrice: null,
|
clientPrice: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 从首页报告卡片带入的 product_en,配置加载后预选 */
|
||||||
|
const initialFeature = ref('')
|
||||||
|
|
||||||
const availableReportTypes = computed(() => {
|
const availableReportTypes = computed(() => {
|
||||||
if (!productConfig.value?.length)
|
if (!productConfig.value?.length)
|
||||||
return []
|
return []
|
||||||
@@ -84,6 +87,17 @@ function openPricePicker() {
|
|||||||
showPricePicker.value = true
|
showPricePicker.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toExampleReport() {
|
||||||
|
const feature = formData.value.productType
|
||||||
|
if (!feature) {
|
||||||
|
uni.showToast({ title: '请先选择报告类型', icon: 'none' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/report-example-webview?feature=${encodeURIComponent(feature)}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async function getPromoteConfig() {
|
async function getPromoteConfig() {
|
||||||
loadingConfig.value = true
|
loadingConfig.value = true
|
||||||
try {
|
try {
|
||||||
@@ -91,7 +105,10 @@ async function getPromoteConfig() {
|
|||||||
if (data.value && !error.value && data.value.code === 200) {
|
if (data.value && !error.value && data.value.code === 200) {
|
||||||
const list = data.value.data.AgentProductConfig || []
|
const list = data.value.data.AgentProductConfig || []
|
||||||
productConfig.value = list
|
productConfig.value = list
|
||||||
const availableType = availableReportTypes.value[0]
|
const preset = initialFeature.value
|
||||||
|
? availableReportTypes.value.find(item => item.value === initialFeature.value)
|
||||||
|
: null
|
||||||
|
const availableType = preset || availableReportTypes.value[0]
|
||||||
if (availableType) {
|
if (availableType) {
|
||||||
selectProductType(availableType.value)
|
selectProductType(availableType.value)
|
||||||
}
|
}
|
||||||
@@ -143,6 +160,12 @@ async function generatePromotionCode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLoad((options) => {
|
||||||
|
const feature = options?.feature
|
||||||
|
if (feature)
|
||||||
|
initialFeature.value = decodeURIComponent(String(feature))
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getPromoteConfig()
|
getPromoteConfig()
|
||||||
})
|
})
|
||||||
@@ -163,8 +186,14 @@ onMounted(() => {
|
|||||||
</view>
|
</view>
|
||||||
<VipBanner />
|
<VipBanner />
|
||||||
|
|
||||||
<view class="card mb-4">
|
<view class="card mb-4 relative">
|
||||||
<view class="mb-2 text-xl font-semibold">
|
<text
|
||||||
|
class="absolute right-4 top-4 z-10 text-sm text-blue-600 active:opacity-70"
|
||||||
|
@click="toExampleReport"
|
||||||
|
>
|
||||||
|
示例报告
|
||||||
|
</text>
|
||||||
|
<view class="mb-2 pr-20 text-xl font-semibold">
|
||||||
生成推广码
|
生成推广码
|
||||||
</view>
|
</view>
|
||||||
<wd-form ref="promotionForm" :model="formData">
|
<wd-form ref="promotionForm" :model="formData">
|
||||||
|
|||||||
3
src/uni-pages.d.ts
vendored
3
src/uni-pages.d.ts
vendored
@@ -9,7 +9,6 @@ type _LocationUrl =
|
|||||||
"/pages/agent-promote-details" |
|
"/pages/agent-promote-details" |
|
||||||
"/pages/agent-rewards-details" |
|
"/pages/agent-rewards-details" |
|
||||||
"/pages/agent-service-agreement" |
|
"/pages/agent-service-agreement" |
|
||||||
"/pages/agent-vip-apply" |
|
|
||||||
"/pages/agent-vip-config" |
|
"/pages/agent-vip-config" |
|
||||||
"/pages/agent-vip" |
|
"/pages/agent-vip" |
|
||||||
"/pages/agent" |
|
"/pages/agent" |
|
||||||
@@ -18,8 +17,6 @@ type _LocationUrl =
|
|||||||
"/pages/help-detail" |
|
"/pages/help-detail" |
|
||||||
"/pages/help-guide" |
|
"/pages/help-guide" |
|
||||||
"/pages/help" |
|
"/pages/help" |
|
||||||
"/pages/history-query" |
|
|
||||||
"/pages/inquire" |
|
|
||||||
"/pages/invitation-agent-apply" |
|
"/pages/invitation-agent-apply" |
|
||||||
"/pages/invitation" |
|
"/pages/invitation" |
|
||||||
"/pages/launch" |
|
"/pages/launch" |
|
||||||
|
|||||||
Reference in New Issue
Block a user