1.没置顶的消息,到最上面去了 2.无法转发图片 3.用户ID 是一串字母+数字 4.视频无法显示 5.消息无法置顶 6.可以引用文字,无法艾特用户 7.图片点开只能显示一半 8.转发不能多选,只能一个个转发 9.转发有转发提示,需取消

This commit is contained in:
annali168290-ux
2026-10-11 00:26:07 +07:00
parent cf66f936e5
commit 1cabf661ca
29 changed files with 3906 additions and 1579 deletions
+112 -28
View File
@@ -8,8 +8,9 @@ require __DIR__ . '/im_web_bootstrap.php';
const WEB_MEDIA_ROOT = '/opt/im-server/media';
const WEB_MEDIA_PUBLIC_PORT = 18000;
const WEB_MEDIA_TYPE_IMAGE = 1;
const WEB_MEDIA_TYPE_FILE = 4;
const WEB_MEDIA_TYPE_IMAGE = 1;
const WEB_MEDIA_TYPE_VIDEO = 3;
const WEB_MEDIA_TYPE_FILE = 4;
const WEB_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
const WEB_FILE_MAX_BYTES = 50 * 1024 * 1024;
@@ -245,13 +246,32 @@ function storeMessageAttachment(
]);
}
function attachmentFromRequest(string $messageType): ?array
{
if (!in_array($messageType, ['image', 'file'], true)) {
return null;
}
$attachmentFile = $_FILES['attachment'] ?? $_FILES['file'] ?? null;
function attachmentFromRequest(string $messageType): ?array
{
if (!in_array($messageType, ['image', 'video', 'file'], true)) {
return null;
}
$forwardUrl = trim((string)($_POST['attachmentUrl'] ?? ''));
if ($forwardUrl !== '') {
$parts = parse_url($forwardUrl);
$scheme = strtolower((string)($parts['scheme'] ?? ''));
if (!in_array($scheme, ['http', 'https'], true) || empty($parts['host']) || strlen($forwardUrl) > 2048) {
respond(400, '媒体地址不合法');
}
$mime = trim((string)($_POST['attachmentMime'] ?? 'application/octet-stream'));
$name = safeUploadName((string)($_POST['attachmentName'] ?? ($messageType === 'image' ? '图片' : ($messageType === 'video' ? '视频.mp4' : '文件'))));
return [
'type' => $messageType,
'url' => $forwardUrl,
'name' => $name,
'mime' => $mime,
'size' => max(0, (int)($_POST['attachmentSize'] ?? 0)),
'mediaType' => $messageType === 'image' ? WEB_MEDIA_TYPE_IMAGE : ($messageType === 'video' ? WEB_MEDIA_TYPE_VIDEO : WEB_MEDIA_TYPE_FILE),
];
}
$attachmentFile = $_FILES['attachment'] ?? $_FILES['file'] ?? null;
if (!is_array($attachmentFile)) {
respond(400, '缺少上传文件');
}
@@ -266,11 +286,15 @@ $sender = messageRequestValue($payload, 'sender');
$target = messageRequestValue($payload, 'target');
$text = messageRequestValue($payload, 'text');
$messageType = messageRequestValue($payload, 'messageType', 'text');
$conversationType = $_POST['conversationType'] ?? $_POST['type'] ?? $payload['conversationType'] ?? $payload['type'] ?? 0;
$isGroupConversation = in_array((string)$conversationType, ['1', 'group', 'channel'], true);
$conversationType = $_POST['conversationType'] ?? $_POST['type'] ?? $payload['conversationType'] ?? $payload['type'] ?? 0;
$isGroupConversation = in_array((string)$conversationType, ['1', 'group', 'channel'], true);
$mentionedUserIds = $payload['mentionedUserIds'] ?? [];
$mentionedUserIds = is_array($mentionedUserIds)
? array_values(array_unique(array_filter(array_map(static fn($value): string => trim((string)$value), $mentionedUserIds))))
: [];
$attachment = null;
if ($sender === '' || $target === '' || ($text === '' && !in_array($messageType, ['image', 'file'], true))) {
if ($sender === '' || $target === '' || ($text === '' && !in_array($messageType, ['image', 'video', 'file'], true))) {
respond(400, '缺少发送者、接收者或消息内容');
}
@@ -285,11 +309,69 @@ try {
. ' where g.`deleted` = 0 and g.`group_id` = ? and m.`user_id` = ?'
. ' limit 1'
);
$memberStatement->execute([$target, $sender]);
$group = $memberStatement->fetch();
if (!$group) {
respond(403, '你不在该群组中');
}
$memberStatement->execute([$target, $sender]);
$group = $memberStatement->fetch();
if (!$group) {
// 手机端创建的原生群不一定存在于 Web 自建群表中,需回退检查 IM 群成员表。
$imDb = imDb();
$nativeGroupStatement = $imDb->prepare(
'select 1 from `t_group` where `_gid` = ? and `_deleted` = 0 limit 1'
);
$nativeGroupStatement->execute([$target]);
$nativeMemberStatement = $imDb->prepare(
'select `_type` from `t_group_member` where `_gid` = ? and `_mid` = ? limit 1'
);
$nativeMemberStatement->execute([$target, $sender]);
$nativeMemberType = $nativeMemberStatement->fetchColumn();
if (!$nativeGroupStatement->fetchColumn() || $nativeMemberType === false) {
respond(403, '你不在该群组中');
}
$attachment = attachmentFromRequest($messageType);
$pushContent = $text !== ''
? $text
: ($attachment
? ((string)$attachment['type'] === 'image' ? '[图片]' : ((string)$attachment['type'] === 'video' ? '[视频]' : '[文件] ' . (string)$attachment['name']))
: $text);
$payloadBody = [
'type' => $attachment ? ((string)$attachment['type'] === 'image' ? 3 : ((string)$attachment['type'] === 'video' ? 6 : 5)) : 1,
'searchableContent' => $pushContent,
'pushContent' => $pushContent,
'content' => $text,
'persistFlag' => 3,
];
if ($mentionedUserIds) {
$payloadBody['mentionedType'] = 1;
$payloadBody['mentionedTarget'] = $mentionedUserIds;
}
if ($attachment) {
$payloadBody['mediaType'] = (int)$attachment['mediaType'];
$payloadBody['remoteMediaUrl'] = (string)$attachment['url'];
$payloadBody['extra'] = json_encode([
'name' => (string)$attachment['name'],
'mime' => (string)$attachment['mime'],
'size' => (int)$attachment['size'],
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
$nativeResult = requireImSuccess(imAdminPost('/admin/message/send', [
'sender' => $sender,
'conv' => ['type' => 1, 'target' => $target, 'line' => 0],
'payload' => $payloadBody,
]), '原生群消息发送失败');
$messageUid = isset($nativeResult['messageUid']) ? (string)$nativeResult['messageUid'] : '';
$timestamp = (int)($nativeResult['timestamp'] ?? webImNowMs());
if ($attachment && $messageUid !== '') {
storeMessageAttachment($appDb, $messageUid, 'group', $target, $sender, $attachment, $timestamp);
}
$role = (int)$nativeMemberType === 2 ? 'owner' : ((int)$nativeMemberType === 1 ? 'admin' : 'member');
respond(0, 'success', [
'messageUid' => $messageUid,
'timestamp' => $timestamp,
'senderRole' => $role,
'attachment' => $attachment,
'nativeError' => '',
]);
}
$category = (string)($group['category'] ?? 'group');
$role = (string)($group['role'] ?? 'member');
if ($category === 'channel' && !in_array($role, ['owner', 'admin'], true)) {
@@ -319,15 +401,19 @@ try {
$pushContent = $text !== ''
? $text
: ($attachment
? ((string)$attachment['type'] === 'image' ? '[图片]' : '[文件] ' . (string)$attachment['name'])
? ((string)$attachment['type'] === 'image' ? '[图片]' : ((string)$attachment['type'] === 'video' ? '[视频]' : '[文件] ' . (string)$attachment['name']))
: $text);
$payloadBody = [
'type' => $attachment ? ((string)$attachment['type'] === 'image' ? 3 : 5) : 1,
$payloadBody = [
'type' => $attachment ? ((string)$attachment['type'] === 'image' ? 3 : ((string)$attachment['type'] === 'video' ? 6 : 5)) : 1,
'searchableContent' => $pushContent,
'pushContent' => $pushContent,
'content' => $text,
'persistFlag' => 3,
];
'persistFlag' => 3,
];
if ($mentionedUserIds) {
$payloadBody['mentionedType'] = 1;
$payloadBody['mentionedTarget'] = $mentionedUserIds;
}
if ($attachment) {
$payloadBody['mediaType'] = (int)$attachment['mediaType'];
$payloadBody['remoteMediaUrl'] = (string)$attachment['url'];
@@ -344,8 +430,7 @@ try {
'target' => $target,
'line' => 0,
],
'payload' => $payloadBody,
'userMessage' => true,
'payload' => $payloadBody,
]), '原生群消息发送失败');
} catch (Throwable $error) {
$nativeError = $error->getMessage() ?: '原生群消息发送失败';
@@ -364,10 +449,10 @@ try {
$pushContent = $text !== ''
? $text
: ($attachment
? ((string)$attachment['type'] === 'image' ? '[图片]' : '[文件] ' . (string)$attachment['name'])
? ((string)$attachment['type'] === 'image' ? '[图片]' : ((string)$attachment['type'] === 'video' ? '[视频]' : '[文件] ' . (string)$attachment['name']))
: $text);
$payloadBody = [
'type' => $attachment ? ((string)$attachment['type'] === 'image' ? 3 : 5) : 1,
'type' => $attachment ? ((string)$attachment['type'] === 'image' ? 3 : ((string)$attachment['type'] === 'video' ? 6 : 5)) : 1,
'searchableContent' => $pushContent,
'pushContent' => $pushContent,
'content' => $text,
@@ -390,8 +475,7 @@ try {
'target' => $target,
'line' => 0,
],
'payload' => $payloadBody,
'userMessage' => true,
'payload' => $payloadBody,
]), '发送失败');
$messageUid = isset($result['messageUid']) ? (string)$result['messageUid'] : '';