修复号码数量列的数据统计方式
This commit is contained in:
@@ -27,6 +27,7 @@ CREATE TABLE `fa_split_ticket` (
|
||||
`number_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '号码数量含离线封号(同步)',
|
||||
`number_offline_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '离线号码数(同步)',
|
||||
`number_banned_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '封号号码数(同步)',
|
||||
`active_number_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '本地开启号码数(status=normal)',
|
||||
`online_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '在线人数(同步)',
|
||||
`sync_status` enum('success','error','pending') NOT NULL DEFAULT 'pending' COMMENT '同步状态',
|
||||
`sync_time` bigint(16) DEFAULT NULL COMMENT '最近同步时间',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
-- 工单表:本地开启号码数(status=normal),列表直接读字段,避免子查询
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
ALTER TABLE `fa_split_ticket`
|
||||
ADD COLUMN `active_number_count` int(10) unsigned NOT NULL DEFAULT 0
|
||||
COMMENT '本地开启号码数(status=normal)' AFTER `number_banned_count`;
|
||||
|
||||
-- 历史数据回填
|
||||
UPDATE `fa_split_ticket` t
|
||||
SET t.`active_number_count` = (
|
||||
SELECT COUNT(*)
|
||||
FROM `fa_split_number` n
|
||||
WHERE n.`admin_id` = t.`admin_id`
|
||||
AND n.`split_link_id` = t.`split_link_id`
|
||||
AND n.`ticket_name` = t.`ticket_name`
|
||||
AND n.`status` = 'normal'
|
||||
);
|
||||
|
||||
-- 加速按工单统计 status=normal 数量
|
||||
ALTER TABLE `fa_split_number`
|
||||
ADD KEY `idx_ticket_active` (`admin_id`, `split_link_id`, `ticket_name`(50), `status`);
|
||||
@@ -7,6 +7,7 @@ namespace app\admin\controller\split;
|
||||
use app\admin\model\split\Link as LinkModel;
|
||||
use app\admin\model\split\Number as NumberModel;
|
||||
use app\common\controller\Backend;
|
||||
use app\common\service\SplitTicketActiveNumberCountService;
|
||||
use think\Db;
|
||||
use think\Exception;
|
||||
use think\exception\DbException;
|
||||
@@ -225,6 +226,7 @@ class Number extends Backend
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
if ($count > 0) {
|
||||
(new SplitTicketActiveNumberCountService())->refreshForNumberIds(explode(',', (string) $ids));
|
||||
$this->success();
|
||||
}
|
||||
$this->error(__('No rows were updated'));
|
||||
@@ -331,6 +333,12 @@ class Number extends Backend
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
|
||||
(new SplitTicketActiveNumberCountService())->refreshForTicketKeys(
|
||||
(int) ($baseRow['admin_id'] ?? $adminId),
|
||||
$splitLinkId,
|
||||
(string) ($baseRow['ticket_name'] ?? '')
|
||||
);
|
||||
|
||||
$msg = __('Inserted %d number(s)', $inserted);
|
||||
if ($skipped > 0) {
|
||||
$msg .= ',' . __('Skipped %d duplicate(s)', $skipped);
|
||||
@@ -378,6 +386,7 @@ class Number extends Backend
|
||||
}
|
||||
|
||||
$result = false;
|
||||
$before = $row->getData();
|
||||
Db::startTrans();
|
||||
try {
|
||||
if ($this->modelValidate) {
|
||||
@@ -397,9 +406,50 @@ class Number extends Backend
|
||||
if ($result === false) {
|
||||
$this->error(__('No rows were updated'));
|
||||
}
|
||||
(new SplitTicketActiveNumberCountService())->refreshAfterNumberEdit($before, $row->getData());
|
||||
$this->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除号码后回写工单本地开启号码数
|
||||
*
|
||||
* @param string|null $ids
|
||||
*/
|
||||
public function del($ids = null)
|
||||
{
|
||||
if (false === $this->request->isPost()) {
|
||||
$this->error(__('Invalid parameters'));
|
||||
}
|
||||
$ids = $ids ?: $this->request->post('ids');
|
||||
if (empty($ids)) {
|
||||
$this->error(__('Parameter %s can not be empty', 'ids'));
|
||||
}
|
||||
$pk = $this->model->getPk();
|
||||
$adminIds = $this->getDataLimitAdminIds();
|
||||
if (is_array($adminIds)) {
|
||||
$this->model->where($this->dataLimitField, 'in', $adminIds);
|
||||
}
|
||||
$list = $this->model->where($pk, 'in', $ids)->select();
|
||||
|
||||
$count = 0;
|
||||
$countService = new SplitTicketActiveNumberCountService();
|
||||
Db::startTrans();
|
||||
try {
|
||||
foreach ($list as $item) {
|
||||
$count += $item->delete();
|
||||
}
|
||||
Db::commit();
|
||||
} catch (PDOException|Exception $e) {
|
||||
Db::rollback();
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
if ($count) {
|
||||
$countService->refreshFromNumberRows($list);
|
||||
$this->success();
|
||||
}
|
||||
$this->error(__('No rows were deleted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新号码状态与手动管理
|
||||
*/
|
||||
@@ -444,6 +494,7 @@ class Number extends Backend
|
||||
if ($count === false || $count === 0) {
|
||||
$this->error(__('No rows were updated'));
|
||||
}
|
||||
(new SplitTicketActiveNumberCountService())->refreshForNumberIds($ids);
|
||||
$this->success(__('Batch update success'));
|
||||
}
|
||||
|
||||
@@ -496,6 +547,8 @@ class Number extends Backend
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
$countService = new SplitTicketActiveNumberCountService();
|
||||
$keyRows = (clone $query)->field('admin_id,split_link_id,ticket_name')->select();
|
||||
Db::startTrans();
|
||||
try {
|
||||
if ($action === 'delete') {
|
||||
@@ -523,6 +576,7 @@ class Number extends Backend
|
||||
$this->error(__('No matching numbers found'));
|
||||
}
|
||||
|
||||
$countService->refreshFromNumberRows($keyRows);
|
||||
$this->success(sprintf(__('Batch operate success'), $count));
|
||||
}
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@ class Ticket extends Backend
|
||||
$params['inbound_count'],
|
||||
$params['speed_per_hour'],
|
||||
$params['number_count'],
|
||||
$params['active_number_count'],
|
||||
$params['number_offline_count'],
|
||||
$params['number_banned_count'],
|
||||
$params['online_count'],
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
use app\admin\model\split\Number;
|
||||
use app\admin\model\split\Ticket;
|
||||
|
||||
/**
|
||||
* 工单本地开启号码数(active_number_count)物化字段维护
|
||||
*
|
||||
* 统计口径:fa_split_number 中 admin_id + split_link_id + ticket_name 匹配且 status=normal
|
||||
*/
|
||||
class SplitTicketActiveNumberCountService
|
||||
{
|
||||
/**
|
||||
* 按工单关联键统计并回写 active_number_count
|
||||
*/
|
||||
public function refreshForTicketKeys(int $adminId, int $linkId, string $ticketName): void
|
||||
{
|
||||
$ticketName = trim($ticketName);
|
||||
if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$count = (int) Number::where('admin_id', $adminId)
|
||||
->where('split_link_id', $linkId)
|
||||
->where('ticket_name', $ticketName)
|
||||
->where('status', 'normal')
|
||||
->count();
|
||||
|
||||
Ticket::where('admin_id', $adminId)
|
||||
->where('split_link_id', $linkId)
|
||||
->where('ticket_name', $ticketName)
|
||||
->update([
|
||||
'active_number_count' => $count,
|
||||
'updatetime' => time(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按工单模型回写
|
||||
*/
|
||||
public function refreshForTicket(Ticket $ticket): void
|
||||
{
|
||||
$this->refreshForTicketKeys(
|
||||
(int) $ticket['admin_id'],
|
||||
(int) $ticket['split_link_id'],
|
||||
(string) $ticket['ticket_name']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量号码 ID:去重后刷新涉及工单
|
||||
*
|
||||
* @param array<int|string> $ids
|
||||
*/
|
||||
public function refreshForNumberIds(array $ids): void
|
||||
{
|
||||
$ids = array_values(array_filter(array_map('intval', $ids)));
|
||||
if ($ids === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = Number::where('id', 'in', $ids)
|
||||
->field('admin_id,split_link_id,ticket_name')
|
||||
->select();
|
||||
|
||||
$this->refreshFromNumberRows($rows);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑单条号码:关联键变更时刷新旧工单与新工单
|
||||
*
|
||||
* @param array<string, mixed> $before
|
||||
* @param array<string, mixed> $after
|
||||
*/
|
||||
public function refreshAfterNumberEdit(array $before, array $after): void
|
||||
{
|
||||
$keys = [];
|
||||
$beforeKey = $this->buildTicketKeyFromRow($before);
|
||||
if ($beforeKey !== null) {
|
||||
$keys[] = $beforeKey;
|
||||
}
|
||||
$afterKey = $this->buildTicketKeyFromRow($after);
|
||||
if ($afterKey !== null) {
|
||||
$keys[] = $afterKey;
|
||||
}
|
||||
$this->refreshForTicketKeyList($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量工单关联键去重后刷新
|
||||
*
|
||||
* @param array<int, array{0:int,1:int,2:string}> $keys
|
||||
*/
|
||||
public function refreshForTicketKeyList(array $keys): void
|
||||
{
|
||||
$seen = [];
|
||||
foreach ($keys as $key) {
|
||||
if (!is_array($key) || count($key) < 3) {
|
||||
continue;
|
||||
}
|
||||
$adminId = (int) $key[0];
|
||||
$linkId = (int) $key[1];
|
||||
$ticketName = trim((string) $key[2]);
|
||||
if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
|
||||
continue;
|
||||
}
|
||||
$hash = $adminId . ':' . $linkId . ':' . $ticketName;
|
||||
if (isset($seen[$hash])) {
|
||||
continue;
|
||||
}
|
||||
$seen[$hash] = true;
|
||||
$this->refreshForTicketKeys($adminId, $linkId, $ticketName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param iterable<int, array<string, mixed>|Number> $rows
|
||||
*/
|
||||
public function refreshFromNumberRows(iterable $rows): void
|
||||
{
|
||||
$keys = [];
|
||||
foreach ($rows as $row) {
|
||||
$data = $row instanceof Number ? $row->getData() : (array) $row;
|
||||
$key = $this->buildTicketKeyFromRow($data);
|
||||
if ($key !== null) {
|
||||
$keys[] = $key;
|
||||
}
|
||||
}
|
||||
$this->refreshForTicketKeyList($keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $row
|
||||
* @return array{0:int,1:int,2:string}|null
|
||||
*/
|
||||
private function buildTicketKeyFromRow(array $row): ?array
|
||||
{
|
||||
$adminId = (int) ($row['admin_id'] ?? 0);
|
||||
$linkId = (int) ($row['split_link_id'] ?? 0);
|
||||
$ticketName = trim((string) ($row['ticket_name'] ?? ''));
|
||||
if ($adminId <= 0 || $linkId <= 0 || $ticketName === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [$adminId, $linkId, $ticketName];
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,8 @@ class SplitTicketRuleService
|
||||
'status' => 'hidden',
|
||||
'updatetime' => time(),
|
||||
]);
|
||||
|
||||
(new SplitTicketActiveNumberCountService())->refreshForTicket($ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,6 +187,8 @@ class SplitTicketRuleService
|
||||
|
||||
Number::where('id', (int) $number['id'])->update($update);
|
||||
}
|
||||
|
||||
(new SplitTicketActiveNumberCountService())->refreshForTicket($ticket);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user