perf: 聊天使用~符号分享文件

This commit is contained in:
kuaifan 2022-11-22 17:40:25 +08:00
parent ab24ca5b4f
commit 5c25bdfa91
6 changed files with 113 additions and 30 deletions

View File

@ -171,15 +171,15 @@ class FileController extends AbstractController
$user = User::auth(); $user = User::auth();
// //
$key = trim(Request::input('key')); $key = trim(Request::input('key'));
if (empty($key)) {
return Base::retError('请输入关键词');
}
// 搜索自己的 // 搜索自己的
$builder = File::whereUserid($user->userid)->where("name", "like", "%{$key}%"); $builder = File::whereUserid($user->userid);
if ($key) {
$builder->where("name", "like", "%{$key}%");
}
$array = $builder->take(50)->get()->toArray(); $array = $builder->take(50)->get()->toArray();
// 搜索共享的 // 搜索共享的
$take = 50 - count($array); $take = 50 - count($array);
if ($take > 0) { if ($take > 0 && $key) {
$list = File::where("name", "like", "%{$key}%") $list = File::where("name", "like", "%{$key}%")
->whereIn('pshare', function ($queryA) use ($user) { ->whereIn('pshare', function ($queryA) use ($user) {
$queryA->select('files.id') $queryA->select('files.id')
@ -1102,24 +1102,7 @@ class FileController extends AbstractController
return Base::retError('文件夹暂不支持此功能'); return Base::retError('文件夹暂不支持此功能');
} }
// //
$fileLink = FileLink::whereFileId($file->id)->whereUserid($user->userid)->first(); $data = FileLink::generateLink($file->id, $user->userid, $refresh == 'yes');
if (empty($fileLink)) { return Base::retSuccess('success', $data);
$fileLink = FileLink::createInstance([
'file_id' => $file->id,
'userid' => $user->userid,
'code' => Base::generatePassword(64),
]);
$fileLink->save();
} else {
if ($refresh == 'yes') {
$fileLink->code = Base::generatePassword(64);
$fileLink->save();
}
}
return Base::retSuccess('success', [
'id' => $file->id,
'url' => Base::fillUrl('single/file/' . $fileLink->code),
'num' => $fileLink->num
]);
} }
} }

View File

@ -2,6 +2,8 @@
namespace App\Models; namespace App\Models;
use App\Module\Base;
/** /**
* App\Models\FileLink * App\Models\FileLink
* *
@ -34,4 +36,35 @@ class FileLink extends AbstractModel
{ {
return $this->hasOne(File::class, 'id', 'file_id'); return $this->hasOne(File::class, 'id', 'file_id');
} }
/**
* 生成链接
* @param $fileId
* @param $userid
* @param $refresh
* @return array
*/
public static function generateLink($fileId, $userid, $refresh = false)
{
$fileLink = FileLink::whereFileId($fileId)->whereUserid($userid)->first();
if (empty($fileLink)) {
$fileLink = FileLink::createInstance([
'file_id' => $fileId,
'userid' => $userid,
'code' => Base::generatePassword(64),
]);
$fileLink->save();
} else {
if ($refresh == 'yes') {
$fileLink->code = Base::generatePassword(64);
$fileLink->save();
}
}
return [
'id' => $fileId,
'url' => Base::fillUrl('single/file/' . $fileLink->code),
'code' => $fileLink->code,
'num' => $fileLink->num
];
}
} }

View File

