edit
This commit is contained in:
@@ -14,8 +14,7 @@ class CommonPhraseController extends ApiController
|
||||
*/
|
||||
public function index(Request $request): Response
|
||||
{
|
||||
$uid = $request->get('uid');
|
||||
return $this->success(Db::name('chat_common_phrase')->where('user_id', $uid)
|
||||
return $this->success(Db::name('chat_common_phrase')->where('user_id', $this->uid)
|
||||
->order('sort', 'desc')
|
||||
->field(['id', 'content', 'sort', 'created_time'])
|
||||
->select());
|
||||
@@ -26,19 +25,18 @@ class CommonPhraseController extends ApiController
|
||||
*/
|
||||
public function store(Request $request): Response
|
||||
{
|
||||
$uid = $request->post('uid');
|
||||
$content = $request->post('content', '');
|
||||
$sort = $request->post('sort', 0);
|
||||
if (empty($content) || mb_strlen($content) > 500) {
|
||||
return $this->error('常用语内容不能为空且长度≤500字');
|
||||
}
|
||||
// 有重复的内容不给添加
|
||||
$msg = Db::name('chat_common_phrase')->where(['user_id' => $uid, 'content' => $content])->find();
|
||||
$msg = Db::name('chat_common_phrase')->where(['user_id' => $this->uid, 'content' => $content])->find();
|
||||
if($msg) {
|
||||
return $this->error('此内容已经存在,不能重复添加');
|
||||
}
|
||||
$res = Db::name('chat_common_phrase')->insert([
|
||||
'user_id' => $uid,
|
||||
'user_id' => $this->uid,
|
||||
'content' => $content,
|
||||
'sort' => $sort,
|
||||
'created_time' => d(),
|
||||
@@ -53,15 +51,24 @@ class CommonPhraseController extends ApiController
|
||||
/**
|
||||
* 删除常用语
|
||||
*/
|
||||
public function destroy(Request $request, int $id): Response
|
||||
public function destroy(Request $request): Response
|
||||
{
|
||||
$uid = $request->uid;
|
||||
$phrase = ChatCommonPhrase::where(['id' => $id, 'user_id' => $uid])->find();
|
||||
$id = $request->post('id');
|
||||
$phrase = Db::name('chat_common_phrase')->where([
|
||||
'user_id' => $this->uid,
|
||||
'id' => $id,
|
||||
])->find();
|
||||
if (!$phrase) {
|
||||
return json(['code' => 404, 'msg' => '常用语不存在']);
|
||||
return $this->error('常用语不存在');
|
||||
}
|
||||
$phrase_del = Db::name('chat_common_phrase')->where([
|
||||
'user_id' => $this->uid,
|
||||
'id' => $id,
|
||||
])->delete();
|
||||
if($phrase_del) {
|
||||
return $this->success();
|
||||
}else {
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
$phrase->delete();
|
||||
return json(['code' => 200, 'msg' => '删除成功']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,60 +5,64 @@ use app\chat\model\ChatGroup;
|
||||
use app\chat\model\ChatGroupMember;
|
||||
use app\chat\model\ChatGroupMute;
|
||||
use app\chat\model\ChatDoNotDisturb;
|
||||
use app\common\controller\ApiController;
|
||||
use app\utils\Session;
|
||||
use support\Request;
|
||||
use support\Response;
|
||||
use support\think\Db;
|
||||
|
||||
class GroupController
|
||||
class GroupController extends ApiController
|
||||
{
|
||||
/**
|
||||
* 创建群(仅商家可创建)
|
||||
*/
|
||||
public function create(Request $request): Response
|
||||
{
|
||||
$uid = $request->uid;
|
||||
$userType = $request->user_type;
|
||||
|
||||
if ($userType != 2) { // 2=商家
|
||||
return json(['code' => 403, 'msg' => '仅商家可创建群聊']);
|
||||
if ($this->user_type == 1) { // 2=商家
|
||||
return $this->error('仅商家可创建群聊');
|
||||
}
|
||||
|
||||
$name = $request->post('name', '');
|
||||
$avatar = $request->post('avatar', '');
|
||||
$shop_id = $request->post('shop_id', 0);
|
||||
if(empty($shop_id)) {
|
||||
return $this->error('参数不完整');
|
||||
}
|
||||
$shop = Db::name('tb_shop_info')->where(['id' => $shop_id])->find();
|
||||
if(empty($shop)) {
|
||||
return $this->error('店铺不存在');
|
||||
}
|
||||
// 查找群数量
|
||||
$count = Db::name('chat_group')->where(['shop_id' => $shop_id])->count();
|
||||
$name = $request->post('name')?:$shop['shop_name'] . '粉丝福利' . $count + 1 . '群';
|
||||
$avatar = $request->post('avatar')?:$shop['logo'];
|
||||
$announcement = $request->post('announcement', '');
|
||||
$isPublic = $request->post('is_public', 0);
|
||||
|
||||
if (empty($name)) {
|
||||
return json(['code' => 400, 'msg' => '群名称不能为空']);
|
||||
}
|
||||
|
||||
$now = time();
|
||||
$now = d();
|
||||
try {
|
||||
Db::startTrans();
|
||||
// 创建群
|
||||
$group = ChatGroup::create([
|
||||
$group_id = Db::name('chat_group')->insertGetId([
|
||||
'name' => $name,
|
||||
'shop_id' => $shop_id,
|
||||
'avatar' => $avatar,
|
||||
'owner_id' => $uid,
|
||||
'owner_id' => $this->uid,
|
||||
'announcement' => $announcement,
|
||||
'is_public' => $isPublic,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now
|
||||
'created_time' => $now,
|
||||
]);
|
||||
|
||||
// 群主加入群
|
||||
ChatGroupMember::create([
|
||||
'group_id' => $group->id,
|
||||
'user_id' => $uid,
|
||||
Db::name('chat_group_member')->insert([
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $this->uid,
|
||||
'role' => 1, // 1=群主
|
||||
'join_time' => $now,
|
||||
'quit_time' => null,
|
||||
'is_kicked' => 0
|
||||
]);
|
||||
Db::commit();
|
||||
return $this->success(['group_id' => $group_id]);
|
||||
}catch (\Throwable $exception) {
|
||||
Db::rollback();
|
||||
return $this->error($exception->getMessage());
|
||||
}
|
||||
|
||||
|
||||
return json([
|
||||
'code' => 200,
|
||||
'msg' => '群创建成功',
|
||||
'data' => ['group_id' => $group->id]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,92 +70,129 @@ class GroupController
|
||||
*/
|
||||
public function join(Request $request): Response
|
||||
{
|
||||
$uid = $request->uid;
|
||||
$groupId = $request->post('group_id', 0);
|
||||
|
||||
if (!$groupId) {
|
||||
return json(['code' => 400, 'msg' => '缺少group_id']);
|
||||
$group_id = $request->post('group_id');
|
||||
$invite = $request->post('invite');
|
||||
if (!$group_id) {
|
||||
return $this->error('缺少group_id');
|
||||
}
|
||||
|
||||
// 验证群是否存在
|
||||
$group = ChatGroup::find($groupId);
|
||||
$group = Db::name('chat_group')->where(['id' => $group_id])->find();
|
||||
if (!$group) {
|
||||
return json(['code' => 404, 'msg' => '群不存在']);
|
||||
return $this->error('群不存在');
|
||||
}
|
||||
|
||||
// 验证是否已在群内
|
||||
$exists = ChatGroupMember::where([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $uid,
|
||||
$exists = Db::name('chat_group_member')->where([
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $this->uid,
|
||||
'quit_time' => null,
|
||||
'is_kicked' => 0
|
||||
])->exists();
|
||||
])->find();
|
||||
|
||||
if ($exists) {
|
||||
return json(['code' => 400, 'msg' => '已在群内']);
|
||||
return $this->error('已在群内');
|
||||
}
|
||||
|
||||
// 被踢用户不能重新加入(需群主邀请)
|
||||
$isKicked = ChatGroupMember::where([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $uid,
|
||||
$isKicked = Db::name('chat_group_member')->where([
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $this->uid,
|
||||
'is_kicked' => 1
|
||||
])->exists();
|
||||
if ($isKicked) {
|
||||
return json(['code' => 403, 'msg' => '你已被移出该群,无法重新加入']);
|
||||
])->find();
|
||||
|
||||
// 如果不是邀请
|
||||
if(empty($invite) && $isKicked) {
|
||||
return $this->error('你已被移出该群,无法重新加入');
|
||||
}
|
||||
$insert_arr = [
|
||||
'group_id' => $group_id,
|
||||
'user_id' => $this->uid,
|
||||
'role' => 3,
|
||||
'join_time' => d(),
|
||||
];
|
||||
$is_insert = true;
|
||||
if($invite) {
|
||||
// 验证邀请参数是否正常
|
||||
$decryptedText = simple_decrypt($invite, config('cons.sercer_key'));
|
||||
$decryptedText_arr = json_decode($decryptedText, true);
|
||||
if($isKicked) {
|
||||
$is_insert = false;
|
||||
$insert_arr['is_kicked'] = 0;
|
||||
}
|
||||
$insert_arr['pid'] = $decryptedText_arr['pid'];
|
||||
$insert_arr['group_id'] = $decryptedText_arr['group_id'];
|
||||
$group_id = $decryptedText_arr['group_id'];
|
||||
}
|
||||
|
||||
// 加入群
|
||||
ChatGroupMember::create([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $uid,
|
||||
'role' => 3, // 3=普通成员
|
||||
'join_time' => time(),
|
||||
'quit_time' => null,
|
||||
'is_kicked' => 0
|
||||
]);
|
||||
|
||||
return json(['code' => 200, 'msg' => '加群成功']);
|
||||
if($is_insert) {
|
||||
$res = Db::name('chat_group_member')->insert($insert_arr);
|
||||
}else {
|
||||
$res = Db::name('chat_group_member')->where(['user_id' => $this->uid, 'group_id' => $group_id])->update($insert_arr);
|
||||
}
|
||||
if($res) {
|
||||
return $this->success();
|
||||
}else {
|
||||
return $this->error();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取群邀请链接参数
|
||||
public function getgrepurl(Request $request): Response
|
||||
{
|
||||
$group_id = $request->post('group_id');
|
||||
if (!$group_id) {
|
||||
return $this->error('缺少group_id');
|
||||
}
|
||||
if($this->user_type == 1) {
|
||||
return $this->error('角色有误');
|
||||
}
|
||||
$data = [
|
||||
'pid' => $this->uid,
|
||||
'group_id' => $group_id
|
||||
];
|
||||
return $this->success(simple_encrypt(json_encode($data), config('cons.sercer_key')));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 退群
|
||||
*/
|
||||
public function quit(Request $request): Response
|
||||
{
|
||||
$uid = $request->uid;
|
||||
$groupId = $request->post('group_id', 0);
|
||||
|
||||
$groupId = $request->post('group_id')?:0;
|
||||
if (!$groupId) {
|
||||
return json(['code' => 400, 'msg' => '缺少group_id']);
|
||||
return $this->error('缺少group_id');
|
||||
}
|
||||
|
||||
// 验证是否是群主(群主不能退群,需转让)
|
||||
$isOwner = ChatGroupMember::where([
|
||||
$owner = Db::name('chat_group_member')->where([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $uid,
|
||||
'role' => 1,
|
||||
'user_id' => $this->uid,
|
||||
'quit_time' => null
|
||||
])->exists();
|
||||
if ($isOwner) {
|
||||
return json(['code' => 403, 'msg' => '群主不能退群,请先转让群主']);
|
||||
}
|
||||
|
||||
// 标记退出时间
|
||||
$member = ChatGroupMember::where([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $uid,
|
||||
'quit_time' => null,
|
||||
'is_kicked' => 0
|
||||
])->find();
|
||||
if (!$member) {
|
||||
return json(['code' => 400, 'msg' => '不在群内']);
|
||||
if ($owner) {
|
||||
if($owner['role'] == 1) {
|
||||
return $this->error('群主不能退群,请先转让群');
|
||||
}
|
||||
}else {
|
||||
return $this->error('不在群内');
|
||||
}
|
||||
$res = Db::name('chat_group_member')->where([
|
||||
'group_id' => $groupId,
|
||||
'user_id' => $this->uid,
|
||||
])->update(['quit_time' => d()]);
|
||||
if($res) {
|
||||
return $this->success();
|
||||
}
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
$member->quit_time = time();
|
||||
$member->save();
|
||||
|
||||
return json(['code' => 200, 'msg' => '退群成功']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 设置群公告(仅群主/管理员)
|
||||
|
||||
@@ -5,6 +5,14 @@ use app\exception\MyBusinessException;
|
||||
use support\exception\BusinessException;
|
||||
class ApiController
|
||||
{
|
||||
public $uid;
|
||||
public $user_type;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->uid = input('uid');
|
||||
$this->user_type = input('user_type');
|
||||
}
|
||||
|
||||
public function success($data = [])
|
||||
{
|
||||
|
||||
@@ -44,6 +44,114 @@ if (!function_exists('d')) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 加密函数(带随机字符,AES-256-CBC)
|
||||
* @param string $plaintext 待加密明文(如字符串、数字)
|
||||
* @param string $key 加密密钥(建议至少 8 位,越复杂越安全)
|
||||
* @return string|false 加密后的密文(失败返回 false)
|
||||
*/
|
||||
function simple_encrypt(string $plaintext, string $key): string|false
|
||||
{
|
||||
try {
|
||||
// 1. 生成随机字符(Salt + IV)
|
||||
$salt = random_bytes(8); // 8 位随机盐值(增加密钥多样性)
|
||||
$iv = random_bytes(16); // 16 位随机 IV(AES-256-CBC 块大小要求)
|
||||
|
||||
// 2. 密钥处理:Salt + 原始密钥 → SHA256 哈希 → 32 位密钥(AES-256 要求)
|
||||
$encryptedKey = hash('sha256', $salt . $key, true); // true 表示返回二进制数据
|
||||
|
||||
// 3. 明文填充:PKCS7 填充(AES 要求明文长度是块大小的整数倍)
|
||||
$blockSize = openssl_cipher_iv_length('aes-256-cbc');
|
||||
$padding = $blockSize - (strlen($plaintext) % $blockSize);
|
||||
$paddedPlaintext = $plaintext . str_repeat(chr($padding), $padding);
|
||||
|
||||
// 4. AES 加密(返回 Base64 编码的密文)
|
||||
$ciphertext = openssl_encrypt(
|
||||
$paddedPlaintext,
|
||||
'aes-256-cbc',
|
||||
$encryptedKey,
|
||||
OPENSSL_RAW_DATA, // 输出原始二进制数据(后续手动 Base64)
|
||||
$iv
|
||||
);
|
||||
|
||||
if ($ciphertext === false) {
|
||||
throw new Exception('加密失败:' . openssl_error_string());
|
||||
}
|
||||
|
||||
// 5. 拼接 Salt + IV + 密文(Base64 编码后用冒号分隔,避免字符冲突)
|
||||
return base64_encode($salt) . ':' . base64_encode($iv) . ':' . base64_encode($ciphertext);
|
||||
} catch (Exception $e) {
|
||||
error_log('加密异常:' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密函数(对应 simple_encrypt)
|
||||
* @param string $ciphertext 加密后的密文
|
||||
* @param string $key 解密密钥(必须与加密密钥一致)
|
||||
* @return string|false 解密后的明文(失败返回 false)
|
||||
*/
|
||||
function simple_decrypt(string $ciphertext, string $key): string|false
|
||||
{
|
||||
try {
|
||||
// 1. 拆分密文:Salt:IV:密文(按冒号分割)
|
||||
$parts = explode(':', $ciphertext);
|
||||
if (count($parts) !== 3) {
|
||||
throw new Exception('密文格式错误');
|
||||
}
|
||||
|
||||
// 2. Base64 解码,获取原始 Salt、IV、密文
|
||||
$salt = base64_decode($parts[0]);
|
||||
$iv = base64_decode($parts[1]);
|
||||
$ciphertextRaw = base64_decode($parts[2]);
|
||||
|
||||
if ($salt === false || $iv === false || $ciphertextRaw === false) {
|
||||
throw new Exception('Base64 解码失败');
|
||||
}
|
||||
|
||||
// 3. 密钥处理(与加密时一致)
|
||||
$encryptedKey = hash('sha256', $salt . $key, true);
|
||||
|
||||
// 4. AES 解密
|
||||
$paddedPlaintext = openssl_decrypt(
|
||||
$ciphertextRaw,
|
||||
'aes-256-cbc',
|
||||
$encryptedKey,
|
||||
OPENSSL_RAW_DATA,
|
||||
$iv
|
||||
);
|
||||
|
||||
if ($paddedPlaintext === false) {
|
||||
throw new Exception('解密失败:' . openssl_error_string());
|
||||
}
|
||||
|
||||
// 5. 去除 PKCS7 填充
|
||||
$padding = ord(substr($paddedPlaintext, -1));
|
||||
$plaintext = substr($paddedPlaintext, 0, -$padding);
|
||||
|
||||
return $plaintext;
|
||||
} catch (Exception $e) {
|
||||
error_log('解密异常:' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 多维数组去重并重新索引
|
||||
* @param array $array 待处理的多维数组
|
||||
|
||||
@@ -15,14 +15,18 @@ class JwtAuthMiddleware implements MiddlewareInterface
|
||||
{
|
||||
$uid = Redis::get('token:client:token:' . $request->header('token'));
|
||||
if($uid) {
|
||||
if($request->isGet()) {
|
||||
$request->setGet('uid', $uid);
|
||||
}elseif ($request->post()) {
|
||||
$request->setPost('uid', $uid);
|
||||
}
|
||||
}else {
|
||||
// 用户
|
||||
$user_type = 1;
|
||||
}else{
|
||||
$uid = Redis::get('token:admin:token:' . $request->header('token'));
|
||||
if(!$uid) {
|
||||
throw new MyBusinessException('请登录', 3000);
|
||||
}
|
||||
// 商家
|
||||
$user_type = 2;
|
||||
}
|
||||
$request->setPost('uid', $uid);
|
||||
$request->setPost('user_type', $user_type);
|
||||
return $handler($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,5 +19,6 @@ return [
|
||||
'user' => 'chaozg',
|
||||
'password' => 'chaozg123',
|
||||
'queue_t' => 'dev',
|
||||
]
|
||||
],
|
||||
'sercer_key' => 'JVt1ZT5gwRqHR8pR7cX6DFvf8BxgKugB'
|
||||
];
|
||||
|
||||
@@ -20,31 +20,32 @@ Route::group('/api/chat', function () {
|
||||
$jwt_middleware = app\middleware\JwtAuthMiddleware::class;
|
||||
// 常用语管理
|
||||
Route::group('/common-phrase', function () {
|
||||
Route::get('', app\chat\controller\CommonPhraseController::class . '@index'); // 列表
|
||||
Route::post('', app\chat\controller\CommonPhraseController::class . '@index'); // 列表
|
||||
Route::post('/add', app\chat\controller\CommonPhraseController::class . '@store'); // 添加
|
||||
Route::post('/del/{id}', app\chat\controller\CommonPhraseController::class . '@destroy'); // 删除
|
||||
Route::post('/del', app\chat\controller\CommonPhraseController::class . '@destroy'); // 删除
|
||||
})->middleware($jwt_middleware);
|
||||
|
||||
// 群聊管理
|
||||
Route::group('/group', function () {
|
||||
Route::post('/create', app\chat\controller\GroupController::class . '@create'); // 创建群(商家)
|
||||
Route::post('/join', app\chat\controller\GroupController::class . '@join'); // 加群
|
||||
Route::post('/getgrepurl', app\chat\controller\GroupController::class . '@getgrepurl'); // 群邀请参数
|
||||
Route::post('/quit', app\chat\controller\GroupController::class . '@quit'); // 退群
|
||||
Route::post('/announcement', app\chat\controller\GroupController::class . '@setAnnouncement'); // 群公告
|
||||
Route::post('/do-not-disturb', app\chat\controller\GroupController::class . '@setDoNotDisturb'); // 免打扰
|
||||
Route::post('/mute', app\chat\controller\GroupController::class . '@muteMember'); // 禁言
|
||||
Route::post('/unmute', app\chat\controller\GroupController::class . '@unmuteMember'); // 解除禁言
|
||||
Route::post('/kick', app\chat\controller\GroupController::class . '@kickMember'); // 踢人
|
||||
Route::get('/members', app\chat\controller\GroupController::class . '@getMembers'); // 群成员列表
|
||||
Route::post('/members', app\chat\controller\GroupController::class . '@getMembers'); // 群成员列表
|
||||
})->middleware($jwt_middleware);
|
||||
|
||||
// 消息管理
|
||||
Route::group('/message', function () {
|
||||
Route::get('/history', app\chat\controller\MessageController::class . '@history'); // 历史消息
|
||||
Route::post('/history', app\chat\controller\MessageController::class . '@history'); // 历史消息
|
||||
Route::post('/mark-read', app\chat\controller\MessageController::class . '@markRead'); // 标记已读
|
||||
Route::post('/mark-read-all', app\chat\controller\MessageController::class . '@markReadAll'); // 全部已读
|
||||
Route::get('/unread-count', app\chat\controller\MessageController::class . '@getUnreadCount'); // 未读总数
|
||||
Route::get('/session-list', app\chat\controller\MessageController::class . '@getSessionList'); // 会话列表
|
||||
Route::post('/unread-count', app\chat\controller\MessageController::class . '@getUnreadCount'); // 未读总数
|
||||
Route::post('/session-list', app\chat\controller\MessageController::class . '@getSessionList'); // 会话列表
|
||||
})->middleware($jwt_middleware);
|
||||
|
||||
// 图片上传(相册/拍照)
|
||||
|
||||
Reference in New Issue
Block a user