diff --git a/Cunkebao/app/traffic-pool/page.tsx b/Cunkebao/app/traffic-pool/page.tsx index 3fea66bd7..10cc5910c 100644 --- a/Cunkebao/app/traffic-pool/page.tsx +++ b/Cunkebao/app/traffic-pool/page.tsx @@ -95,6 +95,22 @@ interface Statistics { todayAddCount: number } +interface ConvertedUser { + id: number + nickname: string + avatar: string + wechatId: string + fromd: string + tags: string[] + createTime: string + status: number +} + +interface ConvertedResponse { + list: ConvertedUser[] + total: number +} + export default function TrafficPoolPage() { const router = useRouter() const searchParams = useSearchParams() @@ -155,12 +171,10 @@ export default function TrafficPoolPage() { limit: "30" }) - // 只有在有搜索关键词时才添加 keyword 参数 if (debouncedSearchQuery) { params.append("keyword", debouncedSearchQuery) } - // 只有在选择了特定来源时才添加 fromd 参数 if (sourceFilter !== "all") { const selectedSource = sourceTypes.find(source => source.id.toString() === sourceFilter) if (selectedSource) { @@ -168,39 +182,51 @@ export default function TrafficPoolPage() { } } - // 只有在选择了特定状态时才添加 status 参数 if (statusFilter !== "all") { params.append("status", statusFilter) } - const response = await api.get>(`/v1/traffic/pool?${params.toString()}`, { - headers: { - Authorization: `Bearer ${localStorage.getItem('token')}` - } - } as any) + const endpoint = activeCategory === "customer" + ? '/v1/traffic/pool/converted' + : '/v1/traffic/pool' + + const response = await api.get>( + `${endpoint}?${params.toString()}`, + { + headers: { + Authorization: `Bearer ${localStorage.getItem('token')}` + } + } as any + ) if (response.code === 200) { - const { list, pagination } = response.data + const { list } = response.data - const transformedUsers = list.map(user => ({ + const transformedUsers: TrafficUser[] = list.map((user: any) => ({ id: user.id.toString(), avatar: user.avatar, - nickname: user.name || user.nickname || '未知用户', + nickname: user.nickname || user.name || '未知用户', wechatId: user.wechatId, - phone: user.phone, - region: user.region, - note: user.note, - status: user.status, + phone: user.phone || '', + region: user.region || '', + note: user.note || '', + status: activeCategory === "customer" ? 3 : user.status, addTime: formatDateTime(user.createTime), source: user.fromd || '未知来源', - assignedTo: user.assignedTo, - category: user.category || "potential", - tags: user.tags || [] + assignedTo: user.assignedTo || '', + category: activeCategory as "potential" | "customer" | "lost", + tags: Array.isArray(user.tags) + ? user.tags.map((tag: string) => ({ + id: tag, + name: tag, + color: 'bg-blue-100 text-blue-800' + })) + : [] })) setUsers(prev => isNewSearch ? transformedUsers : [...prev, ...transformedUsers]) setCurrentPage(page) - setHasMore(list.length > 0 && page < pagination.totalPages) + setHasMore(list.length === 30) } else { toast({ title: "获取数据失败", @@ -222,7 +248,7 @@ export default function TrafficPoolPage() { setIsFetching(false) setLoading(false) } - }, [debouncedSearchQuery, sourceFilter, statusFilter, sourceTypes]) + }, [debouncedSearchQuery, sourceFilter, statusFilter, sourceTypes, activeCategory]) const fetchStatusTypes = useCallback(async () => { try { @@ -456,25 +482,27 @@ export default function TrafficPoolPage() { - + {activeCategory === "potential" && ( + + )} {/* 用户列表 */} @@ -506,14 +534,22 @@ export default function TrafficPoolPage() {
{user.nickname}
- {user.status === 2 ? "已添加" : user.status === 1 ? "待处理" : "已失败"} + {activeCategory === "customer" + ? "已通过" + : user.status === 2 + ? "已添加" + : user.status === 1 + ? "待处理" + : "已失败"}
微信号: {user.wechatId}
@@ -577,14 +613,22 @@ export default function TrafficPoolPage() {
{selectedUser.wechatId}
- {selectedUser.status === 2 ? "已添加" : selectedUser.status === 1 ? "待处理" : "已失败"} + {activeCategory === "customer" + ? "已通过" + : selectedUser.status === 2 + ? "已添加" + : selectedUser.status === 1 + ? "待处理" + : "已失败"} diff --git a/Server/application/cunkebao/config/route.php b/Server/application/cunkebao/config/route.php index 883bd5098..4f983ec52 100644 --- a/Server/application/cunkebao/config/route.php +++ b/Server/application/cunkebao/config/route.php @@ -42,6 +42,7 @@ Route::group('v1/', function () { // 流量池相关 Route::group('traffic/pool', function () { Route::get('', 'app\cunkebao\controller\traffic\GetPotentialListWithInCompanyV1Controller@index'); + Route::get('converted', 'app\cunkebao\controller\traffic\GetConvertedListWithInCompanyV1Controller@index'); Route::get('types', 'app\cunkebao\controller\traffic\GetPotentialTypeSectionV1Controller@index'); Route::get('sources', 'app\cunkebao\controller\traffic\GetTrafficSourceSectionV1Controller@index'); Route::get('statistics', 'app\cunkebao\controller\traffic\GetPoolStatisticsV1Controller@index'); diff --git a/Server/application/cunkebao/controller/traffic/GetConvertedListWithInCompanyV1Controller.php b/Server/application/cunkebao/controller/traffic/GetConvertedListWithInCompanyV1Controller.php new file mode 100644 index 000000000..b152c8dee --- /dev/null +++ b/Server/application/cunkebao/controller/traffic/GetConvertedListWithInCompanyV1Controller.php @@ -0,0 +1,112 @@ +items() as $item) { + $item->tags = json_decode($item->tags); + + array_push($resultSets, $item->toArray()); + } + + return $resultSets; + } + + /** + * 构建查询条件 + * + * @param array $params + * @return array + */ + protected function makeWhere(array $params = []): array + { + if (!empty($keyword = $this->request->param('keyword'))) { + $where[] = ['exp', "w.alias LIKE '%{$keyword}%' OR w.nickname LIKE '%{$keyword}%'"]; + } + + // 来源的筛选 + if ($fromd = $this->request->param('fromd')) { + $where['s.fromd'] = $fromd; + } + + $where['s.companyId'] = $this->getUserInfo('companyId'); + $where['s.status'] = TrafficSourceModel::STATUS_PASSED; + + return array_merge($where, $params); + } + + /** + * 获取流量池列表 + * + * @param array $where + * @return \think\Paginator + */ + protected function getPoolListByCompanyId(array $where): \think\Paginator + { + $query = TrafficSourceModel::alias('s') + ->field( + [ + 'w.id', 'w.nickname', 'w.avatar', + 'CASE WHEN w.alias IS NULL OR w.alias = "" THEN w.wechatId ELSE w.alias END AS wechatId', + 's.fromd', + 'f.tags', 'f.createTime', TrafficSourceModel::STATUS_PASSED . ' status' + ] + ) + ->join('traffic_pool p', 'p.identifier=s.identifier') + ->join('wechat_account w', 'p.wechatId=w.wechatId') + ->join('wechat_friendship f', 'w.wechatId=f.wechatId and f.deleteTime=0') + ->order('s.id desc'); + + foreach ($where as $key => $value) { + if (is_numeric($key) && is_array($value) && isset($value[0]) && $value[0] === 'exp') { + $query->whereExp('', $value[1]); + continue; + } + + $query->where($key, $value); + } + + return $query->paginate($this->request->param('limit/d', 10), false, ['page' => $this->request->param('page/d', 1)]); + } + + /** + * 获取流量池列表 + * + * @return \think\response\Json + */ + public function index() + { + try { + $result = $this->getPoolListByCompanyId( $this->makeWhere() ); + + return ResponseHelper::success( + [ + 'list' => $this->makeResultedSet($result), + 'total' => $result->total(), + ] + ); + } catch (\Exception $e) { + return ResponseHelper::error($e->getMessage(), $e->getCode()); + } + } +} \ No newline at end of file diff --git a/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php b/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php index 945c75c11..09442050d 100644 --- a/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php +++ b/Server/application/cunkebao/controller/traffic/GetPotentialListWithInCompanyV1Controller.php @@ -3,6 +3,7 @@ namespace app\cunkebao\controller\traffic; use app\common\model\TrafficPool as TrafficPoolModel; +use app\common\model\TrafficSource as TrafficSourceModel; use app\common\model\WechatFriendShip as WechatFriendShipModel; use app\cunkebao\controller\BaseController; use library\ResponseHelper; @@ -27,6 +28,8 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController // 状态筛选 if ($status = $this->request->param('status')) { $where['s.status'] = $status; + } else { + $where['s.status'] = array('<>', TrafficSourceModel::STATUS_PASSED); } // 来源的筛选 @@ -63,6 +66,11 @@ class GetPotentialListWithInCompanyV1Controller extends BaseController continue; } + if (is_array($value)) { + $query->where($key, ...$value); + continue; + } + $query->where($key, $value); } diff --git a/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php b/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php index 00d82c76f..bc4a2a9ea 100644 --- a/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php +++ b/Server/extend/WeChatDeviceApi/Adapters/ChuKeBao/Adapter.php @@ -8,6 +8,8 @@ use WeChatDeviceApi\Exceptions\ApiException; // use WeChatDeviceApi\Adapters\ChuKeBao\Client as ChuKeBaoApiClient; use think\Db; +use think\facade\Config; +use think\facade\Log; class Adapter implements WeChatServiceInterface { @@ -16,26 +18,29 @@ class Adapter implements WeChatServiceInterface public function __construct(array $config = []) { - $this->config = $config; + + // $this->config = $config ?: Config::get('wechat_device_api.'); + $this->config = $config ?: Config::get('wechat_device_api.adapters.ChuKeBao'); + // $this->config = $config; // $this->apiClient = new ChuKeBaoApiClient($config['api_key'], $config['api_secret'], $config['base_url']); // 校验配置等... - if (empty($config['api_key']) || empty($config['username']) || empty($config['password'])) { + if (empty($this->config['base_url']) || empty($this->config['username']) || empty($this->config['password'])) { throw new \InvalidArgumentException("ChuKeBao username and password are required."); } } public function addFriend(string $deviceId, string $targetWxId): bool { - // 1. 构建请求参数 (VendorA 特定的格式) + // 1. 构建请求参数 (ChuKeBao 特定的格式) $params = [ 'device_identifier' => $deviceId, 'wechat_user_to_add' => $targetWxId, 'username' => $this->config['username'], 'password' => $this->config['password'], - // ... 其他 VendorA 特定参数 + // ... 其他 ChuKeBao 特定参数 ]; - // 2. 调用 VendorA 的 API (例如使用 GuzzleHttp 或 cURL) + // 2. 调用 ChuKeBao 的 API (例如使用 GuzzleHttp 或 cURL) // $response = $this->apiClient->post('/friend/add', $params); // 伪代码: $url = $this->config['base_url'] . '/friend/add'; @@ -44,16 +49,16 @@ class Adapter implements WeChatServiceInterface // $responseData = json_decode($response->getBody()->getContents(), true); // 模拟API调用 - echo "VendorA: Adding friend {$targetWxId} using device {$deviceId}\n"; + echo "ChuKeBao: Adding friend {$targetWxId} using device {$deviceId}\n"; $responseData = ['code' => 0, 'message' => 'Success']; // 假设的响应 // 3. 处理响应,转换为标准结果 if (!isset($responseData['code'])) { - throw new ApiException("VendorA: Invalid API response for addFriend."); + throw new ApiException("ChuKeBao: Invalid API response for addFriend."); } if ($responseData['code'] !== 0) { - throw new ApiException("VendorA: Failed to add friend - " . ($responseData['message'] ?? 'Unknown error')); + throw new ApiException("ChuKeBao: Failed to add friend - " . ($responseData['message'] ?? 'Unknown error')); } return true; @@ -61,17 +66,17 @@ class Adapter implements WeChatServiceInterface public function likeMoment(string $deviceId, string $momentId): bool { - echo "VendorA: Liking moment {$momentId} using device {$deviceId}\n"; + echo "ChuKeBao: Liking moment {$momentId} using device {$deviceId}\n"; // 实现 VendorA 的点赞逻辑 return true; } public function getGroupList(string $deviceId): array { - echo "VendorA: Getting group list for device {$deviceId}\n"; + echo "ChuKeBao: Getting group list for device {$deviceId}\n"; // 实现 VendorA 的获取群列表逻辑,并转换数据格式 return [ - ['id' => 'group1_va', 'name' => 'VendorA Group 1', 'member_count' => 10], + ['id' => 'group1_va', 'name' => 'ChuKeBao Group 1', 'member_count' => 10], ]; } @@ -79,19 +84,19 @@ class Adapter implements WeChatServiceInterface { echo "VendorA: Getting friend list for device {$deviceId}\n"; return [ - ['id' => 'friend1_va', 'nickname' => 'VendorA Friend 1', 'remark' => 'VA-F1'], + ['id' => 'friend1_va', 'nickname' => 'ChuKeBao Friend 1', 'remark' => 'VA-F1'], ]; } public function getDeviceInfo(string $deviceId): array { - echo "VendorA: Getting device info for device {$deviceId}\n"; + echo "ChuKeBao: Getting device info for device {$deviceId}\n"; return ['id' => $deviceId, 'status' => 'online_va', 'battery' => '80%']; } public function bindDeviceToCompany(string $deviceId, string $companyId): bool { - echo "VendorA: Binding device {$deviceId} to company {$companyId}\n"; + echo "ChuKeBao: Binding device {$deviceId} to company {$companyId}\n"; return true; } @@ -103,7 +108,7 @@ class Adapter implements WeChatServiceInterface */ public function getChatroomMemberList(string $deviceId, string $chatroomId): array { - echo "VendorA: Getting chatroom member list for device {$deviceId}, chatroom {$chatroomId}\n"; + echo "ChuKeBao: Getting chatroom member list for device {$deviceId}, chatroom {$chatroomId}\n"; return [ ['id' => 'member1_va', 'nickname' => 'VendorA Member 1', 'avatar' => ''], ]; @@ -160,7 +165,6 @@ class Adapter implements WeChatServiceInterface $offset = 0; $limit = 2000; - // $usleepTime = 100000; $usleepTime = 50000; do { @@ -179,7 +183,7 @@ class Adapter implements WeChatServiceInterface SELECT wechatId,alias,nickname,pyInitial,quanPin,avatar,gender,region,signature,phone,country,privince,city,createTime,updateTime FROM - s2_wechat_friend GROUP BY wechatId; + s2_wechat_friend GROUP BY wechatId ON DUPLICATE KEY UPDATE alias=VALUES(alias), nickname=VALUES(nickname), @@ -200,26 +204,125 @@ class Adapter implements WeChatServiceInterface } // syncWechatDeviceLoginLog + // public function syncWechatDeviceLoginLog() + // { + // try { + // // 确保使用正确的表名,不要让框架自动添加前缀 + // Db::connect()->table('s2_wechat_account') + // ->alias('a') + // ->join(['s2_device' => 'd'], 'd.imei = a.imei') + // ->join(['s2_company_account' => 'c'], 'c.id = d.currentAccountId') + // ->field('d.id as deviceId, a.wechatId, a.wechatAlive as alive, c.departmentId as companyId, a.updateTime as createTime') + // ->chunk(1000, function ($data) { + // try { + // foreach ($data as $item) { + // Log::info("syncWechatDeviceLoginLog: " . json_encode($item)); + // try { + // // 检查所有必要字段是否存在,如果不存在则设置默认值 + // // if (!isset($item['deviceId']) || !isset($item['wechatId']) || + // // !isset($item['alive']) || !isset($item['companyId']) || + // // !isset($item['createTime'])) { + + // // \think\facade\Log::warning("Missing required field in syncWechatDeviceLoginLog: " . json_encode($item)); + + // // // 为缺失字段设置默认值 + // // $item['deviceId'] = $item['deviceId'] ?? ''; + // // $item['wechatId'] = $item['wechatId'] ?? ''; + // // $item['alive'] = $item['alive'] ?? 0; + // // $item['companyId'] = $item['companyId'] ?? 0; + // // $item['createTime'] = $item['createTime'] ?? date('Y-m-d H:i:s'); + + // // // 如果关键字段仍然为空,则跳过此条记录 + // // if (empty($item['deviceId']) || empty($item['wechatId']) || empty($item['createTime'])) { + // // continue; + // // } + // // } + // if (empty($item['deviceId']) || empty($item['wechatId']) || empty($item['createTime'])) { + // continue; + // } + + // $exists = Db::connect()->table('ck_device_wechat_login') + // ->where('deviceId', $item['deviceId']) + // ->where('wechatId', $item['wechatId']) + // ->where('createTime', $item['createTime']) + // ->find(); + + // if (!$exists) { + // Db::connect()->table('ck_device_wechat_login')->insert($item); + // } + // } catch (\Exception $e) { + // \think\facade\Log::error("处理单条数据时出错: " . $e->getMessage() . ", 数据: " . json_encode($item) . ", 堆栈: " . $e->getTraceAsString()); + // continue; // 跳过这条出错的记录,继续处理下一条 + // } + // } + // } catch (\Exception $e) { + // \think\facade\Log::error("处理批次数据时出错: " . $e->getMessage() . ", 堆栈: " . $e->getTraceAsString()); + // // 不抛出异常,让程序继续处理下一批次数据 + // } + // }); + // } catch (\Exception $e) { + // \think\facade\Log::error("微信好友同步任务异常1: " . $e->getMessage() . ", 堆栈: " . $e->getTraceAsString()); + // // 可以选择重新抛出异常或者返回false + // return false; + // } + + // return true; + // } public function syncWechatDeviceLoginLog() { - Db::table('s2_wechat_account') - ->alias('a') - ->join('s2_device d', 'd.imei = a.imei') - ->join('s2_company_account c', 'c.id = d.currentAccountId') - ->field('d.id as deviceId, a.wechatId, a.wechatAlive as alive, c.departmentId as companyId, a.updateTime as createTime') - ->chunk(1000, function ($data) { - foreach ($data as $item) { - $exists = Db::table('ck_device_wechat_login') + try { + // 确保使用正确的表名,不要让框架自动添加前缀 + $cursor = Db::connect()->table('s2_wechat_account') + ->alias('a') + ->join(['s2_device' => 'd'], 'd.imei = a.imei') + ->join(['s2_company_account' => 'c'], 'c.id = d.currentAccountId') + ->field('d.id as deviceId, a.wechatId, a.wechatAlive as alive, c.departmentId as companyId, a.updateTime as createTime') + ->cursor(); + + foreach ($cursor as $item) { + try { + // 检查所有必要字段是否存在,如果不存在则设置默认值 + if ( + !isset($item['deviceId']) || !isset($item['wechatId']) || + !isset($item['alive']) || !isset($item['companyId']) || + !isset($item['createTime']) + ) { + + Log::warning("Missing required field in syncWechatDeviceLoginLog: " . json_encode($item)); + + // 为缺失字段设置默认值 + $item['deviceId'] = $item['deviceId'] ?? ''; + $item['wechatId'] = $item['wechatId'] ?? ''; + $item['alive'] = $item['alive'] ?? 0; + $item['companyId'] = $item['companyId'] ?? 0; + $item['createTime'] = $item['createTime'] ?? date('Y-m-d H:i:s'); + + // 如果关键字段仍然为空,则跳过此条记录 + if (empty($item['deviceId']) || empty($item['wechatId']) || empty($item['createTime'])) { + continue; + } + } + + $exists = Db::connect()->table('ck_device_wechat_login') ->where('deviceId', $item['deviceId']) ->where('wechatId', $item['wechatId']) ->where('createTime', $item['createTime']) ->find(); if (!$exists) { - Db::table('ck_device_wechat_login')->insert($item); + Db::connect()->table('ck_device_wechat_login')->insert($item); } + } catch (\Exception $e) { + Log::error("处理单条数据时出错: " . $e->getMessage() . ", 数据: " . json_encode($item) . ", 堆栈: " . $e->getTraceAsString()); + continue; // 跳过这条出错的记录,继续处理下一条 } - }); + } + + return true; + } catch (\Exception $e) { + Log::error("微信好友同步任务异常: " . $e->getMessage() . ", 堆栈: " . $e->getTraceAsString()); + return false; + } } /** @@ -230,48 +333,8 @@ class Adapter implements WeChatServiceInterface * @param int $batchSize 每批处理的数据量 * @return int 影响的行数 */ - // public function syncWechatFriendToTrafficPoolBatch($batchSize = 5000) - // { - // // 1. 获取数据总量 - // $total = Db::table('s2_wechat_friend') - // ->group('wechatId') - // ->count(); - - // // 2. 计算需要处理的批次 - // $batchCount = ceil($total / $batchSize); - // $affectedRows = 0; - - // // 3. 分批处理 - // for ($i = 0; $i < $batchCount; $i++) { - // $offset = $i * $batchSize; - - // // 分批查询SQL,使用LIMIT控制每次获取的数据量 - // $sql = "INSERT IGNORE INTO ck_traffic_pool(`identifier`, `wechatId`, `mobile`) - // SELECT wechatId identifier, wechatId, phone - // FROM ( - // SELECT wechatId, phone - // FROM `s2_wechat_friend` - // GROUP BY wechatId - // LIMIT {$offset}, {$batchSize} - // ) AS temp"; - - // $affectedRows += Db::execute($sql); - - // // 释放内存 - // if ($i % 5 == 0) { - // Db::clear(); - // gc_collect_cycles(); - // } - // } - - // return $affectedRows; - // } - - - public function syncWechatFriendToTrafficPoolBatch($batchSize = 5000) { - // 1. 先获取去重后的wechatId清单并建立临时索引 Db::execute("CREATE TEMPORARY TABLE IF NOT EXISTS temp_wechat_ids ( wechatId VARCHAR(64) PRIMARY KEY ) ENGINE=MEMORY"); @@ -281,26 +344,15 @@ class Adapter implements WeChatServiceInterface // 批量插入去重的wechatId Db::execute("INSERT INTO temp_wechat_ids SELECT DISTINCT wechatId FROM s2_wechat_friend"); - // 2. 获取临时表的数据总量 $total = Db::table('temp_wechat_ids')->count(); - // 3. 计算需要处理的批次 $batchCount = ceil($total / $batchSize); $affectedRows = 0; - // 4. 开始事务处理批量数据 try { for ($i = 0; $i < $batchCount; $i++) { $offset = $i * $batchSize; - // 使用临时表和JOIN来提高查询效率 - // $sql = "INSERT IGNORE INTO ck_traffic_pool(`identifier`, `wechatId`, `mobile`) - // SELECT t.wechatId AS identifier, t.wechatId, f.phone AS mobile - // FROM ( - // SELECT wechatId FROM temp_wechat_ids LIMIT {$offset}, {$batchSize} - // ) AS t - // LEFT JOIN s2_wechat_friend f ON t.wechatId = f.wechatId - // GROUP BY t.wechatId"; $sql = "INSERT IGNORE INTO ck_traffic_pool(`identifier`, `wechatId`, `mobile`) SELECT t.wechatId AS identifier, t.wechatId, (SELECT phone FROM s2_wechat_friend @@ -312,38 +364,19 @@ class Adapter implements WeChatServiceInterface $currentAffected = Db::execute($sql); $affectedRows += $currentAffected; - // 更频繁地释放内存 - // if ($i % 2 == 1) { if ($i % 5 == 0) { - // Db::clear(); gc_collect_cycles(); } - // 添加短暂休眠,但不要太长以免影响总体执行时间 - // 20-50毫秒通常是个不错的平衡点 usleep(30000); // 30毫秒 - - // 如果批处理大小很大或者当前批影响行数很多,可以适当增加休眠时间 - // if ($currentAffected > 1000) { - // usleep(20000); // 额外增加20毫秒 - // } - - // 输出进度日志 - // $progress = round(($i + 1) / $batchCount * 100, 2); - // \think\facade\Log::info("Traffic pool sync progress: {$progress}% completed. Rows affected in this batch: {$currentAffected}"); } } catch (\Exception $e) { \think\facade\Log::error("Error in traffic pool sync: " . $e->getMessage()); - // 删除临时表 - // Db::execute("DROP TEMPORARY TABLE IF EXISTS temp_wechat_ids"); throw $e; } finally { Db::execute("DROP TEMPORARY TABLE IF EXISTS temp_wechat_ids"); } - // 5. 清理临时表 - // Db::execute("DROP TEMPORARY TABLE IF EXISTS temp_wechat_ids"); - return $affectedRows; } }