初始化项目:添加后端代码、ThinkPHP框架、前端资源

This commit is contained in:
amb
2026-09-03 12:42:39 +08:00
commit 482bece22e
3726 changed files with 416708 additions and 0 deletions
@@ -0,0 +1,264 @@
<?php
namespace app\common\library\live\message;
use app\common\model\config\System;
/**
* 直播消息服务商管理器
* 服务商统一由通用设置 live_basic.live_message_type 决定,切换后对所有直播间(含历史直播间)立即生效
*/
class Manager
{
/**
* 服务商名称与实现类的映射
* 新增服务商时在此注册即可
* @var array
*/
protected static $providers = [
'aodianyun' => \app\common\library\live\message\provider\Aodianyun::class,
'aliyun' => \app\common\library\live\message\provider\Aliyun::class,
];
/**
* 兼容历史中文值(前端 radio 曾误保存 label)到标准 provider key 的映射
* @var array
*/
protected static $aliasMap = [
'奥点云消息' => 'aodianyun',
'奥点云' => 'aodianyun',
'阿里云消息' => 'aliyun',
'阿里云' => 'aliyun',
];
/**
* 已实例化的服务商(按 provider 名缓存)
* @var array
*/
protected static $instances = [];
/**
* 归一化服务商名称
* 兼容历史中文值;无效值降级为奥点云
* @param string|null $providerName
* @return string
*/
public static function normalizeProvider($providerName)
{
if (!is_string($providerName) || $providerName === '') {
return 'aodianyun';
}
if (isset(self::$aliasMap[$providerName])) {
$providerName = self::$aliasMap[$providerName];
}
return isset(self::$providers[$providerName]) ? $providerName : 'aodianyun';
}
/**
* 判断消息服务是否已开启
* 读取 live_basic.live_message_status 配置,"1" 为开启,"0" 为关闭
* @return bool
*/
public static function isMessageEnabled()
{
try {
$config = System::getConfig('live_basic');
} catch (\Exception $e) {
return true;
}
if (!is_array($config) || !isset($config['live_message_status'])) {
return true;
}
return $config['live_message_status'] !== '0' && $config['live_message_status'] !== 0;
}
/**
* 获取全局配置的服务商名称
* 统一从 System::getConfig('live_basic')['live_message_type'] 读取
* @return string
*/
public static function getGlobalProviderName()
{
try {
$config = System::getConfig('live_basic');
} catch (\Exception $e) {
return 'aodianyun';
}
$providerName = (is_array($config) && isset($config['live_message_type'])) ? $config['live_message_type'] : '';
return self::normalizeProvider($providerName);
}
/**
* 获取服务商实例
* @param string|null $providerName 服务商名称(aodianyun/aliyun),为空则读取全局配置;非空也会归一化,避免中文值导致错误降级
* @return ProviderInterface
*/
public static function provider($providerName = null)
{
if ($providerName === null || $providerName === '') {
$providerName = self::getGlobalProviderName();
} else {
$providerName = self::normalizeProvider($providerName);
}
if (!isset(self::$instances[$providerName])) {
$class = self::$providers[$providerName];
self::$instances[$providerName] = new $class();
}
return self::$instances[$providerName];
}
/**
* 根据课程ID获取服务商实例
* 服务商由全局配置统一决定,参数保留仅为兼容旧调用签名
* @param int $courseId 课程ID(保留参数以兼容既有调用)
* @return ProviderInterface
*/
public static function providerByCourseId($courseId)
{
return self::provider(self::getGlobalProviderName());
}
/**
* 根据课程ID获取服务商名称
* 服务商由全局配置统一决定,参数保留仅为兼容旧调用签名
* @param int $courseId 课程ID(保留参数以兼容既有调用)
* @return string
*/
public static function providerNameByCourseId($courseId)
{
return self::getGlobalProviderName();
}
/**
* 注册自定义服务商(便于扩展)
* @param string $name 服务商名称
* @param string $class 实现类(必须实现 ProviderInterface
* @return void
*/
public static function register($name, $class)
{
self::$providers[$name] = $class;
// 清除已缓存实例以便下次使用新注册类
unset(self::$instances[$name]);
}
/**
* 确保阿里云互动消息群组已创建
* 用于兼容历史直播间:直播间创建时若不是阿里云模式则未建群,切换到阿里云后需要幂等地补建
* 已存在的群会被阿里云识别为重复请求(GroupExist / 类似错误码),此处按成功处理
* @param string $groupId 群组ID(对应 tuzhi_live_room.message_topic
* @param string $groupName 群组名称
* @return bool 是否可用(true=群存在或补建成功;false=补建失败)
*/
public static function ensureAliyunGroup($groupId, $groupName = '')
{
if (!$groupId) {
return false;
}
try {
$result = self::provider('aliyun')->createGroup($groupId, $groupName, '');
if ($result->isSuccess()) {
return true;
}
// 阿里云群组已存在类错误按成功处理,保证幂等
$error = is_string($result->error) ? $result->error : '';
if ($error !== '' && (
stripos($error, 'exist') !== false ||
stripos($error, 'duplicate') !== false ||
stripos($error, 'already') !== false
)) {
return true;
}
\think\Log::error('[live Manager ensureAliyunGroup] createGroup failed: ' . $error . ' group_id=' . $groupId);
return false;
} catch (\Exception $e) {
\think\Log::error('[live Manager ensureAliyunGroup] exception: ' . $e->getMessage() . ' group_id=' . $groupId);
return false;
}
}
/**
* 清理已删除课程对应的阿里云互动消息群组
*
* 逻辑:
* 1. 查找 status=-1(已删除)且课程类型为 live 的课程
* 2. 关联 tuzhi_live_room 获取 message_topic
* 3. 调用 deleteGroup 删除阿里云端的群组
* 4. 清空 live_room.message_topic 标记已清理
*
* @param int $batchSize 单次最多处理数量,防止超时
* @param bool $dryRun 仅预览,不实际删除
* @return array ['deleted' => int, 'failed' => int, 'skipped' => int, 'items' => array]
*/
public static function cleanupOrphanGroups($batchSize = 50, $dryRun = false)
{
$provider = self::getGlobalProviderName();
if ($provider !== 'aliyun') {
return ['deleted' => 0, 'failed' => 0, 'skipped' => 0, 'items' => [], 'msg' => '当前消息服务非阿里云,无需清理'];
}
// 查找已删除课程中仍保留 message_topic 的直播间
$rows = \think\Db::table('tuzhi_live_room r')
->join('tuzhi_course c', 'c.id = r.course_id', 'LEFT')
->where('r.message_topic', '<>', '')
->where('r.message_topic', 'IS NOT NULL')
->where(function ($q) {
// 课程已删除 或 课程不存在(孤儿记录)
$q->where('c.status', -1)->whereOr('c.id', 'IS NULL');
})
->limit($batchSize)
->select(['r.id', 'r.course_id', 'r.message_topic']);
$deleted = 0;
$failed = 0;
$items = [];
$aliyunProvider = self::provider('aliyun');
foreach ($rows as $row) {
$groupId = $row['message_topic'];
$roomId = $row['id'];
$courseId = $row['course_id'];
if ($dryRun) {
$items[] = ['room_id' => $roomId, 'course_id' => $courseId, 'group_id' => $groupId, 'action' => 'preview'];
continue;
}
try {
$result = $aliyunProvider->deleteGroup($groupId, 'system-cleanup');
if ($result->isSuccess()) {
// 清空 message_topic 标记已清理
\think\Db::table('tuzhi_live_room')->where('id', $roomId)->update(['message_topic' => '']);
$deleted++;
$items[] = ['room_id' => $roomId, 'course_id' => $courseId, 'group_id' => $groupId, 'action' => 'deleted'];
} else {
$failed++;
$items[] = ['room_id' => $roomId, 'course_id' => $courseId, 'group_id' => $groupId, 'action' => 'failed', 'error' => $result->error];
\think\Log::error('[live Manager cleanupOrphanGroups] deleteGroup failed: ' . $result->error . ' group_id=' . $groupId);
}
} catch (\Exception $e) {
$failed++;
$items[] = ['room_id' => $roomId, 'course_id' => $courseId, 'group_id' => $groupId, 'action' => 'error', 'error' => $e->getMessage()];
\think\Log::error('[live Manager cleanupOrphanGroups] exception: ' . $e->getMessage() . ' group_id=' . $groupId);
}
}
return [
'deleted' => $deleted,
'failed' => $failed,
'skipped' => count($rows) - $deleted - $failed,
'items' => $items,
];
}
}
@@ -0,0 +1,73 @@
<?php
namespace app\common\library\live\message;
/**
* 直播消息值对象
* 描述一条待发送的消息,封装消息各字段,便于在业务层与服务商层之间传递
*/
class Message
{
/**
* @var string 群组ID(奥点云 topic / 阿里云 GroupId
*/
public $groupId;
/**
* @var string 发送者ID(阿里云必填)
*/
public $senderId;
/**
* @var string 发送者扩展信息
*/
public $senderMeta;
/**
* @var string 消息体(JSON 字符串)
*/
public $body;
/**
* @var int 消息类型
*/
public $msgType;
/**
* @var string 消息唯一标识(用于撤回)
*/
public $msgTid;
/**
* 构造函数
* @param array $data 初始化数据,支持键:group_id/sender_id/sender_meta/body/msg_type/msg_tid
*/
public function __construct(array $data = [])
{
$this->groupId = $data['group_id'] ?? '';
$this->senderId = $data['sender_id'] ?? '';
$this->senderMeta = $data['sender_meta'] ?? '';
$this->body = $data['body'] ?? '';
$this->msgType = isset($data['msg_type']) ? (int)$data['msg_type'] : 10001;
$this->msgTid = $data['msg_tid'] ?? '';
}
/**
* 消息业务类型到阿里云 MsgType 的映射
* text -> 10001
* image -> 10002
* gift -> 10003
* 其他 -> 10099
* @param string $type 业务消息类型
* @return int
*/
public static function mapMsgType($type)
{
$map = [
'text' => 10001,
'image' => 10002,
'gift' => 10003,
];
return isset($map[$type]) ? $map[$type] : 10099;
}
}
@@ -0,0 +1,65 @@
<?php
namespace app\common\library\live\message;
/**
* 直播消息服务商统一接口
* 所有消息服务商(奥点云、阿里云等)均需实现该接口
*/
interface ProviderInterface
{
/**
* 发送消息到群组
* @param string $groupId 群组ID(奥点云为 topic,阿里云为 GroupId
* @param string $body 消息体(JSON 字符串)
* @param int $msgType 消息类型(阿里云自定义类型需 > 10000text=10001,image=10002,gift=10003
* @param string $senderId 发送者ID(阿里云必填,奥点云忽略)
* @param string $senderMeta 发送者扩展信息(阿里云可选)
* @param string $msgTid 消息唯一标识(用于撤回,空则由服务商生成)
* @return Result
*/
public function send($groupId, $body, $msgType = 10001, $senderId = '', $senderMeta = '', $msgTid = '');
/**
* 撤回/删除消息
* @param string $groupId 群组ID
* @param string $msgTid 消息唯一标识(奥点云为 uuid,阿里云为 MsgTid
* @return Result
*/
public function del($groupId, $msgTid);
/**
* 获取群组在线用户
* @param string $groupId 群组ID
* @param int $pageSize 每页数量
* @param int $nextPageToken 下一页起始位置(奥点云作为 skip 偏移量使用)
* @return Result data 包含 total、list、next_page_token、has_more
*/
public function getOnlineUser($groupId, $pageSize = 50, $nextPageToken = 0);
/**
* 获取客户端登录鉴权信息(仅阿里云需要,奥点云返回空数据)
* @param string $userId 用户ID
* @param string $role 角色(admin 或空字符串)
* @return Result data 包含 app_id、app_sign、auth、app_token
*/
public function getLoginAuth($userId, $role = '');
/**
* 创建群组(仅阿里云需要,奥点云直接返回成功)
* @param string $groupId 群组ID
* @param string $groupName 群组名称
* @param string $groupMeta 群组扩展信息
* @return Result
*/
public function createGroup($groupId, $groupName = '', $groupMeta = '');
/**
* 删除群组
* 群组删除后不再可用,在线用户会被通知群已结束
* @param string $groupId 群组ID
* @param string $operatorId 操作者ID(可选)
* @return Result
*/
public function deleteGroup($groupId, $operatorId = '');
}
@@ -0,0 +1,76 @@
<?php
namespace app\common\library\live\message;
/**
* 消息服务统一返回结构
* 用于标准化各服务商的返回结果,便于业务层无差别处理
*/
class Result
{
/**
* @var bool 是否成功
*/
public $success;
/**
* @var mixed 业务数据
*/
public $data;
/**
* @var string 错误信息(失败时填充)
*/
public $error;
/**
* @var mixed 服务商原始返回(用于调试与排查)
*/
public $rawResponse;
/**
* 构造函数
* @param bool $success 是否成功
* @param mixed $data 业务数据
* @param string $error 错误信息
* @param mixed $rawResponse 原始返回
*/
public function __construct($success = true, $data = null, $error = '', $rawResponse = null)
{
$this->success = $success;
$this->data = $data;
$this->error = $error;
$this->rawResponse = $rawResponse;
}
/**
* 构造成功结果
* @param mixed $data 业务数据
* @param mixed $rawResponse 原始返回
* @return Result
*/
public static function success($data = null, $rawResponse = null)
{
return new self(true, $data, '', $rawResponse);
}
/**
* 构造失败结果
* @param string $error 错误信息
* @param mixed $rawResponse 原始返回
* @return Result
*/
public static function fail($error, $rawResponse = null)
{
return new self(false, null, $error, $rawResponse);
}
/**
* 是否成功
* @return bool
*/
public function isSuccess()
{
return $this->success === true;
}
}
@@ -0,0 +1,225 @@
<?php
namespace app\common\library\live\message\provider;
use app\common\library\live\message\ProviderInterface;
use app\common\library\live\message\Result;
use app\common\model\config\System;
use aliyun\LiveMessage;
/**
* 阿里云互动消息服务商适配器
* 基于 \aliyun\LiveMessage 实现统一接口
*/
class Aliyun implements ProviderInterface
{
/**
* @var LiveMessage 阿里云 SDK 实例
*/
protected $sdk;
/**
* 构造函数,从配置 aliyun_message 读取阿里云相关参数并实例化 SDK
*/
public function __construct()
{
$config = System::getConfig('aliyun_message');
$appId = (is_array($config) && isset($config['app_id'])) ? $config['app_id'] : '';
$appKey = (is_array($config) && isset($config['app_key'])) ? $config['app_key'] : '';
$appSign = (is_array($config) && isset($config['app_sign'])) ? $config['app_sign'] : '';
$accessKeyId = (is_array($config) && isset($config['access_key_id'])) ? $config['access_key_id'] : '';
$accessKeySecret = (is_array($config) && isset($config['access_key_secret'])) ? $config['access_key_secret'] : '';
$dataCenter = (is_array($config) && !empty($config['data_center'])) ? $config['data_center'] : 'cn-shanghai';
$this->sdk = new LiveMessage($appId, $appKey, $appSign, $accessKeyId, $accessKeySecret, $dataCenter);
}
/**
* 发送消息到群组
* @param string $groupId 群组ID
* @param string $body 消息体
* @param int $msgType 消息类型(业务 type 映射后的阿里云 MsgType
* @param string $senderId 发送者ID
* @param string $senderMeta 发送者扩展信息
* @param string $msgTid 消息唯一标识
* @return Result data 含 msg_tid
*/
public function send($groupId, $body, $msgType = 10001, $senderId = '', $senderMeta = '', $msgTid = '')
{
// 若未传入 senderId,使用系统默认(管理员发送场景)
if ($senderId === '') {
$senderId = 'system';
}
$result = $this->sdk->sendGroupMessage($groupId, $body, $msgType, $senderId, $senderMeta, $msgTid);
if ($result['success']) {
return Result::success([
'msg_tid' => isset($result['data']['msg_tid']) ? $result['data']['msg_tid'] : '',
], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 撤回/删除消息
* @param string $groupId 群组ID
* @param string $msgTid 阿里云消息唯一标识
* @return Result
*/
public function del($groupId, $msgTid)
{
$result = $this->sdk->deleteGroupMessage($groupId, $msgTid);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取群组在线用户
* 对于超过 2000 人的超级大群,返回 success=false 且 error='SuperLargeGroup',业务层可降级处理
* @param string $groupId 群组ID
* @param int $pageSize 每页数量(10-30,阿里云实际限制)
* @param int $nextPageToken 下一页起始位置
* @return Result data 含 total、list、next_page_token、has_more
*/
public function getOnlineUser($groupId, $pageSize = 20, $nextPageToken = 0)
{
$result = $this->sdk->listGroupUsers($groupId, $pageSize, $nextPageToken);
if ($result['success']) {
$data = $result['data'];
$userIds = [];
if (isset($data['user_list']) && is_array($data['user_list'])) {
foreach ($data['user_list'] as $user) {
if (isset($user['user_id'])) {
$userIds[] = $user['user_id'];
}
}
}
return Result::success([
'total' => count($userIds),
'list' => $userIds,
'next_page_token' => isset($data['next_page_token']) ? $data['next_page_token'] : 0,
'has_more' => isset($data['has_more']) ? $data['has_more'] : false,
], $result['raw']);
}
// 超级大群特殊错误码,保持与接口约定一致
if ($result['error_code'] === 'SuperLargeGroup') {
return Result::fail('SuperLargeGroup', $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取客户端登录鉴权信息
* 实现 token = sha256(appId + appKey + userId + nonce + timestamp + role)
* @param string $userId 用户ID(需过滤,仅保留 A-Z a-z 0-9 -,最长 64 字节)
* @param string $role 角色(admin 或空字符串)
* @return Result data 含 app_id、app_sign、auth、app_token
*/
public function getLoginAuth($userId, $role = '')
{
$appId = $this->sdk->getAppId();
$appKey = $this->sdk->getAppKey();
// userId 过滤:仅保留 [A-Za-z0-9-],最长 64 字节
$filteredUserId = $this->filterUserId($userId);
if ($filteredUserId === '') {
return Result::fail('userId 无效,过滤后为空', null);
}
// nonce 生成:AK- + md5(uniqid(mt_rand, true))
$nonce = 'AK-' . md5(uniqid(mt_rand(), true));
// timestamp:当前时间 + 86400 秒
$timestamp = time() + 86400;
// role 仅允许 admin 或空字符串
$role = ($role === 'admin') ? 'admin' : '';
// 计算 token
$token = hash('sha256', $appId . $appKey . $filteredUserId . $nonce . $timestamp . $role);
$data = [
'app_id' => $appId,
'app_sign' => $this->sdk->getAppSign(),
'auth' => [
'nonce' => $nonce,
'timestamp' => $timestamp,
'role' => $role,
'user_id' => $filteredUserId,
],
'app_token' => $token,
];
return Result::success($data, null);
}
/**
* 创建群组
* @param string $groupId 群组ID
* @param string $groupName 群组名称
* @param string $groupMeta 群组扩展信息
* @return Result
*/
public function createGroup($groupId, $groupName = '', $groupMeta = '')
{
$result = $this->sdk->createGroup($groupId, $groupName, $groupMeta);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 删除群组
* @param string $groupId 群组ID
* @param string $operatorId 操作者ID(可选)
* @return Result
*/
public function deleteGroup($groupId, $operatorId = '')
{
$result = $this->sdk->deleteGroup($groupId, $operatorId);
if ($result['success']) {
return Result::success($result['data'], $result['raw']);
}
return Result::fail($result['error'], $result['raw']);
}
/**
* 获取底层 SDK 实例(供扩展调用,如 listGroups
* @return LiveMessage
*/
public function getSdk()
{
return $this->sdk;
}
/**
* 过滤 userId,仅保留 [A-Za-z0-9-],最长 64 字节
* @param string $userId 原始用户ID
* @return string
*/
protected function filterUserId($userId)
{
$filtered = preg_replace('/[^A-Za-z0-9\-]/', '', (string)$userId);
// 截断到 64 字节
if (strlen($filtered) > 64) {
$filtered = substr($filtered, 0, 64);
}
return $filtered;
}
}
@@ -0,0 +1,164 @@
<?php
namespace app\common\library\live\message\provider;
use app\common\library\live\message\ProviderInterface;
use app\common\library\live\message\Result;
use app\common\model\config\System;
use aodianyun\Dms;
/**
* 奥点云消息服务商适配器
* 封装 \aodianyun\Dms,保持与原 library/live/Message.php 一致的行为
*/
class Aodianyun implements ProviderInterface
{
/**
* @var Dms
*/
protected $dms;
/**
* 构造函数,从配置读取 s_key 并实例化 Dms
*/
public function __construct()
{
$config = System::getConfig('aodianyun');
$sKey = is_array($config) && isset($config['s_key']) ? $config['s_key'] : '';
$this->dms = new Dms($sKey);
}
/**
* 发送消息到群组
* 奥点云 DMS 成功响应:HTTP 201 + {"uuid":"xxx"}(无 Flag 字段)
* 失败响应:{"error":"xxx"} 或 Dms::curl 兜底构造的 ['Flag'=>httpCode, 'FlagString'=>body]
* @param string $groupId 群组ID(奥点云 topic
* @param string $body 消息内容
* @param int $msgType 消息类型(奥点云不使用)
* @param string $senderId 发送者ID(奥点云不使用)
* @param string $senderMeta 发送者扩展信息(奥点云不使用)
* @param string $msgTid 消息唯一标识(奥点云由服务端生成 uuid)
* @return Result data 含 uuid
*/
public function send($groupId, $body, $msgType = 10001, $senderId = '', $senderMeta = '', $msgTid = '')
{
$response = $this->dms->sendMsg($groupId, $body);
// 成功:响应中含 uuid 字段
if (is_array($response) && isset($response['uuid'])) {
$uuid = $response['uuid'];
return Result::success(['uuid' => $uuid, 'msg_tid' => $uuid], $response);
}
$error = $this->extractError($response, '发送失败');
return Result::fail($error, $response);
}
/**
* 撤回/删除消息
* 奥点云 DMS 成功响应:HTTP 204 No Contentbody 为空,Dms::delMsg 返回 null
* 失败响应:{"error":"xxx"} 或 ['Flag'=>httpCode, 'FlagString'=>body]
* @param string $groupId 群组ID
* @param string $msgTid 消息唯一标识(奥点云为 uuid)
* @return Result
*/
public function del($groupId, $msgTid)
{
$response = $this->dms->delMsg($groupId, $msgTid);
// 成功:HTTP 204 空内容,json_decode 返回 nullcurl 失败时 Dms 会构造 ['Flag'=>0, ...] 数组
if ($response === null || (is_array($response) && empty($response))) {
return Result::success([], $response);
}
$error = $this->extractError($response, '删除失败');
return Result::fail($error, $response);
}
/**
* 获取群组在线用户
* 奥点云 DMS 成功响应:{"list":[...], "total":N}
* 失败响应:{"error":"xxx"} 或 ['Flag'=>httpCode, 'FlagString'=>body]
* @param string $groupId 群组ID
* @param int $pageSize 每页数量(奥点云作为 num)
* @param int $nextPageToken 起始偏移量(奥点云作为 skip)
* @return Result data 含 total、list、next_page_token、has_more
*/
public function getOnlineUser($groupId, $pageSize = 50, $nextPageToken = 0)
{
$skip = (int)$nextPageToken;
$num = (int)$pageSize;
$response = $this->dms->getOnlineUser($groupId, $skip, $num);
// 成功:响应中含 total 字段
if (is_array($response) && isset($response['total'])) {
$total = (int)$response['total'];
$list = isset($response['list']) ? $response['list'] : [];
return Result::success([
'total' => $total,
'list' => $list,
'next_page_token' => 0,
'has_more' => false,
], $response);
}
$error = $this->extractError($response, '获取在线用户失败');
return Result::fail($error, $response);
}
/**
* 从奥点云 Dms 响应中提取错误信息
* 优先取官方文档的 error 字段,其次取 Dms::curl 兜底的 FlagString 字段
* @param mixed $response
* @param string $default 默认错误文案
* @return string
*/
protected function extractError($response, $default = '操作失败')
{
if (!is_array($response)) {
return $default;
}
if (isset($response['error']) && $response['error'] !== '') {
return $response['error'];
}
if (isset($response['FlagString']) && $response['FlagString'] !== '') {
return $response['FlagString'];
}
return $default;
}
/**
* 获取客户端登录鉴权信息(奥点云不需要 token 鉴权,返回空数据)
* @param string $userId 用户ID
* @param string $role 角色
* @return Result
*/
public function getLoginAuth($userId, $role = '')
{
return Result::success([], null);
}
/**
* 创建群组(奥点云无需创建群组,直接返回成功)
* @param string $groupId 群组ID
* @param string $groupName 群组名称
* @param string $groupMeta 群组扩展信息
* @return Result
*/
public function createGroup($groupId, $groupName = '', $groupMeta = '')
{
return Result::success([], null);
}
/**
* 删除群组(奥点云无需删除群组,直接返回成功)
* @param string $groupId 群组ID
* @param string $operatorId 操作者ID
* @return Result
*/
public function deleteGroup($groupId, $operatorId = '')
{
return Result::success([], null);
}
}