账号评分

This commit is contained in:
wong
2025-11-20 16:07:57 +08:00
parent 367a250fba
commit b0a60e428c
6 changed files with 3116 additions and 48 deletions

View File

@@ -7,5 +7,27 @@ use think\Model;
class WechatAccountModel extends Model
{
// 设置表名
protected $table = 's2_wechat_account';
protected $table = 's2_wechat_account';
// 定义字段类型
protected $type = [
'healthScore' => 'integer',
'baseScore' => 'integer',
'dynamicScore' => 'integer',
'isModifiedAlias' => 'integer',
'frequentCount' => 'integer',
'consecutiveNoFrequentDays' => 'integer',
'lastFrequentTime' => 'integer',
'lastNoFrequentTime' => 'integer',
'scoreUpdateTime' => 'integer',
];
// 允许批量赋值的字段
protected $field = [
'id', 'wechatId', 'alias', 'nickname', 'avatar', 'gender', 'region', 'signature',
'healthScore', 'baseScore', 'dynamicScore', 'isModifiedAlias',
'lastFrequentTime', 'frequentCount', 'lastNoFrequentTime',
'consecutiveNoFrequentDays', 'scoreUpdateTime',
'createTime', 'updateTime', 'status', 'isDeleted'
];
}

View File

@@ -0,0 +1,159 @@
<?php
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use app\common\service\WechatAccountHealthScoreService;
/**
* 检测和修复s2_wechat_account表中wechatId和alias不一致的问题
* 同时更新isModifiedAlias字段和健康分
*/
class CheckAndFixWechatAccountCommand extends Command
{
protected function configure()
{
$this->setName('wechat:check-and-fix')
->setDescription('检测和修复s2_wechat_account表中wechatId和alias不一致的问题并更新健康分');
}
protected function execute(Input $input, Output $output)
{
$output->writeln("开始检测和修复s2_wechat_account表...");
try {
// 1. 检测wechatId和alias不一致的记录
$output->writeln("步骤1: 检测wechatId和alias不一致的记录...");
$inconsistentAccounts = $this->findInconsistentAccounts();
$output->writeln("发现 " . count($inconsistentAccounts) . " 条不一致记录");
if (empty($inconsistentAccounts)) {
$output->writeln("没有发现不一致的记录,任务完成!");
return;
}
// 2. 修复不一致的记录
$output->writeln("步骤2: 修复不一致的记录...");
$fixedCount = $this->fixInconsistentAccounts($inconsistentAccounts);
$output->writeln("已修复 " . $fixedCount . " 条记录");
// 3. 更新isModifiedAlias字段
$output->writeln("步骤3: 更新isModifiedAlias字段...");
$updatedCount = $this->updateModifiedAliasFlag();
$output->writeln("已更新 " . $updatedCount . " 条记录的isModifiedAlias字段");
// 4. 重新计算健康分
$output->writeln("步骤4: 重新计算健康分...");
$healthScoreService = new WechatAccountHealthScoreService();
$accountIds = array_column($inconsistentAccounts, 'id');
$stats = $healthScoreService->batchCalculateAndUpdate($accountIds, 100);
$output->writeln("健康分计算完成:成功 " . $stats['success'] . " 条,失败 " . $stats['failed'] . "");
if (!empty($stats['errors'])) {
$output->writeln("错误详情:");
foreach ($stats['errors'] as $error) {
$output->writeln(" 账号ID {$error['accountId']}: {$error['error']}");
}
}
$output->writeln("任务完成!");
} catch (\Exception $e) {
$output->writeln("错误: " . $e->getMessage());
$output->writeln($e->getTraceAsString());
}
}
/**
* 查找wechatId和alias不一致的记录
*
* @return array
*/
private function findInconsistentAccounts()
{
// 查找wechatId和alias不一致的记录
// 条件wechatId不为空alias不为空且wechatId != alias
$accounts = Db::table('s2_wechat_account')
->where('isDeleted', 0)
->where('wechatId', '<>', '')
->where('alias', '<>', '')
->whereRaw('wechatId != alias')
->field('id, wechatId, alias, nickname, isModifiedAlias')
->select();
return $accounts ?: [];
}
/**
* 修复不一致的记录
* 策略从s2_wechat_friend表中查找最新的alias值来更新
*
* @param array $accounts 不一致的账号列表
* @return int 修复数量
*/
private function fixInconsistentAccounts($accounts)
{
$fixedCount = 0;
foreach ($accounts as $account) {
$wechatId = $account['wechatId'];
// 从s2_wechat_friend表中查找最新的alias值
$latestAlias = Db::table('s2_wechat_friend')
->where('wechatId', $wechatId)
->where('alias', '<>', '')
->order('updateTime', 'desc')
->value('alias');
// 如果找到了最新的alias则更新
if (!empty($latestAlias) && $latestAlias !== $account['alias']) {
Db::table('s2_wechat_account')
->where('id', $account['id'])
->update([
'alias' => $latestAlias,
'updateTime' => time()
]);
$fixedCount++;
}
}
return $fixedCount;
}
/**
* 更新isModifiedAlias字段
* 如果wechatId和alias不一致则标记为已修改
*
* @return int 更新数量
*/
private function updateModifiedAliasFlag()
{
// 更新isModifiedAlias字段wechatId != alias 的记录标记为1
$updatedCount = Db::table('s2_wechat_account')
->where('isDeleted', 0)
->where('wechatId', '<>', '')
->where('alias', '<>', '')
->whereRaw('wechatId != alias')
->update([
'isModifiedAlias' => 1,
'updateTime' => time()
]);
// 更新isModifiedAlias字段wechatId == alias 的记录标记为0
Db::table('s2_wechat_account')
->where('isDeleted', 0)
->where('wechatId', '<>', '')
->where('alias', '<>', '')
->whereRaw('wechatId = alias')
->update([
'isModifiedAlias' => 0,
'updateTime' => time()
]);
return $updatedCount;
}
}

