您现在的位置是:首页 > 榴榴无忌

商城系统 订单批量删除工具附源代码 最近风大,清清记录更健康[5P]

| 人围观 |

沧海跨云药神2026-09-18 17:37:29

大家好,我是沧海跨云药神
前段时间做的一个小工具,
根据时间线或者某个订单截断数据!

正经行业是不需要这个工具的
不太正经的行业,嗯哼,或许对您有用




控制方法
複製代码
  1. public function index()
  2.     {
  3.         if (request()->isPost()) {
  4.             $action = input('post.action', '');
  5.             if ($action === 'search') {
  6.                 return $this->search();
  7.             } elseif ($action === 'delete') {
  8.                 return $this->delete();
  9.             }
  10.         }
  11.         return MyView();
  12.     }
  13.     private function search()
  14.     {
  15.         $params = [
  16.             'date'     => input('post.date', ''),
  17.             'order_id' => input('post.order_id', 0, 'intval'),
  18.             'page'     => input('post.page', 1, 'intval'),
  19.         ];
  20.         $ret = 自定义名称Service::SearchOrders($params);
  21.         return ApiService::ApiDataReturn($ret);
  22.     }
  23.     private function delete()
  24.     {
  25.         $params = [
  26.             'date'     => input('post.date', ''),
  27.             'order_id' => input('post.order_id', 0, 'intval'),
  28.         ];
  29.         $ret = 自定义名称Service::DeleteOrders($params);
  30.         return ApiService::ApiDataReturn($ret);
  31.     }
複製代码

