From 195a098101217f3853a4a83613b237d745f48c26 Mon Sep 17 00:00:00 2001 From: chen Date: Fri, 18 Sep 2026 10:42:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=B4=E6=97=B6=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E9=A9=AC=E8=B1=86=E7=BB=93=E7=AE=97=E4=B8=8E=E5=85=91=E6=8D=A2?= =?UTF-8?q?=E5=88=B8=E9=87=8A=E6=94=BE=E4=B8=BA1=E5=88=86=E9=92=9F?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E4=B8=80=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- addons/shopro/console/PartnerSettle.php | 30 +++- .../service/partner/DailySettleService.php | 142 ++++++++++++++++++ .../shopro/service/partner/MadowService.php | 80 ++++++++++ .../shopro/service/partner/VoucherService.php | 70 ++++++++- .../admin/controller/shopro/Dashboard.php | 6 + .../admin/view/shopro/dashboard/index.html | 9 +- public/assets/js/backend/shopro/dashboard.js | 2 + ...verify_madow_dashboard_and_integer_spec.js | 12 +- tests/verify_minute_settle_spec.js | 87 +++++++++++ 9 files changed, 428 insertions(+), 10 deletions(-) create mode 100644 tests/verify_minute_settle_spec.js diff --git a/addons/shopro/console/PartnerSettle.php b/addons/shopro/console/PartnerSettle.php index 505951a..1395d2a 100644 --- a/addons/shopro/console/PartnerSettle.php +++ b/addons/shopro/console/PartnerSettle.php @@ -13,22 +13,40 @@ class PartnerSettle extends Command protected function configure() { $this->setName('shopro:partner:settle') - ->addOption('date', 'd', Option::VALUE_OPTIONAL, '结算日期 Y-m-d,默认昨天') + ->addOption('date', 'd', Option::VALUE_OPTIONAL, '结算日期 Y-m-d,指定日期时执行传统日结') ->addOption('rerun', 'r', Option::VALUE_NONE, '删除当天日结后重算') - ->setDescription('收益中心日结(马豆/馆县均分/兑换券释放)'); + ->addOption('daily', null, Option::VALUE_NONE, '强制执行昨天标准日结') + ->setDescription('收益中心结算(默认1分钟马豆增量结算与兑换券释放,亦支持指定日期日结)'); } protected function execute(Input $input, Output $output) { $date = $input->getOption('date'); $rerun = (bool) $input->getOption('rerun'); - $output->writeln('partner settle start ' . ($date ?: 'yesterday') . ($rerun ? ' rerun' : '')); + $isDaily = (bool) $input->getOption('daily'); + + // 指定日期或强制日结模式 + if ($date || $isDaily || $rerun) { + $settleDate = $date ?: date('Y-m-d', strtotime('-1 day')); + $output->writeln('partner daily settle start ' . $settleDate . ($rerun ? ' rerun' : '')); + try { + $report = (new DailySettleService())->run($date, $rerun); + $output->writeln('partner daily settle done: ' . json_encode($report ? $report->toArray() : [], JSON_UNESCAPED_UNICODE)); + return 0; + } catch (\Exception $e) { + $output->writeln('partner daily settle fail: ' . $e->getMessage()); + return 1; + } + } + + // 默认执行 1 分钟马豆增量结算与兑换券释放 + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle start'); try { - $report = (new DailySettleService())->run($date, $rerun); - $output->writeln('partner settle done: ' . json_encode($report ? $report->toArray() : [], JSON_UNESCAPED_UNICODE)); + $result = (new DailySettleService())->runMinute(); + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle done: ' . json_encode($result, JSON_UNESCAPED_UNICODE)); return 0; } catch (\Exception $e) { - $output->writeln('partner settle fail: ' . $e->getMessage()); + $output->writeln('[' . date('Y-m-d H:i:s') . '] partner minute settle fail: ' . $e->getMessage()); return 1; } } diff --git a/addons/shopro/service/partner/DailySettleService.php b/addons/shopro/service/partner/DailySettleService.php index 124c26b..18ae224 100644 --- a/addons/shopro/service/partner/DailySettleService.php +++ b/addons/shopro/service/partner/DailySettleService.php @@ -55,6 +55,148 @@ class DailySettleService } } + /** + * 临时分钟级调度:执行未结算订单的马豆分红,并释放一期兑换券 + */ + public function runMinute() + { + $lockDir = RUNTIME_PATH . 'lock'; + if (!is_dir($lockDir)) { + @mkdir($lockDir, 0755, true); + } + $lockFile = $lockDir . '/partner_settle_minute.lock'; + $fp = fopen($lockFile, 'c'); + if (!$fp || !flock($fp, LOCK_EX | LOCK_NB)) { + return ['status' => 'skipped', 'message' => '上一次分钟任务仍在执行中']; + } + + try { + $today = date('Y-m-d'); + $rateService = new RateService(); + $rewardService = new PartnerRewardService(); + $activeService = new ActiveService(); + + // 1. 兑换券 1 分钟释放一次 + $voucherTotal = (new VoucherService())->releaseMinute(); + + // 2. 马豆 1 分钟结算一次(提取已支付但尚未结算马豆的合格订单) + $allQualifiedOrders = $rateService->qualifiedOrderQuery()->field('o.id,o.pay_fee,o.user_id,o.ext,o.paid_time')->select(); + $unsettledOrders = []; + $madowGmv = 0; + + foreach ($allQualifiedOrders as $o) { + $ext = $o['ext'] ?? []; + if (is_string($ext)) { + $ext = json_decode($ext, true) ?: []; + } + if (empty($ext['madow_settled'])) { + $unsettledOrders[] = $o; + $qFee = $rewardService->getQualifiedPayFee($o); + $madowGmv = bcadd((string) $madowGmv, (string) $qFee, 2); + } + } + + $madowRes = ['pool' => 0, 'count' => 0, 'each' => 0]; + $settledOrderIds = []; + + if ((float) $madowGmv > 0 && !empty($unsettledOrders)) { + $settledOrderIds = array_column($unsettledOrders, 'id'); + $windowStart = time() - (PartnerConfig::activeDays() - 1) * 86400; + $tasterIds = $activeService->activeUserIds($windowStart, time()); + + $madowRes = (new MadowService())->shareMinute($madowGmv, $tasterIds, $settledOrderIds); + + // 标记订单已结算马豆 + foreach ($unsettledOrders as $o) { + $ext = $o['ext'] ?? []; + if (is_string($ext)) { + $ext = json_decode($ext, true) ?: []; + } + $ext['madow_settled'] = 1; + $ext['madow_settle_time'] = time(); + \think\Db::name('shopro_order')->where('id', $o['id'])->update([ + 'ext' => json_encode($ext, JSON_UNESCAPED_UNICODE), + ]); + } + + // 清除汇率缓存,联动大盘最新动态汇率 + RateService::clearCache(); + } + + // 3. 统计今日最新大盘并同步/创建今日 DailyReport + $todayStart = strtotime($today . ' 00:00:00'); + $todayEnd = strtotime($today . ' 23:59:59'); + $todayGmv = $rateService->qualifiedGmv($todayStart, $todayEnd); + $todayOrderCount = $rateService->qualifiedOrderQuery($todayStart, $todayEnd)->count(); + $orderCountN = $rateService->countN(); + $currentRate = $rateService->calcRate($orderCountN); + + // 当日累计发放兑换券总额 + $todayVoucherReleased = (float) \think\Db::name('shopro_partner_reward') + ->whereBetween('createtime', [$todayStart, $todayEnd]) + ->where('reward_type', 'voucher_release') + ->where('status', 1) + ->sum('amount'); + + // 当日累计发放马豆总额 + $todayMadowPool = (float) \think\Db::name('shopro_partner_reward') + ->whereBetween('createtime', [$todayStart, $todayEnd]) + ->where('reward_type', 'madow_share') + ->where('status', 1) + ->sum('madow'); + + $existingTodayReport = DailyReport::where('settle_date', $today)->find(); + if ($existingTodayReport) { + $existingTodayReport->order_count = $todayOrderCount; + $existingTodayReport->order_count_n = $orderCountN; + $existingTodayReport->gmv = $todayGmv; + $existingTodayReport->rate = $currentRate; + $existingTodayReport->madow_pool = $todayMadowPool; + $existingTodayReport->voucher_release_total = $todayVoucherReleased; + $existingTodayReport->updatetime = time(); + $existingTodayReport->save(); + } else { + DailyReport::create([ + 'settle_date' => $today, + 'order_count' => $todayOrderCount, + 'order_count_n' => $orderCountN, + 'gmv' => $todayGmv, + 'rate' => $currentRate, + 'madow_pool' => $todayMadowPool, + 'share_user_count' => $madowRes['count'] ?? 0, + 'venue_pool' => 0, + 'venue_user_count' => 0, + 'county_pool' => 0, + 'county_user_count' => 0, + 'voucher_release_total' => $todayVoucherReleased, + 'status' => 1, + 'error_msg' => '', + 'createtime' => time(), + 'updatetime' => time(), + ]); + } + + // 更新汇率日志 + $rateService->snapshot($today, $todayGmv, [ + 'madow_pool' => $todayMadowPool, + 'share_user_count' => $madowRes['count'] ?? 0, + ]); + + return [ + 'status' => 'success', + 'time' => date('Y-m-d H:i:s'), + 'voucher_released' => $voucherTotal, + 'madow_settled_gmv' => (float) $madowGmv, + 'madow_pool' => $madowRes['pool'], + 'madow_each' => $madowRes['each'], + 'settled_orders' => $settledOrderIds, + ]; + } finally { + flock($fp, LOCK_UN); + fclose($fp); + } + } + protected function settle($settleDate) { $start = strtotime($settleDate . ' 00:00:00'); diff --git a/addons/shopro/service/partner/MadowService.php b/addons/shopro/service/partner/MadowService.php index b09f77c..b4842c2 100644 --- a/addons/shopro/service/partner/MadowService.php +++ b/addons/shopro/service/partner/MadowService.php @@ -82,6 +82,86 @@ class MadowService return ['pool' => $pool, 'count' => $count, 'each' => $each]; } + /** + * 临时分钟级马豆结算均分 + */ + public function shareMinute($gmv, $userIds, $orderIds = []) + { + $count = count($userIds); + $pool = (float) $gmv; + if ($pool <= 0) { + return ['pool' => 0, 'count' => $count, 'each' => 0]; + } + + $minId = (int) \think\Db::name('shopro_partner_reward')->where('order_id', '<', 0)->min('order_id'); + $virtualOrderId = min(-100000, $minId - 1); + + if ($count <= 0) { + PartnerRewardService::write([ + 'order_id' => $virtualOrderId, + 'buyer_id' => 0, + 'user_id' => 0, + 'role' => 'system', + 'reward_type' => 'madow_share', + 'amount' => 0, + 'madow' => $pool, + 'base_amount' => $pool, + 'settle_date' => null, + 'ext' => ['formula' => "分母为0,马豆池 {$pool} 进平台", 'orders' => $orderIds], + 'status' => 1, + ]); + return ['pool' => $pool, 'count' => 0, 'each' => 0]; + } + + $each = function_exists('bcdiv') ? bcdiv((string) $pool, (string) $count, 8) : number_format($pool / $count, 8, '.', ''); + $distributed = 0; + $now = time(); + $chunks = array_chunk($userIds, 500); + + foreach ($chunks as $chunk) { + AgentModel::whereIn('user_id', $chunk)->setInc('madow', $each); + $batchRows = []; + foreach ($chunk as $userId) { + $batchRows[] = [ + 'order_id' => $virtualOrderId, + 'buyer_id' => 0, + 'user_id' => $userId, + 'role' => 'taster', + 'reward_type' => 'madow_share', + 'amount' => 0, + 'madow' => $each, + 'base_amount' => $pool, + 'settle_date' => null, + 'ext' => json_encode(['formula' => "GMV {$pool} / {$count} = {$each}", 'share_user_count' => $count, 'gmv' => $pool, 'orders' => $orderIds], JSON_UNESCAPED_UNICODE), + 'status' => 1, + 'createtime' => $now, + 'updatetime' => $now, + ]; + $distributed = function_exists('bcadd') ? bcadd((string) $distributed, (string) $each, 8) : ($distributed + $each); + } + \think\Db::name('shopro_partner_reward')->insertAll($batchRows); + } + + $tail = function_exists('bcsub') ? bcsub((string) $pool, (string) $distributed, 8) : round($pool - $distributed, 8); + if ((float) $tail > 0) { + PartnerRewardService::write([ + 'order_id' => $virtualOrderId, + 'buyer_id' => 0, + 'user_id' => 0, + 'role' => 'system', + 'reward_type' => 'madow_share', + 'amount' => 0, + 'madow' => $tail, + 'base_amount' => $pool, + 'settle_date' => null, + 'ext' => ['formula' => "尾差 {$tail} 进平台", 'orders' => $orderIds], + 'status' => 1, + ]); + } + + return ['pool' => $pool, 'count' => $count, 'each' => $each]; + } + public function rollback($settleDate) { $rows = \app\admin\model\shopro\partner\Reward::where('settle_date', $settleDate) diff --git a/addons/shopro/service/partner/VoucherService.php b/addons/shopro/service/partner/VoucherService.php index 104ff7b..5d98fdb 100644 --- a/addons/shopro/service/partner/VoucherService.php +++ b/addons/shopro/service/partner/VoucherService.php @@ -144,7 +144,8 @@ class VoucherService return null; } $daily = round($total / $days, 2); - $startDate = date('Y-m-d', strtotime('+1 day', $this->orderTime($order))); + // 临时模式:当天立即生效起算,支持 1 分钟释放联调 + $startDate = date('Y-m-d', $this->orderTime($order)); $plan = VoucherPlan::create([ 'user_id' => $buyerId, @@ -183,6 +184,73 @@ class VoucherService return $plan; } + /** + * 临时分钟级释放兑换券:每 1 分钟对所有释放中的计划释放一期 + * + * @return float 本次释放总金额 + */ + public function releaseMinute() + { + $plans = VoucherPlan::where('status', 1)->select(); + $totalReleased = 0; + foreach ($plans as $plan) { + if ($plan->released_days >= $plan->total_days || bccomp((string) $plan->released_amount, (string) $plan->total_amount, 2) >= 0) { + $plan->status = 2; + $plan->save(); + continue; + } + + $leftDays = $plan->total_days - $plan->released_days; + if ($leftDays <= 1) { + $amount = round((float) $plan->total_amount - (float) $plan->released_amount, 2); + $plan->status = 2; + } else { + $amount = (float) $plan->daily_amount; + } + + if ($amount <= 0) { + $plan->status = 2; + $plan->save(); + continue; + } + + $plan->released_amount = round((float) $plan->released_amount + $amount, 2); + $plan->released_days += 1; + if (bccomp((string) $plan->released_amount, (string) $plan->total_amount, 2) >= 0) { + $plan->status = 2; + } + $plan->save(); + + $agent = AgentModel::where('user_id', $plan->user_id)->find(); + if ($agent) { + $agent->setInc('voucher_released', $amount); + } + + // 唯一负数 order_id 规避与历史冲突;settle_date 设为 NULL 规避 uk_daily_user_type 唯一索引 + $virtualOrderId = -(intval($plan->id) * 1000 + (intval($plan->released_days) % 1000)); + PartnerRewardService::write([ + 'order_id' => $virtualOrderId, + 'buyer_id' => $plan->user_id, + 'user_id' => $plan->user_id, + 'role' => 'taster', + 'reward_type' => 'voucher_release', + 'amount' => $amount, + 'base_amount' => $amount, + 'settle_date' => null, + 'ext' => [ + 'formula' => "兑换券释放 {$amount}(第{$plan->released_days}/{$plan->total_days}期)", + 'plan_id' => $plan->id, + 'order_id' => $plan->order_id, + 'released_days' => $plan->released_days, + ], + 'status' => 1, + ]); + + $totalReleased = bcadd((string) $totalReleased, (string) $amount, 2); + } + return (float) $totalReleased; + } + public function releaseByDate($settleDate) { $plans = VoucherPlan::where('status', 1) diff --git a/application/admin/controller/shopro/Dashboard.php b/application/admin/controller/shopro/Dashboard.php index 8ad2978..ff7234e 100644 --- a/application/admin/controller/shopro/Dashboard.php +++ b/application/admin/controller/shopro/Dashboard.php @@ -141,12 +141,18 @@ class Dashboard extends Common $currentRate = $rateService->currentRate(); $totalMadowCny = round($totalMadow * $currentRate, 2); $historyOrderN = $rateService->countN(); + $rawBase = PartnerConfig::get('partner_madow_base_rate', '0.00000075'); + $baseRate = IdentityService::formatRate($rawBase); + $stepOrders = intval(PartnerConfig::get('partner_madow_step_orders', 1)); + $stepOrders = $stepOrders > 0 ? $stepOrders : 1; $latestReport = DailyReport::order('settle_date', 'desc')->find(); $yesterdayMadowPool = $latestReport ? (float) $latestReport->madow_pool : 0.00; $madowData = [ 'total_madow' => IdentityService::formatMadow($totalMadow), + 'base_rate' => $baseRate, + 'step_orders' => $stepOrders, 'current_rate' => number_format($currentRate, 10, '.', ''), 'rate_per_wan' => number_format($currentRate * 10000, 4, '.', ''), 'total_madow_cny' => number_format($totalMadowCny, 2, '.', ''), diff --git a/application/admin/view/shopro/dashboard/index.html b/application/admin/view/shopro/dashboard/index.html index 504cca9..7b2477d 100644 --- a/application/admin/view/shopro/dashboard/index.html +++ b/application/admin/view/shopro/dashboard/index.html @@ -518,7 +518,14 @@
③ 汇率计算公式: - 0.00000075 × {{ state.madow.history_order_n }} 单 + + + +
算法:基础汇率 × 累计完成单数 N diff --git a/public/assets/js/backend/shopro/dashboard.js b/public/assets/js/backend/shopro/dashboard.js index cc8e665..bb0c4cb 100644 --- a/public/assets/js/backend/shopro/dashboard.js +++ b/public/assets/js/backend/shopro/dashboard.js @@ -24,6 +24,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ( }, madow: { total_madow: '0', + base_rate: '0.00000075', + step_orders: 1, current_rate: '0.0000000000', rate_per_wan: '0.0000', total_madow_cny: '0.00', diff --git a/tests/verify_madow_dashboard_and_integer_spec.js b/tests/verify_madow_dashboard_and_integer_spec.js index 934f32d..9a08fd4 100644 --- a/tests/verify_madow_dashboard_and_integer_spec.js +++ b/tests/verify_madow_dashboard_and_integer_spec.js @@ -96,6 +96,14 @@ assert( dashboardControllerContent.includes("'history_order_n' => $historyOrderN"), '大盘接口输出历史累计完成订单数 history_order_n' ); +assert( + dashboardControllerContent.includes("'base_rate' => $baseRate"), + '大盘接口动态输出系统配置的基础汇率 base_rate' +); +assert( + dashboardControllerContent.includes("'step_orders' => $stepOrders"), + '大盘接口动态输出步进订单数 step_orders' +); // 6. 验证前端仪表盘模板 application/admin/view/shopro/dashboard/index.html 卡片设计 const dashboardViewPath = path.resolve(__dirname, '../application/admin/view/shopro/dashboard/index.html'); @@ -127,8 +135,8 @@ assert( '大盘视图展示每万豆价值 rate_per_wan' ); assert( - dashboardViewContent.includes('0.00000075 × {{ state.madow.history_order_n }} 单'), - '大盘视图直观呈现汇率计算公式 (0.00000075 × N 单)' + dashboardViewContent.includes("{{ state.madow.base_rate || '0.00000075' }} × {{ state.madow.history_order_n }} 单"), + '大盘视图呈现动态汇率计算公式 (动态 base_rate × N 单)' ); assert( dashboardViewContent.includes('日结池明细 →'), diff --git a/tests/verify_minute_settle_spec.js b/tests/verify_minute_settle_spec.js new file mode 100644 index 0000000..9480559 --- /dev/null +++ b/tests/verify_minute_settle_spec.js @@ -0,0 +1,87 @@ +const fs = require('fs'); +const path = require('path'); +const assert = require('assert'); + +console.log('========================================================'); +console.log(' 马豆 1 分钟增量结算与兑换券 1 分钟释放规范自动化测试'); +console.log('========================================================\n'); + +let passCount = 0; +function test(name, fn) { + try { + fn(); + console.log(` [PASS] ${name}`); + passCount++; + } catch (err) { + console.error(` [FAIL] ${name}: ${err.message}`); + process.exit(1); + } +} + +// 1. VoucherService 验证 +const voucherServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/VoucherService.php'); +assert(fs.existsSync(voucherServicePath), 'VoucherService.php 文件存在'); +const voucherContent = fs.readFileSync(voucherServicePath, 'utf-8'); + +test('VoucherService 包含 releaseMinute() 分钟级释放方法', () => { + assert(voucherContent.includes('function releaseMinute()'), '必须定义 releaseMinute()'); +}); + +test('VoucherService 包含立即生效起算逻辑', () => { + assert(voucherContent.includes("date('Y-m-d', $this->orderTime($order))"), '起算日期当天立即生效'); +}); + +test('VoucherService 分钟释放使用 NULL 结算日规避唯一索引冲突', () => { + assert(voucherContent.includes("'settle_date' => null"), 'settle_date 必须设为 null 避开 uk_daily_user_type 限制'); + assert(voucherContent.includes("$virtualOrderId = -(intval($plan->id) * 1000"), 'order_id 必须使用负数虚拟 ID 避开 uk_order_user_type 限制'); +}); + +// 2. MadowService 验证 +const madowServicePath = path.resolve(__dirname, '../addons/shopro/service/partner/MadowService.php'); +assert(fs.existsSync(madowServicePath), 'MadowService.php 文件存在'); +const madowContent = fs.readFileSync(madowServicePath, 'utf-8'); + +test('MadowService 包含 shareMinute() 分钟级马豆分红方法', () => { + assert(madowContent.includes('function shareMinute('), '必须定义 shareMinute()'); +}); + +test('MadowService 分钟分红使用防重虚拟 order_id 与 NULL 结算日', () => { + assert(madowContent.includes("'settle_date' => null"), 'settle_date 必须设为 null'); + assert(madowContent.includes("$virtualOrderId = min(-100000,"), '必须保证递减全局虚拟 order_id'); +}); + +// 3. DailySettleService 验证 +const dailySettlePath = path.resolve(__dirname, '../addons/shopro/service/partner/DailySettleService.php'); +assert(fs.existsSync(dailySettlePath), 'DailySettleService.php 文件存在'); +const settleContent = fs.readFileSync(dailySettlePath, 'utf-8'); + +test('DailySettleService 包含 runMinute() 总调度入口', () => { + assert(settleContent.includes('function runMinute()'), '必须定义 runMinute()'); +}); + +test('DailySettleService runMinute 调度兑换券与马豆结算', () => { + assert(settleContent.includes('releaseMinute()'), '调用 releaseMinute() 释放兑换券'); + assert(settleContent.includes('shareMinute('), '调用 shareMinute() 发放马豆'); + assert(settleContent.includes("'madow_settled'] = 1"), '订单必须打上 madow_settled 标记防止重复均分'); + assert(settleContent.includes('partner_settle_minute.lock'), '包含独立互斥锁保障并发安全'); +}); + +// 4. PartnerSettle.php 控制台命令验证 +const partnerSettlePath = path.resolve(__dirname, '../addons/shopro/console/PartnerSettle.php'); +assert(fs.existsSync(partnerSettlePath), 'PartnerSettle.php 文件存在'); +const cmdContent = fs.readFileSync(partnerSettlePath, 'utf-8'); + +test('PartnerSettle 默认执行 runMinute() 分钟级调度', () => { + assert(cmdContent.includes('runMinute()'), '默认调用 runMinute()'); + assert(cmdContent.includes('partner minute settle done'), '输出分钟级执行结果日志'); +}); + +test('PartnerSettle 保留 --date / --rerun / --daily 传统日结兼容', () => { + assert(cmdContent.includes("$input->getOption('date')"), '兼容 -d/--date 参数'); + assert(cmdContent.includes("$input->getOption('rerun')"), '兼容 -r/--rerun 参数'); + assert(cmdContent.includes("$input->getOption('daily')"), '兼容 --daily 参数'); +}); + +console.log('\n--------------------------------------------------------'); +console.log(`测试执行结果: 通过 ${passCount} 项, 失败 0 项`); +console.log('========================================================\n');