From 8eb253784a4452c2d5da4b7286a7bd909ad96262 Mon Sep 17 00:00:00 2001 From: Dev Date: Wed, 14 Oct 2026 15:46:49 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9C=80=E6=B1=82=E5=88=97=E8=A1=A8=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E5=88=B7=E6=96=B0=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/application/api/controller/Common.php | 3 ++ .../common/service/DemandService.php | 43 +++++++++++++++---- .../miniapp/pages/demand/contract/index.js | 18 +++++++- .../miniapp/pages/demand/contract/index.wxml | 2 +- frontend/miniapp/pages/demand/detail/index.js | 22 ++++++++-- .../miniapp/pages/demand/detail/index.wxml | 2 +- frontend/miniapp/services/home/home.js | 36 ++++++++++++++++ 7 files changed, 111 insertions(+), 15 deletions(-) diff --git a/backend/application/api/controller/Common.php b/backend/application/api/controller/Common.php index 6069d23..a9111a8 100644 --- a/backend/application/api/controller/Common.php +++ b/backend/application/api/controller/Common.php @@ -7,6 +7,7 @@ use app\common\exception\UploadException; use app\common\library\Upload; use app\common\model\Area; use app\common\model\Version; +use app\common\service\DemandService; use fast\Random; use think\captcha\Captcha; use think\Config; @@ -189,6 +190,8 @@ class Common extends Api 'backendLabels' => $toLabels($back_techs), 'otherLabels' => $toLabels($other_techs), 'developTypes' => $developTypes, + // 平台服务费比例(0~1),前端据此计算开发者预计到手金额 + 'platform_commission_ratio' => (float)DemandService::getPlatformCommissionRatio(), ]; $this->success('', $config); diff --git a/backend/application/common/service/DemandService.php b/backend/application/common/service/DemandService.php index 52c6dfb..da27180 100644 --- a/backend/application/common/service/DemandService.php +++ b/backend/application/common/service/DemandService.php @@ -72,6 +72,36 @@ class DemandService const BUTTON_CONFIRM_RECEIPT = 'confirmReceipt'; //确认收货 const BUTTON_DELIVER_GOODS = 'deliverGoods'; //开发者发货 + /** + * 获取平台服务费比例(0~1),后台填写大于 1 时按百分比处理,如 10 表示 10% + * @return string + */ + public static function getPlatformCommissionRatio(): string + { + $ratio = config('site.platform_commission_ratio'); + if (!is_numeric($ratio) || $ratio <= 0) { + return '0'; + } + $ratio = (string)$ratio; + if (bccomp($ratio, '1', 4) > 0) { + $ratio = bcdiv($ratio, '100', 4); + } + + return bccomp($ratio, '1', 4) > 0 ? '1' : bcadd($ratio, '0', 4); + } + + /** + * 计算扣除平台服务费后开发者实得金额 + * @param mixed $amount 订单金额(元) + * @return string + */ + public static function getDeveloperIncome($amount): string + { + $ratio = self::getPlatformCommissionRatio(); + + return bcmul((string)$amount, bcsub('1', $ratio, 4), 2); + } + /** * 创建需求 * @@ -600,8 +630,7 @@ class DemandService $userId = $contract->demandBidding->user_id; //开发者冻结金额增加 $demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FIRST_PAYMENT); - $ratio = (float)config('site.platform_commission_ratio'); - $amount = $demandOrder->payment_amount * (1 - $ratio); + $amount = self::getDeveloperIncome($demandOrder->payment_amount); $title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益'; $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id); AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id); @@ -638,8 +667,7 @@ class DemandService $userId = $demand->winBidding->user_id; //开发者冻结金额增加 $demandOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT); - $ratio = (float)config('site.platform_commission_ratio'); - $amount = $demandOrder->payment_amount * (1 - $ratio); + $amount = self::getDeveloperIncome($demandOrder->payment_amount); $title = OrderService::ORDER_TYPE_MAP[$demandOrder->order_type] ?? '需求收益'; $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, $userId, $amount, $title . '-冻结金额增加', AccountLogService::TYPE_FREEZE, 0, AccountLogService::INC_EXP_INCREASE, $demandOrder->id); AccountService::updateData($userId, 0, $amount, 0, 0, $log_res->id); @@ -728,12 +756,11 @@ class DemandService 'order_status' => DemandService::STATUS_CONFIRM_RECEIPT, 'settle_status' => CommonService::ONGOING, ]; - $ratio = (float)config('site.platform_commission_ratio'); - Demands::with(['demandContracts', 'winBidding'])->where($where)->chunk(100, function ($demands) use ($ratio) { + Demands::with(['demandContracts', 'winBidding'])->where($where)->chunk(100, function ($demands) { foreach ($demands as $demand) { try { //开启事务 抛出异常时自动回滚 - DB::transaction(function () use ($demand, $ratio) { + DB::transaction(function () use ($demand) { $userId = $demand->merchant->user_id; $show_time = $demand->goodsInfo->show_time ? $demand->goodsInfo->show_time : $demand->goodsInfo->created_at; Log::info('订单收益解冻:', ['show_time' => $show_time, 'unfreeze_time' => strtotime(date('Y-m-d', strtotime($show_time) + 3 * 3600) . ' 09:00')]); @@ -741,7 +768,7 @@ class DemandService $demand->status = DemandService::STATUS_FINISHED; $demand->settle_status = CommonService::SUCCESS; $demand->save(); - $amount = ($demand->demandContracts->total_amount ?? 0) * (1 - $ratio); + $amount = self::getDeveloperIncome($demand->demandContracts->total_amount ?? 0); //写入余额日志 $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_FREEZE, -$amount, '需求收益解冻-冻结扣除', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount); $log_res = AccountLogService::addLog(AccountLogService::ACCOUNT_TYPE_AMOUNT, +$amount, '需求收益解冻-余额增加', AccountLogService::TYPE_UNFREEZE, 0, $demand->id, $demand->order_amount); diff --git a/frontend/miniapp/pages/demand/contract/index.js b/frontend/miniapp/pages/demand/contract/index.js index deae751..792e928 100644 --- a/frontend/miniapp/pages/demand/contract/index.js +++ b/frontend/miniapp/pages/demand/contract/index.js @@ -1,5 +1,6 @@ import { fetchDemandContractDetail, demandOperate } from '../../../services/demand/fetchDemand'; +import { fetchPlatformCommissionRatio, calcActualAccount } from '../../../services/home/home'; // pages/demand/contract/index.js Page({ @@ -9,6 +10,8 @@ Page({ data: { demandId: 0, actualAccount: 0, + commissionRatio: 0.1, // 平台服务费比例,来自 common/getMiniConfig + commissionPercent: 10, // 平台服务费百分比,用于提示文案 contract: null, agreementUrl: '', // 签约条款URL phoneError: '', // 个人联系电话错误提示 @@ -61,6 +64,17 @@ Page({ agreementUrl }); this.getContractDetail(); + this.loadCommissionRatio(); + }, + + // 拉取平台服务费比例,并按新比例重算预计到手金额 + async loadCommissionRatio() { + const ratio = await fetchPlatformCommissionRatio(); + this.setData({ + commissionRatio: ratio, + commissionPercent: Math.round(ratio * 10000) / 100, + actualAccount: calcActualAccount(this.data.formData?.totalCost, ratio) + }); }, /** @@ -191,10 +205,9 @@ Page({ }, onTotalCostChange(e) { - const number = Number(e.detail.value * 0.9); this.setData({ 'formData.totalCost': e.detail.value, - 'actualAccount': Math.round(e.detail.value * 0.9) + actualAccount: calcActualAccount(e.detail.value, this.data.commissionRatio) }); }, @@ -518,6 +531,7 @@ Page({ 'formData.taskContent': resData.task_content, 'formData.needDays': resData.need_days, 'formData.totalCost': resData.total_amount, + actualAccount: calcActualAccount(resData.total_amount, this.data.commissionRatio), }); // 客户签约时,附件展示开发者签约时上传的附件,仅可预览,不可删除和上传 diff --git a/frontend/miniapp/pages/demand/contract/index.wxml b/frontend/miniapp/pages/demand/contract/index.wxml index 14920e6..7ca21a2 100644 --- a/frontend/miniapp/pages/demand/contract/index.wxml +++ b/frontend/miniapp/pages/demand/contract/index.wxml @@ -64,7 +64,7 @@ /> - + diff --git a/frontend/miniapp/pages/demand/detail/index.js b/frontend/miniapp/pages/demand/detail/index.js index 296c600..b4b1e29 100644 --- a/frontend/miniapp/pages/demand/detail/index.js +++ b/frontend/miniapp/pages/demand/detail/index.js @@ -1,5 +1,6 @@ // pages/demand/detail.js import { fetchDemandDetail, joinDemandBidding, demandOperate } from '../../../services/demand/fetchDemand'; +import { fetchPlatformCommissionRatio, calcActualAccount } from '../../../services/home/home'; Page({ /** @@ -11,6 +12,8 @@ Page({ needDays: '', remark: '', actualAccount: 0, + commissionRatio: 0.1, // 平台服务费比例,来自 common/getMiniConfig + commissionPercent: 10, // 平台服务费百分比,用于提示文案 activeValues: [0, 1, 2, 3, 4], demandInfo: null, freshPage: false, // 返回本页时是否需要重新拉取详情(签约/发货/支付后置为 true) @@ -33,7 +36,7 @@ Page({ const demandInfo = res.data; this.setData({ demandInfo, - actualAccount: parseFloat(demandInfo?.myBidding?.quoted_price || demandInfo?.demand_contracts?.total_amount || 0) * 0.9 + actualAccount: calcActualAccount(this.getQuoteAmount(demandInfo), this.data.commissionRatio) }, () => resolve()); // setData 回调:页面已重新渲染 }, () => { @@ -43,6 +46,19 @@ Page({ ); }); }, + // 报价金额:优先已投标报价,其次合同总费用,最后为当前输入 + getQuoteAmount(demandInfo) { + return demandInfo?.myBidding?.quoted_price || demandInfo?.demand_contracts?.total_amount || this.data.quotedPrice || 0; + }, + // 拉取平台服务费比例,并按新比例重算预计到手金额 + async loadCommissionRatio() { + const ratio = await fetchPlatformCommissionRatio(); + this.setData({ + commissionRatio: ratio, + commissionPercent: Math.round(ratio * 10000) / 100, + actualAccount: calcActualAccount(this.getQuoteAmount(this.data.demandInfo), ratio) + }); + }, // 取文件扩展名对应的 openDocument 类型(默认 pdf) getFileType(url) { const ext = String(url || '').split('?')[0].split('#')[0].split('.').pop().toLowerCase(); @@ -178,8 +194,7 @@ Page({ const field = e.currentTarget.dataset.field; const value = e.detail.value; if (field == 'quotedPrice') { - let actualAccount = parseInt(value * 0.9); - this.setData({ actualAccount }); + this.setData({ actualAccount: calcActualAccount(value, this.data.commissionRatio) }); } this.setData({ [`${field}`]: value @@ -682,6 +697,7 @@ Page({ opType }); this.loadDemandDetail(id); + this.loadCommissionRatio(); wx.$util.checkSubscriptionsSetting(); //从列表「前去验收」进入时,提示先到沟通群查看/体验交付成果再验收 if (options.fromAccept == '1') { diff --git a/frontend/miniapp/pages/demand/detail/index.wxml b/frontend/miniapp/pages/demand/detail/index.wxml index 0292549..bcfc571 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxml +++ b/frontend/miniapp/pages/demand/detail/index.wxml @@ -44,7 +44,7 @@ - + 报价 diff --git a/frontend/miniapp/services/home/home.js b/frontend/miniapp/services/home/home.js index 2f8c91e..46de38b 100644 --- a/frontend/miniapp/services/home/home.js +++ b/frontend/miniapp/services/home/home.js @@ -56,3 +56,39 @@ export function fetchHome() { export function fetchConfig() { return wx.$util.request(wx.$api.CommonGetMiniConfig, {}, 'GET'); } + +// 与后端 site.platform_commission_ratio 默认值一致,接口失败时兜底 +const DEFAULT_COMMISSION_RATIO = 0.1; +let commissionRatioCache = null; + +/** + * 获取平台服务费比例(0~1),成功后缓存,失败返回默认值且不缓存,下次重新请求 + * @returns {Promise} + */ +export async function fetchPlatformCommissionRatio() { + if (commissionRatioCache !== null) { + return commissionRatioCache; + } + try { + const res = await fetchConfig(); + const ratio = Number(res?.data?.platform_commission_ratio); + if (res.code === 1 && ratio >= 0 && ratio <= 1) { + commissionRatioCache = ratio; + return ratio; + } + } catch (err) { + console.error('fetchPlatformCommissionRatio failed:', err); + } + return DEFAULT_COMMISSION_RATIO; +} + +/** + * 计算扣除平台服务费后的预计到手金额(保留两位小数) + * @param {number|string} amount 报价/总费用(元) + * @param {number} ratio 平台服务费比例 + * @returns {number} + */ +export function calcActualAccount(amount, ratio) { + const value = Number(amount) || 0; + return Math.round(value * (1 - ratio) * 100) / 100; +}