服务文件
複製代码
  1. class 自定义名称Service
  2. {
  3.     /**
  4.      * 搜索订单(预览列表)
  5.      */
  6.     public static function SearchOrders($params)
  7.     {
  8.         $where = self::BuildWhere($params);
  9.         if (empty($where)) {
  10.             return DataReturn('请选择日期或输入订单ID', -1);
  11.         }
  12.         $page = isset($params['page']) ? intval($params['page']) : 1;
  13.         $limit = 20;
  14.         $total = Db::name('Order')->where($where)->count();
  15.         $list = Db::name('Order')
  16.             ->where($where)
  17.             ->field('id, order_no, user_id, total_price, status, pay_status, add_time')
  18.             ->order('id', 'desc')
  19.             ->page($page, $limit)
  20.             ->select()
  21.             ->toArray();
  22.         if (!empty($list)) {
  23.             $order_ids = array_column($list, 'id');
  24.             $user_ids = array_column($list, 'user_id');
  25.             // 用户信息
  26.             $users = Db::name('User')
  27.                 ->whereIn('id', $user_ids)
  28.                 ->field('id, username, email')
  29.                 ->select()
  30.                 ->toArray();
  31.             $userMap = [];
  32.             foreach ($users as $u) {
  33.                 $userMap[$u['id']] = !empty($u['email']) ? $u['email'] : $u['username'];
  34.             }
  35.             // 收货地址
  36.             $addresses = Db::name('OrderAddress')
  37.                 ->whereIn('order_id', $order_ids)
  38.                 ->field('order_id, name, tel, province_name, city_name, county_name, address')
  39.                 ->select()
  40.                 ->toArray();
  41.             $addrMap = [];
  42.             foreach ($addresses as $addr) {
  43.                 $addrMap[$addr['order_id']] = $addr['name'] . ' ' . $addr['tel'] . ','
  44.                     . $addr['province_name'] . $addr['city_name'] . $addr['county_name'] . ' ' . $addr['address'];
  45.             }
  46.             // 商品信息(含规格)
  47.             $goods = Db::name('OrderDetail')
  48.                 ->whereIn('order_id', $order_ids)
  49.                 ->field('order_id, title, spec')
  50.                 ->select()
  51.                 ->toArray();
  52.             $goodsMap = [];
  53.             foreach ($goods as $g) {
  54.                 $spec_text = '';
  55.                 if (!empty($g['spec'])) {
  56.                     $spec_arr = json_decode($g['spec'], true);
  57.                     if (is_array($spec_arr)) {
  58.                         $spec_text = implode(' ', array_map(function($v) {
  59.                             return $v['type'] . ':' . $v['value'];
  60.                         }, $spec_arr));
  61.                     }
  62.                 }
  63.                 $goodsMap[$g['order_id']][] = [
  64.                     'title' => $g['title'],
  65.                     'spec'  => $spec_text,
  66.                 ];
  67.             }
  68.             foreach ($list as &$item) {
  69.                 $item['user_display'] = $userMap[$item['user_id']] ?? '未知用户';
  70.                 $item['address'] = $addrMap[$item['id']] ?? '无地址';
  71.                 $item['goods_list'] = $goodsMap[$item['id']] ?? [];
  72.             }
  73.         }
  74.         $totalPrice = Db::name('Order')->where($where)->sum('total_price');
  75.         return DataReturn('success', 0, [
  76.             'list'       => $list,
  77.             'total'      => $total,
  78.             'totalPrice' => $totalPrice ?: 0,
  79.             'page'       => $page,
  80.             'limit'      => $limit,
  81.         ]);
  82.     }
  83.     /**
  84.      * 删除订单及关联数据(按时间线清理所有支付记录,不限业务类型)
  85.      */
  86.     public static function DeleteOrders($params)
  87.     {
  88.         $where = self::BuildWhere($params);
  89.         if (empty($where)) {
  90.             return DataReturn('请选择日期或输入订单ID', -1);
  91.         }
  92.         $order_ids = Db::name('Order')->where($where)->column('id');
  93.         if (empty($order_ids)) {
  94.             return DataReturn('没有符合条件的订单', -1);
  95.         }
  96.         $total = count($order_ids);
  97.         $max_order_id = max($order_ids);
  98.         $max_order_time = Db::name('Order')
  99.             ->whereIn('id', $order_ids)
  100.             ->max('add_time');
  101.         Db::startTrans();
  102.         try {
  103.             // 1. 删除消息(所有历史订单消息,业务类型为'订单'或'order')
  104.             Db::name('Message')
  105.                 ->whereIn('business_type', ['订单', 'order'])
  106.                 ->where('business_id', '>', 1)
  107.                 ->where('business_id', '<=', $max_order_id)
  108.                 ->delete();
  109.             // 2. 删除订单关联的子表(除支付相关外)
  110.             $chunks = array_chunk($order_ids, 200);
  111.             foreach ($chunks as $chunk) {
  112.                 Db::name('OrderDetail')->whereIn('order_id', $chunk)->delete();
  113.                 Db::name('OrderAddress')->whereIn('order_id', $chunk)->delete();
  114.                 Db::name('OrderAftersale')->whereIn('order_id', $chunk)->delete();
  115.                 Db::name('OrderCurrency')->whereIn('order_id', $chunk)->delete();
  116.                 Db::name('OrderGoodsInventoryLog')->whereIn('order_id', $chunk)->delete();
  117.                 Db::name('OrderStatusHistory')->whereIn('order_id', $chunk)->delete();
  118.                 Db::name('OrderExtractionCode')->whereIn('order_id', $chunk)->delete();
  119.                 Db::name('OrderFictitiousValue')->whereIn('order_id', $chunk)->delete();
  120.                 // 删除订单主表
  121.                 Db::name('Order')->whereIn('id', $chunk)->delete();
  122.             }
  123.             // 3. 按时间线删除支付日志关联表(不限业务类型)
  124.             if (!empty($max_order_time)) {
  125.                 Db::name('PayLogValue')
  126.                     ->where('add_time', '<=', $max_order_time)
  127.                     ->delete();
  128.             }
  129.             // 4. 按时间线删除支付日志主表(不限业务类型)
  130.             if (!empty($max_order_time)) {
  131.                 Db::name('PayLog')
  132.                     ->where('add_time', '<=', $max_order_time)
  133.                     ->delete();
  134.             }
  135.             // 5. 按时间线删除支付请求日志(不限业务类型)
  136.             if (!empty($max_order_time)) {
  137.                 Db::name('PayRequestLog')
  138.                     ->where('add_time', '<=', $max_order_time)
  139.                     ->delete();
  140.             }
  141.             Db::commit();
  142.             return DataReturn("成功删除 {$total} 条订单及其关联数据;支付记录清理至时间线:".date('Y-m-d H:i:s', $max_order_time)."(不限业务类型)", 0);
  143.         } catch (\Exception $e) {
  144.             Db::rollback();
  145.             return DataReturn('删除失败:' . $e->getMessage(), -1);
  146.         }
  147.     }
  148.     /**
  149.      * 构建查询条件
  150.      */
  151.     private static function BuildWhere($params)
  152.     {
  153.         $where = [];
  154.         if (!empty($params['date'])) {
  155.             $timestamp = strtotime($params['date']);
  156.             if ($timestamp !== false) {
  157.                 $where[] = ['add_time', '<=', $timestamp + 86399];
  158.             }
  159.         } elseif (!empty($params['order_id'])) {
  160.             $where[] = ['id', '<=', intval($params['order_id'])];
  161.         }
  162.         return $where;
  163.     }
  164. }
