mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-17 03:03:41 +00:00
perf: 优化预览消息
This commit is contained in:
parent
312acdab51
commit
bd15915648
@ -368,7 +368,7 @@ class ProjectTask extends AbstractModel
|
|||||||
}
|
}
|
||||||
}, $matches[0]);
|
}, $matches[0]);
|
||||||
}, $content);
|
}, $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']) {
|
if ($data['last_msg'] && $data['last_msg']['type'] != 'preview') {
|
||||||
foreach ($data['last_msg']['emoji'] as &$value) {
|
$msgData = $data['last_msg'];
|
||||||
unset($value['userids']);
|
$msgData['emoji'] = Base::array_only_recursive($msgData['emoji'], ['symbol']);
|
||||||
}
|
$msgData['msg'] = ['preview' => WebSocketDialogMsg::previewMsg($msgData)];
|
||||||
if ($data['last_msg']['type'] === 'text') {
|
$msgData['type'] = 'preview';
|
||||||
$data['last_msg']['msg']['text'] = WebSocketDialogMsg::previewTextMsg($data['last_msg']['msg']);
|
$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':
|
case 'meeting':
|
||||||
$action = Doo::translate("会议");
|
$action = Doo::translate("会议");
|
||||||
return "[{$action}] ${$data['msg']['name']}";
|
return "[{$action}] " . Base::cutStr($data['msg']['name'], 30);
|
||||||
|
|
||||||
case 'file':
|
case 'file':
|
||||||
return self::previewFileMsg($data['msg']);
|
return self::previewFileMsg($data['msg']);
|
||||||
@ -593,17 +593,45 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
return "[{$action}] " . self::previewMsg($data['msg']['data']);
|
return "[{$action}] " . self::previewMsg($data['msg']['data']);
|
||||||
|
|
||||||
case 'notice':
|
case 'notice':
|
||||||
return Doo::translate($data['msg']['notice']);
|
return Base::cutStr(Doo::translate($data['msg']['notice']), 30);
|
||||||
|
|
||||||
case 'template':
|
case 'template':
|
||||||
return self::previewTemplateMsg($data['msg']);
|
return self::previewTemplateMsg($data['msg']);
|
||||||
|
|
||||||
|
case 'preview':
|
||||||
|
return $data['msg']['preview'];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
$action = Doo::translate("未知的消息");
|
$action = Doo::translate("未知的消息");
|
||||||
return "[{$action}]";
|
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
|
* @param $msg
|
||||||
@ -619,7 +647,7 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
return "[{$action}]";
|
return "[{$action}]";
|
||||||
}
|
}
|
||||||
$action = Doo::translate("文件");
|
$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'];
|
return $msg['title_raw'];
|
||||||
}
|
}
|
||||||
if ($msg['type'] === 'task_list' && count($msg['list']) === 1) {
|
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'])) {
|
if (!empty($msg['title'])) {
|
||||||
return Doo::translate($msg['title']);
|
return Doo::translate($msg['title']);
|
||||||
}
|
}
|
||||||
if ($msg['type'] === 'content' && is_string($msg['content']) && $msg['content'] !== '') {
|
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('未知的消息');
|
return Doo::translate('未知的消息');
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -698,33 +725,6 @@ class WebSocketDialogMsg extends AbstractModel
|
|||||||
return $msg;
|
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
|
* @param $text
|
||||||
|
|||||||
@ -375,79 +375,33 @@ class Base
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 截取字符串
|
* 截取字符串
|
||||||
* @param string $string 字符串
|
* @param string $str 字符串
|
||||||
* @param int $length 截取长度
|
* @param int $length 截取长度
|
||||||
* @param int $start 何处开始
|
* @param int $start 何处开始
|
||||||
* @param string $dot 超出尾部添加
|
* @param string $suffix 后缀(超出长度显示,默认:...)
|
||||||
* @param string $charset 默认编码
|
|
||||||
* @return string
|
* @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') {
|
$strLen = mb_strlen($str);
|
||||||
if (Base::getStrlen($string) <= $length) return $string;
|
// 处理负数长度
|
||||||
$strcut = Base::utf8Substr($string, $length, $start);
|
if ($length < 0) {
|
||||||
return $strcut . $dot;
|
$length = max($strLen + $length, 0);
|
||||||
} 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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $strcut . $dot;
|
// 处理负数起始位置
|
||||||
}
|
if ($start < 0) {
|
||||||
|
$start = max($strLen + $start, 0);
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
$num = strlen($str);
|
// 处理边界情况
|
||||||
$cnNum = 0;
|
if ($length === 0 || $start >= $strLen) {
|
||||||
for ($i = 0; $i < $num; $i++) {
|
return '';
|
||||||
if (ord(substr($str, $i + 1, 1)) > 127) {
|
|
||||||
$cnNum++;
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
$enNum = $num - ($cnNum * 2);
|
$result = mb_substr($str, $start, $length);
|
||||||
$number = ($enNum / 2) + $cnNum;
|
// 只有当实际截取的长度小于原字符串长度时才添加后缀
|
||||||
return ceil($number);
|
if ($start + $length < $strLen) {
|
||||||
}
|
return $result . $suffix;
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return join(array_slice($new_str, $start));
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2025,6 +1979,20 @@ class Base
|
|||||||
return $array;
|
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
|
* @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;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串是否包含
|
* 字符串是否包含
|
||||||
* @param string
|
* @param string
|
||||||
@ -1226,6 +1225,36 @@ const timezone = require("dayjs/plugin/timezone");
|
|||||||
extractImageParameterAll(html) {
|
extractImageParameterAll(html) {
|
||||||
const imgTags = html.match(/<img\s+[^>]*?>/g) || [];
|
const imgTags = html.match(/<img\s+[^>]*?>/g) || [];
|
||||||
return imgTags.map(imgTag => this.extractImageParameter(imgTag));
|
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(/\[image:(.*?)\]/g, `<img class="${imgClassName}" src="$1">`)
|
||||||
text = text.replace(/\{\{RemoteURL\}\}/g, this.apiUrl('../'))
|
text = text.replace(/\{\{RemoteURL\}\}/g, this.apiUrl('../'))
|
||||||
} else {
|
} else {
|
||||||
const tmpText = text.substring(0, 30)
|
text = $A.cutString(text, 30)
|
||||||
if (tmpText.length < text.length) {
|
|
||||||
text = tmpText + '...'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return text
|
return text
|
||||||
},
|
},
|
||||||
@ -409,7 +406,7 @@ import {MarkdownPreview} from "../store/markdown";
|
|||||||
case 'record':
|
case 'record':
|
||||||
return `[${$A.L('语音')}]`
|
return `[${$A.L('语音')}]`
|
||||||
case 'meeting':
|
case 'meeting':
|
||||||
return `[${$A.L('会议')}] ${data.msg.name}`
|
return `[${$A.L('会议')}] ${$A.cutString(data.msg.name, 30)}`
|
||||||
case 'file':
|
case 'file':
|
||||||
return $A.fileMsgSimpleDesc(data.msg, imgClassName)
|
return $A.fileMsgSimpleDesc(data.msg, imgClassName)
|
||||||
case 'tag':
|
case 'tag':
|
||||||
@ -419,9 +416,11 @@ import {MarkdownPreview} from "../store/markdown";
|
|||||||
case 'todo':
|
case 'todo':
|
||||||
return `[${$A.L(data.msg.action === 'remove' ? '取消待办' : (data.msg.action === 'done' ? '完成' : '设待办'))}] ${$A.getMsgSimpleDesc(data.msg.data)}`
|
return `[${$A.L(data.msg.action === 'remove' ? '取消待办' : (data.msg.action === 'done' ? '完成' : '设待办'))}] ${$A.getMsgSimpleDesc(data.msg.data)}`
|
||||||
case 'notice':
|
case 'notice':
|
||||||
return $A.L(data.msg.notice)
|
return $A.cutString($A.L(data.msg.notice), 30)
|
||||||
case 'template':
|
case 'template':
|
||||||
return $A.templateMsgSimpleDesc(data.msg)
|
return $A.templateMsgSimpleDesc(data.msg)
|
||||||
|
case 'preview':
|
||||||
|
return data.msg.preview
|
||||||
default:
|
default:
|
||||||
return `[${$A.L('未知的消息')}]`
|
return `[${$A.L('未知的消息')}]`
|
||||||
}
|
}
|
||||||
@ -450,7 +449,7 @@ import {MarkdownPreview} from "../store/markdown";
|
|||||||
} else if (msg.ext == 'mp4') {
|
} else if (msg.ext == 'mp4') {
|
||||||
return `[${$A.L('视频')}]`
|
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
|
return msg.title_raw
|
||||||
}
|
}
|
||||||
if (msg.type === 'task_list' && $A.arrayLength(msg.list) === 1) {
|
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) {
|
if (msg.title) {
|
||||||
return $A.L(msg.title)
|
return $A.L(msg.title)
|
||||||
}
|
}
|
||||||
if (msg.type === 'content' && typeof msg.content === 'string' && msg.content !== '') {
|
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('未知的消息')
|
return $A.L('未知的消息')
|
||||||
},
|
},
|
||||||
|
|||||||
@ -412,6 +412,9 @@ export default {
|
|||||||
case 'file':
|
case 'file':
|
||||||
searchString += ` ${last_msg.msg.name}`
|
searchString += ` ${last_msg.msg.name}`
|
||||||
break
|
break
|
||||||
|
case 'preview':
|
||||||
|
searchString += ` ${last_msg.msg.preview}`
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!$A.strExists(searchString, dialogSearchKey)) {
|
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 = {
|
const newData = {
|
||||||
id: dialog_id,
|
id: dialog_id,
|
||||||
last_at: data.last_msg && data.last_msg.created_at,
|
|
||||||
last_msg: data.last_msg,
|
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) {
|
if (data.update_read) {
|
||||||
// 更新未读数量
|
// 更新未读数量
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user