完整版V1 加入爬虫功能

This commit is contained in:
root
2026-06-09 03:36:30 +08:00
parent 34d76cce74
commit a68b83fcbd
69 changed files with 5058 additions and 56 deletions
@@ -0,0 +1,54 @@
-- 工单云控同步:Node 服务地址与各类型同步周期(分钟,0=不自动同步)
SET NAMES utf8mb4;
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_scrm_node_host', 'split', '云控 Node 服务地址', '所有云控蜘蛛共用的 Headless 服务根地址', 'string', '', 'http://127.0.0.1:3001', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_scrm_node_host' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_fail_pause_threshold', 'split', '连续同步失败暂停阈值', '连续同步失败达到该次数后自动关闭工单并暂停定时同步;同步成功后将清零重新计数;0 表示不因失败自动暂停', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_fail_pause_threshold' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_a2c', 'split', 'A2C云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_a2c' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_haiwang', 'split', '海王同步周期(分钟)', '0 表示不自动同步', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_haiwang' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_huojian', 'split', '火箭云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_huojian' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_xinghe', 'split', '星河云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_xinghe' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_ss_customer', 'split', 'SS云控(Customer)同步周期(分钟)', '0 表示不自动同步', 'number', '', '5', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_ss_customer' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_ceo_scrm', 'split', 'CEO SCRM同步周期(分钟)', '0 表示不自动同步(蜘蛛未实现)', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_ceo_scrm' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_taiji', 'split', '太极云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_taiji' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_ss_channel', 'split', 'SS云控(Channel)同步周期(分钟)', '0 表示不自动同步', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_ss_channel' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_yifafa', 'split', '译发发云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_yifafa' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_whatshub', 'split', 'Whatshub云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_whatshub' LIMIT 1);
INSERT INTO `fa_config` (`name`, `group`, `title`, `tip`, `type`, `visible`, `value`, `content`, `rule`, `extend`, `setting`)
SELECT 'split_sync_interval_sihai', 'split', '四海云控同步周期(分钟)', '0 表示不自动同步', 'number', '', '0', '', '', '', NULL
FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `fa_config` WHERE `name` = 'split_sync_interval_sihai' LIMIT 1);
@@ -15,6 +15,7 @@ CREATE TABLE `fa_split_number` (
`inbound_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '进线人数',
`manual_manage` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '手动管理:0=否,1=是',
`status` enum('normal','hidden') NOT NULL DEFAULT 'normal' COMMENT '状态:normal=正常,hidden=停用',
`weigh` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序权重(越大越靠前)',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
@@ -22,6 +23,7 @@ CREATE TABLE `fa_split_number` (
KEY `admin_id` (`admin_id`),
KEY `split_link_id` (`split_link_id`),
KEY `status` (`status`),
KEY `weigh` (`weigh`),
KEY `number` (`number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='分流号码表';
@@ -0,0 +1,7 @@
-- 号码表:排序权重(可选,跳转轮转按 id 顺序;随机打乱通过新号码随机插入顺序实现)
SET NAMES utf8mb4;
ALTER TABLE `fa_split_number`
ADD COLUMN `weigh` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '排序权重(越大越靠前)' AFTER `status`;
UPDATE `fa_split_number` SET `weigh` = `id` WHERE `weigh` = 0;
@@ -0,0 +1,20 @@
-- 工单云控定时同步:扩展字段 + 手动同步权限节点
SET NAMES utf8mb4;
ALTER TABLE `fa_split_ticket`
ADD COLUMN `sync_fail_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '连续同步失败次数' AFTER `sync_message`,
ADD COLUMN `speed_snapshot_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '速度计算基准完成数' AFTER `sync_fail_count`,
ADD COLUMN `speed_snapshot_time` bigint(16) DEFAULT NULL COMMENT '速度计算基准时间' AFTER `speed_snapshot_count`;
ALTER TABLE `fa_split_number`
ADD COLUMN `platform_status` enum('online','offline','unknown') NOT NULL DEFAULT 'unknown' COMMENT '云控平台在线状态' AFTER `manual_manage`,
ADD COLUMN `last_sync_visit_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上次同步时访问次数' AFTER `platform_status`,
ADD COLUMN `last_sync_inbound_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '上次同步时进线人数' AFTER `last_sync_visit_count`,
ADD COLUMN `no_inbound_click_streak` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '进线无增长期间连续点击增量' AFTER `last_sync_inbound_count`;
INSERT INTO `fa_auth_rule` (`type`, `pid`, `name`, `title`, `icon`, `condition`, `remark`, `ismenu`, `createtime`, `updatetime`, `weigh`, `status`)
SELECT 'file', m.id, 'split.ticket/sync', '同步状态', 'fa fa-circle-o', '', '', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'
FROM `fa_auth_rule` m
WHERE m.name = 'split.ticket' AND m.ismenu = 1
AND NOT EXISTS (SELECT 1 FROM `fa_auth_rule` WHERE `name` = 'split.ticket/sync' LIMIT 1)
LIMIT 1;
@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace app\admin\command;
use app\common\service\SplitTicketSyncLogger;
use app\common\service\SplitTicketSyncService;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
/**
* 工单云控定时同步 CLI
*
* 用法:
* php think split:sync-tickets
* php think split:sync-tickets --ticket=12
*/
class SplitSyncTickets extends Command
{
protected function configure(): void
{
$this->setName('split:sync-tickets')
->addOption('ticket', 't', Option::VALUE_OPTIONAL, '指定工单 ID(强制同步,忽略周期)', '')
->setDescription('同步分流工单云控数据');
}
protected function execute(Input $input, Output $output): void
{
set_time_limit(0);
SplitTicketSyncLogger::log('cli', 'command start', [
'ticketOption' => trim((string) $input->getOption('ticket')),
'appDebug' => SplitTicketSyncLogger::isEnabled(),
]);
$service = new SplitTicketSyncService();
$ticketId = trim((string) $input->getOption('ticket'));
if ($ticketId !== '' && ctype_digit($ticketId)) {
$result = $service->syncOne((int) $ticketId, true);
if (!empty($result['skipped'])) {
$output->writeln('<comment>跳过: ' . ($result['message'] ?? '') . '</comment>');
return;
}
if ($result['success']) {
$output->writeln('<info>工单 #' . $ticketId . ' 同步成功</info>');
} else {
$output->writeln('<error>工单 #' . $ticketId . ' 同步失败: ' . ($result['message'] ?? '') . '</error>');
}
return;
}
$count = $service->syncDueTickets();
$output->writeln('<info>本次处理工单数: ' . $count . '</info>');
if (SplitTicketSyncLogger::isEnabled()) {
$output->writeln('<comment>调试日志已写入 runtime/log/split_sync.log</comment>');
}
}
}