同步失败原因,最近同步成功的时间记录

This commit is contained in:
root
2026-06-20 05:07:11 +08:00
parent d5a0ffa6db
commit e95f4a227c
19 changed files with 884 additions and 74 deletions
@@ -0,0 +1,14 @@
-- 工单同步日志增强:最近成功时间/方式、完整失败原因
SET NAMES utf8mb4;
ALTER TABLE `fa_split_ticket`
MODIFY COLUMN `sync_message` text COMMENT '同步失败完整原因',
ADD COLUMN `sync_success_time` bigint(16) DEFAULT NULL COMMENT '最近一次同步成功时间' AFTER `sync_time`,
ADD COLUMN `sync_success_mode` enum('auto','manual') DEFAULT NULL COMMENT '最近成功同步方式:auto=自动,manual=手动' AFTER `sync_success_time`;
UPDATE `fa_split_ticket`
SET `sync_success_time` = `sync_time`
WHERE `sync_status` = 'success'
AND `sync_success_time` IS NULL
AND `sync_time` IS NOT NULL
AND `sync_time` > 0;
@@ -62,12 +62,13 @@ class SplitSyncTickets extends Command
try {
$count = $service->syncDueTickets();
$output->writeln('<info>本次处理工单数: ' . $count . '</info>');
$output->writeln('<comment>汇总日志已写入 runtime/log/split_sync.log</comment>');
} finally {
$cronLock->release();
}
if (SplitTicketSyncLogger::isEnabled()) {
$output->writeln('<comment>调试日志已写入 runtime/log/split_sync.log</comment>');
$output->writeln('<comment>详细调试日志已写入 runtime/log/split_sync.log</comment>');
}
}
}
@@ -273,6 +273,8 @@ class Ticket extends Backend
$params['sync_status'],
$params['sync_time'],
$params['sync_message'],
$params['sync_success_time'],
$params['sync_success_mode'],
$params['sync_fail_count'],
$params['speed_snapshot_count'],
$params['speed_snapshot_time'],
@@ -37,6 +37,13 @@ return [
'Sync display success' => '同步成功 / 在线 %s',
'Sync display pending' => '待同步',
'Sync display error' => '同步异常',
'Sync display auto paused' => '自动同步已暂停',
'Sync success time' => '最近同步成功',
'Sync mode auto' => '自动',
'Sync mode manual' => '手动',
'Sync tooltip auto paused' => '连续失败 %s 次,已达暂停阈值 %s,自动同步已暂停',
'Sync tooltip error prefix' => '异常原因:',
'Cron log path hint' => '汇总日志已写入 runtime/log/split_sync.log',
'Createtime' => '创建时间',
'Copy' => '拷贝',
'Summary row' => '汇总',
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace app\admin\model\split;
use app\common\service\SplitSyncConfigService;
use think\Db;
use think\Model;
@@ -31,6 +32,9 @@ class Ticket extends Model
'ticket_progress_text',
'inbound_ratio_text',
'sync_display_text',
'sync_success_text',
'sync_tooltip_text',
'sync_auto_paused',
];
/**
@@ -152,13 +156,35 @@ class Ticket extends Model
}
/**
* 同步状态展示文案
* 是否因连续失败暂停自动同步(工单仍为开启状态)
*
* @param array<string, mixed> $data
*/
public static function isAutoSyncPaused(array $data): bool
{
if ((string) ($data['status'] ?? '') !== 'normal') {
return false;
}
$threshold = SplitSyncConfigService::getFailPauseThreshold();
if ($threshold <= 0) {
return false;
}
return (int) ($data['sync_fail_count'] ?? 0) >= $threshold;
}
/**
* 同步状态展示文案(列表列默认显示,异常详情见 tooltip)
*
* @param mixed $value
* @param array<string, mixed> $data
*/
public function getSyncDisplayTextAttr($value, $data): string
{
if (self::isAutoSyncPaused($data)) {
$threshold = SplitSyncConfigService::getFailPauseThreshold();
return sprintf((string) __('Sync display auto paused'), $threshold);
}
$status = (string) ($data['sync_status'] ?? 'pending');
$online = (int) ($data['online_count'] ?? 0);
if ($status === 'success') {
@@ -170,6 +196,66 @@ class Ticket extends Model
return (string) __('Sync display error');
}
/**
* 同步状态列 tooltip 完整说明
*
* @param mixed $value
* @param array<string, mixed> $data
*/
public function getSyncTooltipTextAttr($value, $data): string
{
$parts = [];
if (self::isAutoSyncPaused($data)) {
$threshold = SplitSyncConfigService::getFailPauseThreshold();
$parts[] = sprintf(
(string) __('Sync tooltip auto paused'),
(int) ($data['sync_fail_count'] ?? 0),
$threshold
);
}
$message = trim((string) ($data['sync_message'] ?? ''));
if ($message !== '') {
$parts[] = (string) __('Sync tooltip error prefix') . $message;
}
return implode("\n", $parts);
}
/**
* 是否暂停自动同步(供前端样式判断)
*
* @param mixed $value
* @param array<string, mixed> $data
*/
public function getSyncAutoPausedAttr($value, $data): bool
{
return self::isAutoSyncPaused($data);
}
/**
* 最近一次同步成功时间及方式
*
* @param mixed $value
* @param array<string, mixed> $data
*/
public function getSyncSuccessTextAttr($value, $data): string
{
$ts = (int) ($data['sync_success_time'] ?? 0);
if ($ts <= 0) {
return '';
}
$timeText = date('Y-m-d H:i:s', $ts);
$mode = (string) ($data['sync_success_mode'] ?? '');
if ($mode === 'auto') {
return $timeText . ' (' . (string) __('Sync mode auto') . ')';
}
if ($mode === 'manual') {
return $timeText . ' (' . (string) __('Sync mode manual') . ')';
}
return $timeText;
}
public function setStartTimeAttr($value): ?int
{
return self::parseTimeValue($value);
@@ -67,6 +67,24 @@
font-size: 14px;
color: #0f172a;
}
.split-sync-success-normal {
color: #3c763d;
font-weight: 600;
}
.split-sync-success-stopped {
color: #a94442;
font-weight: 600;
}
.split-ticket-sync-status-paused {
color: #8a6d3b;
font-weight: 600;
cursor: help;
border-bottom: 1px dotted #8a6d3b;
}
.split-ticket-sync-status-error {
cursor: help;
border-bottom: 1px dotted #a94442;
}
</style>
<div class="panel panel-default panel-intro">
<div class="panel-heading">