mirror of
https://github.com/kuaifan/dootask.git
synced 2026-03-03 16:02:08 +00:00
no message
This commit is contained in:
parent
5c3d8727e0
commit
1de42f5c72
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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*src=\"data:image\/(png|jpg|jpeg);base64,(.*?)\"(.*?)>(<\/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 class=\"mention\"(.*?)>.*?<\/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, '<p>');
|
||||
$text = preg_replace("/\<p.*?\>/i", "<p>", $text);
|
||||
$text = preg_replace("/\[:IMG:(.*?):\]/i", "<img src=\"{{RemoteURL}}$1\"/>", $text);
|
||||
$text = preg_replace("/\[:@:(.*?):(.*?):\]/i", "<span class=\"mention user\" data-id=\"$1\">@$2</span>", $text);
|
||||
return preg_replace("/\[:#:(.*?):(.*?):\]/i", "<span class=\"mention task\" data-id=\"$1\">#$2</span>", $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @param int $dialog_id 会话ID(即 聊天室ID)
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<div class="dialog-content">
|
||||
<!--文本-->
|
||||
<div v-if="msgData.type === 'text'" class="content-text">
|
||||
<pre class="no-dark-mode">{{textMsg(msgData.msg.text)}}</pre>
|
||||
<pre class="no-dark-mode" @click="viewText" v-html="textMsg(msgData.msg.text)"></pre>
|
||||
</div>
|
||||
<!--文件-->
|
||||
<div v-else-if="msgData.type === 'file'" :class="`content-file ${msgData.msg.type}`">
|
||||
@ -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(/<img src="(.*?)"\/>/);
|
||||
}
|
||||
}
|
||||
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(/<img src="(.*?)"\/>/g);
|
||||
array.some(res => {
|
||||
list.push(res.match(/<img src="(.*?)"\/>/)[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: '下载文件',
|
||||
|
||||
@ -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>$/, "</span></p>")
|
||||
//
|
||||
let tempId = $A.randomString(16);
|
||||
this.tempMsgs.push({
|
||||
id: tempId,
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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(/<img src=".*?"\/>/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 '';
|
||||
|
||||
1
resources/assets/sass/components/_.scss
vendored
1
resources/assets/sass/components/_.scss
vendored
@ -1,5 +1,4 @@
|
||||
@import "auto-tip";
|
||||
@import "chat-input";
|
||||
@import "circle";
|
||||
@import "drawer-overlay";
|
||||
@import "img-update";
|
||||
|
||||
30
resources/assets/sass/dark.scss
vendored
30
resources/assets/sass/dark.scss
vendored
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
@import "chat-input";
|
||||
@import "dialog-group-info";
|
||||
@import "dialog-wrapper";
|
||||
@import "file-content";
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user