From 1de42f5c7277a9d5e1e7935dd23bf610bd98ad61 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Fri, 15 Apr 2022 21:12:26 +0800 Subject: [PATCH] no message --- app/Helpers/Function.php | 7 ++ app/Http/Controllers/Api/DialogController.php | 8 +-- app/Models/WebSocketDialogMsg.php | 34 ++++++++++ .../manage}/components/ChatInput.vue | 0 .../js/pages/manage/components/DialogView.vue | 64 ++++++++++++++----- .../pages/manage/components/DialogWrapper.vue | 4 +- .../js/pages/manage/components/TaskDetail.vue | 2 +- .../assets/js/pages/manage/messenger.vue | 11 ++-- resources/assets/sass/components/_.scss | 1 - resources/assets/sass/dark.scss | 30 +++++++-- resources/assets/sass/pages/components/_.scss | 1 + .../{ => pages}/components/chat-input.scss | 0 .../sass/pages/components/dialog-wrapper.scss | 28 +++++++- 13 files changed, 156 insertions(+), 34 deletions(-) rename resources/assets/js/{ => pages/manage}/components/ChatInput.vue (100%) rename resources/assets/sass/{ => pages}/components/chat-input.scss (100%) diff --git a/app/Helpers/Function.php b/app/Helpers/Function.php index 13f4fc583..15b3936cc 100644 --- a/app/Helpers/Function.php +++ b/app/Helpers/Function.php @@ -15,3 +15,10 @@ if (!function_exists('seeders_at')) { return date("Y-m-d H:i:s", $time); } } + +if (!function_exists('md5s')) { + function md5s($val, $len = 16) + { + return substr(md5($val), 32 - $len); + } +} diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index 688b346a7..490d3aa77 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -214,7 +214,7 @@ class DialogController extends AbstractController */ public function msg__sendtext() { - Base::checkClientVersion('0.8.1'); + Base::checkClientVersion('0.12.95'); $user = User::auth(); // $chat_nickname = Base::settingFind('system', 'chat_nickname'); @@ -228,14 +228,14 @@ class DialogController extends AbstractController $dialog_id = Base::getPostInt('dialog_id'); $text = trim(Base::getPostValue('text')); // + WebSocketDialog::checkDialog($dialog_id); + // + $text = WebSocketDialogMsg::formatMsg($text, $dialog_id); if (mb_strlen($text) < 1) { return Base::retError('消息内容不能为空'); } elseif (mb_strlen($text) > 20000) { return Base::retError('消息内容最大不能超过20000字'); } - // - WebSocketDialog::checkDialog($dialog_id); - // if (mb_strlen($text) > 2000) { $array = mb_str_split($text, 2000); } else { diff --git a/app/Models/WebSocketDialogMsg.php b/app/Models/WebSocketDialogMsg.php index b62f5c67c..b4341f5fa 100644 --- a/app/Models/WebSocketDialogMsg.php +++ b/app/Models/WebSocketDialogMsg.php @@ -198,6 +198,40 @@ class WebSocketDialogMsg extends AbstractModel }); } + /** + * 处理文本消息内容,用于发送前 + * @param $text + * @param $dialog_id + * @return mixed|string|string[] + */ + public static function formatMsg($text, $dialog_id) + { + // 图片 + preg_match_all("/(<\/img>)*/s", $text, $matchs); + foreach ($matchs[2] as $key => $base64) { + $tmpPath = "uploads/chat/" . date("Ym") . "/" . $dialog_id . "/"; + Base::makeDir(public_path($tmpPath)); + $tmpPath .= md5s($base64) . "." . $matchs[1][$key]; + if (file_put_contents(public_path($tmpPath), base64_decode($base64))) { + $text = str_replace($matchs[0][$key], "[:IMG:{$tmpPath}:]", $text); + } + } + // @成员 #任务 + preg_match_all("/.*?<\/span>.*?<\/span>.*?<\/span>/s", $text, $matchs); + foreach ($matchs[1] as $key => $str) { + preg_match("/data-denotation-char=\"(.*?)\"/", $str, $matchChar); + preg_match("/data-id=\"(.*?)\"/", $str, $matchId); + preg_match("/data-value=\"(.*?)\"/", $str, $matchValye); + $text = str_replace($matchs[0][$key], "[:{$matchChar[1]}:{$matchId[1]}:{$matchValye[1]}:]", $text); + } + // 过滤标签 + $text = strip_tags($text, '

'); + $text = preg_replace("/\/i", "

", $text); + $text = preg_replace("/\[:IMG:(.*?):\]/i", "", $text); + $text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "@$2", $text); + return preg_replace("/\[:#:(.*?):(.*?):\]/i", "#$2", $text); + } + /** * 发送消息 * @param int $dialog_id 会话ID(即 聊天室ID) diff --git a/resources/assets/js/components/ChatInput.vue b/resources/assets/js/pages/manage/components/ChatInput.vue similarity index 100% rename from resources/assets/js/components/ChatInput.vue rename to resources/assets/js/pages/manage/components/ChatInput.vue diff --git a/resources/assets/js/pages/manage/components/DialogView.vue b/resources/assets/js/pages/manage/components/DialogView.vue index 9fcd43c7d..93098c82a 100644 --- a/resources/assets/js/pages/manage/components/DialogView.vue +++ b/resources/assets/js/pages/manage/components/DialogView.vue @@ -10,7 +10,7 @@

-
{{textMsg(msgData.msg.text)}}
+

                 
@@ -173,6 +173,7 @@ export default { return "" } text = text.trim().replace(/(\n\x20*){3,}/g, "\n\n"); + text = text.replace(/\{\{RemoteURL\}\}/g, $A.apiUrl('../')) return text; }, @@ -223,22 +224,18 @@ export default { }); }, + viewText({target}) { + if (target.nodeName === "IMG") { + this.viewPicture(target.currentSrc); + } else if (target.classList.contains('mention') && target.classList.contains('task')) { + this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id"))); + } + }, + viewFile() { - const {id, dialog_id, msg} = this.msgData; + const {msg} = this.msgData; if (['jpg', 'jpeg', 'gif', 'png'].includes(msg.ext)) { - const list = $A.cloneJSON(this.dialogMsgs.filter(item => { - return item.dialog_id === dialog_id && item.type === 'file' && ['jpg', 'jpeg', 'gif', 'png'].includes(item.msg.ext); - })).sort((a, b) => { - return a.id - b.id; - }); - const index = list.findIndex(item => item.id === id); - if (index > -1) { - this.$store.state.previewImageIndex = index; - this.$store.state.previewImageList = list.map(({msg}) => msg.path); - } else { - this.$store.state.previewImageIndex = 0; - this.$store.state.previewImageList = [msg.path]; - } + this.viewPicture(msg.path); return } if (this.$Electron) { @@ -260,6 +257,43 @@ export default { } }, + viewPicture(currentUrl) { + const {dialog_id} = this.msgData; + const data = $A.cloneJSON(this.dialogMsgs.filter(item => { + if (item.dialog_id === dialog_id) { + if (item.type === 'file') { + return ['jpg', 'jpeg', 'gif', 'png'].includes(item.msg.ext); + } else if (item.type === 'text') { + return item.msg.text.match(//); + } + } + return false; + })).sort((a, b) => { + return a.id - b.id; + }); + // + let list = []; + data.some(({type, msg}) => { + if (type === 'file') { + list.push(msg.path) + } else if (type === 'text') { + const array = msg.text.match(//g); + array.some(res => { + list.push(res.match(//)[1].replace(/\{\{RemoteURL\}\}/g, $A.apiUrl('../'))) + }) + } + }) + // + let index = list.findIndex(item => item === currentUrl); + if (index > -1) { + this.$store.state.previewImageIndex = index; + this.$store.state.previewImageList = list; + } else { + this.$store.state.previewImageIndex = 0; + this.$store.state.previewImageList = [currentUrl]; + } + }, + downFile() { $A.modalConfirm({ title: '下载文件', diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue index 297817c3e..cc9298db4 100644 --- a/resources/assets/js/pages/manage/components/DialogWrapper.vue +++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue @@ -162,7 +162,7 @@ import {Store} from "le5le-store"; import UserInput from "../../../components/UserInput"; import DrawerOverlay from "../../../components/DrawerOverlay"; import DialogGroupInfo from "./DialogGroupInfo"; -import ChatInput from "../../../components/ChatInput"; +import ChatInput from "./ChatInput"; export default { name: "DialogWrapper", @@ -324,6 +324,8 @@ export default { if (this.msgText == '') { return; } + this.msgText = this.msgText.replace(/<\/span> <\/p>$/, "

") + // let tempId = $A.randomString(16); this.tempMsgs.push({ id: tempId, diff --git a/resources/assets/js/pages/manage/components/TaskDetail.vue b/resources/assets/js/pages/manage/components/TaskDetail.vue index 6920faa0c..f9f21843c 100644 --- a/resources/assets/js/pages/manage/components/TaskDetail.vue +++ b/resources/assets/js/pages/manage/components/TaskDetail.vue @@ -434,7 +434,7 @@ import DialogWrapper from "./DialogWrapper"; import ProjectLog from "./ProjectLog"; import {Store} from "le5le-store"; import TaskMenu from "./TaskMenu"; -import ChatInput from "../../../components/ChatInput"; +import ChatInput from "./ChatInput"; export default { name: "TaskDetail", diff --git a/resources/assets/js/pages/manage/messenger.vue b/resources/assets/js/pages/manage/messenger.vue index 8989a8e00..885d6cf8a 100644 --- a/resources/assets/js/pages/manage/messenger.vue +++ b/resources/assets/js/pages/manage/messenger.vue @@ -397,14 +397,17 @@ export default { if ($A.isJson(data)) { switch (data.type) { case 'text': - return data.msg.text + let text = data.msg.text; + text = text.replace(//g, `[${this.$L('图片')}]`) + text = text.replace(/<[^>]+>/g,"") + return text case 'file': if (data.msg.type == 'img') { - return '[' + this.$L('图片') + ']' + return `[${this.$L('图片')}]` } - return '[' + this.$L('文件') + '] ' + data.msg.name + return `[${this.$L('文件')}] ${data.msg.name}` default: - return '[' + this.$L('未知的消息') + ']' + return `[${this.$L('未知的消息')}]` } } return ''; diff --git a/resources/assets/sass/components/_.scss b/resources/assets/sass/components/_.scss index 7f9832ed7..1c3ac5523 100644 --- a/resources/assets/sass/components/_.scss +++ b/resources/assets/sass/components/_.scss @@ -1,5 +1,4 @@ @import "auto-tip"; -@import "chat-input"; @import "circle"; @import "drawer-overlay"; @import "img-update"; diff --git a/resources/assets/sass/dark.scss b/resources/assets/sass/dark.scss index 174745b48..9031850c7 100644 --- a/resources/assets/sass/dark.scss +++ b/resources/assets/sass/dark.scss @@ -171,17 +171,35 @@ body.dark-mode-reverse { > ul { > li { .dialog-view { - .dialog-content { - background-color: #e1e1e1; - .content-text { - color: #ffffff; + .dialog-head { + .dialog-content { + background-color: #e1e1e1; + .content-text { + color: #ffffff; + .content-text { + > pre { + .mention { + color: #000000; + } + } + } + } } } } &.self { .dialog-view { - .dialog-content { - background-color: #8bcf70; + .dialog-head { + .dialog-content { + background-color: #8bcf70; + .content-text { + > pre { + .mention { + color: #000000; + } + } + } + } } } } diff --git a/resources/assets/sass/pages/components/_.scss b/resources/assets/sass/pages/components/_.scss index 55279d23b..d1dd6aa91 100755 --- a/resources/assets/sass/pages/components/_.scss +++ b/resources/assets/sass/pages/components/_.scss @@ -1,3 +1,4 @@ +@import "chat-input"; @import "dialog-group-info"; @import "dialog-wrapper"; @import "file-content"; diff --git a/resources/assets/sass/components/chat-input.scss b/resources/assets/sass/pages/components/chat-input.scss similarity index 100% rename from resources/assets/sass/components/chat-input.scss rename to resources/assets/sass/pages/components/chat-input.scss diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss index d1b24dfec..cca2bbe72 100644 --- a/resources/assets/sass/pages/components/dialog-wrapper.scss +++ b/resources/assets/sass/pages/components/dialog-wrapper.scss @@ -221,12 +221,14 @@ background-color: #F4F5F7; padding: 8px; min-width: 32px; - border-radius: 6px 6px 6px 0; + border-radius: 0 6px 6px 6px; display: flex; align-items: flex-start; .content-text { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; color: #333333; + > pre { display: block; margin: 0; @@ -235,6 +237,22 @@ white-space: pre-wrap; word-wrap: break-word; word-break: break-word; + img { + max-width: 220px; + max-height: 220px; + } + .mention { + color: $flow-status-end-color; + background-color: transparent; + user-select: auto; + margin-right: 0; + > span { + margin: 0; + } + &.task { + cursor: pointer; + } + } } } @@ -461,10 +479,16 @@ .dialog-content { background-color: $primary-color; - border-radius: 6px 6px 0 6px; + border-radius: 6px 0 6px 6px; .content-text { color: #ffffff; + + > pre { + .mention { + color: #333333; + } + } } .content-file {