From bd1591564804c5690a3187ed31a2e0f8f224e1a7 Mon Sep 17 00:00:00 2001 From: kuaifan Date: Sat, 2 Nov 2024 08:21:29 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Models/ProjectTask.php | 2 +- app/Models/WebSocketDialog.php | 13 ++- app/Models/WebSocketDialogMsg.php | 66 ++++++------- app/Module/Base.php | 96 +++++++------------ resources/assets/js/functions/common.js | 31 +++++- resources/assets/js/functions/web.js | 17 ++-- .../assets/js/pages/manage/messenger.vue | 3 + resources/assets/js/store/actions.js | 2 +- 8 files changed, 114 insertions(+), 116 deletions(-) diff --git a/app/Models/ProjectTask.php b/app/Models/ProjectTask.php index 6ca01eb96..09edffe81 100644 --- a/app/Models/ProjectTask.php +++ b/app/Models/ProjectTask.php @@ -368,7 +368,7 @@ class ProjectTask extends AbstractModel } }, $matches[0]); }, $content); - return Base::cutStr(strip_tags($content), 100, 0, "..."); + return Base::cutStr(strip_tags($content), 100); } /** diff --git a/app/Models/WebSocketDialog.php b/app/Models/WebSocketDialog.php index b67d5c98b..77ff247bb 100644 --- a/app/Models/WebSocketDialog.php +++ b/app/Models/WebSocketDialog.php @@ -251,13 +251,12 @@ class WebSocketDialog extends AbstractModel } // 最后消息处理 - if ($data['last_msg']) { - foreach ($data['last_msg']['emoji'] as &$value) { - unset($value['userids']); - } - if ($data['last_msg']['type'] === 'text') { - $data['last_msg']['msg']['text'] = WebSocketDialogMsg::previewTextMsg($data['last_msg']['msg']); - } + if ($data['last_msg'] && $data['last_msg']['type'] != 'preview') { + $msgData = $data['last_msg']; + $msgData['emoji'] = Base::array_only_recursive($msgData['emoji'], ['symbol']); + $msgData['msg'] = ['preview' => WebSocketDialogMsg::previewMsg($msgData)]; + $msgData['type'] = 'preview'; + $data['last_msg'] = array_intersect_key($msgData, array_flip(['id', 'type', 'msg', 'userid', 'percentage', 'emoji', 'created_at'])); } // 对方信息 diff --git a/app/Models/WebSocketDialogMsg.php b/app/Models/WebSocketDialogMsg.php index 444fe5930..49c75a267 100644 --- a/app/Models/WebSocketDialogMsg.php +++ b/app/Models/WebSocketDialogMsg.php @@ -575,7 +575,7 @@ class WebSocketDialogMsg extends AbstractModel case 'meeting': $action = Doo::translate("会议"); - return "[{$action}] ${$data['msg']['name']}"; + return "[{$action}] " . Base::cutStr($data['msg']['name'], 30); case 'file': return self::previewFileMsg($data['msg']); @@ -593,17 +593,45 @@ class WebSocketDialogMsg extends AbstractModel return "[{$action}] " . self::previewMsg($data['msg']['data']); case 'notice': - return Doo::translate($data['msg']['notice']); + return Base::cutStr(Doo::translate($data['msg']['notice']), 30); case 'template': return self::previewTemplateMsg($data['msg']); + case 'preview': + return $data['msg']['preview']; + default: $action = Doo::translate("未知的消息"); return "[{$action}]"; } } + /** + * 返回文本预览消息 + * @param array $msgData + * @param bool $preserveHtml 保留html格式 + * @return string|string[]|null + */ + private static function previewTextMsg($msgData, $preserveHtml = false) + { + $text = $msgData['text'] ?? ''; + if (!$text) return ''; + if ($msgData['type'] === 'md') { + $text = Base::markdown2html($text); + } + $text = preg_replace("/]*?alt=\"(\S+)\"[^>]*?>/", "[$1]", $text); + $text = preg_replace("/]*?>/", "[动画表情]", $text); + $text = preg_replace("/]*?>/", "[图片]", $text); + if (!$preserveHtml) { + $text = strip_tags($text); + $text = str_replace([" ", "&", "<", ">"], [" ", "&", "<", ">"], $text); + $text = preg_replace("/\s+/", " ", $text); + $text = Base::cutStr($text, 30); + } + return $text; + } + /** * 预览文件消息 * @param $msg @@ -619,7 +647,7 @@ class WebSocketDialogMsg extends AbstractModel return "[{$action}]"; } $action = Doo::translate("文件"); - return "[{$action}] {$msg['name']}"; + return "[{$action}] " . Base::cutStr($msg['name'], 30); } /** @@ -633,16 +661,15 @@ class WebSocketDialogMsg extends AbstractModel return $msg['title_raw']; } if ($msg['type'] === 'task_list' && count($msg['list']) === 1) { - return Doo::translate($msg['title']) . ": " . $msg['list'][0]['name']; + return Doo::translate($msg['title']) . ": " . Base::cutStr($msg['list'][0]['name'], 30); } if (!empty($msg['title'])) { return Doo::translate($msg['title']); } if ($msg['type'] === 'content' && is_string($msg['content']) && $msg['content'] !== '') { - return Doo::translate($msg['content']); + return Base::cutStr(Doo::translate($msg['content']), 30); } return Doo::translate('未知的消息'); - } /** @@ -698,33 +725,6 @@ class WebSocketDialogMsg extends AbstractModel return $msg; } - /** - * 返回文本预览消息 - * @param array $msgData - * @param bool $preserveHtml 保留html格式 - * @return string|string[]|null - */ - public static function previewTextMsg($msgData, $preserveHtml = false) - { - $text = $msgData['text'] ?? ''; - if (!$text) return ''; - if ($msgData['type'] === 'md') { - $text = Base::markdown2html($text); - } - $text = preg_replace("/]*?alt=\"(\S+)\"[^>]*?>/", "[$1]", $text); - $text = preg_replace("/]*?>/", "[动画表情]", $text); - $text = preg_replace("/]*?>/", "[图片]", $text); - if (!$preserveHtml) { - $text = strip_tags($text); - $text = str_replace([" ", "&", "<", ">"], [" ", "&", "<", ">"], $text); - $text = preg_replace("/\s+/", " ", $text); - if (mb_strlen($text) > 30) { - $text = mb_substr($text, 0, 30) . "..."; - } - } - return $text; - } - /** * 处理文本消息内容,用于发送前 * @param $text diff --git a/app/Module/Base.php b/app/Module/Base.php index 4ca24d9f3..b26a9026f 100755 --- a/app/Module/Base.php +++ b/app/Module/Base.php @@ -375,79 +375,33 @@ class Base /** * * 截取字符串 - * @param string $string 字符串 + * @param string $str 字符串 * @param int $length 截取长度 * @param int $start 何处开始 - * @param string $dot 超出尾部添加 - * @param string $charset 默认编码 + * @param string $suffix 后缀(超出长度显示,默认:...) * @return string */ - public static function cutStr($string, $length, $start = 0, $dot = '', $charset = 'utf-8') + public static function cutStr(string $str, int $length, int $start = 0, string $suffix = '...') { - if (strtolower($charset) == 'utf-8') { - if (Base::getStrlen($string) <= $length) return $string; - $strcut = Base::utf8Substr($string, $length, $start); - return $strcut . $dot; - } else { - $length = $length * 2; - if (strlen($string) <= $length) return $string; - $strcut = ''; - for ($i = 0; $i < $length; $i++) { - $strcut .= ord($string[$i]) > 127 ? $string[$i] . $string[++$i] : $string[$i]; - } + $strLen = mb_strlen($str); + // 处理负数长度 + if ($length < 0) { + $length = max($strLen + $length, 0); } - return $strcut . $dot; - } - - /** - * PHP获取字符串中英文混合长度 - * @param string $str 字符串 - * @param string $charset 编码 - * @return float 返回长度,1中文=1位,2英文=1位 - */ - public static function getStrlen($str, $charset = 'utf-8') - { - if (strtolower($charset) == 'utf-8') { - $str = iconv('utf-8', 'GBK//IGNORE', $str); + // 处理负数起始位置 + if ($start < 0) { + $start = max($strLen + $start, 0); } - $num = strlen($str); - $cnNum = 0; - for ($i = 0; $i < $num; $i++) { - if (ord(substr($str, $i + 1, 1)) > 127) { - $cnNum++; - $i++; - } + // 处理边界情况 + if ($length === 0 || $start >= $strLen) { + return ''; } - $enNum = $num - ($cnNum * 2); - $number = ($enNum / 2) + $cnNum; - return ceil($number); - } - - /** - * PHP截取UTF-8字符串,解决半字符问题。 - * @param string $str 源字符串 - * @param int $len 左边的子串的长度 - * @param int $start 何处开始 - * @return string 取出的字符串, 当$len小于等于0时, 会返回整个字符串 - */ - public static function utf8Substr($str, $len, $start = 0) - { - $len = $len * 2; - $new_str = []; - for ($i = 0; $i < $len; $i++) { - $temp_str = substr($str, 0, 1); - if (ord($temp_str) > 127) { - $i++; - if ($i < $len) { - $new_str[] = substr($str, 0, 3); - $str = substr($str, 3); - } - } else { - $new_str[] = substr($str, 0, 1); - $str = substr($str, 1); - } + $result = mb_substr($str, $start, $length); + // 只有当实际截取的长度小于原字符串长度时才添加后缀 + if ($start + $length < $strLen) { + return $result . $suffix; } - return join(array_slice($new_str, $start)); + return $result; } /** @@ -2025,6 +1979,20 @@ class Base return $array; } + /** + * 多维数组只保留指定键值 + * @param $array + * @param $keys + * @return array + */ + public static function array_only_recursive($array, $keys) { + return array_map(function ($item) use ($keys) { + return is_array($item) + ? array_intersect_key($item, array_flip($keys)) + : $item; + }, $array); + } + /** * 是否微信 * @return bool diff --git a/resources/assets/js/functions/common.js b/resources/assets/js/functions/common.js index aa106676d..2c7bb9754 100755 --- a/resources/assets/js/functions/common.js +++ b/resources/assets/js/functions/common.js @@ -86,7 +86,6 @@ const timezone = require("dayjs/plugin/timezone"); return str; }, - /** * 字符串是否包含 * @param string @@ -1226,6 +1225,36 @@ const timezone = require("dayjs/plugin/timezone"); extractImageParameterAll(html) { const imgTags = html.match(/]*?>/g) || []; return imgTags.map(imgTag => this.extractImageParameter(imgTag)); + }, + + /** + * 增强版的字符串截取 + * @param str + * @param length + * @param start + * @param suffix + * @returns {string} + */ + cutString(str, length, start = 0, suffix = '...') { + const chars = [...str]; + // 如果长度为负数,则从末尾开始计数 + if (length < 0) { + length = Math.max(chars.length + length, 0); + } + // 如果起始位置为负数,则从末尾开始计数 + if (start < 0) { + start = Math.max(chars.length + start, 0); + } + // 如果截取长度为0或起始位置超出字符串长度,返回空字符串 + if (length === 0 || start >= chars.length) { + return ''; + } + const sliced = chars.slice(start, start + length); + // 只有当实际截取的长度小于原字符串长度时才添加后缀 + if (start + length < chars.length) { + return sliced.join('') + suffix; + } + return sliced.join(''); } }); diff --git a/resources/assets/js/functions/web.js b/resources/assets/js/functions/web.js index 523f0a8e4..746ec40fd 100755 --- a/resources/assets/js/functions/web.js +++ b/resources/assets/js/functions/web.js @@ -281,10 +281,7 @@ import {MarkdownPreview} from "../store/markdown"; text = text.replace(/\[image:(.*?)\]/g, ``) text = text.replace(/\{\{RemoteURL\}\}/g, this.apiUrl('../')) } else { - const tmpText = text.substring(0, 30) - if (tmpText.length < text.length) { - text = tmpText + '...' - } + text = $A.cutString(text, 30) } return text }, @@ -409,7 +406,7 @@ import {MarkdownPreview} from "../store/markdown"; case 'record': return `[${$A.L('语音')}]` case 'meeting': - return `[${$A.L('会议')}] ${data.msg.name}` + return `[${$A.L('会议')}] ${$A.cutString(data.msg.name, 30)}` case 'file': return $A.fileMsgSimpleDesc(data.msg, imgClassName) case 'tag': @@ -419,9 +416,11 @@ import {MarkdownPreview} from "../store/markdown"; case 'todo': return `[${$A.L(data.msg.action === 'remove' ? '取消待办' : (data.msg.action === 'done' ? '完成' : '设待办'))}] ${$A.getMsgSimpleDesc(data.msg.data)}` case 'notice': - return $A.L(data.msg.notice) + return $A.cutString($A.L(data.msg.notice), 30) case 'template': return $A.templateMsgSimpleDesc(data.msg) + case 'preview': + return data.msg.preview default: return `[${$A.L('未知的消息')}]` } @@ -450,7 +449,7 @@ import {MarkdownPreview} from "../store/markdown"; } else if (msg.ext == 'mp4') { return `[${$A.L('视频')}]` } - return `[${$A.L('文件')}] ${msg.name}` + return `[${$A.L('文件')}] ${$A.cutString(msg.name, 30)}` }, /** @@ -463,13 +462,13 @@ import {MarkdownPreview} from "../store/markdown"; return msg.title_raw } if (msg.type === 'task_list' && $A.arrayLength(msg.list) === 1) { - return $A.L(msg.title) + ": " + msg.list[0].name + return $A.L(msg.title) + ": " + $A.cutString(msg.list[0].name, 30) } if (msg.title) { return $A.L(msg.title) } if (msg.type === 'content' && typeof msg.content === 'string' && msg.content !== '') { - return $A.L(msg.content) + return $A.cutString($A.L(msg.content), 30) } return $A.L('未知的消息') }, diff --git a/resources/assets/js/pages/manage/messenger.vue b/resources/assets/js/pages/manage/messenger.vue index 2dde7ea9d..eb18df809 100644 --- a/resources/assets/js/pages/manage/messenger.vue +++ b/resources/assets/js/pages/manage/messenger.vue @@ -412,6 +412,9 @@ export default { case 'file': searchString += ` ${last_msg.msg.name}` break + case 'preview': + searchString += ` ${last_msg.msg.preview}` + break } } if (!$A.strExists(searchString, dialogSearchKey)) { diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 9b412f72c..9c2c85938 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -3634,8 +3634,8 @@ export default { // 更新最后消息 const newData = { id: dialog_id, - last_at: data.last_msg && data.last_msg.created_at, last_msg: data.last_msg, + last_at: data.last_msg ? data.last_msg.created_at : $A.daytz().format("YYYY-MM-DD HH:mm:ss"), } if (data.update_read) { // 更新未读数量