修正 Proxied、 SSL/TLS 设为 Flexible、开启 Always Use HTTPS

This commit is contained in:
root
2026-06-10 06:44:57 +08:00
parent a68b83fcbd
commit 5dea4c8b28
31 changed files with 950 additions and 160 deletions
@@ -14,8 +14,6 @@ use think\Exception;
*/
class SplitTicketSyncService
{
private const FAIL_PAUSE_THRESHOLD = 5;
private SplitTicketNumberSyncService $numberSync;
private SplitTicketRuleService $ruleService;
@@ -38,24 +36,42 @@ class SplitTicketSyncService
{
$ticket = Ticket::get($ticketId);
if (!$ticket) {
SplitTicketSyncLogger::log('sync', 'ticket not found', ['ticketId' => $ticketId]);
return ['success' => false, 'message' => '工单不存在'];
}
SplitTicketSyncLogger::setTicketContext($ticketId, (string) $ticket['ticket_type']);
SplitTicketSyncLogger::log('sync', 'syncOne start', [
'force' => $force,
'status' => (string) $ticket['status'],
'syncFailCount' => (int) ($ticket['sync_fail_count'] ?? 0),
'syncTime' => (int) ($ticket['sync_time'] ?? 0),
'pageUrl' => (string) $ticket['ticket_url'],
'nodeHost' => SplitSyncConfigService::getNodeHost(),
]);
if (!$force) {
$skip = $this->shouldSkip($ticket);
if ($skip !== null) {
SplitTicketSyncLogger::log('sync', 'skipped', ['reason' => $skip]);
SplitTicketSyncLogger::clearTicketContext();
return ['success' => false, 'message' => $skip, 'skipped' => true];
}
}
if (!$this->lockService->acquire($ticketId)) {
SplitTicketSyncLogger::log('sync', 'lock busy', ['ticketId' => $ticketId]);
SplitTicketSyncLogger::clearTicketContext();
return ['success' => false, 'message' => '工单正在同步中', 'skipped' => true];
}
try {
return $this->doSync($ticket);
$result = $this->doSync($ticket);
SplitTicketSyncLogger::log('sync', 'syncOne end', $result);
return $result;
} finally {
$this->lockService->release($ticketId);
SplitTicketSyncLogger::clearTicketContext();
}
}
@@ -65,13 +81,25 @@ class SplitTicketSyncService
public function syncDueTickets(): int
{
$count = 0;
$list = Ticket::where('status', 'normal')
->where('sync_fail_count', '<', self::FAIL_PAUSE_THRESHOLD)
->select();
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
$query = Ticket::where('status', 'normal');
if ($failThreshold > 0) {
$query->where('sync_fail_count', '<', $failThreshold);
}
$list = $query->select();
SplitTicketSyncLogger::log('cron', 'scan start', [
'candidateCount' => count($list),
]);
foreach ($list as $ticket) {
$skip = $this->shouldSkip($ticket);
if ($skip !== null) {
SplitTicketSyncLogger::log('cron', 'candidate skipped', [
'ticketId' => (int) $ticket['id'],
'ticketType' => (string) $ticket['ticket_type'],
'reason' => $skip,
]);
continue;
}
$result = $this->syncOne((int) $ticket['id'], false);
@@ -81,6 +109,7 @@ class SplitTicketSyncService
$count++;
}
SplitTicketSyncLogger::log('cron', 'scan end', ['processedCount' => $count]);
return $count;
}
@@ -92,15 +121,21 @@ class SplitTicketSyncService
$ticketType = (string) $ticket['ticket_type'];
$pageUrl = trim((string) $ticket['ticket_url']);
if ($pageUrl === '') {
SplitTicketSyncLogger::log('sync', 'empty pageUrl');
$this->markFailure($ticket, '工单链接为空');
return ['success' => false, 'message' => '工单链接为空'];
}
if (!SplitScrmSpiderFactory::isSupported($ticketType)) {
SplitTicketSyncLogger::log('sync', 'spider not supported', ['ticketType' => $ticketType]);
$this->markFailure($ticket, '工单类型尚未实现蜘蛛');
return ['success' => false, 'message' => '工单类型尚未实现蜘蛛'];
}
SplitTicketSyncLogger::log('sync', 'create spider', [
'ticketType' => $ticketType,
'hasAccount' => trim((string) ($ticket['account'] ?? '')) !== '',
]);
$spider = SplitScrmSpiderFactory::create(
$ticketType,
$pageUrl,
@@ -114,22 +149,24 @@ class SplitTicketSyncService
Db::startTrans();
try {
SplitTicketSyncLogger::log('sync', 'spider run begin');
$finalData = $spider->run();
if (!$finalData instanceof UnifiedScrmData) {
throw new Exception('蜘蛛返回数据无效');
}
$this->numberSync->syncFromUnifiedData($ticket, $finalData);
$this->ruleService->applyNumberRules($ticket);
$completeCount = max(0, $finalData->todayNewCount);
$this->ruleService->applyTicketStatusRules($ticket, $completeCount);
$freshTicket = Ticket::get((int) $ticket['id']);
if ($freshTicket) {
$freshTicket = Ticket::get((int) $ticket['id']) ?: $ticket;
if ((string) $freshTicket['status'] === 'hidden') {
$this->ruleService->cascadeTicketClosedToNumbers($freshTicket);
$ticket = $freshTicket;
}
// 号码开关最后统一由 applyNumberRules 判定(单号上限/下号比率/云控在线)
$this->ruleService->applyNumberRules($freshTicket);
$ticket = $freshTicket;
$inboundCount = $this->numberSync->sumInboundForTicket($ticket);
$speed = $this->calcSpeedPerHour($ticket, $completeCount);
@@ -149,10 +186,17 @@ class SplitTicketSyncService
$this->applySyncResult($ticket, $payload, true, '');
Db::commit();
SplitTicketSyncLogger::log('sync', 'db commit ok', $payload);
return ['success' => true, 'message' => '同步成功'];
} catch (\Throwable $e) {
Db::rollback();
$msg = mb_substr($e->getMessage(), 0, 255, 'UTF-8');
SplitTicketSyncLogger::log('sync', 'exception', [
'type' => get_class($e),
'message' => $msg,
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
$this->markFailure($ticket, $msg);
return ['success' => false, 'message' => $msg];
}
@@ -163,8 +207,9 @@ class SplitTicketSyncService
if ((string) $ticket['status'] === 'hidden') {
return '工单已关闭';
}
if ((int) ($ticket['sync_fail_count'] ?? 0) >= self::FAIL_PAUSE_THRESHOLD) {
return '连续同步失败超过5次已暂停';
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
if ($failThreshold > 0 && (int) ($ticket['sync_fail_count'] ?? 0) >= $failThreshold) {
return sprintf('连续同步失败超过%d次已暂停', $failThreshold);
}
if (!SplitScrmSpiderFactory::isSupported((string) $ticket['ticket_type'])) {
return '工单类型尚未实现';
@@ -174,7 +219,13 @@ class SplitTicketSyncService
return '该类型未配置自动同步周期';
}
$lastSync = (int) ($ticket['sync_time'] ?? 0);
if ($lastSync > 0 && (time() - $lastSync) < ($interval * 60)) {
$elapsed = $lastSync > 0 ? (time() - $lastSync) : null;
if ($lastSync > 0 && $elapsed !== null && $elapsed < ($interval * 60)) {
SplitTicketSyncLogger::log('sync', 'interval not reached', [
'intervalMinutes' => $interval,
'elapsedSeconds' => $elapsed,
'needSeconds' => $interval * 60,
]);
return '未到同步周期';
}
return null;
@@ -208,12 +259,26 @@ class SplitTicketSyncService
private function markFailure(Ticket $ticket, string $message): void
{
$failCount = (int) ($ticket['sync_fail_count'] ?? 0) + 1;
$ticket->save([
$failThreshold = SplitSyncConfigService::getFailPauseThreshold();
$previousSyncStatus = (string) ($ticket['sync_status'] ?? 'pending');
$neverSyncedSuccessfully = $previousSyncStatus === 'pending' && (int) ($ticket['sync_time'] ?? 0) <= 0;
$update = [
'sync_status' => 'error',
'sync_time' => time(),
'sync_message' => mb_substr($message, 0, 255, 'UTF-8'),
'sync_fail_count' => $failCount,
]);
];
// 新建工单首次同步失败:立即关闭;已同步过的工单仍按连续失败阈值关闭
if ($neverSyncedSuccessfully || ($failThreshold > 0 && $failCount >= $failThreshold)) {
$update['status'] = 'hidden';
}
$ticket->save($update);
if (isset($update['status']) && $update['status'] === 'hidden') {
$fresh = Ticket::get((int) $ticket['id']);
if ($fresh) {
$this->ruleService->cascadeTicketClosedToNumbers($fresh);
}
}
}
/**