Files
tydata-mini/src/pages/agentVipConfig.vue
liangzai e8dea8b561
Some checks failed
Check / lint (18.x, macos-latest) (push) Has been cancelled
Check / lint (18.x, ubuntu-latest) (push) Has been cancelled
Check / lint (18.x, windows-latest) (push) Has been cancelled
Check / lint (20.x, macos-latest) (push) Has been cancelled
Check / lint (20.x, ubuntu-latest) (push) Has been cancelled
Check / lint (20.x, windows-latest) (push) Has been cancelled
Check / lint (22.x, macos-latest) (push) Has been cancelled
Check / lint (22.x, ubuntu-latest) (push) Has been cancelled
Check / lint (22.x, windows-latest) (push) Has been cancelled
Check / typecheck (18.x, macos-latest) (push) Has been cancelled
Check / typecheck (18.x, ubuntu-latest) (push) Has been cancelled
Check / typecheck (18.x, windows-latest) (push) Has been cancelled
Check / typecheck (20.x, macos-latest) (push) Has been cancelled
Check / typecheck (20.x, ubuntu-latest) (push) Has been cancelled
Check / typecheck (20.x, windows-latest) (push) Has been cancelled
Check / typecheck (22.x, macos-latest) (push) Has been cancelled
Check / typecheck (22.x, ubuntu-latest) (push) Has been cancelled
Check / typecheck (22.x, windows-latest) (push) Has been cancelled
Check / build (build, 18.x, macos-latest) (push) Has been cancelled
Check / build (build, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 18.x, windows-latest) (push) Has been cancelled
Check / build (build, 20.x, macos-latest) (push) Has been cancelled
Check / build (build, 20.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 20.x, windows-latest) (push) Has been cancelled
Check / build (build, 22.x, macos-latest) (push) Has been cancelled
Check / build (build, 22.x, ubuntu-latest) (push) Has been cancelled
Check / build (build, 22.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 18.x, macos-latest) (push) Has been cancelled
Check / build (build:app, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 20.x, macos-latest) (push) Has been cancelled
Check / build (build:app, 20.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 20.x, windows-latest) (push) Has been cancelled
Check / build (build:app, 22.x, macos-latest) (push) Has been cancelled
Check / build (build:app, 22.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:app, 22.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, macos-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 18.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 20.x, macos-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 20.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 20.x, windows-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 22.x, macos-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 22.x, ubuntu-latest) (push) Has been cancelled
Check / build (build:mp-weixin, 22.x, windows-latest) (push) Has been cancelled
first commit
2026-02-10 14:13:29 +08:00

