新增功能
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\doctor;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 医生预约模型
|
||||
* Class Appointment
|
||||
* @package app\common\model\doctor
|
||||
*/
|
||||
class Appointment extends BaseModel
|
||||
{
|
||||
protected $name = 'doctor_appointment';
|
||||
|
||||
// 自动时间戳类型设置为整型
|
||||
protected $autoWriteTimestamp = true;
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
protected $deleteTime = false;
|
||||
|
||||
// 时间字段取出后的默认时间格式(设置为false表示保持整型)
|
||||
protected $dateFormat = false;
|
||||
|
||||
/**
|
||||
* @notes 状态描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusDescAttr($value, $data)
|
||||
{
|
||||
$statusMap = [
|
||||
1 => '已预约',
|
||||
2 => '已取消',
|
||||
3 => '已完成',
|
||||
];
|
||||
return $statusMap[$data['status']] ?? '未知';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 时段描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getPeriodDescAttr($value, $data)
|
||||
{
|
||||
return $data['period'] == 'morning' ? '上午' : '下午';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 预约类型描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getAppointmentTypeDescAttr($value, $data)
|
||||
{
|
||||
$typeMap = [
|
||||
'video' => '视频问诊',
|
||||
'text' => '图文问诊',
|
||||
'phone' => '电话问诊',
|
||||
];
|
||||
return $typeMap[$data['appointment_type']] ?? '未知';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 预约日期格式化
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getAppointmentDateTextAttr($value, $data)
|
||||
{
|
||||
return $data['appointment_date'] ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 关联患者
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function patient()
|
||||
{
|
||||
return $this->hasOne('app\common\model\user\User', 'id', 'patient_id')
|
||||
->bind(['patient_name' => 'nickname', 'patient_phone' => 'mobile']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 关联医生
|
||||
* @return \think\model\relation\HasOne
|
||||
*/
|
||||
public function doctor()
|
||||
{
|
||||
return $this->hasOne('app\adminapi\logic\auth\AdminLogic', 'id', 'doctor_id')
|
||||
->bind(['doctor_name' => 'name']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\doctor;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 医生排班模型
|
||||
* Class Roster
|
||||
* @package app\common\model\doctor
|
||||
*/
|
||||
class Roster extends BaseModel
|
||||
{
|
||||
protected $name = 'doctor_roster';
|
||||
|
||||
// 自动时间戳类型设置为整型
|
||||
protected $autoWriteTimestamp = true;
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
// 时间字段取出后的默认时间格式(设置为false表示保持整型)
|
||||
protected $dateFormat = false;
|
||||
|
||||
/**
|
||||
* @notes 状态描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusDescAttr($value, $data)
|
||||
{
|
||||
$statusMap = [
|
||||
1 => '出诊',
|
||||
2 => '停诊',
|
||||
3 => '休息',
|
||||
4 => '请假',
|
||||
];
|
||||
return $statusMap[$data['status']] ?? '未知';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 时段描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getPeriodDescAttr($value, $data)
|
||||
{
|
||||
return $data['period'] == 'morning' ? '上午' : '下午';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 日期格式化
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getDateTextAttr($value, $data)
|
||||
{
|
||||
return $data['date'] ?? '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | likeadmin快速开发前后端分离管理后台(PHP版)
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\common\model\tcm;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 血糖血压记录模型
|
||||
* Class BloodRecord
|
||||
* @package app\common\model\tcm
|
||||
*/
|
||||
class BloodRecord extends BaseModel
|
||||
{
|
||||
protected $name = 'tcm_blood_record';
|
||||
|
||||
// 自动时间戳类型设置为整型
|
||||
protected $autoWriteTimestamp = true;
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
// 时间字段取出后的默认时间格式(设置为false表示保持整型)
|
||||
protected $dateFormat = false;
|
||||
|
||||
/**
|
||||
* @notes 记录日期格式化
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getRecordDateTextAttr($value, $data)
|
||||
{
|
||||
return !empty($data['record_date']) ? date('Y-m-d', $data['record_date']) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 血压文本
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getBloodPressureTextAttr($value, $data)
|
||||
{
|
||||
if (!empty($data['systolic_pressure']) && !empty($data['diastolic_pressure'])) {
|
||||
return $data['systolic_pressure'] . '/' . $data['diastolic_pressure'] . ' mmHg';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\tcm;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 通话记录模型
|
||||
* Class CallRecord
|
||||
* @package app\common\model\tcm
|
||||
*/
|
||||
class CallRecord extends BaseModel
|
||||
{
|
||||
protected $name = 'tcm_call_record';
|
||||
|
||||
/**
|
||||
* @notes 关联诊单
|
||||
*/
|
||||
public function diagnosis()
|
||||
{
|
||||
return $this->belongsTo('app\common\model\tcm\Diagnosis', 'diagnosis_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取通话类型文本
|
||||
*/
|
||||
public function getCallTypeTextAttr($value, $data)
|
||||
{
|
||||
$types = [
|
||||
1 => '语音通话',
|
||||
2 => '视频通话'
|
||||
];
|
||||
return $types[$data['call_type']] ?? '未知';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 获取状态文本
|
||||
*/
|
||||
public function getStatusTextAttr($value, $data)
|
||||
{
|
||||
$status = [
|
||||
1 => '进行中',
|
||||
2 => '已结束',
|
||||
3 => '未接听',
|
||||
4 => '已取消'
|
||||
];
|
||||
return $status[$data['status']] ?? '未知';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | likeadmin快速开发前后端分离管理后台(PHP版)
|
||||
// +----------------------------------------------------------------------
|
||||
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
|
||||
// | 开源版本可自由商用,可去除界面版权logo
|
||||
// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
|
||||
// | github下载:https://github.com/likeshop-github/likeadmin
|
||||
// | 访问官网:https://www.likeadmin.cn
|
||||
// | likeadmin团队 版权所有 拥有最终解释权
|
||||
// +----------------------------------------------------------------------
|
||||
// | author: likeadminTeam
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace app\common\model\tcm;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 中医辨房病因诊单模型
|
||||
* Class Diagnosis
|
||||
* @package app\common\model\tcm
|
||||
*/
|
||||
class Diagnosis extends BaseModel
|
||||
{
|
||||
protected $name = 'tcm_diagnosis';
|
||||
|
||||
// 自动时间戳类型设置为整型
|
||||
protected $autoWriteTimestamp = true;
|
||||
protected $createTime = 'create_time';
|
||||
protected $updateTime = 'update_time';
|
||||
protected $deleteTime = 'delete_time';
|
||||
|
||||
// 时间字段取出后的默认时间格式(设置为false表示保持整型)
|
||||
protected $dateFormat = false;
|
||||
|
||||
/**
|
||||
* @notes 性别描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getGenderDescAttr($value, $data)
|
||||
{
|
||||
return $data['gender'] == 1 ? '男' : '女';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 状态描述
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getStatusDescAttr($value, $data)
|
||||
{
|
||||
return $data['status'] == 1 ? '启用' : '禁用';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 诊断日期格式化
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return string
|
||||
*/
|
||||
public function getDiagnosisDateTextAttr($value, $data)
|
||||
{
|
||||
return !empty($data['diagnosis_date']) ? date('Y-m-d', $data['diagnosis_date']) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 既往史数组
|
||||
* @param $value
|
||||
* @param $data
|
||||
* @return array
|
||||
*/
|
||||
public function getPastHistoryArrAttr($value, $data)
|
||||
{
|
||||
return !empty($data['past_history']) ? explode(',', $data['past_history']) : [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\model\tcm;
|
||||
|
||||
use app\common\model\BaseModel;
|
||||
|
||||
/**
|
||||
* 患者TRTC账号模型
|
||||
* Class PatientTrtc
|
||||
* @package app\common\model\tcm
|
||||
*/
|
||||
class PatientTrtc extends BaseModel
|
||||
{
|
||||
protected $name = 'tcm_patient_trtc';
|
||||
|
||||
/**
|
||||
* @notes 关联诊单
|
||||
*/
|
||||
public function diagnosis()
|
||||
{
|
||||
return $this->hasMany('app\common\model\tcm\Diagnosis', 'patient_id', 'patient_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 检查是否过期
|
||||
*/
|
||||
public function isExpired(): bool
|
||||
{
|
||||
return $this->expire_time > 0 && $this->expire_time < time();
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 更新最后登录时间
|
||||
*/
|
||||
public function updateLastLogin(): bool
|
||||
{
|
||||
$this->last_login_time = time();
|
||||
return $this->save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
/**
|
||||
* 腾讯云IM UserSig生成类(官方算法)
|
||||
* 参考:https://github.com/tencentyun/tls-sig-api-v2-php
|
||||
*/
|
||||
class TLSSigAPIv2
|
||||
{
|
||||
private $sdkappid;
|
||||
private $key;
|
||||
|
||||
public function __construct($sdkappid, $key)
|
||||
{
|
||||
$this->sdkappid = $sdkappid;
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成UserSig
|
||||
* @param string $identifier 用户ID
|
||||
* @param int $expire 过期时间(秒)
|
||||
* @return string UserSig
|
||||
*/
|
||||
public function genUserSig($identifier, $expire = 86400)
|
||||
{
|
||||
return $this->__genSig($identifier, $expire, '', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带权限的UserSig
|
||||
* @param string $identifier 用户ID
|
||||
* @param int $expire 过期时间(秒)
|
||||
* @param string $userbuf 用户权限buffer
|
||||
* @return string UserSig
|
||||
*/
|
||||
public function genUserSigWithUserBuf($identifier, $expire, $userbuf)
|
||||
{
|
||||
return $this->__genSig($identifier, $expire, $userbuf, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 内部方法:生成签名
|
||||
*/
|
||||
private function __genSig($identifier, $expire, $userbuf, $userbuf_enabled)
|
||||
{
|
||||
$current = time();
|
||||
$sigDoc = [
|
||||
'TLS.ver' => '2.0',
|
||||
'TLS.identifier' => strval($identifier),
|
||||
'TLS.sdkappid' => intval($this->sdkappid),
|
||||
'TLS.expire' => intval($expire),
|
||||
'TLS.time' => intval($current)
|
||||
];
|
||||
|
||||
$base64_userbuf = '';
|
||||
if ($userbuf_enabled) {
|
||||
$base64_userbuf = base64_encode($userbuf);
|
||||
$sigDoc['TLS.userbuf'] = $base64_userbuf;
|
||||
}
|
||||
|
||||
$sig = $this->hmacsha256($identifier, $current, $expire, $base64_userbuf, $userbuf_enabled);
|
||||
$sigDoc['TLS.sig'] = base64_encode($sig);
|
||||
|
||||
$json_text = json_encode($sigDoc);
|
||||
$compressed = gzcompress($json_text);
|
||||
|
||||
return $this->base64_url_encode($compressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成HMAC-SHA256签名
|
||||
*/
|
||||
private function hmacsha256($identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled)
|
||||
{
|
||||
$content_to_be_signed = "TLS.identifier:" . $identifier . "\n"
|
||||
. "TLS.sdkappid:" . $this->sdkappid . "\n"
|
||||
. "TLS.time:" . $curr_time . "\n"
|
||||
. "TLS.expire:" . $expire . "\n";
|
||||
|
||||
if ($userbuf_enabled) {
|
||||
$content_to_be_signed .= "TLS.userbuf:" . $base64_userbuf . "\n";
|
||||
}
|
||||
|
||||
return hash_hmac('sha256', $content_to_be_signed, $this->key, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 URL安全编码
|
||||
*/
|
||||
private function base64_url_encode($input)
|
||||
{
|
||||
return str_replace(['+', '/', '='], ['*', '-', '_'], base64_encode($input));
|
||||
}
|
||||
|
||||
/**
|
||||
* Base64 URL安全解码
|
||||
*/
|
||||
private function base64_url_decode($base64_url_string)
|
||||
{
|
||||
return base64_decode(str_replace(['*', '-', '_'], ['+', '/', '='], $base64_url_string));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证UserSig
|
||||
* @param string $sig UserSig
|
||||
* @param string $identifier 用户ID
|
||||
* @param int $init_time 初始化时间
|
||||
* @param int $expire_time 过期时间
|
||||
* @param string $userbuf 用户权限buffer
|
||||
* @param string $error_msg 错误信息
|
||||
* @return bool 是否有效
|
||||
*/
|
||||
public function verifySig($sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg)
|
||||
{
|
||||
try {
|
||||
$error_msg = '';
|
||||
$compressed_sig = $this->base64_url_decode($sig);
|
||||
$pre_level = error_reporting(E_ERROR);
|
||||
$uncompressed_sig = gzuncompress($compressed_sig);
|
||||
error_reporting($pre_level);
|
||||
|
||||
if ($uncompressed_sig === false) {
|
||||
throw new \Exception('gzuncompress error');
|
||||
}
|
||||
|
||||
$sig_doc = json_decode($uncompressed_sig, true);
|
||||
if ($sig_doc === false) {
|
||||
throw new \Exception('json_decode error');
|
||||
}
|
||||
|
||||
if ($sig_doc['TLS.identifier'] !== $identifier) {
|
||||
throw new \Exception('identifier dosen\'t match');
|
||||
}
|
||||
|
||||
if ($sig_doc['TLS.sdkappid'] != $this->sdkappid) {
|
||||
throw new \Exception('sdkappid dosen\'t match');
|
||||
}
|
||||
|
||||
$sig = base64_decode($sig_doc['TLS.sig']);
|
||||
if ($sig === false) {
|
||||
throw new \Exception('sig base64_decode error');
|
||||
}
|
||||
|
||||
$init_time = $sig_doc['TLS.time'];
|
||||
$expire_time = $sig_doc['TLS.expire'];
|
||||
|
||||
$curr_time = time();
|
||||
if ($curr_time > $init_time + $expire_time) {
|
||||
throw new \Exception('sig expired');
|
||||
}
|
||||
|
||||
$userbuf_enabled = false;
|
||||
$base64_userbuf = '';
|
||||
if (isset($sig_doc['TLS.userbuf'])) {
|
||||
$base64_userbuf = $sig_doc['TLS.userbuf'];
|
||||
$userbuf = base64_decode($base64_userbuf);
|
||||
$userbuf_enabled = true;
|
||||
}
|
||||
|
||||
$sigCalculated = $this->hmacsha256($identifier, $init_time, $expire_time, $base64_userbuf, $userbuf_enabled);
|
||||
|
||||
if ($sig != $sigCalculated) {
|
||||
throw new \Exception('verify failed');
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (\Exception $ex) {
|
||||
$error_msg = $ex->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\service;
|
||||
|
||||
/**
|
||||
* 腾讯云IM服务类
|
||||
* Class TencentImService
|
||||
* @package app\common\service
|
||||
*/
|
||||
class TencentImService
|
||||
{
|
||||
private $sdkAppId;
|
||||
private $secretKey;
|
||||
private $adminIdentifier = 'administrator'; // 管理员账号
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$config = config('project.trtc');
|
||||
$this->sdkAppId = $config['sdkAppId'];
|
||||
$this->secretKey = $config['secretKey'];
|
||||
|
||||
\think\facade\Log::info('TencentImService初始化 - sdkAppId: ' . $this->sdkAppId . ', secretKey长度: ' . strlen($this->secretKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 生成UserSig(使用腾讯云官方算法)
|
||||
* @param string $userId
|
||||
* @param int $expire
|
||||
* @return string|false
|
||||
*/
|
||||
private function generateUserSig(string $userId, int $expire = 86400)
|
||||
{
|
||||
try {
|
||||
$api = new TLSSigAPIv2($this->sdkAppId, $this->secretKey);
|
||||
$userSig = $api->genUserSig($userId, $expire);
|
||||
|
||||
\think\facade\Log::info('UserSig生成成功 - userId: ' . $userId . ', sig长度: ' . strlen($userSig));
|
||||
|
||||
return $userSig;
|
||||
} catch (\Exception $e) {
|
||||
\think\facade\Log::error('生成UserSig失败: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 导入单个账号到IM
|
||||
* @param string $userId 用户ID
|
||||
* @param string $nick 昵称(可选)
|
||||
* @param string $faceUrl 头像URL(可选)
|
||||
* @return array|false
|
||||
*/
|
||||
public function importAccount(string $userId, string $nick = '', string $faceUrl = '')
|
||||
{
|
||||
try {
|
||||
\think\facade\Log::info('开始导入IM账号 - userId: ' . $userId . ', nick: ' . $nick . ', sdkAppId: ' . $this->sdkAppId);
|
||||
|
||||
// 生成管理员UserSig
|
||||
$adminUserSig = $this->generateUserSig($this->adminIdentifier);
|
||||
|
||||
if (!$adminUserSig) {
|
||||
throw new \Exception('生成管理员UserSig失败');
|
||||
}
|
||||
|
||||
\think\facade\Log::info('管理员UserSig生成成功');
|
||||
|
||||
// 构建请求URL
|
||||
$random = rand(0, 4294967295);
|
||||
$url = sprintf(
|
||||
'https://console.tim.qq.com/v4/im_open_login_svc/account_import?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json',
|
||||
$this->sdkAppId,
|
||||
$this->adminIdentifier,
|
||||
urlencode($adminUserSig),
|
||||
$random
|
||||
);
|
||||
|
||||
\think\facade\Log::info('请求URL构建完成');
|
||||
|
||||
// 构建请求体
|
||||
$data = [
|
||||
'UserID' => $userId
|
||||
];
|
||||
|
||||
if ($nick) {
|
||||
$data['Nick'] = $nick;
|
||||
}
|
||||
|
||||
if ($faceUrl) {
|
||||
$data['FaceUrl'] = $faceUrl;
|
||||
}
|
||||
|
||||
\think\facade\Log::info('请求数据: ' . json_encode($data, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 发送请求
|
||||
$result = $this->httpPost($url, json_encode($data));
|
||||
|
||||
\think\facade\Log::info('HTTP响应: ' . substr($result, 0, 500));
|
||||
|
||||
if (!$result) {
|
||||
throw new \Exception('请求失败:无响应');
|
||||
}
|
||||
|
||||
$response = json_decode($result, true);
|
||||
|
||||
if (!$response) {
|
||||
throw new \Exception('响应解析失败:' . substr($result, 0, 200));
|
||||
}
|
||||
|
||||
\think\facade\Log::info('响应解析成功: ' . json_encode($response, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 检查响应状态
|
||||
if ($response['ActionStatus'] !== 'OK') {
|
||||
$errorMsg = sprintf(
|
||||
'导入账号失败 - ErrorCode: %s, ErrorInfo: %s',
|
||||
$response['ErrorCode'] ?? 'unknown',
|
||||
$response['ErrorInfo'] ?? '未知错误'
|
||||
);
|
||||
throw new \Exception($errorMsg);
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'userId' => $userId,
|
||||
'message' => '账号导入成功'
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$errorMsg = sprintf(
|
||||
'导入IM账号失败 - userId: %s, error: %s',
|
||||
$userId,
|
||||
$e->getMessage()
|
||||
);
|
||||
\think\facade\Log::error($errorMsg);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'userId' => $userId,
|
||||
'message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 批量导入账号
|
||||
* @param array $accounts 账号列表 [['userId' => 'xxx', 'nick' => 'xxx', 'faceUrl' => 'xxx'], ...]
|
||||
* @return array
|
||||
*/
|
||||
public function batchImportAccounts(array $accounts): array
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($accounts as $account) {
|
||||
$userId = $account['userId'] ?? '';
|
||||
$nick = $account['nick'] ?? '';
|
||||
$faceUrl = $account['faceUrl'] ?? '';
|
||||
|
||||
if (!$userId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $this->importAccount($userId, $nick, $faceUrl);
|
||||
$results[] = $result;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 删除账号
|
||||
* @param array $userIds 用户ID列表
|
||||
* @return array|false
|
||||
*/
|
||||
public function deleteAccounts(array $userIds)
|
||||
{
|
||||
try {
|
||||
// 生成管理员UserSig
|
||||
$adminUserSig = $this->generateUserSig($this->adminIdentifier);
|
||||
|
||||
if (!$adminUserSig) {
|
||||
throw new \Exception('生成管理员UserSig失败');
|
||||
}
|
||||
|
||||
// 构建请求URL
|
||||
$random = rand(0, 4294967295);
|
||||
$url = sprintf(
|
||||
'https://console.tim.qq.com/v4/im_open_login_svc/account_delete?sdkappid=%s&identifier=%s&usersig=%s&random=%s&contenttype=json',
|
||||
$this->sdkAppId,
|
||||
$this->adminIdentifier,
|
||||
urlencode($adminUserSig),
|
||||
$random
|
||||
);
|
||||
|
||||
// 构建请求体
|
||||
$data = [
|
||||
'DeleteItem' => array_map(function($userId) {
|
||||
return ['UserID' => $userId];
|
||||
}, $userIds)
|
||||
];
|
||||
|
||||
// 发送请求
|
||||
$result = $this->httpPost($url, json_encode($data));
|
||||
|
||||
if (!$result) {
|
||||
throw new \Exception('请求失败');
|
||||
}
|
||||
|
||||
$response = json_decode($result, true);
|
||||
|
||||
if (!$response) {
|
||||
throw new \Exception('响应解析失败');
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if ($response['ActionStatus'] !== 'OK') {
|
||||
throw new \Exception($response['ErrorInfo'] ?? '删除账号失败');
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => '账号删除成功'
|
||||
];
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\think\facade\Log::error('删除IM账号失败', [
|
||||
'userIds' => $userIds,
|
||||
'error' => $e->getMessage()
|
||||
]);
|
||||
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $e->getMessage()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes 发送HTTP POST请求
|
||||
* @param string $url
|
||||
* @param string $data
|
||||
* @return string|false
|
||||
*/
|
||||
private function httpPost(string $url, string $data)
|
||||
{
|
||||
$ch = curl_init();
|
||||
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($data)
|
||||
]);
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$error = curl_error($ch);
|
||||
|
||||
curl_close($ch);
|
||||
|
||||
if ($error) {
|
||||
\think\facade\Log::error('HTTP请求失败', [
|
||||
'url' => $url,
|
||||
'error' => $error
|
||||
]);
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user