From 25804d500e7d3aab4e5a32d836ad4c4f2161eed3 Mon Sep 17 00:00:00 2001 From: Dev Date: Tue, 27 Oct 2026 18:30:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E5=B8=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/admin/lang/zh-cn/demands.php | 1 + backend/application/api/controller/Demand.php | 4 +++ .../common/service/DemandService.php | 2 ++ .../common/service/VirtualPayService.php | 9 +++--- backend/application/extra/common.php | 2 +- backend/public/assets/js/backend/demands.js | 1 + .../miniapp/pages/demand/contract/index.js | 28 +++++++++++------ .../miniapp/pages/demand/contract/index.wxml | 2 +- frontend/miniapp/pages/demand/detail/index.js | 30 ++++++++++++------- .../miniapp/pages/demand/detail/index.wxml | 2 +- .../miniapp/pages/demand/publish/index.js | 12 ++++++++ 11 files changed, 66 insertions(+), 27 deletions(-) diff --git a/backend/application/admin/lang/zh-cn/demands.php b/backend/application/admin/lang/zh-cn/demands.php index 201dd16..73d81b1 100644 --- a/backend/application/admin/lang/zh-cn/demands.php +++ b/backend/application/admin/lang/zh-cn/demands.php @@ -11,6 +11,7 @@ return [ 'Files' => '附件', 'Desc' => '需求详情', 'Contact' => '联系方式', + 'Pay_platform' => '发布终端', 'Budget_amount' => '预算(元)', 'Limit_time' => '工期(天)', 'Weigh' => '排序', diff --git a/backend/application/api/controller/Demand.php b/backend/application/api/controller/Demand.php index f2cfb9a..8e70585 100644 --- a/backend/application/api/controller/Demand.php +++ b/backend/application/api/controller/Demand.php @@ -8,6 +8,7 @@ use app\common\service\ContractService; use app\common\service\DemandBiddingService; use app\common\service\DemandService; use app\common\service\OrderShipService; +use app\common\service\VirtualPayService; use think\exception\HttpResponseException; use think\Lang; use think\Validate; @@ -273,6 +274,9 @@ class Demand extends Api try { $demandId = $this->request->param('demandId', 0); $info = ContractService::getWinBiddingContract($demandId); + $demand = DemandService::getOne(['id' => $demandId]); + $platform = $demand ? VirtualPayService::normalizePayPlatform($demand->pay_platform) : ''; + $info->pay_platform = $platform !== '' ? $platform : 'android'; if (empty($info->data_json['customData']) && ($firstContract = ContractService::getFirstContract($demandId))) { $data_json = $info->data_json; $data_json['customData'] = $firstContract->data_json['customData'] ?? []; diff --git a/backend/application/common/service/DemandService.php b/backend/application/common/service/DemandService.php index 5b5c220..673ab80 100644 --- a/backend/application/common/service/DemandService.php +++ b/backend/application/common/service/DemandService.php @@ -151,6 +151,8 @@ class DemandService 'files' => $data['files'] ?? [], 'budget_amount' => $data['budget_amount'] ?? 0, 'limit_time' => $data['limit_time'] ?? 0, + // 客户发布需求时的手机系统,报价预估按这个终端。真正付款可能换设备,以支付记录为准 + 'pay_platform' => VirtualPayService::normalizePayPlatform($data['pay_platform'] ?? '') ?: 'android', 'publish_status' => CommonService::ONGOING, 'status' => self::STATUS_NO ]; diff --git a/backend/application/common/service/VirtualPayService.php b/backend/application/common/service/VirtualPayService.php index c1b61e8..38f35d7 100644 --- a/backend/application/common/service/VirtualPayService.php +++ b/backend/application/common/service/VirtualPayService.php @@ -481,8 +481,9 @@ class VirtualPayService } /** + * 代币数量,保留两位小数。1元=1代币时,0.01元对应 0.01 个代币 * @param float|string $amountYuan - * @return int + * @return float * @throws \Exception */ private static function coinQuantity($amountYuan) @@ -495,11 +496,9 @@ class VirtualPayService if ($coinPerYuan < 1) { $coinPerYuan = 1; } - if (($fen * $coinPerYuan) % 100 !== 0) { - throw new \Exception('订单金额须为整数元才能按1元=1代币支付'); - } + $quantity = bcdiv(bcmul((string)$fen, (string)$coinPerYuan, 0), '100', 2); - return intdiv($fen * $coinPerYuan, 100); + return (float)$quantity; } /** diff --git a/backend/application/extra/common.php b/backend/application/extra/common.php index 8baa73b..187003b 100644 --- a/backend/application/extra/common.php +++ b/backend/application/extra/common.php @@ -40,7 +40,7 @@ return [ 'transfer_authorization_notify_url' => Env::get('app.url') . '/api/account/transferAuthorizationNotify', ], // 小程序虚拟支付(类目不支持普通微信支付时使用) - // 代币比例须与 MP「虚拟支付-代币配置」一致:1元=1代币。buyQuantity 只能是整数,订单金额须为整数元 + // 代币比例须与 MP「虚拟支付-代币配置」一致:1元=1代币。数量保留两位小数,0.01元=0.01代币 'virtual_pay' => [ 'offer_id' => Env::get('wechat.vp_offer_id', ''), 'app_key' => Env::get('wechat.vp_app_key', ''), // 现网 AppKey,env=0 diff --git a/backend/public/assets/js/backend/demands.js b/backend/public/assets/js/backend/demands.js index fdd308a..790f14e 100644 --- a/backend/public/assets/js/backend/demands.js +++ b/backend/public/assets/js/backend/demands.js @@ -60,6 +60,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin class: 'autocontent', formatter: Table.api.formatter.content }, + {field: 'pay_platform', title: __('Pay_platform'), searchList: {"android":"安卓","ios":"苹果"}, formatter: Table.api.formatter.normal}, {field: 'budget_amount', title: __('Budget_amount'), operate: 'BETWEEN'}, {field: 'limit_time', title: __('Limit_time'), operate: false}, {field: 'weigh', title: __('Weigh'), operate: false}, diff --git a/frontend/miniapp/pages/demand/contract/index.js b/frontend/miniapp/pages/demand/contract/index.js index bddd3d1..433f86f 100644 --- a/frontend/miniapp/pages/demand/contract/index.js +++ b/frontend/miniapp/pages/demand/contract/index.js @@ -9,8 +9,10 @@ Page({ */ data: { demandId: 0, - androidAccount: 0, - iosAccount: 0, + actualAccount: 0, + payPlatform: 'android', // 客户发布需求时的手机系统 + platformName: '安卓', + payFeePercent: 1, commissionRatio: 0.1, // 平台服务费比例,来自 common/getMiniConfig commissionPercent: 10, androidPayFeeRate: 0.01, @@ -73,12 +75,17 @@ Page({ }, incomePreview(amount, rates) { - const commissionRatio = rates ? rates.commissionRatio : this.data.commissionRatio; - const androidPayFeeRate = rates ? rates.androidPayFeeRate : this.data.androidPayFeeRate; - const iosPayFeeRate = rates ? rates.iosPayFeeRate : this.data.iosPayFeeRate; + const commissionRatio = rates && rates.commissionRatio !== undefined ? rates.commissionRatio : this.data.commissionRatio; + const androidPayFeeRate = rates && rates.androidPayFeeRate !== undefined ? rates.androidPayFeeRate : this.data.androidPayFeeRate; + const iosPayFeeRate = rates && rates.iosPayFeeRate !== undefined ? rates.iosPayFeeRate : this.data.iosPayFeeRate; + const rawPlatform = rates && rates.payPlatform !== undefined ? rates.payPlatform : this.data.payPlatform; + const payPlatform = rawPlatform === 'ios' ? 'ios' : 'android'; + const payFeeRate = payPlatform === 'ios' ? iosPayFeeRate : androidPayFeeRate; return { - androidAccount: calcActualAccount(amount, commissionRatio, androidPayFeeRate), - iosAccount: calcActualAccount(amount, commissionRatio, iosPayFeeRate), + actualAccount: calcActualAccount(amount, commissionRatio, payFeeRate), + payPlatform, + payFeePercent: toPercent(payFeeRate), + platformName: payPlatform === 'ios' ? 'iOS' : '安卓', }; }, // 拉取平台服务费和支付费率,并重算预计到手金额 @@ -91,7 +98,10 @@ Page({ iosPayFeeRate: rates.iosPayFeeRate, androidFeePercent: toPercent(rates.androidPayFeeRate), iosFeePercent: toPercent(rates.iosPayFeeRate), - ...this.incomePreview(this.data.formData?.totalCost, rates), + ...this.incomePreview(this.data.formData?.totalCost, { + ...rates, + payPlatform: this.data.payPlatform, + }), }); }, @@ -549,7 +559,7 @@ Page({ 'formData.taskContent': resData.task_content, 'formData.needDays': resData.need_days, 'formData.totalCost': resData.total_amount, - ...this.incomePreview(resData.total_amount), + ...this.incomePreview(resData.total_amount, { payPlatform: resData.pay_platform }), }); // 客户签约时,附件展示开发者签约时上传的附件,仅可预览,不可删除和上传 diff --git a/frontend/miniapp/pages/demand/contract/index.wxml b/frontend/miniapp/pages/demand/contract/index.wxml index 08a6821..ce2e179 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 320adfb..477653d 100644 --- a/frontend/miniapp/pages/demand/detail/index.js +++ b/frontend/miniapp/pages/demand/detail/index.js @@ -11,8 +11,10 @@ Page({ quotedPrice: '', needDays: '', remark: '', - androidAccount: 0, - iosAccount: 0, + actualAccount: 0, + payPlatform: 'android', // 客户发布需求时的手机系统 + platformName: '安卓', + payFeePercent: 1, commissionRatio: 0.1, // 平台服务费比例,来自 common/getMiniConfig commissionPercent: 10, androidPayFeeRate: 0.01, @@ -41,7 +43,7 @@ Page({ const demandInfo = res.data; this.setData({ demandInfo, - ...this.incomePreview(this.getQuoteAmount(demandInfo)) + ...this.incomePreview(this.getQuoteAmount(demandInfo), { payPlatform: demandInfo.pay_platform }) }, () => resolve()); // setData 回调:页面已重新渲染 }, () => { @@ -55,14 +57,19 @@ Page({ getQuoteAmount(demandInfo) { return demandInfo?.myBidding?.quoted_price || demandInfo?.demand_contracts?.total_amount || this.data.quotedPrice || 0; }, - // 按当前报价计算安卓、iOS 两种预计到手 + // 按客户发布需求时的手机系统计算预计到手 incomePreview(amount, rates) { - const commissionRatio = rates ? rates.commissionRatio : this.data.commissionRatio; - const androidPayFeeRate = rates ? rates.androidPayFeeRate : this.data.androidPayFeeRate; - const iosPayFeeRate = rates ? rates.iosPayFeeRate : this.data.iosPayFeeRate; + const commissionRatio = rates && rates.commissionRatio !== undefined ? rates.commissionRatio : this.data.commissionRatio; + const androidPayFeeRate = rates && rates.androidPayFeeRate !== undefined ? rates.androidPayFeeRate : this.data.androidPayFeeRate; + const iosPayFeeRate = rates && rates.iosPayFeeRate !== undefined ? rates.iosPayFeeRate : this.data.iosPayFeeRate; + const rawPlatform = rates && rates.payPlatform !== undefined ? rates.payPlatform : this.data.payPlatform; + const payPlatform = rawPlatform === 'ios' ? 'ios' : 'android'; + const payFeeRate = payPlatform === 'ios' ? iosPayFeeRate : androidPayFeeRate; return { - androidAccount: calcActualAccount(amount, commissionRatio, androidPayFeeRate), - iosAccount: calcActualAccount(amount, commissionRatio, iosPayFeeRate), + actualAccount: calcActualAccount(amount, commissionRatio, payFeeRate), + payPlatform, + payFeePercent: toPercent(payFeeRate), + platformName: payPlatform === 'ios' ? 'iOS' : '安卓', }; }, // 拉取平台服务费和支付费率,并重算预计到手金额 @@ -75,7 +82,10 @@ Page({ iosPayFeeRate: rates.iosPayFeeRate, androidFeePercent: toPercent(rates.androidPayFeeRate), iosFeePercent: toPercent(rates.iosPayFeeRate), - ...this.incomePreview(this.getQuoteAmount(this.data.demandInfo), rates), + ...this.incomePreview(this.getQuoteAmount(this.data.demandInfo), { + ...rates, + payPlatform: (this.data.demandInfo && this.data.demandInfo.pay_platform) || this.data.payPlatform, + }), }); }, // 取文件扩展名对应的 openDocument 类型(默认 pdf) diff --git a/frontend/miniapp/pages/demand/detail/index.wxml b/frontend/miniapp/pages/demand/detail/index.wxml index a50558d..867ebf0 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/pages/demand/publish/index.js b/frontend/miniapp/pages/demand/publish/index.js index 808e303..76b80cf 100644 --- a/frontend/miniapp/pages/demand/publish/index.js +++ b/frontend/miniapp/pages/demand/publish/index.js @@ -4,6 +4,17 @@ import { fetchConfig } from '../../../services/home/home'; // 联系方式:仅允许英文、数字、下划线、中划线(不含中文与特殊字符) const CONTACT_REG = /^[A-Za-z0-9_-]+$/; +// 客户发布需求时的手机系统。iOS 单独记,其余按安卓 +function currentPayPlatform() { + let platform = ''; + try { + platform = String((wx.getSystemInfoSync() || {}).platform || '').toLowerCase(); + } catch (err) { + platform = ''; + } + return platform === 'ios' ? 'ios' : 'android'; +} + Page({ /** @@ -170,6 +181,7 @@ Page({ budget_amount: budgetAmount, limit_time: limitTime, contact: contact, + pay_platform: currentPayPlatform(), }, 'POST').then(res => { if (res.code === 1) { wx.requestSubscribeMessage({