514 lines
19 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="p-4 mx-auto min-h-screen">
<!-- 标题部分 -->
<view class="card mb-4 p-4 bg-gradient-to-r from-blue-500 to-blue-600 rounded-lg shadow-lg text-white">
<text class="text-2xl font-extrabold mb-2 block">专业报告定价配置</text>
<text class="opacity-90 block">请选择报告类型并设置定价策略助您实现精准定价</text>
</view>
<view class="mb-4 bg-white rounded-lg overflow-hidden px-4 flex items-center justify-between">
<span class="text-blue-600 font-medium text-sm">📝 选择报告</span>
<wd-picker custom-class="flex-1" v-model="selectedReportText" :columns="reportOptions" title="选择报告类型"
@confirm="onConfirm" />
</view>
<view v-if="selectedReportText" class="space-y-6">
<!-- 配置卡片 -->
<view class="card">
<!-- 当前报告标题 -->
<view class="flex items-center mb-6">
<text class="text-xl font-semibold text-gray-800">
{{ selectedReportText }}配置
</text>
</view>
<!-- 显示当前产品的基础成本信息 -->
<view v-if="productConfigData && productConfigData.cost_price"
class="px-4 py-2 mb-4 bg-gray-50 border border-gray-200 rounded-lg shadow-sm">
<text class="text-lg font-semibold text-gray-700 block">报告基础配置信息</text>
<view class="mt-1 text-sm text-gray-600">
<text class="block">基础成本价<text class="font-medium">{{ productConfigData.cost_price }}</text> </text>
<text class="block">最高设定金额上限<text class="font-medium">{{ productConfigData.price_range_max }}</text>
</text>
<text class="block">最高设定比例上限<text class="font-medium">{{ priceRatioMax }}</text> %</text>
</view>
</view>
<!-- 分隔线 -->
<view class="my-6 flex items-center justify-center">
<view class="bg-gray-200 h-px flex-1"></view>
<text class="mx-2 text-gray-400 text-sm">成本策略配置</text>
<view class="bg-gray-200 h-px flex-1"></view>
</view>
<!-- 表单部分 -->
<wd-form>
<!-- 加价金额 -->
<wd-form-item label="加价金额" prop="price_increase_amount">
<wd-input v-model="configData.price_increase_amount" type="number" placeholder="0"
@blur="validateDecimal('price_increase_amount')" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示最大加价金额为{{ priceIncreaseAmountMax }}</text>
<text class="block">说明加价金额是在基础成本价上增加的额外费用决定下级报告的最低定价您将获得所有输入的金额利润</text>
</view>
<!-- 分隔线 -->
<view class="my-6 flex items-center justify-center">
<view class="bg-gray-200 h-px flex-1"></view>
<text class="mx-2 text-gray-400 text-sm">定价策略配置</text>
<view class="bg-gray-200 h-px flex-1"></view>
</view>
<!-- 定价区间最低 -->
<wd-form-item label="定价区间最低" prop="price_range_from">
<wd-input v-model="configData.price_range_from" type="number" placeholder="0"
@blur="() => { validateDecimal('price_range_from'); validateRange(); }" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示定价区间最低金额不能低于基础最低 {{ productConfigData?.price_range_min || 0 }} + 加价金额</text>
<text class="block">说明设定的定价区间最低金额为定价区间的起始值若下级设定的报告金额在区间内则区间内部分将按比例获得收益</text>
</view>
<!-- 定价区间最高 -->
<wd-form-item label="定价区间最高" prop="price_range_to">
<wd-input v-model="configData.price_range_to" type="number" placeholder="0"
@blur="() => { validateDecimal('price_range_to'); validateRange(); }" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示定价区间最高金额不能超过上限{{ productConfigData?.price_range_max || 0 }}和大于定价区间最低金额{{
priceIncreaseMax
}}</text>
<text class="block">说明设定的定价区间最高金额为定价区间的结束值若下级设定的报告金额在区间内则区间内部分将按比例获得收益</text>
</view>
<!-- 收取比例 -->
<wd-form-item label="收取比例" prop="price_ratio">
<wd-input v-model="configData.price_ratio" type="number" placeholder="0" @blur="validateRatio" />
</wd-form-item>
<view class="text-xs text-gray-400 mt-1">
<text class="block">提示最大收取比例为{{ priceRatioMax }}%</text>
<text class="block">说明收取比例表示对定价区间内即报告金额超过最低金额小于最高金额的部分的金额按此比例进行利润分成</text>
</view>
</wd-form>
</view>
<!-- 保存按钮 -->
<button type="primary" class="bg-blue-500 text-white py-1 rounded-xl w-full" @click="handleSubmit">
保存当前报告配置
</button>
</view>
<!-- 未选择提示 -->
<view v-else class="text-center py-12">
<text class="text-gray-400 text-4xl block mb-4"></text>
<text class="text-gray-500 block">请先选择需要配置的报告类型</text>
</view>
</view>
</template>
<script setup>
import { ref, reactive, computed, onMounted, watch } from 'vue'
import { getAgentMembershipUserConfig, saveAgentMembershipUserConfig } from '@/apis/agent'
// 报告类型选项
const reportOptions = [
{ label: '人事背调', value: 1 },
{ label: '老板企业报告', value: 2 },
{ label: '家政风险', value: 3 },
{ label: '婚恋风险', value: 4 },
{ label: '贷前背调', value: 5 },
{ label: '租赁风险', value: 6 },
{ label: '个人风险', value: 7 },
]
// 状态管理
const showPicker = ref(false)
const selectedReportId = ref(1)
const selectedReportText = ref('人事背调')
const configData = ref({})
const productConfigData = ref({})
const priceIncreaseMax = ref(null)
const priceIncreaseAmountMax = ref(null)
const priceRatioMax = ref(null)
const rangeError = ref(false)
const ratioError = ref(false)
const increaseError = ref(false)
// 金额输入格式验证:确保最多两位小数
const validateDecimal = (field) => {
console.log(`validateDecimal开始: field=${field}, 值=${configData.value[field]}`)
const value = configData.value[field]
if (value === null || value === undefined) {
console.log(`validateDecimal: ${field}为空,退出验证`)
return
}
const numValue = Number(value)
if (isNaN(numValue)) {
console.log(`validateDecimal: ${field}无法转换为数字设置为null`)
configData.value[field] = null
return
}
const fixedValue = parseFloat(numValue.toFixed(2))
console.log(`validateDecimal: ${field}原值=${numValue},处理后=${fixedValue}`)
configData.value[field] = fixedValue
if (field === 'price_increase_amount') {
console.log(`validateDecimal: 检查加价金额上限 ${fixedValue} vs ${priceIncreaseAmountMax.value}`)
if (fixedValue > priceIncreaseAmountMax.value) {
configData.value[field] = priceIncreaseAmountMax.value
console.log(`validateDecimal: 加价金额超过上限,已修正为${priceIncreaseAmountMax.value}`)
uni.showToast({
title: `加价金额最大为${priceIncreaseAmountMax.value}`,
icon: 'none'
})
increaseError.value = true
setTimeout(() => {
increaseError.value = false
}, 2000)
} else {
increaseError.value = false
}
// 当加价金额改变后,重新验证价格区间
validateRange()
}
console.log(`validateDecimal结束: ${field}最终值=${configData.value[field]}`)
}
// 价格区间验证
const validateRange = () => {
console.log('validateRange开始:',
`最低=${configData.value.price_range_from}`,
`最高=${configData.value.price_range_to}`)
// if (configData.value.price_range_from === null || configData.value.price_range_to === null) {
// console.log('validateRange: 价格区间值为null退出验证')
// rangeError.value = false
// return
// }
if (isNaN(configData.value.price_range_from) || isNaN(configData.value.price_range_to)) {
console.log('validateRange: 价格区间值非数字,退出验证')
return
}
const additional = configData.value.price_increase_amount || 0
console.log(`validateRange: 加价金额=${additional}`)
const minAllowed = parseFloat(
(Number(productConfigData.value.cost_price) + Number(additional)).toFixed(2)
) // 使用成本价作为最小值
const maxAllowed = productConfigData.value.price_range_max // 使用产品配置中的最大价格作为最大值
console.log(`validateRange: 最低允许=${minAllowed}, 最高允许=${maxAllowed}`)
// 检查最低金额
if (configData.value.price_range_from < minAllowed) {
console.log(`validateRange: 定价区间最低金额(${configData.value.price_range_from})小于允许最低值(${minAllowed}),进行修正`)
configData.value.price_range_from = minAllowed
uni.showToast({
title: `定价区间最低金额不能低于成本价 ${minAllowed}`,
icon: 'none'
})
rangeError.value = true
closeRangeError()
configData.value.price_range_to = parseFloat(
(Number(configData.value.price_range_from) + Number(priceIncreaseMax.value)).toFixed(2)
)
console.log(`validateRange: 已调整最高金额为 ${configData.value.price_range_to}`)
return
}
// 检查最高金额是否小于最低金额
if (configData.value.price_range_to < configData.value.price_range_from) {
console.log(`validateRange: 定价区间最高金额(${configData.value.price_range_to})小于最低金额(${configData.value.price_range_from}),进行修正`)
uni.showToast({
title: '定价区间最高金额不能低于定价区间最低金额',
icon: 'none'
})
if (configData.value.price_range_from + priceIncreaseMax.value > maxAllowed) {
configData.value.price_range_to = maxAllowed
console.log(`validateRange: 最高值已修正为最大允许值 ${maxAllowed}`)
} else {
configData.value.price_range_to = configData.value.price_range_from + priceIncreaseMax.value
console.log(`validateRange: 最高值已修正为最低金额+最大增加值 ${configData.value.price_range_to}`)
}
rangeError.value = true
closeRangeError()
return
}
// 检查差值
const diff = parseFloat(
(configData.value.price_range_to - configData.value.price_range_from).toFixed(2)
)
console.log(`validateRange: 价格区间差值=${diff}, 最大允许差值=${priceIncreaseMax.value}`)
if (diff > priceIncreaseMax.value) {
console.log(`validateRange: 价格区间差值超过最大允许值,进行修正`)
uni.showToast({
title: `价格区间最大差值为${priceIncreaseMax.value}`,
icon: 'none'
})
configData.value.price_range_to = parseFloat(
(Number(configData.value.price_range_from) + Number(priceIncreaseMax.value)).toFixed(2)
)
console.log(`validateRange: 已调整最高金额为 ${configData.value.price_range_to}`)
closeRangeError()
return
}
// 检查最高金额是否超过上限
if (configData.value.price_range_to > maxAllowed) {
console.log(`validateRange: 定价区间最高金额(${configData.value.price_range_to})超过上限(${maxAllowed}),进行修正`)
configData.value.price_range_to = maxAllowed
uni.showToast({
title: `定价区间最高金额不能超过 ${maxAllowed}`,
icon: 'none'
})
closeRangeError()
}
if (!rangeError.value) {
rangeError.value = false
}
console.log('validateRange结束:',
`最终最低=${configData.value.price_range_from}`,
`最终最高=${configData.value.price_range_to}`)
}
// 收取比例验证(修改为保留两位小数,不再四舍五入取整)
const validateRatio = () => {
console.log(`validateRatio开始: 值=${configData.value.price_ratio}`)
let value = configData.value.price_ratio
if (value === null || value === undefined) {
console.log('validateRatio: 值为空,退出验证')
return
}
const numValue = Number(value)
if (isNaN(numValue)) {
console.log('validateRatio: 值无法转换为数字设置为null')
configData.value.price_ratio = null
ratioError.value = true
return
}
console.log(`validateRatio: 检查比例范围 ${numValue} vs 最大值${priceRatioMax.value}`)
if (numValue > priceRatioMax.value) {
console.log(`validateRatio: 比例超过最大值,已修正为${priceRatioMax.value}`)
configData.value.price_ratio = priceRatioMax.value
uni.showToast({
title: `收取比例最大为${priceRatioMax.value}%`,
icon: 'none'
})
ratioError.value = true
setTimeout(() => {
ratioError.value = false
}, 1000)
} else if (numValue < 0) {
console.log('validateRatio: 比例小于0已修正为0')
configData.value.price_ratio = 0
ratioError.value = true
} else {
configData.value.price_ratio = parseFloat(numValue.toFixed(2))
ratioError.value = false
}
console.log(`validateRatio结束: 最终值=${configData.value.price_ratio}`)
}
// 获取配置
const getConfig = async () => {
try {
console.log(`getConfig开始: 获取产品ID=${selectedReportId.value}的配置`)
const res = await getAgentMembershipUserConfig({ product_id: selectedReportId.value })
if (res.code === 200) {
const respConfigData = res.data.agent_membership_user_config
console.log("respConfigData", respConfigData)
configData.value = {
id: respConfigData.product_id,
price_range_from: respConfigData.price_range_from || null,
price_range_to: respConfigData.price_range_to || null,
price_ratio: respConfigData.price_ratio * 100 || null, // 转换为百分比
price_increase_amount: respConfigData.price_increase_amount || null,
}
productConfigData.value = res.data.product_config
// 设置动态限制值
priceIncreaseMax.value = res.data.price_increase_max
priceIncreaseAmountMax.value = res.data.price_increase_amount
priceRatioMax.value = res.data.price_ratio * 100
console.log('getConfig: 配置加载成功',
`最大差值=${priceIncreaseMax.value}`,
`最大加价=${priceIncreaseAmountMax.value}`,
`最大比例=${priceRatioMax.value}%`)
console.log('getConfig: 当前配置', configData.value)
}
} catch (error) {
console.error("getConfig错误:", error)
uni.showToast({
title: '配置加载失败',
icon: 'none'
})
}
}
// 提交处理
const handleSubmit = async () => {
try {
if (!finalValidation()) {
return
}
// 前端数据转换
const submitData = {
product_id: configData.value.id,
price_range_from: configData.value.price_range_from || 0,
price_range_to: configData.value.price_range_to || 0,
price_ratio: (configData.value.price_ratio || 0) / 100, // 转换为小数
price_increase_amount: configData.value.price_increase_amount || 0,
}
const res = await saveAgentMembershipUserConfig(submitData)
if (res.code === 200) {
uni.showToast({
title: '保存成功',
icon: 'success'
})
getConfig()
}
} catch (error) {
console.log("handleSubmit错误:", error)
uni.showToast({
title: '保存失败,请稍后重试',
icon: 'none'
})
}
}
// 最终验证函数
const finalValidation = () => {
// 校验最低金额不能为空且大于0
if (!configData.value.price_range_from || configData.value.price_range_from <= 0) {
uni.showToast({
title: "定价区间最低金额不能为空",
icon: 'none'
})
return false
}
// 校验最高金额不能为空且大于0
if (!configData.value.price_range_to || configData.value.price_range_to <= 0) {
uni.showToast({
title: "定价区间最高金额不能为空",
icon: 'none'
})
return false
}
// 校验收取比例不能为空且大于0
if (!configData.value.price_ratio || configData.value.price_ratio <= 0) {
uni.showToast({
title: "收取比例不能为空",
icon: 'none'
})
return false
}
// 验证最低金额必须小于最高金额
if (configData.value.price_range_from >= configData.value.price_range_to) {
uni.showToast({
title: "定价区间最低金额必须小于定价区间最高金额",
icon: 'none'
})
return false
}
// 验证价格区间差值不能超过最大允许差值
const finalDiff = parseFloat(
(configData.value.price_range_to - configData.value.price_range_from).toFixed(2)
)
if (finalDiff > priceIncreaseMax.value) {
uni.showToast({
title: `价格区间最大差值为${priceIncreaseMax.value}`,
icon: 'none'
})
return false
}
// 验证最高金额不能超过产品配置中设定的上限
if (configData.value.price_range_to > productConfigData.value.price_range_max) {
uni.showToast({
title: `定价区间最高金额不能超过${productConfigData.value.price_range_max}`,
icon: 'none'
})
return false
}
// 验证最低金额不能低于成本价+加价金额(加价金额允许为空)
const additional = configData.value.price_increase_amount || 0
if (configData.value.price_range_from < productConfigData.value.cost_price + additional) {
uni.showToast({
title: `定价区间最低金额不能低于成本价${productConfigData.value.cost_price + additional}`,
icon: 'none'
})
return false
}
return true
}
// 选择器确认
const onConfirm = (e) => {
const { selectedItems } = e
selectedReportId.value = selectedItems.value
selectedReportText.value = selectedItems.label
showPicker.value = false
// 重置错误状态
rangeError.value = false
ratioError.value = false
increaseError.value = false
getConfig()
}
const closeRangeError = () => {
setTimeout(() => {
rangeError.value = false
}, 2000)
}
onMounted(() => {
getConfig()
})
</script>
<style>
.card {
border-radius: 24rpx;
background-color: white;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
padding: 32rpx;
margin-bottom: 32rpx;
}
.space-y-6 {
display: flex;
flex-direction: column;
}
.space-y-6 > view {
margin-bottom: 48rpx;
}
.space-y-6 > view:last-child {
margin-bottom: 0;
}
</style>
<route type="page" lang="json">{
"layout": "page",
"title": "会员代理报告配置",
"agent": true,
"auth": true
}</route>