View File

@@ -0,0 +1,378 @@
<?php
namespace app\common\service;
use think\Db;
use think\Exception;
/**
* 微信账号健康分评分服务
* 基于《微信健康分规则v2.md》实现
*
* 健康分 = 基础分 + 动态分
* 基础分60-100分默认60分 + 基础信息10分 + 好友数量30分
* 动态分:扣分和加分规则
*/
class WechatAccountHealthScoreService
{
// 默认基础分
const DEFAULT_BASE_SCORE = 60;
// 基础信息权重和分数
const BASE_INFO_WEIGHT = 0.2;
const BASE_INFO_SCORE = 10;
// 好友数量权重和分数
const FRIEND_COUNT_WEIGHT = 0.3;
const FRIEND_COUNT_MAX_SCORE = 30;
// 动态分扣分规则
const PENALTY_FIRST_FREQUENT = -15; // 首次频繁扣15分
const PENALTY_SECOND_FREQUENT = -25; // 再次频繁扣25分
const PENALTY_BANNED = -60; // 封号扣60分
// 动态分加分规则
const BONUS_NO_FREQUENT_PER_DAY = 5; // 连续3天不触发频繁每天+5分
/**
* 计算并更新账号健康分
*
* @param int $accountId 账号IDs2_wechat_account表的id
* @param array $accountData 账号数据(可选,如果不传则从数据库查询)
* @return array 返回评分结果
*/
public function calculateAndUpdate($accountId, $accountData = null)
{
try {
// 获取账号数据
if (empty($accountData)) {
$accountData = Db::table('s2_wechat_account')
->where('id', $accountId)
->find();
}
if (empty($accountData)) {
throw new Exception("账号不存在:{$accountId}");
}
// 计算基础分
$baseScore = $this->calculateBaseScore($accountData);
// 计算动态分
$dynamicScore = $this->calculateDynamicScore($accountData);
// 计算总分
$healthScore = $baseScore + $dynamicScore;
// 确保健康分在合理范围内0-100
$healthScore = max(0, min(100, $healthScore));
// 更新数据库
$updateData = [
'healthScore' => $healthScore,
'baseScore' => $baseScore,
'dynamicScore' => $dynamicScore,
'scoreUpdateTime' => time()
];
Db::table('s2_wechat_account')
->where('id', $accountId)
->update($updateData);
return [
'accountId' => $accountId,
'wechatId' => $accountData['wechatId'] ?? '',
'healthScore' => $healthScore,
'baseScore' => $baseScore,
'dynamicScore' => $dynamicScore,
'baseInfoScore' => $this->getBaseInfoScore($accountData),
'friendCountScore' => $this->getFriendCountScore($accountData['totalFriend'] ?? 0),
'maxAddFriendPerDay' => $this->getMaxAddFriendPerDay($healthScore)
];
} catch (Exception $e) {
throw new Exception("计算健康分失败:" . $e->getMessage());
}
}
/**
* 计算基础分
* 基础分 = 默认60分 + 基础信息分(10分) + 好友数量分(30分)
*
* @param array $accountData 账号数据
* @return int 基础分
*/
private function calculateBaseScore($accountData)
{
$baseScore = self::DEFAULT_BASE_SCORE;
// 基础信息分已修改微信号得10分
$baseScore += $this->getBaseInfoScore($accountData);
// 好友数量分最高30分
$totalFriend = $accountData['totalFriend'] ?? 0;
$baseScore += $this->getFriendCountScore($totalFriend);
return $baseScore;
}
/**
* 获取基础信息分
* 已修改微信号10分
*
* @param array $accountData 账号数据
* @return int 基础信息分
*/
private function getBaseInfoScore($accountData)
{
// 检查是否已修改微信号
// 如果isModifiedAlias字段为1或者wechatId和alias不一致则认为已修改
$isModifiedAlias = isset($accountData['isModifiedAlias']) ? (int)$accountData['isModifiedAlias'] : 0;
$wechatId = trim($accountData['wechatId'] ?? '');
$alias = trim($accountData['alias'] ?? '');
// 如果字段标记为已修改或者wechatId和alias不一致则得分
if ($isModifiedAlias == 1 || (!empty($wechatId) && !empty($alias) && $wechatId !== $alias)) {
return self::BASE_INFO_SCORE;
}
return 0;
}
/**
* 获取好友数量分
* 根据好友数量区间得分最高30分
*
* @param int $totalFriend 总好友数
* @return int 好友数量分
*/
private function getFriendCountScore($totalFriend)
{
if ($totalFriend <= 50) {
return 3; // 0-50: 3分
} elseif ($totalFriend <= 500) {
return 6; // 51-500: 6分
} elseif ($totalFriend <= 3000) {
return 8; // 501-3000: 8分
} else {
return 12; // 3001以上: 12分
}
}
/**
* 计算动态分
* 动态分 = 扣分 + 加分
*
* @param array $accountData 账号数据
* @return int 动态分
*/
private function calculateDynamicScore($accountData)
{
$dynamicScore = 0;
// 处理扣分
$dynamicScore += $this->calculatePenalty($accountData);
// 处理加分
$dynamicScore += $this->calculateBonus($accountData);
return $dynamicScore;
}
/**
* 计算扣分
* 首次频繁:-15分
* 再次频繁:-25分
* 封号:-60分
*
* @param array $accountData 账号数据
* @return int 扣分数
*/
private function calculatePenalty($accountData)
{
$penalty = 0;
// 检查是否有频繁记录
$lastFrequentTime = $accountData['lastFrequentTime'] ?? null;
$frequentCount = $accountData['frequentCount'] ?? 0;
if (!empty($lastFrequentTime)) {
// 判断是首次频繁还是再次频繁
if ($frequentCount == 1) {
$penalty += self::PENALTY_FIRST_FREQUENT; // 首次频繁-15分
} elseif ($frequentCount >= 2) {
$penalty += self::PENALTY_SECOND_FREQUENT; // 再次频繁-25分
}
}
// 检查是否封号这里需要根据实际业务逻辑判断比如status字段或其他标识
// 假设status=0表示封号
$status = $accountData['status'] ?? 1;
if ($status == 0) {
$penalty += self::PENALTY_BANNED; // 封号-60分
}
return $penalty;
}
/**
* 计算加分
* 连续3天不触发频繁每天+5分
*
* @param array $accountData 账号数据
* @return int 加分数
*/
private function calculateBonus($accountData)
{
$bonus = 0;
$lastNoFrequentTime = $accountData['lastNoFrequentTime'] ?? null;
$consecutiveNoFrequentDays = $accountData['consecutiveNoFrequentDays'] ?? 0;
// 如果连续不频繁天数>=3则每天+5分
if ($consecutiveNoFrequentDays >= 3) {
$bonus = $consecutiveNoFrequentDays * self::BONUS_NO_FREQUENT_PER_DAY;
}
return $bonus;
}
/**
* 根据健康分计算每日最大加人次数
* 公式:每日最大加人次数 = 健康分 * 0.2
*
* @param int $healthScore 健康分
* @return int 每日最大加人次数
*/
public function getMaxAddFriendPerDay($healthScore)
{
return (int)floor($healthScore * 0.2);
}
/**
* 批量计算并更新多个账号的健康分
*
* @param array $accountIds 账号ID数组
* @param int $batchSize 每批处理数量
* @return array 处理结果统计
*/
public function batchCalculateAndUpdate($accountIds = [], $batchSize = 100)
{
$stats = [
'total' => 0,
'success' => 0,
'failed' => 0,
'errors' => []
];
// 如果没有指定账号ID则处理所有账号
if (empty($accountIds)) {
$accountIds = Db::table('s2_wechat_account')
->where('isDeleted', 0)
->column('id');
}
$stats['total'] = count($accountIds);
// 分批处理
$batches = array_chunk($accountIds, $batchSize);
foreach ($batches as $batch) {
foreach ($batch as $accountId) {
try {
$this->calculateAndUpdate($accountId);
$stats['success']++;
} catch (Exception $e) {
$stats['failed']++;
$stats['errors'][] = [
'accountId' => $accountId,
'error' => $e->getMessage()
];
}
}
}
return $stats;
}
/**
* 记录频繁事件
*
* @param int $accountId 账号ID
* @return bool
*/
public function recordFrequent($accountId)
{
$accountData = Db::table('s2_wechat_account')
->where('id', $accountId)
->find();
if (empty($accountData)) {
return false;
}
$frequentCount = ($accountData['frequentCount'] ?? 0) + 1;
$updateData = [
'lastFrequentTime' => time(),
'frequentCount' => $frequentCount,
'consecutiveNoFrequentDays' => 0, // 重置连续不频繁天数
'lastNoFrequentTime' => null
];
Db::table('s2_wechat_account')
->where('id', $accountId)
->update($updateData);
// 重新计算健康分
$this->calculateAndUpdate($accountId);
return true;
}
/**
* 记录不频繁事件(用于加分)
*
* @param int $accountId 账号ID
* @return bool
*/
public function recordNoFrequent($accountId)
{
$accountData = Db::table('s2_wechat_account')
->where('id', $accountId)
->find();
if (empty($accountData)) {
return false;
}
$lastNoFrequentTime = $accountData['lastNoFrequentTime'] ?? null;
$consecutiveNoFrequentDays = $accountData['consecutiveNoFrequentDays'] ?? 0;
$currentTime = time();
// 如果上次不频繁时间是昨天或更早,则增加连续天数
if (empty($lastNoFrequentTime) || ($currentTime - $lastNoFrequentTime) >= 86400) {
// 如果间隔超过1天重置为1天
if (!empty($lastNoFrequentTime) && ($currentTime - $lastNoFrequentTime) > 86400 * 2) {
$consecutiveNoFrequentDays = 1;
} else {
$consecutiveNoFrequentDays++;
}
}
$updateData = [
'lastNoFrequentTime' => $currentTime,
'consecutiveNoFrequentDays' => $consecutiveNoFrequentDays
];
Db::table('s2_wechat_account')
->where('id', $accountId)
->update($updateData);
// 重新计算健康分
$this->calculateAndUpdate($accountId);
return true;
}
}

