$queryx->last_query()获取执行的SQL语句,只能是单条语句如find()

本文探讨了使用ORM工厂方法进行数据库查询时遇到的问题,特别是在尝试获取所有记录时无法成功获取的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


$queryx = orm::factory($this->model)->find();
//print_r($queryx);
echo($queryx->last_query());

find_all()获取不到!!
public function forwardDeliveryFeeVerifyDo($yearMonth):bool{ $monthTimeRange = $this->getMonthTimeRange($yearMonth); $itemizationMonthList = ItemizationModel::whereBetween('business_time',[$monthTimeRange['startTime'],$monthTimeRange['endTime']])->select()->toArray(); //遍历选中月份的正向配送明细进行规则计算 foreach($itemizationMonthList as $key => $value){ $warehouse = DeliveryRangeModel::where('province',$value['destination_province'])->field('warehouse')->find(); //本应发货仓 (计算规则: 根据正向配送费明细表la_delivery_fee的目的省 与 配送范围表la_delivery_range的省份匹配 省份对应的仓库名称就是本应发货仓) $itemizationMonthList[$key]['original_warehouse'] = $warehouse->warehouse ? $warehouse->warehouse : ''; //是否跨仓 (计算规则: 若正向配送费明细表la_delivery_fee的仓库名称等于上面拿到的本应发货仓,则标记不跨仓否则标记跨仓 1夸仓 0不夸仓) $itemizationMonthList[$key]['is_cross_warehouse'] = $value['warehouse_name'] == $warehouse->warehouse ? '0' : '1'; //理论重量 (计算规则: 正向配送明细表la_delivery_fee当中的logistics_order_code物流履约单号去匹配正向配送货品明细表la_delivery_goods_detail当中的logistics_order_no物流履约单号 // 两者是一对多的关系-->一个明细表的物流履约单号对应一个或者多个货品明细表里的物流履约单号; // 然后拿着正向配送货品明细表la_delivery_goods_detail当中的货品件数quantity,根据字段货品ID-->product_id匹配仓库费基础物量重量信息表la_warehouse_facility当中的京东商品代码jd_product_code或者 // 菜鸟货品ID-->cainiao_product_id去查对应的单品重量,然后用单品重量*正向配送货品明细表la_delivery_goods_detail当中的货品件数quantity之和就是理论重量) if(!empty($value["logistics_order_code"])){ $goodsDetailsInfo = GoodsDetailModel::where('logistics_order_no',$value['logistics_order_code'])->field('product_id,quantity')->select()->toArray(); //print_r($goodsDetailsInfo);die; if(!empty($goodsDetailsInfo)){ $weight = 0; foreach($goodsDetailsInfo as $k => $v){ //single_item_weight单位为克 $singleItemWeightPro = GoodsWeightModel::where('cainiao_product_id',$v['product_id'])->field('single_item_weight')->find(); $weight += $v['quantity'] * $singleItemWeightPro->single_item_weight; } //TODO: 3.1415926 保留三位小数 直接就是 3.141 暂定 $itemizationMonthList[$key]['theoretical_weight'] = $weight; }else{ //$itemizationMonthList[$key]['theoretical_weight'] = 0; //如果明细表有单号但是货品明细表匹配不到则跳过 不再进行接下来的复杂运算 continue; } }else{ //$itemizationMonthList[$key]['theoretical_weight'] = 0; //如果明细表单号都没有则直接跳过 不再进行接下来的复杂运算 continue; } //Kg (计算规则: 理论重量/1000) //TODO: Kg是否要四舍五入还是直接向上取整? $itemizationMonthList[$key]['kg'] = $itemizationMonthList[$key]['theoretical_weight'] / 1000; //重量差异 (计算规则: 仓库名称当中如果包含成都两个关键字,也就是成都仓那么【计费包材体积1kg计泡8000】<1000,取【计费包材体积1kg计泡8000】/1000-Kg;计费包材体积1kg计泡8000】>1000,取max( 计费包材体积1kg计泡8000,计费包材体积计泡8000)/1000-Kg; // 如果包含沈阳两个关键字,也就是沈阳仓那么取max(计费包材体积1kg计泡8000,计费包材体积计泡8000)/1000-Kg) if (str_contains($value['warehouse_name'], "成都")) { $weight_difference = 0; if($value['bubble_volume_1kg'] < 1000){ $weight_difference = $value['bubble_volume_1kg'] / 1000 - $itemizationMonthList[$key]['kg']; }elseif($value['bubble_volume_1kg'] > 1000){ $weight_difference = max($value['bubble_volume_1kg'],$value['bubble_volume']) / 1000 - $itemizationMonthList[$key]['kg']; } $itemizationMonthList[$key]['weight_difference'] = $weight_difference; } elseif(str_contains($value['warehouse_name'], "沈阳")) { $itemizationMonthList[$key]['weight_difference'] = max($value['bubble_volume_1kg'],$value['bubble_volume']) / 1000 - $itemizationMonthList[$key]['kg']; } //计费重量 (计算规则: 若0<kg<0.5,则取0.5;若0.5<kg<=1 则取 1;若 kg>1,则向上取整) $itemizationMonthList[$key]['charge_weight'] = $itemizationMonthList[$key]['kg'] > 1 ? ceil($itemizationMonthList[$key]['kg']) : ($itemizationMonthList[$key]['kg'] < 0.5 ? 0.5 : 1); //理论费用 (计算规则: 仓库名称+目的省匹配正向配送费报价表:la_delivery_fee_quote,基于计费重量匹配报价表计算金额) $deliveryFeeQuoteInfo = DeliveryQuoteModel::where('destination','=',$value['destination_province'])->where('warehouse','=',$value['warehouse_name'])->find()->toArray(); $theoreticalFee = $this->calculateTheoreticalFee($itemizationMonthList[$key]['charge_weight'],$deliveryFeeQuoteInfo); $itemizationMonthList[$key]['theoretical_fee'] = $theoreticalFee; //理论费用差异 (计算规则:计费金额-理论费用) $itemizationMonthList[$key]['fee_difference'] = $value['charge_amount'] - $theoreticalFee; //不跨仓费用 (计算规则:本应发货仓+目的省 正向配送费报价表:la_delivery_fee_quote,基于计费重量匹配报价表计算金额); //不跨仓的话那么 不跨仓费用应该就等于理论费用 if($itemizationMonthList[$key]['is_cross_warehouse'] == '1'){ //跨仓了就要重新计算不跨仓费用 $deliveryFeeQuoteYesInfo = DeliveryQuoteModel::where('destination','=',$value['destination_province'])->where('warehouse','=',$itemizationMonthList[$key]['original_warehouse'])->find()->toArray(); $itemizationMonthList[$key]['non_cross_warehouse_fee'] = $this->calculateTheoreticalFee($itemizationMonthList[$key]['charge_weight'],$deliveryFeeQuoteYesInfo); }else{ $itemizationMonthList[$key]['non_cross_warehouse_fee'] = $theoreticalFee; } //跨仓差异 (计算规则:计费金额-不跨仓费用) $itemizationMonthList[$key]['cross_warehouse_difference'] = $value['charge_amount'] - $itemizationMonthList[$key]['non_cross_warehouse_fee']; } //因为涉及到的关联关系比较多,未必每一行数据都能正确匹配到相关数据,所以我们只对物流履约单号匹配成功的数据做更新操作 foreach($itemizationMonthList as $key => $value){ if(empty($value['original_warehouse']) || empty($value['theoretical_weight']) || $value['theoretical_weight'] == 0){ //记录日志 Log::warning('【正向配送费核对仓库名称或物流履约单号不匹配】--月份为:'.$yearMonth."的费用核对匹配不到仓库名称或者物流履约单号,明细数据id为".$value['id']); unset($itemizationMonthList[$key]); } } //批量分批次更新数据库 $status = true; $batchSize = 50; // 每批10条记录 $totalCount = count($itemizationMonthList); $batchCount = ceil($totalCount / $batchSize); $itemizationModel = new ItemizationModel(); for ($i = 0; $i < $batchCount; $i++) { $batchData = array_slice($itemizationMonthList, $i * $batchSize, $batchSize); try { $itemizationModel->startTrans(); // 使用批量更新替代循环单条更新 $itemizationModel->saveAll($batchData); $itemizationModel->commit(); } catch (\Exception $e) { $itemizationModel->rollback(); //记录日志 Log::error('【正向配送费核对异常】--月份为:'.$yearMonth."的费用核对发生错误:" . $e->getMessage()); //其中一个批次数据处理失败则直接退出循环 不再继续执行后续批次的数据处理 报错给前端显示 $status = false; break; } } return $status; } 我现在需要对数据库当中接近100万的数据进行处理,这是我之前写的业务逻辑代码肯定不行,因为不能一次性读取100万出来去处理,可以使用使用游标分批处理chunk, 然后再高效批量更新,你看一下是我其他模块的处理业务逻辑的代码就是这么做的: public function ReverseDeliveryFeeVerifyDo($yearMonth): bool { $monthTimeRange = $this->getMonthTimeRange($yearMonth); //使用键值对缓存报价数据 $quoteMap = QuoteModel::column('price', 'warehous'); if (empty($quoteMap)) { Log::warning("【逆向配送费报价数据缺失】月份:{$yearMonth}"); return false; } $status = true; $batchSize = 500; //批次大小即每次读取的数据条数 $reconnectInterval = 200; //每10万条重新连接一次数据库 200批次后重连(每200批=10万条) $updateCount = 0; try { //使用游标分批处理(减少内存占用) $query = ItemizationModel::whereBetween('business_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ])->field('id,billing_amount,warehouse_name'); $query->chunk($batchSize, function ($items) use ($quoteMap, &$updateCount, &$status, $reconnectInterval) { static $batchCount = 0; $batchCount++; //批量更新缓冲区 $updateBuffer = []; foreach ($items as $item) { if (isset($quoteMap[$item->warehouse_name])) { $updateBuffer[$item->id] = [ 'theoretical_amount' => $quoteMap[$item->warehouse_name], 'fee_difference' => $item->billing_amount - $quoteMap[$item->warehouse_name] ]; } else { $updateBuffer[$item->id] = [ 'theoretical_amount' => null, 'fee_difference' => null ]; } } //高效批量更新 $this->batchUpdate($updateBuffer); $updateCount += count($updateBuffer); // 条件重连(减少不必要重连) if ($batchCount % $reconnectInterval === 0) { $this->reconnectDatabase(); Log::info("逆向配送费用核对已处理 {$updateCount} 条,进行数据库重连"); } unset($items, $updateBuffer); }); } catch (\Exception $e) { Log::error("逆向配送费核对异常: {$e->getMessage()}"); $status = false; } Log::info("逆向配送费用核对处理完成,共更新 {$updateCount} 条记录"); return $status; } //高效批量更新方法(单SQL更新多条) private function batchUpdate(array $data) { if (empty($data)) return; $table = 'la_reverse_delivery_fee'; $cases = []; $ids = []; $params = []; // 构建CASE WHEN更新语句 foreach (['theoretical_amount', 'fee_difference'] as $field) { $cases[$field] = 'CASE id '; foreach ($data as $id => $row) { $cases[$field] .= "WHEN {$id} THEN ? "; $params[] = $row[$field]; $ids[] = $id; } $cases[$field] .= 'END'; } $idsStr = implode(',', $ids); /* 最后的执行sql可以视为(案例sql): UPDATE la_reverse_delivery_fee SET theoretical_amount = CASE id WHEN 1001 THEN 100 -- 当ID=1001时,更新为100 WHEN 1002 THEN 200 -- 当ID=1002时,更新为200 END, fee_difference = CASE id WHEN 1001 THEN 5 -- 当ID=1001时,更新为5 WHEN 1002 THEN 10 -- 当ID=1002时,更新为10 END WHERE id IN (1001,1002); 其实就是巧妙地利用了 SQL 的CASE WHEN语法,将多行更新合并为单条 SQL,是一种常见的数据库优化技巧! */ $sql = "UPDATE {$table} SET theoretical_amount = {$cases['theoretical_amount']}, fee_difference = {$cases['fee_difference']} WHERE id IN ({$idsStr})"; Db::execute($sql, $params); } //数据库重连方法 private function reconnectDatabase() { try { $connection = \think\facade\Db::connect(); $connection->close(); $connection->connect(); } catch (\Exception $e) { //print_r("数据库连接失败(直接干死结束进程):".$e->getMessage());die; Log::error('【逆向配送费用核对数据库重连失败】' . $e->getMessage()); } } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 (git有问题未解决 暂时无法写入common.php当中 临时放这) * @param string $yearMonth * @return array * @author 胡军 * @date 2025/06/19 */ private function getMonthTimeRange(string $yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $yearMonth)) { throw new InvalidArgumentException('输入格式不正确,必须为YYYY-MM格式'); } list($year, $month) = explode('-', $yearMonth); // 构建开始时间 $startTime = "{$year}-{$month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $lastDay = (new \DateTime("{$year}-{$month}-01")) ->modify('last day of this month') ->format('d'); // 构建结束时间 $endTime = "{$year}-{$month}-{$lastDay} 23:59:59"; return [ 'startTime' => $startTime, 'endTime' => $endTime ]; } 请模仿下面的帮我处理一下我之前的直接取出100万数据进行处理的老代码
07-06
/** * @notes 京东收到派服务费核对逻辑 * @param $yearMonth * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author 胡军 * @date 2025/07/01 */ public function deliveryPrimaryRegionsVerifyDo($yearMonth):bool{ $monthTimeRange = $this->getMonthTimeRange($yearMonth); $status = true; // 初始化状态 // 使用use关键字将$yearMonth传入闭包 如果闭包返回 false,chunk() 会立即停止处理后续数据块 DeliveryPrimaryRegionsItemizationModel::whereBetween('order_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ])->chunk(100, function ($items) use ($yearMonth,&$status) { // 临时存储当前批次的结果 $itemizationMonthList = []; foreach ($items as $item) { //print_r($item->id."处理完成".PHP_EOL); $processRet = $this->processItem($item, $yearMonth); if(!empty($processRet)){ $itemizationMonthList[] = $processRet; } } // 优化后的事务处理->将整个批次作为一个事务处理,减少事务开启次数 $itemizationModel = new DeliveryPrimaryRegionsItemizationModel(); try { $itemizationModel->startTrans(); // 直接处理整个批次数据 $itemizationModel->saveAll($itemizationMonthList); $itemizationModel->commit(); } catch (\Exception $e) { $itemizationModel->rollback(); Log::error('【京东收派服务费明细核对】--月份为:'.$yearMonth."的费用核对发生错误:" . $e->getMessage()); $status = false; return false; } }); return $status; } // 将处理逻辑封装到单独方法当中 private function processItem($item,$yearMonth) { //实际配送特惠送区域型 $deliveryPrimary = DeliveryPrimaryRegionsQuoteModel::where('origin_province','=',$item['origin_province']) ->where('origin_location','=',$item['origin_city']) ->where('destination_province','=',$item['destination_province']) ->where('destination_location','=',$item['destination_city']) ->find(); if(!empty($deliveryPrimary)){ $deliveryPrimaryData = $deliveryPrimary->toArray(); //1、实际配送特惠送区域型->始发省&始发市&目的省&目的市去匹配对应收派服务费报价表中的始发省&始发市&目的省&目的市对应的京东标快分区值 $item['actual_delivery_area_type'] = $deliveryPrimaryData['jd_standard_partition']; }else{ //记录错误日志 Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的[始发省&始发市&目的省&目的市] 没有匹配到 京东收派服务费报价表:la_primary_regions_quote对应的 [始发省&始发市&目的省&目的市],明细记录id为".$item['id']); return []; } //本应发货特惠送区域类型 $laPrimaryRegions = DeliveryPrimaryRegionsModel::where('province','=',$item['destination_province']) ->where('city','=',$item['destination_city'])->find(); if(!empty($laPrimaryRegions)){ //2、本应发货特惠送区域类型->目的省&目的市匹配对应一级区域表中的省&市对应的京东标快分区值 $laPrimaryRegionsData = $laPrimaryRegions->toArray(); $item['expected_delivery_area_type'] = $laPrimaryRegionsData['jd_zone']; }else{ //记录错误日志 Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的[目的省&目的市] 没有匹配到 京东收派服务费一级区域表:la_primary_regions对应的 [目的省&目的市],明细记录id为".$item['id']); return []; } //3、是否跨仓->当实际配送特惠送区域型=实际配送特惠送区域时写入不跨仓否则跨仓 $item['is_cross_warehouse'] = $item['actual_delivery_area_type'] == $item['expected_delivery_area_type'] ? '2' : '1'; //4、理论重量: 收派服务费核对明细的平台订单号关联la_scm_day_outbound_data当中的billNo字段,查询该订单billNo下货品goodsNo及数量quantity,再通过关联基础数据物料la_warehouse_facility表的单品重量(通过条码)计算该订单下各货品的重量,并按照订单号分组、求和。 $scmDayOutboundData = ScmDayOutboundDataModel::where('billNo','=',$item['platform_order_number'])->select()->toArray(); if(!empty($scmDayOutboundData)){ $weightTotal = 0; foreach($scmDayOutboundData as $k => $v){ //skuBarcode $goodsWeightModel = GoodsWeightModel::where('barcode','=',$v['skuBarcode'])->field('single_item_weight')->find(); if(!empty($goodsWeightModel)){ $goodsWeight = $goodsWeightModel->toArray(); //la_scm_day_outbound_data数量*la_warehouse_facility单品重量(kg) $weightTotal += $v['quantity'] * $goodsWeight['single_item_weight']; }else{ //记录错误日志 Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表平台订单号关联la_scm_day_outbound_data当中的billNo字段 但是billNo字段关联基础数据物料la_warehouse_facility表的条码skuBarcode失败,明细记录id为".$item['id']); return []; } } $item['theoretical_weight'] = $weightTotal; }else{ Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的平台订单号platform_order_number 没有匹配到 每日出库数据明细表:la_scm_day_outbound_data对应的关联单号billNo,明细记录id为".$item['id']); return []; } //5、重量取整-> 理论重量向上取0.5 if(is_numeric($item['theoretical_weight'])) { //如果是浮点数那么向上取0.5 $floatValue = (float)$item['theoretical_weight']; $item['weight_rounded'] = ceil($floatValue * 2) / 2; }else{ //如果是整数那么就直接赋值即可 $item['weight_rounded'] = $item['theoretical_weight']; } //6、重量差异-> 计费重量-重量取整 $item['weight_difference'] = $item['billing_weight'] - $item['weight_rounded']; //7、金额核验->(存在重复代码待优化 赶工期......) // ①费用类型=快递改址费 5; // ②费用类型=保价费 0.3; // ③费用类型=快递_转寄服务费 5; // ④费用类型=快递超长超重,【计费重量】*1元/kg // ⑤费用类型=快递运费,始发省&始发市&目的省&目的市,匹配对应 收派服务费报价表中的 始发省&始发市&目的省&目的市 对应的报价,使用【计费重量】按照报价计算: // 若 计费重量<=1 计算公式为:首重金额*0.28; // 若1<计费用重量<=30 计算公式为:(首重金额+(计费重量-1)*续重1金额)*0.28; // 若 计费重量>30 计算公式为:(首重金额+(计费重量-1)*续重1金额+(计费重量-30)*续重2金额)*0.28 if($item['fee_type'] == '快递改址费' || $item['fee_type'] == '快递_转寄服务费'){ $item['amount_verification'] = 5; }elseif($item['fee_type'] == '保价费'){ $item['amount_verification'] = 0.3; }elseif($item['fee_type'] == '快递超长超重'){ $item['amount_verification'] = $item['billing_weight'] * 1; }elseif($item['fee_type'] == '快递运费'){ if($item['billing_weight'] <= 1){ $item['amount_verification'] = $deliveryPrimary->first_weight * 0.28; }elseif($item['billing_weight'] <= 30){ $item['amount_verification'] = ($deliveryPrimary->first_weight + ($item['billing_weight'] - 1) * $deliveryPrimary->continued_weight1) * 0.28; }else{ // >30的情况 $item['amount_verification'] = ($deliveryPrimary->first_weight + ($item['billing_weight'] - 1) * $deliveryPrimary->continued_weight1 + ($item['billing_weight'] - 30) * $deliveryPrimary->continued_weight2) * 0.28; } }else{ Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的费用类型fee_type 没有匹配到 京东收派服务费报价表:la_delivery_primary_regions对应的费用类型,明细记录id为".$item['id']); return []; } //8、核验差异—>结算金额-金额核验 $item['verification_difference'] = $item['settlement_amount'] - $item['amount_verification']; //9、理论计费->(存在重复代码待优化 赶工期......) // ①费用类型=快递改址费 5; // ②费用类型=保价费 0.3; // ③费用类型=快递_转寄服务费 5; // ④费用类型=快递超长超重,【计费重量】*1元/kg // ⑤费用类型=快递运费, 始发省&始发市&目的省&目的市去匹配对应 收派服务费报价表中的 始发省&始发市&目的省&目的市 当中对应的报价,使用【理论重量】向上取整 1,按照报价计算 // 若理论重量取整后<=1 计算公式为->首重*0.28; // 若1<理论重量<=30 计算公式为:(首重+(理论重量-1)*续重1)*0.28; // 若理论重量>30 计算公式为:(首重+(理论重量-1)*续重1+(理论重量-30)*续重2)*0.28 if($item['fee_type'] == '快递改址费' || $item['fee_type'] == '快递_转寄服务费'){ $item['theoretical_billing'] = 5; }elseif($item['fee_type'] == '保价费'){ $item['theoretical_billing'] = 0.3; }elseif($item['fee_type'] == '快递超长超重'){ $item['theoretical_billing'] = $item['billing_weight'] * 1; }elseif($item['fee_type'] == '快递运费'){ $roundedUp = ceil($item['theoretical_weight']); if($roundedUp <= 1){ $item['theoretical_billing'] = $deliveryPrimary->first_weight * 0.28; }elseif($roundedUp <= 30){ $item['theoretical_billing'] = ($deliveryPrimary->first_weight + ($item['billing_weight'] - 1) * $deliveryPrimary->continued_weight1) * 0.28; }else{ // >30的情况 $item['theoretical_billing'] = ($deliveryPrimary->first_weight + ($item['billing_weight'] - 1) * $deliveryPrimary->continued_weight1 + ($item['billing_weight'] - 30) * $deliveryPrimary->continued_weight2) * 0.28; } }else{ Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的费用类型fee_type 没有匹配到 京东收派服务费报价表:la_delivery_primary_regions对应的费用类型,明细记录id为".$item['id']); return []; } //10、理论差异->结算金额-理论计费 $item['theoretical_difference'] = $item['settlement_amount'] - $item['theoretical_billing']; //11、不跨仓收费->(存在重复代码待优化 赶工期......) // ①费用类型=快递改址费 5; // ②费用类型=保价费 0.3; // ③费用类型=快递_转寄服务费 5; // ④费用类型=快递超长超重,【计费重量】*1元/kg // ⑤费用类型=快递运费,目的省&目的市,匹配对应 收派服务费报价表中的 目的省&目的市 对应的报价,使用【计费重量】按照一级区域报价计算 // 若计费重量<=1 计算公式为:首重*0.28; // 若1<计费用重量<=30 计算公式为:(首重+(计费重量-1)*续重1)*0.28; // 若计费重量>30 计算公式为:(首重+(计费重量-1)*续重1+(计费重量-30)*续重2)*0.28; $deliveryPrimaryRegions = DeliveryPrimaryRegionsModel::where('province','=',$item['destination_province']) ->where('city','=',$item['destination_city']) ->find(); if(empty($deliveryPrimaryRegions)){ //记录错误日志 Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的[目的省&目的市] 没有匹配到 京东收派服务费一级区域表:la_primary_regions对应的 [目的省&目的市],明细记录id为".$item['id']); return []; } if($item['fee_type'] == '快递改址费' || $item['fee_type'] == '快递_转寄服务费'){ $item['non_cross_warehouse_fee'] = 5; }elseif($item['fee_type'] == '保价费'){ $item['non_cross_warehouse_fee'] = 0.3; }elseif($item['fee_type'] == '快递超长超重'){ $item['non_cross_warehouse_fee'] = $item['billing_weight'] * 1; }elseif($item['fee_type'] == '快递运费'){ if($item['billing_weight'] <= 1){ $item['non_cross_warehouse_fee'] = $deliveryPrimaryRegions->first_wt * 0.28; }elseif($item['billing_weight'] <= 30){ $item['non_cross_warehouse_fee'] = ($deliveryPrimaryRegions->first_wt + ($item['billing_weight'] - 1) * $deliveryPrimaryRegions->add_wt1) * 0.28; }else{ // >30的情况 $item['non_cross_warehouse_fee'] = ($deliveryPrimaryRegions->first_wt + ($item['billing_weight'] - 1) * $deliveryPrimaryRegions->add_wt1 + ($item['billing_weight'] - 30) * $deliveryPrimaryRegions->add_wt2) * 0.28; } }else{ Log::warning('【京东收派服务费明细核对】--月份为:'.$yearMonth."的明细表la_primary_regions_mx当中的[目的省&目的市] 没有匹配到 京东收派服务费一级区域表:la_primary_regions对应的 [目的省&目的市],明细记录id为".$item['id']); return []; } //12、跨仓差异->结算金额-不跨仓收费 $item['cross_warehouse_difference'] = $item['settlement_amount'] - $item['theoretical_billing']; return $item->toArray(); } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 (git有问题未解决 暂时无法写入common.php当中 临时放这) * @param string $yearMonth * @return array * @author 胡军 * @date 2025/07/01 */ private function getMonthTimeRange(string $yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $yearMonth)) { throw new InvalidArgumentException('输入格式不正确,必须为YYYY-MM格式'); } list($year, $month) = explode('-', $yearMonth); // 构建开始时间 $startTime = "{$year}-{$month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $lastDay = (new \DateTime("{$year}-{$month}-01")) ->modify('last day of this month') ->format('d'); // 构建结束时间 $endTime = "{$year}-{$month}-{$lastDay} 23:59:59"; return [ 'startTime' => $startTime, 'endTime' => $endTime ]; } 这是我核算100万数据的代码,虽然使用了分块处理但是我感觉还有优化的空间,我之前优化完的代码就很好我可以提供给你代码做参考: /** * @notes 非销售出库明细核对逻辑(优化版) * @param $yearMonth * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author 胡军 * @date 2025/06/25 */ public function nonSalesFeeVerifyDo($yearMonth): bool { // 获取指定月份的时间范围(月初到月末) $monthTimeRange = $this->getMonthTimeRange($yearMonth); // 预加载并缓存报价数据,使用键值对存储(仓库名 => 报价信息) // 避免在后续循环中重复查询数据库,提高性能 $warehouseQuotes = []; $warehouseList = NonSalesItemizationModel::whereBetween('business_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ])->group('warehouse_name')->column('warehouse_name'); // 批量获取所有仓库的报价记录 foreach ($warehouseList as $warehouse) { // 获取该仓库的报价记录 $quoteResult = NonSalesQuoteModel::where('warehouse', $warehouse)->select()->toArray(); if (!empty($quoteResult)) { $newQuoteResult = []; foreach ($quoteResult as $item) { $newQuoteResult[$item['fee_item']] = $item; } $warehouseQuotes[$warehouse] = $newQuoteResult; } } $status = true; // 处理状态标识 $batchSize = 500; // 批次大小即每次读取的数据条数 $reconnectInterval = 200; // 每10万条重新连接一次数据库(200批次=10万条) $updateCount = 0; // 记录已更新的总记录数 $batchCount = 0; // 记录当前批次数 try { // 使用游标分批处理数据,每次只加载少量数据到内存 // 避免一次性加载大量数据导致内存溢出 $query = NonSalesItemizationModel::whereBetween('business_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ]); $query->chunk($batchSize, function ($items) use ( &$status, // 引用传递处理状态 &$updateCount, // 引用传递更新计数 &$batchCount, // 引用传递批次计数 $warehouseQuotes, // 仓库报价数据 $reconnectInterval, // 重连间隔 $yearMonth ) { $batchCount++; $updateBuffer = []; // 批量更新缓冲区,存储待更新的数据 // 遍历当前批次的所有明细记录 foreach ($items as $item) { $warehouseName = $item->warehouse_name; $itemData = $item->toArray(); // 检查仓库是否有对应的报价数据 if (isset($warehouseQuotes[$warehouseName])) { $quoteData = $warehouseQuotes[$warehouseName]; // 处理数量数据,确保不为空 $boxCount = !empty($itemData['box_count']) ? $itemData['box_count'] : 0; $looseItems = !empty($itemData['loose_items']) ? $itemData['loose_items'] : 0; // 计算理论费用 $theoreticalFee = $boxCount * $quoteData['整箱']['amount'] + $looseItems * $quoteData['拆零']['amount']; // 计算费用差异 $feeDifference = $itemData['charge_amount'] - $theoreticalFee; } else { // 记录无匹配报价的日志,方便后续排查 Log::warning('【菜鸟非销售出库费明细核对报价单仓库名称不匹配】--月份为:' . $yearMonth . "的订单明细核对匹配不到非销售出库费报价表la_nonsales_fee_quote当中的仓库名称,明细数据id为" . $itemData['id']); // 对于未匹配到的记录,设置为null以便标识 $theoreticalFee = null; $feeDifference = null; } // 准备更新数据,存入缓冲区 $updateBuffer[$itemData['id']] = [ 'theoretical_fee' => $theoreticalFee, // 理论费用 'fee_difference' => $feeDifference // 费用差异 ]; } // 使用高效的批量更新方法将缓冲区数据写入数据库 $this->batchUpdate('la_nosales_fee', $updateBuffer, [ 'theoretical_fee', 'fee_difference' ]); $updateCount += count($updateBuffer); // 更新总计数 // 定期重连数据库,避免长时间运行导致连接断开 if ($batchCount % $reconnectInterval === 0) { $this->reconnectDatabase(); Log::info("菜鸟非销售出库费用核对已处理 {$updateCount} 条,进行数据库重连"); } // 释放内存,避免内存泄漏 unset($items, $updateBuffer); }); } catch (\Exception $e) { // 记录异常信息,确保错误可追溯 Log::error('【菜鸟非销售出库费明细核对异常】--月份为:' . $yearMonth . "的费用核对发生错误:" . $e->getMessage()); $status = false; // 标记处理失败 } // 记录处理完成信息,包含更新的总记录数 Log::info("菜鸟非销售出库费用核对处理完成,共更新 {$updateCount} 条记录"); return $status; } /** * 高效批量更新方法(单SQL更新多条) * @param string $table 表名 * @param array $data 更新数据,格式:[id => ['field1' => 'value1', 'field2' => 'value2']] * @param array $fields 需要更新的字段 */ private function batchUpdate(string $table, array $data, array $fields) { // 数据为空时直接返回,避免无效操作 if (empty($data) || empty($fields)) return; $cases = []; // 存储CASE WHEN语句的数组 $ids = []; // 存储所有需要更新的ID $params = []; // 存储预处理语句的参数 // 构建CASE WHEN更新语句(每个字段一个CASE WHEN) foreach ($fields as $field) { $cases[$field] = 'CASE id '; // 为每个ID和对应字段值构建WHEN子句 foreach ($data as $id => $row) { $cases[$field] .= "WHEN {$id} THEN ? "; // 占位符用于预处理语句 $params[] = $row[$field]; // 对应的值 $ids[] = $id; // 记录ID } $cases[$field] .= 'END'; // 结束CASE语句 } // 去重并拼接ID列表 $idsStr = implode(',', array_unique($ids)); // 构建SET子句(每个字段的CASE WHEN语句) $setClauses = []; foreach ($fields as $field) { $setClauses[] = "{$field} = {$cases[$field]}"; } // 构建完整的UPDATE SQL语句 /* 最后的执行sql可以视为(案例sql): UPDATE la_reverse_delivery_fee SET theoretical_amount = CASE id WHEN 1001 THEN 100 -- 当ID=1001时,更新为100 WHEN 1002 THEN 200 -- 当ID=1002时,更新为200 END, fee_difference = CASE id WHEN 1001 THEN 5 -- 当ID=1001时,更新为5 WHEN 1002 THEN 10 -- 当ID=1002时,更新为10 END WHERE id IN (1001,1002); 其实就是巧妙地利用了 SQL 的CASE WHEN语法,将多行更新合并为单条 SQL,是一种常见的数据库优化技巧! */ $sql = "UPDATE {$table} SET " . implode(', ', $setClauses) . " WHERE id IN ({$idsStr})"; // 执行预处理语句,提高安全性和性能 Db::execute($sql, $params); } // 数据库重连方法,用于长时间运行的任务,避免连接超时 private function reconnectDatabase() { try { $connection = \think\facade\Db::connect(); $connection->close(); // 关闭当前连接 $connection->connect(); // 重新建立连接 } catch (\Exception $e) { // 记录重连失败日志,但不中断程序执行 Log::error('【菜鸟非销售出库费用核对数据库重连失败】' . $e->getMessage()); } } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 * @param string $yearMonth * @return array * @author 胡军 * @date 2025/06/25 */ private function getMonthTimeRange(string $yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $yearMonth)) { throw new InvalidArgumentException('输入格式不正确,必须为YYYY-MM格式'); } list($year, $month) = explode('-', $yearMonth); // 构建开始时间 $startTime = "{$year}-{$month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $lastDay = (new \DateTime("{$year}-{$month}-01")) ->modify('last day of this month') ->format('d'); // 构建结束时间 $endTime = "{$year}-{$month}-{$lastDay} 23:59:59"; return [ 'startTime' => $startTime, 'endTime' => $endTime ]; } 请根据我后面给你的优化完的代码使用的技术方案来优化我给你的要优化的代码,记住一定最后要提供完整代码并且我的原有的注释信息请保留下来方便我阅读
最新发布
07-09
/** * @notes 京东装卸服务费核对逻辑 * @param $yearMonth * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author 胡军 * @date 2025/06/30 */ public function calCulateFeeVerifyDo($yearMonth):bool{ $monthTimeRange = $this->getMonthTimeRange($yearMonth); $itemizationMonthList = CalculateFeeItemizationModel::whereBetween('business_time',[$monthTimeRange['startTime'],$monthTimeRange['endTime']])->select()->toArray(); foreach($itemizationMonthList as $key => $value){ //订单体积(m³): 订单体积/1000000 $itemizationMonthList[$key]['order_volume_cubic_meter'] = $value['order_volume'] / 1000000; //订单重量(t): 订单重量/1000 $itemizationMonthList[$key]['order_weight_ton'] = $value['order_weight'] / 1000; if($itemizationMonthList[$key]['order_weight_ton'] > 0){ //商品体积(m³/t): 订单体积(m³)/ 订单重量(t) 保留两位小数 $itemizationMonthList[$key]['commodity_volume'] = round($itemizationMonthList[$key]['order_volume_cubic_meter'] / $itemizationMonthList[$key]['order_weight_ton'],2); //品类: 商品体积(m³/t)>3, 品类=泡货,否则=重货 $itemizationMonthList[$key]['category'] = $itemizationMonthList[$key]['commodity_volume'] > 3 ? '泡货' : '重货'; //费用单价: 匹配装卸服务费报价对应的品类始发库房名称(仓库)的报价 $calCulateFeeArr = CalculateFeeQuoteModel::where('warehouse', $value['origin_warehouse_name'])->find(); if ($calCulateFeeArr) { $calCulateFeeArr = $calCulateFeeArr->toArray(); } else { $calCulateFeeArr = []; } if(!empty($calCulateFeeArr)){ //理论费用: ① 品类=重货时,订单重量(t)*费用单价; ②品类=泡货时,订单体积(m³)*费用单价 if($itemizationMonthList[$key]['category'] == '泡货'){ //费用单价 $itemizationMonthList[$key]['unit_price'] = $calCulateFeeArr['bulky_goods']; //理论费用 $itemizationMonthList[$key]['theoretical_cost'] = $itemizationMonthList[$key]['order_volume_cubic_meter'] * $itemizationMonthList[$key]['unit_price']; } if($itemizationMonthList[$key]['category'] == '重货'){ //费用单价 $itemizationMonthList[$key]['unit_price'] = $calCulateFeeArr['heavy_goods']; //理论费用 $itemizationMonthList[$key]['theoretical_cost'] = $itemizationMonthList[$key]['order_weight_ton'] * $itemizationMonthList[$key]['unit_price']; } }else{ Log::warning('【京东装卸服务费明细核对】--月份为:'.$yearMonth."的明细表la_calculate没有匹配到装卸服务费报价表:la_calculate_quote对应的仓库名称,明细记录id为".$value['id']); unset($itemizationMonthList[$key]); continue; } //折后费用: 理论费用*0.8 $itemizationMonthList[$key]['discounted_cost'] = $itemizationMonthList[$key]['theoretical_cost'] * 0.8; //费用差异: 结算金额-折后费用 $itemizationMonthList[$key]['difference'] = $value['settlement_amount'] - $itemizationMonthList[$key]['discounted_cost']; }else{ Log::warning('【京东装卸服务费明细核对】--月份为:'.$yearMonth."的订单重量(t)为0导致被除数为0异常报错,明细记录id为".$value['id']); unset($itemizationMonthList[$key]); continue; } } //批量分批次更新数据库 $status = true; $batchSize = 50; // 每批10条记录 $totalCount = count($itemizationMonthList); $batchCount = ceil($totalCount / $batchSize); $itemizationModel = new CalculateFeeItemizationModel(); for ($i = 0; $i < $batchCount; $i++) { $batchData = array_slice($itemizationMonthList, $i * $batchSize, $batchSize); try { $itemizationModel->startTrans(); // 使用批量更新替代循环单条更新 $itemizationModel->saveAll($batchData); $itemizationModel->commit(); } catch (\Exception $e) { $itemizationModel->rollback(); //记录日志 Log::error('【京东装卸服务费明细核对异常】--月份为:'.$yearMonth."的明细费用核对发生错误:" . $e->getMessage()); //其中一个批次数据处理失败则直接退出循环 不再继续执行后续批次的数据处理 报错给前端显示 $status = false; break; } } return $status; } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 (git有问题未解决 暂时无法写入common.php当中 临时放这) * @param string $yearMonth * @return array * @author 胡军 * @date 2025/06/27 */ private function getMonthTimeRange(string $yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $yearMonth)) { throw new InvalidArgumentException('输入格式不正确,必须为YYYY-MM格式'); } list($year, $month) = explode('-', $yearMonth); // 构建开始时间 $startTime = "{$year}-{$month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $lastDay = (new \DateTime("{$year}-{$month}-01")) ->modify('last day of this month') ->format('d'); // 构建结束时间 $endTime = "{$year}-{$month}-{$lastDay} 23:59:59"; return [ 'startTime' => $startTime, 'endTime' => $endTime ]; } 这是我的业务逻辑代码用户核验100万数据,但是我感觉肯定有性能问题,然后我之前优化了其他模块的100万数据核验,但是两者业务逻辑不通,我提供给你,请你按照我优化好的技术思路来优化我上面的代码,不要忘记为我提供最终的优化好的完整代码包括注释信息 一下是我优化好的模块的核验100万的代码: /** * @notes 非销售出库明细核对逻辑(优化版) * @param $yearMonth * @return bool * @throws DataNotFoundException * @throws DbException * @throws ModelNotFoundException * @author 胡军 * @date 2025/06/25 */ public function nonSalesFeeVerifyDo($yearMonth): bool { // 获取指定月份的时间范围(月初到月末) $monthTimeRange = $this->getMonthTimeRange($yearMonth); // 预加载并缓存报价数据,使用键值对存储(仓库名 => 报价信息) // 避免在后续循环中重复查询数据库,提高性能 $warehouseQuotes = []; $warehouseList = NonSalesItemizationModel::whereBetween('business_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ])->group('warehouse_name')->column('warehouse_name'); // 批量获取所有仓库的报价记录 foreach ($warehouseList as $warehouse) { // 获取该仓库的报价记录 $quoteResult = NonSalesQuoteModel::where('warehouse', $warehouse)->select()->toArray(); if (!empty($quoteResult)) { $newQuoteResult = []; foreach ($quoteResult as $item) { $newQuoteResult[$item['fee_item']] = $item; } $warehouseQuotes[$warehouse] = $newQuoteResult; } } $status = true; // 处理状态标识 $batchSize = 500; // 批次大小即每次读取的数据条数 $reconnectInterval = 200; // 每10万条重新连接一次数据库(200批次=10万条) $updateCount = 0; // 记录已更新的总记录数 $batchCount = 0; // 记录当前批次数 try { // 使用游标分批处理数据,每次只加载少量数据到内存 // 避免一次性加载大量数据导致内存溢出 $query = NonSalesItemizationModel::whereBetween('business_time', [ $monthTimeRange['startTime'], $monthTimeRange['endTime'] ]); $query->chunk($batchSize, function ($items) use ( &$status, // 引用传递处理状态 &$updateCount, // 引用传递更新计数 &$batchCount, // 引用传递批次计数 $warehouseQuotes, // 仓库报价数据 $reconnectInterval, // 重连间隔 $yearMonth ) { $batchCount++; $updateBuffer = []; // 批量更新缓冲区,存储待更新的数据 // 遍历当前批次的所有明细记录 foreach ($items as $item) { $warehouseName = $item->warehouse_name; $itemData = $item->toArray(); // 检查仓库是否有对应的报价数据 if (isset($warehouseQuotes[$warehouseName])) { $quoteData = $warehouseQuotes[$warehouseName]; // 处理数量数据,确保不为空 $boxCount = !empty($itemData['box_count']) ? $itemData['box_count'] : 0; $looseItems = !empty($itemData['loose_items']) ? $itemData['loose_items'] : 0; // 计算理论费用 $theoreticalFee = $boxCount * $quoteData['整箱']['amount'] + $looseItems * $quoteData['拆零']['amount']; // 计算费用差异 $feeDifference = $itemData['charge_amount'] - $theoreticalFee; } else { // 记录无匹配报价的日志,方便后续排查 Log::warning('【菜鸟非销售出库费明细核对报价单仓库名称不匹配】--月份为:' . $yearMonth . "的订单明细核对匹配不到非销售出库费报价表la_nonsales_fee_quote当中的仓库名称,明细数据id为" . $itemData['id']); // 对于未匹配到的记录,设置为null以便标识 $theoreticalFee = null; $feeDifference = null; } // 准备更新数据,存入缓冲区 $updateBuffer[$itemData['id']] = [ 'theoretical_fee' => $theoreticalFee, // 理论费用 'fee_difference' => $feeDifference // 费用差异 ]; } // 使用高效的批量更新方法将缓冲区数据写入数据库 $this->batchUpdate('la_nosales_fee', $updateBuffer, [ 'theoretical_fee', 'fee_difference' ]); $updateCount += count($updateBuffer); // 更新总计数 // 定期重连数据库,避免长时间运行导致连接断开 if ($batchCount % $reconnectInterval === 0) { $this->reconnectDatabase(); Log::info("菜鸟非销售出库费用核对已处理 {$updateCount} 条,进行数据库重连"); } // 释放内存,避免内存泄漏 unset($items, $updateBuffer); }); } catch (\Exception $e) { // 记录异常信息,确保错误可追溯 Log::error('【菜鸟非销售出库费明细核对异常】--月份为:' . $yearMonth . "的费用核对发生错误:" . $e->getMessage()); $status = false; // 标记处理失败 } // 记录处理完成信息,包含更新的总记录数 Log::info("菜鸟非销售出库费用核对处理完成,共更新 {$updateCount} 条记录"); return $status; } /** * 高效批量更新方法(单SQL更新多条) * @param string $table 表名 * @param array $data 更新数据,格式:[id => ['field1' => 'value1', 'field2' => 'value2']] * @param array $fields 需要更新的字段 */ private function batchUpdate(string $table, array $data, array $fields) { // 数据为空时直接返回,避免无效操作 if (empty($data) || empty($fields)) return; $cases = []; // 存储CASE WHEN语句的数组 $ids = []; // 存储所有需要更新的ID $params = []; // 存储预处理语句的参数 // 构建CASE WHEN更新语句(每个字段一个CASE WHEN) foreach ($fields as $field) { $cases[$field] = 'CASE id '; // 为每个ID和对应字段值构建WHEN子句 foreach ($data as $id => $row) { $cases[$field] .= "WHEN {$id} THEN ? "; // 占位符用于预处理语句 $params[] = $row[$field]; // 对应的值 $ids[] = $id; // 记录ID } $cases[$field] .= 'END'; // 结束CASE语句 } // 去重并拼接ID列表 $idsStr = implode(',', array_unique($ids)); // 构建SET子句(每个字段的CASE WHEN语句) $setClauses = []; foreach ($fields as $field) { $setClauses[] = "{$field} = {$cases[$field]}"; } // 构建完整的UPDATE SQL语句 /* 最后的执行sql可以视为(案例sql): UPDATE la_reverse_delivery_fee SET theoretical_amount = CASE id WHEN 1001 THEN 100 -- 当ID=1001时,更新为100 WHEN 1002 THEN 200 -- 当ID=1002时,更新为200 END, fee_difference = CASE id WHEN 1001 THEN 5 -- 当ID=1001时,更新为5 WHEN 1002 THEN 10 -- 当ID=1002时,更新为10 END WHERE id IN (1001,1002); 其实就是巧妙地利用了 SQL 的CASE WHEN语法,将多行更新合并为单条 SQL,是一种常见的数据库优化技巧! */ $sql = "UPDATE {$table} SET " . implode(', ', $setClauses) . " WHERE id IN ({$idsStr})"; // 执行预处理语句,提高安全性和性能 Db::execute($sql, $params); } // 数据库重连方法,用于长时间运行的任务,避免连接超时 private function reconnectDatabase() { try { $connection = \think\facade\Db::connect(); $connection->close(); // 关闭当前连接 $connection->connect(); // 重新建立连接 } catch (\Exception $e) { // 记录重连失败日志,但不中断程序执行 Log::error('【菜鸟非销售出库费用核对数据库重连失败】' . $e->getMessage()); } } /** * @notes 根据年月比如2025-05获取当月时间范围 精确到秒 * @param string $yearMonth * @return array * @author 胡军 * @date 2025/06/25 */ private function getMonthTimeRange(string $yearMonth): array { // 验证输入格式 (YYYY-MM) if (!preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $yearMonth)) { throw new InvalidArgumentException('输入格式不正确,必须为YYYY-MM格式'); } list($year, $month) = explode('-', $yearMonth); // 构建开始时间 $startTime = "{$year}-{$month}-01 00:00:00"; // 使用DateTime类计算当月最后一天 $lastDay = (new \DateTime("{$year}-{$month}-01")) ->modify('last day of this month') ->format('d'); // 构建结束时间 $endTime = "{$year}-{$month}-{$lastDay} 23:59:59"; return [ 'startTime' => $startTime, 'endTime' => $endTime ]; }
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值