增加自媒体渠道
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
class QywxMediaChannel extends BaseModel
|
||||
{
|
||||
protected $name = 'qywx_media_channel';
|
||||
|
||||
protected $autoWriteTimestamp = true;
|
||||
|
||||
protected $createTime = 'create_time';
|
||||
|
||||
protected $updateTime = 'update_time';
|
||||
|
||||
protected $dateFormat = false;
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service\qywx;
|
||||
|
||||
use app\common\model\QywxExternalContact;
|
||||
use app\common\model\QywxMediaChannel;
|
||||
use think\db\Query;
|
||||
use think\facade\Db;
|
||||
|
||||
class MediaChannelService
|
||||
{
|
||||
/**
|
||||
* @return array<int, array{code: string, name: string}>
|
||||
*/
|
||||
public static function getOptions(): array
|
||||
{
|
||||
$rows = QywxMediaChannel::where('status', 1)
|
||||
->field('channel_code, channel_name')
|
||||
->order('channel_name asc, id asc')
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
return array_map(static fn (array $row): array => [
|
||||
'code' => (string) ($row['channel_code'] ?? ''),
|
||||
'name' => (string) ($row['channel_name'] ?? ''),
|
||||
], $rows);
|
||||
}
|
||||
|
||||
public static function getDefaultCode(): string
|
||||
{
|
||||
return (string) QywxMediaChannel::where('status', 1)
|
||||
->order('id asc')
|
||||
->value('channel_code');
|
||||
}
|
||||
|
||||
public static function isValidCode(string $channelCode): bool
|
||||
{
|
||||
$channelCode = trim($channelCode);
|
||||
if ($channelCode === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return QywxMediaChannel::where('status', 1)
|
||||
->where('channel_code', $channelCode)
|
||||
->count() > 0;
|
||||
}
|
||||
|
||||
public static function normalizeStatsCode(string $channelCode): string
|
||||
{
|
||||
return self::isValidCode($channelCode) ? trim($channelCode) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
public static function getChannelByCode(string $channelCode): ?array
|
||||
{
|
||||
$channelCode = trim($channelCode);
|
||||
if ($channelCode === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$row = QywxMediaChannel::where('status', 1)
|
||||
->where('channel_code', $channelCode)
|
||||
->find();
|
||||
|
||||
return $row ? $row->toArray() : null;
|
||||
}
|
||||
|
||||
public static function getNameByCode(string $channelCode): string
|
||||
{
|
||||
$channel = self::getChannelByCode($channelCode);
|
||||
return (string) ($channel['channel_name'] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed>|null $channel
|
||||
*/
|
||||
public static function applyFollowUsersChannelFilter(Query $query, string $field, ?array $channel): void
|
||||
{
|
||||
if ($channel === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$patterns = self::buildLikePatterns($channel);
|
||||
if ($patterns === []) {
|
||||
$query->whereRaw('1 = 0');
|
||||
return;
|
||||
}
|
||||
|
||||
$segments = [];
|
||||
$bindings = [];
|
||||
foreach ($patterns as $pattern) {
|
||||
$segments[] = $field . ' LIKE ?';
|
||||
$bindings[] = $pattern;
|
||||
}
|
||||
|
||||
$query->whereRaw('(' . implode(' OR ', $segments) . ')', $bindings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{scanned_contacts: int, discovered_tags: int, inserted_or_updated: int}
|
||||
*/
|
||||
public static function scanFromContacts(int $batchSize = 200): array
|
||||
{
|
||||
$lastId = 0;
|
||||
$scannedContacts = 0;
|
||||
$discoveredTags = [];
|
||||
$upserted = 0;
|
||||
$now = time();
|
||||
|
||||
while (true) {
|
||||
$rows = QywxExternalContact::where('id', '>', $lastId)
|
||||
->field('id, follow_users')
|
||||
->order('id asc')
|
||||
->limit($batchSize)
|
||||
->select()
|
||||
->toArray();
|
||||
|
||||
if ($rows === []) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$lastId = (int) ($row['id'] ?? 0);
|
||||
if ($lastId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$scannedContacts++;
|
||||
$followUsers = json_decode((string) ($row['follow_users'] ?? '[]'), true);
|
||||
$followUsers = is_array($followUsers) ? $followUsers : [];
|
||||
|
||||
foreach (self::extractTagsFromFollowUsers($followUsers) as $tag) {
|
||||
$tagKey = self::buildTagUniqKey($tag['source_tag_id'], $tag['source_tag_name']);
|
||||
if ($tagKey === '' || isset($discoveredTags[$tagKey])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$discoveredTags[$tagKey] = true;
|
||||
$channelCode = self::buildChannelCode($tag['source_tag_id'], $tag['source_tag_name']);
|
||||
$channelName = $tag['source_tag_name'] !== '' ? $tag['source_tag_name'] : $tag['source_tag_id'];
|
||||
|
||||
$rowData = [
|
||||
'channel_code' => $channelCode,
|
||||
'channel_name' => $channelName,
|
||||
'source_tag_id' => $tag['source_tag_id'],
|
||||
'source_tag_name' => $tag['source_tag_name'],
|
||||
'source_group_name' => $tag['source_group_name'],
|
||||
'tag_uniq_key' => $tagKey,
|
||||
'status' => 1,
|
||||
'last_seen_time' => $now,
|
||||
'create_time' => $now,
|
||||
'update_time' => $now,
|
||||
];
|
||||
|
||||
Db::name('qywx_media_channel')->duplicate([
|
||||
'channel_name',
|
||||
'source_tag_id',
|
||||
'source_tag_name',
|
||||
'source_group_name',
|
||||
'status',
|
||||
'last_seen_time',
|
||||
'update_time',
|
||||
])->insert($rowData);
|
||||
$upserted++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'scanned_contacts' => $scannedContacts,
|
||||
'discovered_tags' => count($discoveredTags),
|
||||
'inserted_or_updated' => $upserted,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $channel
|
||||
* @return string[]
|
||||
*/
|
||||
private static function buildLikePatterns(array $channel): array
|
||||
{
|
||||
$patterns = [];
|
||||
$tagId = trim((string) ($channel['source_tag_id'] ?? ''));
|
||||
$tagName = trim((string) ($channel['source_tag_name'] ?? ''));
|
||||
|
||||
if ($tagId !== '') {
|
||||
$escapedTagId = addcslashes($tagId, '%_\\');
|
||||
$patterns[] = '%"tag_id":"' . $escapedTagId . '"%';
|
||||
$patterns[] = '%"id":"' . $escapedTagId . '"%';
|
||||
}
|
||||
|
||||
if ($tagName !== '') {
|
||||
$escapedTagName = addcslashes($tagName, '%_\\');
|
||||
$patterns[] = '%"name":"' . $escapedTagName . '"%';
|
||||
$patterns[] = '%"tag_name":"' . $escapedTagName . '"%';
|
||||
}
|
||||
|
||||
return array_values(array_unique($patterns));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, mixed> $followUsers
|
||||
* @return array<int, array{source_tag_id: string, source_tag_name: string, source_group_name: string}>
|
||||
*/
|
||||
private static function extractTagsFromFollowUsers(array $followUsers): array
|
||||
{
|
||||
$tags = [];
|
||||
foreach ($followUsers as $followUser) {
|
||||
if (!is_array($followUser)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rawTags = $followUser['tags'] ?? [];
|
||||
if (!is_array($rawTags)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($rawTags as $tag) {
|
||||
if (!is_array($tag)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tagId = trim((string) ($tag['tag_id'] ?? $tag['id'] ?? ''));
|
||||
$tagName = trim((string) ($tag['name'] ?? $tag['tag_name'] ?? ''));
|
||||
$groupName = trim((string) ($tag['group_name'] ?? ''));
|
||||
$uniqKey = self::buildTagUniqKey($tagId, $tagName);
|
||||
if ($uniqKey === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$tags[$uniqKey] = [
|
||||
'source_tag_id' => $tagId,
|
||||
'source_tag_name' => $tagName,
|
||||
'source_group_name' => $groupName,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($tags);
|
||||
}
|
||||
|
||||
private static function buildTagUniqKey(string $tagId, string $tagName): string
|
||||
{
|
||||
$tagId = trim($tagId);
|
||||
$tagName = trim($tagName);
|
||||
if ($tagId !== '') {
|
||||
return 'tag_id:' . $tagId;
|
||||
}
|
||||
if ($tagName !== '') {
|
||||
return 'tag_name:' . md5(mb_strtolower($tagName, 'UTF-8'));
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private static function buildChannelCode(string $tagId, string $tagName): string
|
||||
{
|
||||
$tagId = trim($tagId);
|
||||
if ($tagId !== '') {
|
||||
return 'tag_' . preg_replace('/[^A-Za-z0-9_\-]/', '_', $tagId);
|
||||
}
|
||||
|
||||
$normalizedName = trim(mb_strtolower($tagName, 'UTF-8'));
|
||||
return 'tagname_' . substr(md5($normalizedName), 0, 16);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user