View File

@@ -2816,6 +2816,8 @@ class WorkbenchController extends Controller
$limit = $this->request->param('limit', 10);
$workbenchId = $this->request->param('workbenchId', 0);
$keyword = $this->request->param('keyword', '');
$pushType = $this->request->param('pushType', ''); // 推送类型筛选:''=全部, 'friend'=好友消息, 'group'=群消息, 'announcement'=群公告
$status = $this->request->param('status', ''); // 状态筛选:''=全部, 'success'=已完成, 'progress'=进行中, 'failed'=失败
$userId = $this->request->userInfo['id'];
// 构建工作台查询条件
@@ -2840,10 +2842,11 @@ class WorkbenchController extends Controller
$workbenchWhere[] = ['w.id', '=', $workbenchId];
}
// 按内容ID、工作台ID和时间分组统计每次推送
$query = Db::name('workbench_group_push_item')
// 1. 先查询所有已执行的推送记录(按推送时间分组)
$pushHistoryQuery = Db::name('workbench_group_push_item')
->alias('wgpi')
->join('workbench w', 'w.id = wgpi.workbenchId', 'left')
->join('workbench_group_push wgp', 'wgp.workbenchId = wgpi.workbenchId', 'left')
->join('content_item ci', 'ci.id = wgpi.contentId', 'left')
->join('content_library cl', 'cl.id = ci.libraryId', 'left')
->where($workbenchWhere)
@@ -2853,52 +2856,57 @@ class WorkbenchController extends Controller
'wgpi.contentId',
'FROM_UNIXTIME(wgpi.createTime, "%Y-%m-%d %H:00:00") as pushTime',
'wgpi.targetType',
'wgp.groupPushSubType',
'MIN(wgpi.createTime) as createTime',
'COUNT(DISTINCT wgpi.id) as totalCount',
'cl.name as contentLibraryName'
])
->group('wgpi.workbenchId, wgpi.contentId, pushTime, wgpi.targetType');
->group('wgpi.workbenchId, wgpi.contentId, pushTime, wgpi.targetType, wgp.groupPushSubType');
if (!empty($keyword)) {
$query->where('w.name|cl.name|ci.content', 'like', '%' . $keyword . '%');
$pushHistoryQuery->where('w.name|cl.name|ci.content', 'like', '%' . $keyword . '%');
}
// 获取分页数据
$list = $query->order('createTime', 'desc')
->page($page, $limit)
->select();
// 对于有 group by 的查询,统计总数需要重新查询
$totalQuery = Db::name('workbench_group_push_item')
->alias('wgpi')
->join('workbench w', 'w.id = wgpi.workbenchId', 'left')
->join('content_item ci', 'ci.id = wgpi.contentId', 'left')
->join('content_library cl', 'cl.id = ci.libraryId', 'left')
->where($workbenchWhere);
if (!empty($keyword)) {
$totalQuery->where('w.name|cl.name|ci.content', 'like', '%' . $keyword . '%');
}
// 统计分组后的记录数(使用子查询)
$subQuery = $totalQuery
$pushHistoryList = $pushHistoryQuery->order('createTime', 'desc')->select();
// 2. 查询所有任务(包括未执行的)
$allTasksQuery = Db::name('workbench')
->alias('w')
->join('workbench_group_push wgp', 'wgp.workbenchId = w.id', 'left')
->where($workbenchWhere)
->field([
'wgpi.workbenchId',
'wgpi.contentId',
'FROM_UNIXTIME(wgpi.createTime, "%Y-%m-%d %H:00:00") as pushTime',
'wgpi.targetType'
])
->group('wgpi.workbenchId, wgpi.contentId, pushTime, wgpi.targetType')
->buildSql();
$total = Db::table('(' . $subQuery . ') as temp')->count();
'w.id as workbenchId',
'w.name as workbenchName',
'w.createTime',
'wgp.targetType',
'wgp.groupPushSubType',
'wgp.groups',
'wgp.friends',
'wgp.trafficPools'
]);
// 处理每条记录
foreach ($list as &$item) {
if (!empty($keyword)) {
$allTasksQuery->where('w.name', 'like', '%' . $keyword . '%');
}
$allTasks = $allTasksQuery->select();
// 3. 合并数据:已执行的推送记录 + 未执行的任务
$resultList = [];
$executedWorkbenchIds = [];
// 处理已执行的推送记录
foreach ($pushHistoryList as $item) {
$itemWorkbenchId = $item['workbenchId'];
$contentId = $item['contentId'];
$pushTime = $item['pushTime'];
$targetType = intval($item['targetType']);
$groupPushSubType = isset($item['groupPushSubType']) ? intval($item['groupPushSubType']) : 1;
// 标记该工作台已有执行记录
if (!in_array($itemWorkbenchId, $executedWorkbenchIds)) {
$executedWorkbenchIds[] = $itemWorkbenchId;
}
// 将时间字符串转换为时间戳范围(小时级别)
$pushTimeStart = strtotime($pushTime);
@@ -2937,23 +2945,149 @@ class WorkbenchController extends Controller
$failCount = 0; // 简化处理,实际需要从发送状态获取
// 状态判断
$status = $successCount > 0 ? 'success' : 'failed';
$itemStatus = $successCount > 0 ? 'success' : 'failed';
if ($failCount > 0 && $successCount > 0) {
$status = 'partial';
$itemStatus = 'partial';
}
$item['pushType'] = $targetType == 1 ? '群推送' : '好友推送';
$item['pushTypeCode'] = $targetType;
$item['targetCount'] = $targetCount;
$item['successCount'] = $successCount;
$item['failCount'] = $failCount;
$item['status'] = $status;
$item['statusText'] = $status == 'success' ? '成功' : ($status == 'partial' ? '部分成功' : '失败');
$item['createTime'] = date('Y-m-d H:i:s', $item['createTime']);
// 任务名称(工作台名称)
$item['taskName'] = $item['workbenchName'] ?? '';
// 推送类型判断
$pushTypeText = '';
$pushTypeCode = '';
if ($targetType == 1) {
// 群推送
if ($groupPushSubType == 2) {
$pushTypeText = '群公告';
$pushTypeCode = 'announcement';
} else {
$pushTypeText = '群消息';
$pushTypeCode = 'group';
}
} else {
// 好友推送
$pushTypeText = '好友消息';
$pushTypeCode = 'friend';
}
$resultList[] = [
'workbenchId' => $itemWorkbenchId,
'taskName' => $item['workbenchName'] ?? '',
'pushType' => $pushTypeText,
'pushTypeCode' => $pushTypeCode,
'targetCount' => $targetCount,
'successCount' => $successCount,
'failCount' => $failCount,
'status' => $itemStatus,
'statusText' => $this->getStatusText($itemStatus),
'createTime' => date('Y-m-d H:i:s', $item['createTime']),
'contentLibraryName' => $item['contentLibraryName'] ?? ''
];
}
unset($item);
// 处理未执行的任务
foreach ($allTasks as $task) {
$taskWorkbenchId = $task['workbenchId'];
// 如果该任务已有执行记录,跳过(避免重复)
if (in_array($taskWorkbenchId, $executedWorkbenchIds)) {
continue;
}
$targetType = isset($task['targetType']) ? intval($task['targetType']) : 1;
$groupPushSubType = isset($task['groupPushSubType']) ? intval($task['groupPushSubType']) : 1;
// 计算目标数量(从配置中获取)
$targetCount = 0;
if ($targetType == 1) {
// 群推送:统计配置的群数量
$groups = json_decode($task['groups'] ?? '[]', true);
$targetCount = is_array($groups) ? count($groups) : 0;
} else {
// 好友推送:统计配置的好友数量或流量池数量
$friends = json_decode($task['friends'] ?? '[]', true);
$trafficPools = json_decode($task['trafficPools'] ?? '[]', true);
$friendCount = is_array($friends) ? count($friends) : 0;
$poolCount = is_array($trafficPools) ? count($trafficPools) : 0;
// 如果配置了流量池,目标数量暂时显示为流量池数量(实际数量需要从流量池中统计)
$targetCount = $friendCount > 0 ? $friendCount : $poolCount;
}
// 推送类型判断
$pushTypeText = '';
$pushTypeCode = '';
if ($targetType == 1) {
// 群推送
if ($groupPushSubType == 2) {
$pushTypeText = '群公告';
$pushTypeCode = 'announcement';
} else {
$pushTypeText = '群消息';
$pushTypeCode = 'group';
}
} else {
// 好友推送
$pushTypeText = '好友消息';
$pushTypeCode = 'friend';
}
$resultList[] = [
'workbenchId' => $taskWorkbenchId,
'taskName' => $task['workbenchName'] ?? '',
'pushType' => $pushTypeText,
'pushTypeCode' => $pushTypeCode,
'targetCount' => $targetCount,
'successCount' => 0,
'failCount' => 0,
'status' => 'pending',
'statusText' => '进行中',
'createTime' => date('Y-m-d H:i:s', $task['createTime']),
'contentLibraryName' => ''
];
}
// 应用筛选条件
$filteredList = [];
foreach ($resultList as $item) {
// 推送类型筛选
if (!empty($pushType)) {
if ($pushType === 'friend' && $item['pushTypeCode'] !== 'friend') {
continue;
}
if ($pushType === 'group' && $item['pushTypeCode'] !== 'group') {
continue;
}
if ($pushType === 'announcement' && $item['pushTypeCode'] !== 'announcement') {
continue;
}
}
// 状态筛选
if (!empty($status)) {
if ($status === 'success' && $item['status'] !== 'success') {
continue;
}
if ($status === 'progress') {
// 进行中:包括 partial 和 pending
if ($item['status'] !== 'partial' && $item['status'] !== 'pending') {
continue;
}
}
if ($status === 'failed' && $item['status'] !== 'failed') {
continue;
}
}
$filteredList[] = $item;
}
// 按创建时间倒序排序
usort($filteredList, function($a, $b) {
return strtotime($b['createTime']) - strtotime($a['createTime']);
});
// 分页处理
$total = count($filteredList);
$offset = ($page - 1) * $limit;
$list = array_slice($filteredList, $offset, $limit);
return json([
'code' => 200,
@@ -2967,5 +3101,21 @@ class WorkbenchController extends Controller
]);
}
/**
* 获取状态文本
* @param string $status 状态码
* @return string 状态文本
*/
private function getStatusText($status)
{
$statusMap = [
'success' => '已完成',
'partial' => '进行中',
'pending' => '进行中',
'failed' => '失败'
];
return $statusMap[$status] ?? '未知';
}
}