@ -644,15 +644,47 @@ class WebSocketDialogMsg extends AbstractModel
} }
} }
} }
// @成员、#任务 // @成员、#任务、~文件
preg_match_all("/<span\s+class=\"mention\"(.*?)>.*?<\/span>.*?<\/span>.*?<\/span>/s", $text, $matchs); preg_match_all("/<span\s+class=\"mention\"(.*?)>.*?<\/span>.*?<\/span>.*?<\/span>/s", $text, $matchs);
foreach ($matchs[1] as $key => $str) { foreach ($matchs[1] as $key => $str) {
preg_match("/data-denotation-char=\"(.*?)\"/", $str, $matchChar); preg_match("/data-denotation-char=\"(.*?)\"/", $str, $matchChar);
preg_match("/data-id=\"(.*?)\"/", $str, $matchId); preg_match("/data-id=\"(.*?)\"/", $str, $matchId);
preg_match("/data-value=\"(.*?)\"/", $str, $matchValye); preg_match("/data-value=\"(.*?)\"/", $str, $matchValye);
$text = str_replace($matchs[0][$key], "[:{$matchChar[1]}:{$matchId[1]}:{$matchValye[1]}:]", $text); $keyId = $matchId[1];
if ($matchChar[1] === "~") {
if (Base::isNumber($keyId)) {
$file = File::permissionFind($keyId);
if ($file->type == 'folder') {
throw new ApiException('文件夹不支持分享');
} }
// 处理链接 $fileLink = FileLink::generateLink($file->id, User::userid());
$keyId = $fileLink['code'];
} else {
preg_match("/\/single\/file\/(.*?)$/i", $keyId, $match);
if ($match && strlen($match[1]) >= 32) {
$keyId = $match[1];
} else {
throw new ApiException('文件分享错误');
}
}
}
$text = str_replace($matchs[0][$key], "[:{$matchChar[1]}:{$keyId}:{$matchValye[1]}:]", $text);
}
// 文件分享链接
preg_match_all("/(https*:\/\/)((\w|=|\?|\.|\/|&|-|:|\+|%|;|#)+)/i", $text, $matchs);
if ($matchs) {
foreach ($matchs[0] as $str) {
preg_match("/\/single\/file\/(.*?)$/i", $str, $match);
if ($match && strlen($match[1]) >= 32) {
$file = File::select(['files.id', 'files.name', 'files.ext'])->join('file_links as L', 'files.id', '=', 'L.file_id')->where('L.code', $match[1])->first();
if ($file && $file->name) {
$name = $file->ext ? "{$file->name}.{$file->ext}" : $file->name;
$text = str_replace($str, "[:~:{$match[1]}:{$name}:]", $text);
}
}
}
}
// 处理链接标签
preg_match_all("/<a[^>]*?href=([\"'])(.*?)\\1[^>]*?>([^<]*?)<\/a>/is", $text, $matchs); preg_match_all("/<a[^>]*?href=([\"'])(.*?)\\1[^>]*?>([^<]*?)<\/a>/is", $text, $matchs);
foreach ($matchs[2] as $key => $str) { foreach ($matchs[2] as $key => $str) {
$herf = $matchs[2][$key]; $herf = $matchs[2][$key];
@ -665,6 +697,7 @@ class WebSocketDialogMsg extends AbstractModel
$text = preg_replace("/\[:IMAGE:(.*?):(.*?):(.*?):(.*?):(.*?):\]/i", "<img class=\"$1\" width=\"$2\" height=\"$3\" src=\"{{RemoteURL}}$4\" alt=\"$5\"/>", $text); $text = preg_replace("/\[:IMAGE:(.*?):(.*?):(.*?):(.*?):(.*?):\]/i", "<img class=\"$1\" width=\"$2\" height=\"$3\" src=\"{{RemoteURL}}$4\" alt=\"$5\"/>", $text);
$text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "<span class=\"mention user\" data-id=\"$1\">@$2</span>", $text); $text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "<span class=\"mention user\" data-id=\"$1\">@$2</span>", $text);
$text = preg_replace("/\[:#:(.*?):(.*?):\]/i", "<span class=\"mention task\" data-id=\"$1\">#$2</span>", $text); $text = preg_replace("/\[:#:(.*?):(.*?):\]/i", "<span class=\"mention task\" data-id=\"$1\">#$2</span>", $text);
$text = preg_replace("/\[:~:(.*?):(.*?):\]/i", "<a class=\"mention file\" href=\"{{RemoteURL}}single/file/$1\" target=\"_blank\">~$2</a>", $text);
return preg_replace("/^(<p><\/p>)+|(<p><\/p>)+$/i", "", $text); return preg_replace("/^(<p><\/p>)+|(<p><\/p>)+$/i", "", $text);
} }

View File