複製代码


视图文件
複製代码
  1. <div class="content-right">
  2.     <div class="content">
  3.         <div class="am-panel am-panel-default">
  4.             <div class="am-panel-hd am-cf">
  5.                 <h3 class="am-fl"><i class="am-icon-trash-o"></i> 批量删除订单</h3>
  6.             </div>
  7.             <div class="am-panel-bd">
  8.                 <div class="am-alert am-alert-danger">
  9.                     <strong>⚠️ 谨慎操作</strong> 此操作将永久删除符合条件的订单及其所有关联数据,不可恢复!
  10.                 </div>
  11.                 <!-- 搜索表单 -->
  12.                 <div class="am-form am-form-inline" id="searchForm">
  13.                     <div class="am-form-group">
  14.                         <label class="am-margin-right-sm">截止日期</label>
  15.                         <input type="date" name="date" id="date" class="am-form-field" style="width:160px;" />
  16.                         <button type="button" class="am-btn am-btn-default am-btn-sm am-margin-left-xs" id="clearDateBtn" style="height:34px;line-height:34px;padding:0 10px;">清除</button>
  17.                     </div>
  18.                     <div class="am-form-group am-margin-left">
  19.                         <label class="am-margin-right-sm">截止订单</label>
  20.                         <input type="number" name="order_id" id="order_id" placeholder="输入订单ID" class="am-form-field" style="width:150px;" min="1" />
  21.                     </div>
  22.                     <button type="button" class="am-btn am-btn-primary" id="searchBtn">查询</button>
  23.                     <button type="button" class="am-btn am-btn-danger" id="deleteBtn">删除</button>
  24.                     <span class="am-text-muted am-margin-left-sm">(填日期则忽略ID)</span>
  25.                 </div>
  26.                 <div class="am-margin-top-sm">
  27.                     <span>共 <strong id="totalCount">0</strong> 条订单,合计金额:<strong id="totalPrice">0.00</strong> 元</span>
  28.                 </div>
  29.                 <!-- 卡片式订单列表 -->
  30.                 <div id="orderList" class="am-margin-top-sm">
  31.                     <div class="am-text-center am-padding-vertical-lg" style="color:#999;">请点击「查询」预览订单</div>
  32.                 </div>
  33.                 <!-- 分页 -->
  34.                 <div class="am-cf">
  35.                     <ul class="am-pagination am-fr" id="pageList"></ul>
  36.                 </div>
  37.             </div>
  38.         </div>
  39.     </div>
  40. </div>
複製代码

视觉样式代码 略
事件点击代码 略
防水图不能略

最近风大,清清记录更健康

随手一赞 手留余香!


此贴由沧海跨云药神重新编辑:2026-09-17 03:00

随便看看