2301
Server/sql.sql Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
# 微信健康分规则 v2
## 一、定义
当客户收到手机设备后,登录了微信号,我们将对其微信号进行健康分的评估。
**健康分 = 基础分 + 动态分**
健康分只与系统中的"每日自动添加好友次数"这个功能相关联。\
通过健康分体系来定义一个微信号每日**最佳、最稳定的添加次数**。\
后期还可将健康分作为标签属性,用于快速筛选微信号。
**公式:每日最大加人次数 = 健康分 × 0.2**
## 二、基础分
基础分为 **60--100 分**
`60 + 40基础加成分` 四个维度参数组成,每个参数具有不同权重。
### 基础分组成
类型 权重 分数
------------ ------ ------
基础信息 0.2 10
好友数量 0.3 30
默认基础分 --- 60
### 1. 基础信息(权重 0.2,满分 10
类型 权重 分数
-------------- ------ ------
已修改微信号 1 10
### 2. 好友数量(权重 0.3,满分 30
好友数量范围 权重 分数
-------------- ------ ------
0--50 0.1 3
51--500 0.2 6
501--3000 0.3 8
3001 以上 0.4 12
## 三、动态分规则
### 扣分规则
场景 扣分 处罚
---------- ------ --------------
首次频繁 15 暂停 24 小时
再次频繁 25 暂停 24 小时
封号 60 暂停 72 小时
### 加分规则
场景 加分
--------------------- ------
连续 3 天不触发频繁 5/日