mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-03 16:02:08 +00:00
perf: 优化预览消息
This commit is contained in:
parent
312acdab51
commit
bd15915648
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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']));
|
||||
}
|
||||
|
||||
// 对方信息
|
||||
|
||||
@ -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("/<img\s+class=\"emoticon\"[^>]*?alt=\"(\S+)\"[^>]*?>/", "[$1]", $text);
|
||||
$text = preg_replace("/<img\s+class=\"emoticon\"[^>]*?>/", "[动画表情]", $text);
|
||||
$text = preg_replace("/<img\s+class=\"browse\"[^>]*?>/", "[图片]", $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("/<img\s+class=\"emoticon\"[^>]*?alt=\"(\S+)\"[^>]*?>/", "[$1]", $text);
|
||||
$text = preg_replace("/<img\s+class=\"emoticon\"[^>]*?>/", "[动画表情]", $text);
|
||||
$text = preg_replace("/<img\s+class=\"browse\"[^>]*?>/", "[图片]", $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
|
||||
|
||||
@ -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
|
||||
|
||||
31
resources/assets/js/functions/common.js
vendored
31
resources/assets/js/functions/common.js
vendored
@ -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(/<img\s+[^>]*?>/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('');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
17
resources/assets/js/functions/web.js
vendored
17
resources/assets/js/functions/web.js
vendored
@ -281,10 +281,7 @@ import {MarkdownPreview} from "../store/markdown";
|
||||
text = text.replace(/\[image:(.*?)\]/g, `<img class="${imgClassName}" src="$1">`)
|
||||
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('未知的消息')
|
||||
},
|
||||
|
||||
@ -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)) {
|
||||
|
||||
2
resources/assets/js/store/actions.js
vendored
2
resources/assets/js/store/actions.js
vendored
@ -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) {
|
||||
// 更新未读数量
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user