@ -225,6 +225,7 @@ export default {
userList: null, userList: null,
userCache: null, userCache: null,
taskList: null, taskList: null,
fileList: {},
showMore: false, showMore: false,
showEmoji: false, showEmoji: false,
@ -414,12 +415,14 @@ export default {
this.userList = null; this.userList = null;
this.userCache = null; this.userCache = null;
this.taskList = null; this.taskList = null;
this.fileList = {};
this.$emit('input', this.getInputCache()) this.$emit('input', this.getInputCache())
}, },
taskId() { taskId() {
this.userList = null; this.userList = null;
this.userCache = null; this.userCache = null;
this.taskList = null; this.taskList = null;
this.fileList = {};
this.$emit('input', this.getInputCache()) this.$emit('input', this.getInputCache())
}, },
@ -548,7 +551,7 @@ export default {
}, },
mention: { mention: {
allowedChars: /^\S*$/, allowedChars: /^\S*$/,
mentionDenotationChars: ["@", "#"], mentionDenotationChars: ["@", "#", "~"],
defaultMenuOrientation: this.defaultMenuOrientation, defaultMenuOrientation: this.defaultMenuOrientation,
isolateCharacter: true, isolateCharacter: true,
positioningStrategy: 'fixed', positioningStrategy: 'fixed',
@ -568,11 +571,12 @@ export default {
return "Loading..."; return "Loading...";
}, },
source: (searchTerm, renderList, mentionChar) => { source: (searchTerm, renderList, mentionChar) => {
const mentionName = mentionChar == "@" ? 'user-mention' : 'task-mention'; const mentionName = mentionChar == "@" ? 'user-mention' : (mentionChar == "#" ? 'task-mention' : 'file-mention');
const containers = document.getElementsByClassName("ql-mention-list-container"); const containers = document.getElementsByClassName("ql-mention-list-container");
for (let i = 0; i < containers.length; i++) { for (let i = 0; i < containers.length; i++) {
containers[i].classList.remove("user-mention"); containers[i].classList.remove("user-mention");
containers[i].classList.remove("task-mention"); containers[i].classList.remove("task-mention");
containers[i].classList.remove("file-mention");
containers[i].classList.add(mentionName); containers[i].classList.add(mentionName);
$A.scrollPreventThrough(containers[i]); $A.scrollPreventThrough(containers[i]);
} }
@ -1223,6 +1227,31 @@ export default {
taskCallback([]) taskCallback([])
break; break;
case "~": // ~
this.mentionMode = "file-mention";
if ($A.isArray(this.fileList[searchTerm])) {
resultCallback(this.fileList[searchTerm])
return;
}
this.fileTimer && clearTimeout(this.fileTimer)
this.fileTimer = setTimeout(_ => {
this.$store.dispatch("searchFiles", searchTerm).then(({data}) => {
this.fileList[searchTerm] = [{
label: [{id: 0, value: this.$L('文件分享查看'), disabled: true}],
list: data.filter(item => item.type !== "folder").map(item => {
return {
id: item.id,
value: item.ext ? `${item.name}.${item.ext}` : item.name
}
})
}];
resultCallback(this.fileList[searchTerm])
}).catch(() => {
resultCallback([])
})
}, 300)
break;
default: default:
resultCallback([]) resultCallback([])
break; break;

View File

@ -1867,7 +1867,8 @@ export default {
this.replyActiveUpdate = true this.replyActiveUpdate = true
let {text} = this.operateItem.msg let {text} = this.operateItem.msg
if (text.indexOf("mention") > -1) { if (text.indexOf("mention") > -1) {
text = text.replace(/<span class="mention (.*?)" data-id="(\d+)">([@#])(.*?)<\/span>/g, '<span class="mention" data-denotation-char="$3" data-id="$2" data-value="$4">&#xFEFF;<span contenteditable="false"><span class="ql-mention-denotation-char">$3</span>$4</span>&#xFEFF;</span>') text = text.replace(/<a class="mention file" href="([^'"]*)"([^>]*)>~([^>]*)<\/a>/g, '<span class="mention" data-denotation-char="~" data-id="$1" data-value="$3">&#xFEFF;<span contenteditable="false"><span class="ql-mention-denotation-char">~</span>$3</span>&#xFEFF;</span>')
text = text.replace(/<span class="mention ([^'"]*)" data-id="(\d+)">([@#])([^>]*)<\/span>/g, '<span class="mention" data-denotation-char="$3" data-id="$2" data-value="$4">&#xFEFF;<span contenteditable="false"><span class="ql-mention-denotation-char">$3</span>$4</span>&#xFEFF;</span>')
} }
this.msgText = $A.formatMsgBasic(text) this.msgText = $A.formatMsgBasic(text)
} }

View File

@ -587,6 +587,10 @@
cursor: pointer; cursor: pointer;
} }
&.file {
cursor: pointer;
}
&.me { &.me {
font-size: 13px; font-size: 13px;
font-weight: 600; font-weight: 600;