f
This commit is contained in:
@@ -162,12 +162,13 @@ export function getLatestVersion() {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注销账号
|
* 注销账号(需传入短信验证码)
|
||||||
*/
|
*/
|
||||||
export function cancelAccount() {
|
export function cancelAccount(code) {
|
||||||
return request({
|
return request({
|
||||||
url: '/user/cancelOut',
|
url: '/user/cancelOut',
|
||||||
method: 'POST'
|
method: 'POST',
|
||||||
|
data: { code }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ export const activateAgentMembership = (data) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取代理会员配置(VIP/SVIP价格等)
|
||||||
|
*/
|
||||||
|
export const getAgentMembershipInfo = () => {
|
||||||
|
return request({
|
||||||
|
url: '/agent/membership/info',
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取代理会员用户配置
|
* 获取代理会员用户配置
|
||||||
* @param {Object} params 查询参数 {product_id}
|
* @param {Object} params 查询参数 {product_id}
|
||||||
|
|||||||
4
src/auto-imports.d.ts
vendored
4
src/auto-imports.d.ts
vendored
@@ -12,7 +12,6 @@ declare global {
|
|||||||
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
|
const aesEncrypt: typeof import('./utils/crypto.js')['aesEncrypt']
|
||||||
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 autoUpdateCheck: typeof import('./utils/autoUpdateCheck.js')['default']
|
|
||||||
const buildPromotionH5Url: typeof import('./utils/promotionH5Url.js')['buildPromotionH5Url']
|
const buildPromotionH5Url: typeof import('./utils/promotionH5Url.js')['buildPromotionH5Url']
|
||||||
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']
|
||||||
@@ -228,7 +227,6 @@ declare global {
|
|||||||
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
const useFullscreen: typeof import('@vueuse/core')['useFullscreen']
|
||||||
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
const useGamepad: typeof import('@vueuse/core')['useGamepad']
|
||||||
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
const useGeolocation: typeof import('@vueuse/core')['useGeolocation']
|
||||||
const useHotUpdate: typeof import('./composables/useHotUpdate.js')['useHotUpdate']
|
|
||||||
const useId: typeof import('vue')['useId']
|
const useId: typeof import('vue')['useId']
|
||||||
const useIdle: typeof import('@vueuse/core')['useIdle']
|
const useIdle: typeof import('@vueuse/core')['useIdle']
|
||||||
const useImage: typeof import('@vueuse/core')['useImage']
|
const useImage: typeof import('@vueuse/core')['useImage']
|
||||||
@@ -359,7 +357,6 @@ declare module 'vue' {
|
|||||||
readonly aesEncrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesEncrypt']>
|
readonly aesEncrypt: UnwrapRef<typeof import('./utils/crypto.js')['aesEncrypt']>
|
||||||
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 autoUpdateCheck: UnwrapRef<typeof import('./utils/autoUpdateCheck.js')['default']>
|
|
||||||
readonly buildPromotionH5Url: UnwrapRef<typeof import('./utils/promotionH5Url.js')['buildPromotionH5Url']>
|
readonly buildPromotionH5Url: UnwrapRef<typeof import('./utils/promotionH5Url.js')['buildPromotionH5Url']>
|
||||||
readonly chatCrypto: UnwrapRef<typeof import('./utils/chatCrypto.js')['default']>
|
readonly chatCrypto: UnwrapRef<typeof import('./utils/chatCrypto.js')['default']>
|
||||||
readonly chatEncrypt: UnwrapRef<typeof import('./utils/chatEncrypt.js')['default']>
|
readonly chatEncrypt: UnwrapRef<typeof import('./utils/chatEncrypt.js')['default']>
|
||||||
@@ -574,7 +571,6 @@ declare module 'vue' {
|
|||||||
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
|
readonly useFullscreen: UnwrapRef<typeof import('@vueuse/core')['useFullscreen']>
|
||||||
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
|
readonly useGamepad: UnwrapRef<typeof import('@vueuse/core')['useGamepad']>
|
||||||
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
|
readonly useGeolocation: UnwrapRef<typeof import('@vueuse/core')['useGeolocation']>
|
||||||
readonly useHotUpdate: UnwrapRef<typeof import('./composables/useHotUpdate.js')['useHotUpdate']>
|
|
||||||
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
readonly useId: UnwrapRef<typeof import('vue')['useId']>
|
||||||
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
|
readonly useIdle: UnwrapRef<typeof import('@vueuse/core')['useIdle']>
|
||||||
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
|
readonly useImage: UnwrapRef<typeof import('@vueuse/core')['useImage']>
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
<div class="border-b border-gray-200">
|
<div class="border-b border-gray-200">
|
||||||
<wd-input v-model="price" type="number" label="¥" label-width="28px" size="large"
|
<wd-input v-model="price" type="number" label="¥" label-width="28px" size="large"
|
||||||
:placeholder="`${productConfig.price_range_min} - ${productConfig.price_range_max}`"
|
:placeholder="priceRangePlaceholder" @blur="onBlurPrice"
|
||||||
@blur="onBlurPrice" custom-class="wd-input" />
|
custom-class="wd-input" />
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-between mt-2">
|
<div class="flex items-center justify-between mt-2">
|
||||||
<div>推广收益为<span class="text-orange-500"> {{ promotionRevenue }} </span>元</div>
|
<div>推广收益为<span class="text-orange-500"> {{ promotionRevenue }} </span>元</div>
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
<div>我的成本 = 提价成本 + 底价成本</div>
|
<div>我的成本 = 提价成本 + 底价成本</div>
|
||||||
<div class="mt-1">提价成本:超过平台标准定价部分,平台会收取部分成本价</div>
|
<div class="mt-1">提价成本:超过平台标准定价部分,平台会收取部分成本价</div>
|
||||||
<div class="">设定范围:<span class="text-orange-500">{{
|
<div class="">设定范围:<span class="text-orange-500">{{
|
||||||
productConfig.price_range_min }}</span>元 - <span class="text-orange-500">{{
|
productConfig?.price_range_min ?? '--' }}</span>元 - <span class="text-orange-500">{{
|
||||||
productConfig.price_range_max }}</span>元</div>
|
productConfig?.price_range_max ?? '--' }}</span>元</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 pb-4">
|
<div class="px-4 pb-4">
|
||||||
<wd-button class="w-full" round type="primary" size="large" @click="onConfirm">确认</wd-button>
|
<wd-button class="w-full" round type="primary" size="large" @click="onConfirm">确认</wd-button>
|
||||||
@@ -60,6 +60,13 @@ watch(show, () => {
|
|||||||
price.value = defaultPrice.value
|
price.value = defaultPrice.value
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const priceRangePlaceholder = computed(() => {
|
||||||
|
const min = productConfig.value?.price_range_min
|
||||||
|
const max = productConfig.value?.price_range_max
|
||||||
|
if (min === undefined || max === undefined) return '请输入价格'
|
||||||
|
return `${min} - ${max}`
|
||||||
|
})
|
||||||
|
|
||||||
const costPrice = computed(() => {
|
const costPrice = computed(() => {
|
||||||
if (!productConfig.value) return 0.00
|
if (!productConfig.value) return 0.00
|
||||||
// 平台定价成本
|
// 平台定价成本
|
||||||
@@ -88,6 +95,9 @@ const promotionRevenue = computed(() => {
|
|||||||
|
|
||||||
// 价格校验与修正逻辑
|
// 价格校验与修正逻辑
|
||||||
const validatePrice = (currentPrice) => {
|
const validatePrice = (currentPrice) => {
|
||||||
|
if (!productConfig.value) {
|
||||||
|
return { newPrice: Number(defaultPrice.value || 0), message: '当前产品配置不可用,请重新选择报告类型' }
|
||||||
|
}
|
||||||
const min = productConfig.value.price_range_min;
|
const min = productConfig.value.price_range_min;
|
||||||
const max = productConfig.value.price_range_max;
|
const max = productConfig.value.price_range_max;
|
||||||
let newPrice = Number(currentPrice);
|
let newPrice = Number(currentPrice);
|
||||||
@@ -159,17 +169,22 @@ const onBlurPrice = () => {
|
|||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
justify-content: center !important;
|
justify-content: center !important;
|
||||||
|
|
||||||
:deep(.wd-input__label-inner) {
|
:deep(.wd-input__label-inner) {
|
||||||
font-size: 24px !important; /* 增大label字体 */
|
font-size: 24px !important;
|
||||||
|
/* 增大label字体 */
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.wd-input__inner) {
|
:deep(.wd-input__inner) {
|
||||||
font-size: 24px !important; /* 增大输入框内字体 */
|
font-size: 24px !important;
|
||||||
|
/* 增大输入框内字体 */
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.wd-input) {
|
:deep(.wd-input) {
|
||||||
height: auto !important; /* 确保高度自适应 */
|
height: auto !important;
|
||||||
padding: 8px 0 !important; /* 增加垂直内边距 */
|
/* 确保高度自适应 */
|
||||||
|
padding: 8px 0 !important;
|
||||||
|
/* 增加垂直内边距 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,341 +0,0 @@
|
|||||||
import { ref } from 'vue'
|
|
||||||
import { getApiBaseUrl } from '@/utils/runtimeEnv.js'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* WGT热更新处理
|
|
||||||
* 静默下载更新,无需重启应用
|
|
||||||
*/
|
|
||||||
export function useHotUpdate() {
|
|
||||||
const updating = ref(false)
|
|
||||||
const hasNewVersion = ref(false)
|
|
||||||
const currentVersion = ref('')
|
|
||||||
const latestVersion = ref('')
|
|
||||||
const downloadProgress = ref(0)
|
|
||||||
const serverWgtUrl = ref('') // 保存服务器更新包地址
|
|
||||||
|
|
||||||
// 测试模式相关状态
|
|
||||||
const isTestMode = ref(false)
|
|
||||||
const mockWgtUrl = 'https://example.com/mock-update.wgt' // 模拟更新包地址
|
|
||||||
|
|
||||||
// 获取当前应用版本
|
|
||||||
const getCurrentVersion = () => {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
plus.runtime.getProperty(plus.runtime.appid, function(inf) {
|
|
||||||
const wgtVer = inf.version
|
|
||||||
currentVersion.value = wgtVer
|
|
||||||
resolve(wgtVer)
|
|
||||||
})
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef APP-PLUS
|
|
||||||
const defaultVersion = '1.0.0' // 非APP环境下的默认值
|
|
||||||
currentVersion.value = defaultVersion
|
|
||||||
resolve(defaultVersion)
|
|
||||||
// #endif
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 只检查版本,不自动更新
|
|
||||||
* 适用于手动触发的更新检查
|
|
||||||
*/
|
|
||||||
const checkVersionOnly = async () => {
|
|
||||||
try {
|
|
||||||
// 测试模式直接返回有新版本
|
|
||||||
if (isTestMode.value) {
|
|
||||||
await getCurrentVersion()
|
|
||||||
latestVersion.value = incrementVersion(currentVersion.value)
|
|
||||||
serverWgtUrl.value = mockWgtUrl
|
|
||||||
hasNewVersion.value = true
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前版本
|
|
||||||
await getCurrentVersion()
|
|
||||||
|
|
||||||
// 替换为使用回调函数的方式
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
uni.request({
|
|
||||||
url: `${getApiBaseUrl()}/app/version`,
|
|
||||||
method: 'GET',
|
|
||||||
success: (res) => {
|
|
||||||
if (!res || res.statusCode !== 200 || !res.data || res.data.code !== 200 || !res.data.data) {
|
|
||||||
resolve(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const serverInfo = res.data.data
|
|
||||||
latestVersion.value = serverInfo.version
|
|
||||||
|
|
||||||
// 保存服务器wgt地址,以便后续手动更新使用
|
|
||||||
if (serverInfo.wgtUrl) {
|
|
||||||
serverWgtUrl.value = serverInfo.wgtUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
// 比较版本号,检查是否有新版本
|
|
||||||
hasNewVersion.value = compareVersion(serverInfo.version, currentVersion.value) > 0
|
|
||||||
|
|
||||||
resolve(hasNewVersion.value)
|
|
||||||
},
|
|
||||||
fail: (error) => {
|
|
||||||
console.error('检查版本失败', error)
|
|
||||||
resolve(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('检查版本失败', error)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动增加版本号,用于测试
|
|
||||||
*/
|
|
||||||
const incrementVersion = (version) => {
|
|
||||||
const parts = version.split('.')
|
|
||||||
const lastPart = parseInt(parts[parts.length - 1]) + 1
|
|
||||||
parts[parts.length - 1] = lastPart.toString()
|
|
||||||
return parts.join('.')
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启用或禁用测试模式
|
|
||||||
*/
|
|
||||||
const toggleTestMode = (enabled = true) => {
|
|
||||||
isTestMode.value = enabled
|
|
||||||
console.log('测试模式已' + (enabled ? '启用' : '禁用'))
|
|
||||||
return isTestMode.value
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查更新并自动静默更新(App.vue使用)
|
|
||||||
const checkUpdate = async () => {
|
|
||||||
try {
|
|
||||||
// 如果是测试模式,不进行实际的静默更新
|
|
||||||
if (isTestMode.value) {
|
|
||||||
await getCurrentVersion()
|
|
||||||
latestVersion.value = incrementVersion(currentVersion.value)
|
|
||||||
hasNewVersion.value = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前版本
|
|
||||||
await getCurrentVersion()
|
|
||||||
|
|
||||||
// 替换为使用回调函数的方式
|
|
||||||
uni.request({
|
|
||||||
url: `${getApiBaseUrl()}/app/version`,
|
|
||||||
method: 'GET',
|
|
||||||
success: (res) => {
|
|
||||||
if (!res || res.statusCode !== 200 || !res.data || res.data.code !== 200 || !res.data.data) return
|
|
||||||
console.log('update version res', res)
|
|
||||||
const serverInfo = res.data.data
|
|
||||||
latestVersion.value = serverInfo.version
|
|
||||||
|
|
||||||
// 比较版本号,检查是否有新版本
|
|
||||||
if (compareVersion(serverInfo.version, currentVersion.value) > 0) {
|
|
||||||
hasNewVersion.value = true
|
|
||||||
// 如果有wgt下载地址,执行静默更新
|
|
||||||
if (serverInfo.wgtUrl) {
|
|
||||||
serverWgtUrl.value = serverInfo.wgtUrl
|
|
||||||
silentUpdate(serverInfo.wgtUrl)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hasNewVersion.value = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fail: (error) => {
|
|
||||||
console.error('检查更新失败', error)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
console.error('检查更新失败', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 比较版本号 (v1 > v2 返回1,v1 < v2 返回-1,相等返回0)
|
|
||||||
const compareVersion = (v1, v2) => {
|
|
||||||
const v1Parts = v1.split('.').map(Number)
|
|
||||||
const v2Parts = v2.split('.').map(Number)
|
|
||||||
|
|
||||||
for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
|
|
||||||
const v1Part = v1Parts[i] || 0
|
|
||||||
const v2Part = v2Parts[i] || 0
|
|
||||||
|
|
||||||
if (v1Part > v2Part) return 1
|
|
||||||
if (v1Part < v2Part) return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 静默下载并安装更新
|
|
||||||
const silentUpdate = (wgtUrl) => {
|
|
||||||
if (updating.value) return Promise.reject('更新已在进行中')
|
|
||||||
|
|
||||||
updating.value = true
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
const dtask = plus.downloader.createDownload(wgtUrl, {
|
|
||||||
filename: '_doc/update/'
|
|
||||||
}, (download, status) => {
|
|
||||||
if (status === 200) {
|
|
||||||
installing(download.filename)
|
|
||||||
.then(() => {
|
|
||||||
updating.value = false
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
updating.value = false
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
updating.value = false
|
|
||||||
reject('下载更新包失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
dtask.start()
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef APP-PLUS
|
|
||||||
updating.value = false
|
|
||||||
resolve() // 非APP环境下直接返回成功
|
|
||||||
// #endif
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 安装wgt包
|
|
||||||
const installing = (filePath) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
plus.runtime.install(filePath, {
|
|
||||||
force: false // 不重启应用
|
|
||||||
}, () => {
|
|
||||||
console.log('安装wgt成功')
|
|
||||||
resolve()
|
|
||||||
// 删除下载的安装包
|
|
||||||
plus.io.resolveLocalFileSystemURL(filePath, (entry) => {
|
|
||||||
entry.remove()
|
|
||||||
})
|
|
||||||
}, (error) => {
|
|
||||||
console.error('安装wgt失败', error)
|
|
||||||
reject(error)
|
|
||||||
})
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef APP-PLUS
|
|
||||||
resolve() // 非APP环境下直接返回成功
|
|
||||||
// #endif
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手动更新,提供进度回调
|
|
||||||
* @param {string} wgtUrl 更新包下载地址
|
|
||||||
* @returns {Promise} 返回更新结果Promise
|
|
||||||
*/
|
|
||||||
const manualUpdate = (wgtUrl) => {
|
|
||||||
if (updating.value) return Promise.reject('更新已在进行中')
|
|
||||||
|
|
||||||
updating.value = true
|
|
||||||
downloadProgress.value = 0
|
|
||||||
|
|
||||||
// 如果是测试模式,模拟下载进度而不实际下载
|
|
||||||
if (isTestMode.value) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
let progress = 0
|
|
||||||
const interval = setInterval(() => {
|
|
||||||
progress += 5
|
|
||||||
downloadProgress.value = progress
|
|
||||||
|
|
||||||
if (progress >= 100) {
|
|
||||||
clearInterval(interval)
|
|
||||||
setTimeout(() => {
|
|
||||||
updating.value = false
|
|
||||||
resolve()
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
}, 200)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
const dtask = plus.downloader.createDownload(wgtUrl, {
|
|
||||||
filename: '_doc/update/'
|
|
||||||
}, (download, status) => {
|
|
||||||
if (status === 200) {
|
|
||||||
installing(download.filename)
|
|
||||||
.then(() => {
|
|
||||||
updating.value = false
|
|
||||||
resolve()
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
updating.value = false
|
|
||||||
reject(err)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
updating.value = false
|
|
||||||
reject('下载更新包失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 监听下载进度
|
|
||||||
dtask.addEventListener('statechanged', (task, status) => {
|
|
||||||
switch (task.state) {
|
|
||||||
case 1: // 开始
|
|
||||||
console.log('开始下载更新...')
|
|
||||||
break
|
|
||||||
case 2: // 已连接到服务器
|
|
||||||
console.log('已连接到服务器...')
|
|
||||||
break
|
|
||||||
case 3: // 下载中
|
|
||||||
const totalSize = task.totalSize
|
|
||||||
const downloadedSize = task.downloadedSize
|
|
||||||
const progress = Math.round(downloadedSize / totalSize * 100) || 0
|
|
||||||
downloadProgress.value = progress
|
|
||||||
console.log(`下载进度: ${progress}%`)
|
|
||||||
break
|
|
||||||
case 4: // 下载完成
|
|
||||||
console.log('下载完成')
|
|
||||||
downloadProgress.value = 100
|
|
||||||
break
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
dtask.start()
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef APP-PLUS
|
|
||||||
// 模拟下载进度
|
|
||||||
let progress = 0
|
|
||||||
const timer = setInterval(() => {
|
|
||||||
progress += 5
|
|
||||||
downloadProgress.value = progress
|
|
||||||
if (progress >= 100) {
|
|
||||||
clearInterval(timer)
|
|
||||||
updating.value = false
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}, 200)
|
|
||||||
// #endif
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
updating,
|
|
||||||
hasNewVersion,
|
|
||||||
currentVersion,
|
|
||||||
latestVersion,
|
|
||||||
downloadProgress,
|
|
||||||
serverWgtUrl,
|
|
||||||
isTestMode,
|
|
||||||
checkUpdate,
|
|
||||||
checkVersionOnly,
|
|
||||||
manualUpdate,
|
|
||||||
toggleTestMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,12 +23,11 @@ function handleClickLeft() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<wd-navbar :title="title" left-text="返回" placeholder left-arrow safe-area-inset-top fixed @click-left="handleClickLeft" />
|
<wd-navbar :title="title" left-text="返回" placeholder left-arrow safe-area-inset-top fixed
|
||||||
|
@click-left="handleClickLeft" />
|
||||||
<view class="box-border min-h-screen">
|
<view class="box-border min-h-screen">
|
||||||
<slot />
|
<slot />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -369,7 +369,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, reactive, computed } from 'vue'
|
import { ref, onMounted, reactive, computed } from 'vue'
|
||||||
import { useToast } from 'wot-design-uni'
|
import { useToast } from 'wot-design-uni'
|
||||||
import { activateAgentMembership } from '@/apis/agent'
|
import { activateAgentMembership, getAgentMembershipInfo } from '@/apis/agent'
|
||||||
import { formatExpiryTime } from '@/utils/format'
|
import { formatExpiryTime } from '@/utils/format'
|
||||||
import { getCompanyName } from '@/utils/runtimeEnv.js'
|
import { getCompanyName } from '@/utils/runtimeEnv.js'
|
||||||
|
|
||||||
@@ -451,6 +451,12 @@ const buttonClass = computed(() => {
|
|||||||
return `${baseClass} bg-gradient-to-r from-amber-500 to-amber-600 active:from-amber-600 active:to-amber-700 text-white`
|
return `${baseClass} bg-gradient-to-r from-amber-500 to-amber-600 active:from-amber-600 active:to-amber-700 text-white`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function toFiniteNumber(value, fallback = 0) {
|
||||||
|
if (value === null || value === undefined || value === '') return fallback
|
||||||
|
const n = typeof value === 'number' ? value : Number(value)
|
||||||
|
return Number.isFinite(n) ? n : fallback
|
||||||
|
}
|
||||||
|
|
||||||
// VIP价格配置
|
// VIP价格配置
|
||||||
const vipConfig = reactive({
|
const vipConfig = reactive({
|
||||||
price: 399, // VIP价格
|
price: 399, // VIP价格
|
||||||
@@ -630,6 +636,8 @@ const revenueData = computed(() => {
|
|||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// 从本地缓存获取代理信息
|
// 从本地缓存获取代理信息
|
||||||
loadAgentInfo()
|
loadAgentInfo()
|
||||||
|
// 从后端加载会员配置(价格和收益参数)
|
||||||
|
await loadMembershipInfo()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 从本地缓存加载代理信息
|
// 从本地缓存加载代理信息
|
||||||
@@ -650,20 +658,52 @@ const loadAgentInfo = () => {
|
|||||||
|
|
||||||
const selectedType = ref('vip') // 默认选择VIP
|
const selectedType = ref('vip') // 默认选择VIP
|
||||||
const showPayment = ref(false)
|
const showPayment = ref(false)
|
||||||
|
function buildPayData(type) {
|
||||||
|
return {
|
||||||
|
product_name: `${type === 'vip' ? 'VIP' : 'SVIP'}代理`,
|
||||||
|
sell_price: type === 'vip' ? toFiniteNumber(vipConfig.price) : toFiniteNumber(vipConfig.svipPrice),
|
||||||
|
}
|
||||||
|
}
|
||||||
const payData = ref({
|
const payData = ref({
|
||||||
product_name: `${selectedType.value.toUpperCase()}代理`,
|
product_name: `${selectedType.value.toUpperCase()}代理`,
|
||||||
sell_price: vipConfig.price,
|
sell_price: toFiniteNumber(vipConfig.price),
|
||||||
})
|
})
|
||||||
const payID = ref('')
|
const payID = ref('')
|
||||||
|
|
||||||
|
async function loadMembershipInfo() {
|
||||||
|
try {
|
||||||
|
const res = await getAgentMembershipInfo()
|
||||||
|
if (res.code !== 200 || !res.data) return
|
||||||
|
|
||||||
|
const configData = res.data
|
||||||
|
if (configData.vip_config) {
|
||||||
|
const vipData = configData.vip_config
|
||||||
|
vipConfig.price = toFiniteNumber(vipData.price, vipConfig.price)
|
||||||
|
vipConfig.vipCommission = toFiniteNumber(vipData.report_commission, vipConfig.vipCommission)
|
||||||
|
vipConfig.vipFloatingRate = toFiniteNumber(vipData.price_ratio, vipConfig.vipFloatingRate / 100) * 100
|
||||||
|
vipConfig.vipConversionBonus = toFiniteNumber(vipData.lower_convert_vip_reward, vipConfig.vipConversionBonus)
|
||||||
|
vipConfig.vipWithdrawalLimit = toFiniteNumber(vipData.exemption_amount, vipConfig.vipWithdrawalLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configData.svip_config) {
|
||||||
|
const svipData = configData.svip_config
|
||||||
|
vipConfig.svipPrice = toFiniteNumber(svipData.price, vipConfig.svipPrice)
|
||||||
|
vipConfig.svipCommission = toFiniteNumber(svipData.report_commission, vipConfig.svipCommission)
|
||||||
|
vipConfig.svipFloatingRate = toFiniteNumber(svipData.price_ratio, vipConfig.svipFloatingRate / 100) * 100
|
||||||
|
vipConfig.withdrawRatio = toFiniteNumber(svipData.lower_withdraw_reward_ratio, vipConfig.withdrawRatio / 100) * 100
|
||||||
|
vipConfig.svipConversionBonus = toFiniteNumber(svipData.lower_convert_svip_reward, vipConfig.svipConversionBonus)
|
||||||
|
vipConfig.svipWithdrawalLimit = toFiniteNumber(svipData.exemption_amount, vipConfig.svipWithdrawalLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
payData.value = buildPayData(selectedType.value)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
// 选择代理类型
|
// 选择代理类型
|
||||||
function selectType(type) {
|
function selectType(type) {
|
||||||
selectedType.value = type
|
selectedType.value = type
|
||||||
// 更新payData中的价格和产品名称
|
// 更新payData中的价格和产品名称
|
||||||
payData.value = {
|
payData.value = buildPayData(type)
|
||||||
product_name: `${type === 'vip' ? 'VIP' : 'SVIP'}代理`,
|
|
||||||
sell_price: type === 'vip' ? vipConfig.price : vipConfig.svipPrice,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 申请VIP或SVIP
|
// 申请VIP或SVIP
|
||||||
@@ -681,6 +721,11 @@ async function applyVip() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if (toFiniteNumber(payData.value.sell_price) <= 0) {
|
||||||
|
toast.error('会员价格加载中,请稍后重试')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const res = await activateAgentMembership({
|
const res = await activateAgentMembership({
|
||||||
type: selectedType.value.toUpperCase(),
|
type: selectedType.value.toUpperCase(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
<!-- 定价 -->
|
<!-- 定价 -->
|
||||||
<wd-input label="客户查询价" label-width="100px" v-model="formData.clientPrice" placeholder="请输入价格" readonly
|
<wd-input label="客户查询价" label-width="100px" v-model="formData.clientPrice" placeholder="请输入价格" readonly
|
||||||
clickable @click="showPricePicker = true" prop="clientPrice" suffix-icon="arrow-right"
|
clickable @click="openPricePicker" prop="clientPrice" suffix-icon="arrow-right"
|
||||||
:rules="[{ required: true, message: '请输入客户查询价' }]" />
|
:rules="[{ required: true, message: '请输入客户查询价' }]" />
|
||||||
</wd-cell-group>
|
</wd-cell-group>
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ const generatePromotionCode = async () => {
|
|||||||
try {
|
try {
|
||||||
const res = await generatePromotionLink({
|
const res = await generatePromotionLink({
|
||||||
product: formData.value.productType,
|
product: formData.value.productType,
|
||||||
price: formData.value.clientPrice
|
price: String(formData.value.clientPrice)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
@@ -201,7 +201,8 @@ const selectProductType = (reportTypeValue) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
pickerProductConfig.value = matchedConfig
|
pickerProductConfig.value = matchedConfig
|
||||||
formData.value.clientPrice = Number(matchedConfig.p_pricing_standard)
|
// 与 App / H5 一致:默认客户查询价取成本价
|
||||||
|
formData.value.clientPrice = matchedConfig.cost_price
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取产品配置
|
// 获取产品配置
|
||||||
@@ -242,10 +243,23 @@ const onPriceChange = (price) => {
|
|||||||
formData.value.clientPrice = price
|
formData.value.clientPrice = price
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openPricePicker = () => {
|
||||||
|
if (!pickerProductConfig.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '请选择有效报告类型',
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
showPricePicker.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 类型选择确认
|
// 类型选择确认
|
||||||
const onConfirmType = (e) => {
|
const onConfirmType = (e) => {
|
||||||
const selectedValue = e?.value?.[0] ?? e?.value ?? e?.selectedOptions?.[0]?.value
|
const rawValue = e?.value ?? e?.selectedItems?.[0]?.value ?? e?.selectedOptions?.[0]?.value
|
||||||
if (selectedValue !== undefined && selectedValue !== null && selectedValue !== '')
|
const selectedValue = Array.isArray(rawValue) ? rawValue[0] : rawValue
|
||||||
|
if (selectedValue === undefined || selectedValue === null || selectedValue === '')
|
||||||
|
return
|
||||||
selectProductType(selectedValue)
|
selectProductType(selectedValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import { useHotUpdate } from '@/composables/useHotUpdate'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自动更新检查工具
|
|
||||||
* 用于在应用运行期间定期检查更新
|
|
||||||
*/
|
|
||||||
class AutoUpdateChecker {
|
|
||||||
constructor() {
|
|
||||||
this.checkInterval = 4 * 60 * 60 * 1000 // 默认4小时检查一次更新
|
|
||||||
this.timer = null
|
|
||||||
this.hotUpdate = useHotUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动定时检查
|
|
||||||
* @param {Number} interval 可选,检查间隔时间(毫秒)
|
|
||||||
*/
|
|
||||||
startAutoCheck(interval) {
|
|
||||||
// 先清除可能存在的定时器
|
|
||||||
this.stopAutoCheck()
|
|
||||||
|
|
||||||
// 设置检查间隔时间
|
|
||||||
if (interval && typeof interval === 'number') {
|
|
||||||
this.checkInterval = interval
|
|
||||||
}
|
|
||||||
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
// 启动定时器
|
|
||||||
this.timer = setInterval(() => {
|
|
||||||
this.hotUpdate.checkUpdate()
|
|
||||||
}, this.checkInterval)
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止定时检查
|
|
||||||
*/
|
|
||||||
stopAutoCheck() {
|
|
||||||
if (this.timer) {
|
|
||||||
clearInterval(this.timer)
|
|
||||||
this.timer = null
|
|
||||||
}
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 立即执行一次检查
|
|
||||||
*/
|
|
||||||
checkNow() {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
this.hotUpdate.checkUpdate()
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建单例
|
|
||||||
const autoUpdateChecker = new AutoUpdateChecker()
|
|
||||||
|
|
||||||
export default autoUpdateChecker
|
|
||||||
Reference in New Issue
Block a user