feat: 新增聊天表情
@ -206,17 +206,28 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
*/
|
||||
public static function formatMsg($text, $dialog_id)
|
||||
{
|
||||
// 图片
|
||||
// 图片 [:IMAGE:className:width:height:src:alt:]
|
||||
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);
|
||||
$imagesize = getimagesize(public_path($tmpPath));
|
||||
$text = str_replace($matchs[0][$key], "[:IMAGE:browse:{$imagesize[0]}:{$imagesize[1]}:{$tmpPath}::]", $text);
|
||||
}
|
||||
}
|
||||
// @成员 #任务
|
||||
// 表情图片
|
||||
preg_match_all("/<img class=\"emoticon\"(.*?)>/s", $text, $matchs);
|
||||
foreach ($matchs[1] as $key => $str) {
|
||||
preg_match("/data-asset=\"(.*?)\"/", $str, $matchAsset);
|
||||
preg_match("/data-name=\"(.*?)\"/", $str, $matchName);
|
||||
if (file_exists(public_path($matchAsset[1]))) {
|
||||
$imagesize = getimagesize(public_path($matchAsset[1]));
|
||||
$text = str_replace($matchs[0][$key], "[:IMAGE:emoticon:{$imagesize[0]}:{$imagesize[1]}:{$matchAsset[1]}:{$matchName[1]}:]", $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);
|
||||
@ -227,7 +238,7 @@ class WebSocketDialogMsg extends AbstractModel
|
||||
// 过滤标签
|
||||
$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("/\[:IMAGE:(.*?):(.*?):(.*?):(.*?):(.*?):\]/i", "<img class=\"$1\" width=\"$2\" height=\"$3\" src=\"{{RemoteURL}}$4\" alt=\"$5\"/>", $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);
|
||||
}
|
||||
|
||||
@ -69,7 +69,6 @@
|
||||
"view-design-hi": "^4.7.0-20",
|
||||
"vue": "^2.6.14",
|
||||
"vue-clipboard2": "^0.3.3",
|
||||
"vue-emoji-picker": "^1.0.3",
|
||||
"vue-kityminder-ggg": "^1.3.10",
|
||||
"vue-loader": "^15.9.8",
|
||||
"vue-resize-observer": "^2.0.16",
|
||||
|
||||
13
resources/assets/js/functions/web.js
vendored
@ -375,6 +375,19 @@
|
||||
*/
|
||||
getDialogMention(dialog) {
|
||||
return dialog ? (dialog.mention || 0) : 0
|
||||
},
|
||||
|
||||
/**
|
||||
* 返回文本信息预览格式
|
||||
* @param text
|
||||
* @returns {*}
|
||||
*/
|
||||
getMsgTextPreview(text) {
|
||||
if (!text) return '';
|
||||
text = text.replace(/<img\s+class="emoticon"[^>]*?alt="(\S+)"[^>]*?>/g, "[$1]")
|
||||
text = text.replace(/<img\s+class="emoticon"[^>]*?>/g, `[${$A.L('表情')}]`)
|
||||
text = text.replace(/<img\s+class="browse"[^>]*?>/g, `[${$A.L('图片')}]`)
|
||||
return text.replace(/<[^>]+>/g,"")
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -898,9 +898,7 @@ export default {
|
||||
let body = '';
|
||||
switch (type) {
|
||||
case 'text':
|
||||
body = msg.text;
|
||||
body = body.replace(/<img src=".*?"\/>/g, `[${this.$L('图片')}]`)
|
||||
body = body.replace(/<[^>]+>/g,"")
|
||||
body = $A.getMsgTextPreview(msg.text)
|
||||
break;
|
||||
case 'file':
|
||||
body = '[' + this.$L(msg.type == 'img' ? '图片信息' : '文件信息') + ']'
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div class="chat-emoji-wrapper">
|
||||
<ul class="chat-emoji-box overlay-y" :class="type">
|
||||
<li v-for="item in list" @click="onSelect(item)">
|
||||
<img v-if="item.type === 'emoticon'" :src="item.src" :title="item.name" :alt="item.name"/>
|
||||
<span v-else v-html="item.html" :title="item.name"></span>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="chat-emoji-menu">
|
||||
<li :class="{active: type === 'emoji'}" @click="type='emoji'">
|
||||
<span>😀</span>
|
||||
</li>
|
||||
<li v-for="item in emoticonList" :class="{active: type === 'emoticon' && emoticonPath == item.path}" @click="onEmoticon(item.path)">
|
||||
<img :title="item.name" :alt="item.name" :src="item.src"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
name: 'ChatEmoji',
|
||||
props: {
|
||||
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 'emoji',
|
||||
emoticonPath: '',
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
computed: {
|
||||
list() {
|
||||
if (this.type === 'emoji') {
|
||||
if (!$A.isArray(window.emojiData)) {
|
||||
return [];
|
||||
}
|
||||
return window.emojiData.sort(function (a, b) {
|
||||
return a.emoji_order - b.emoji_order;
|
||||
}).map(item => {
|
||||
return {
|
||||
type: 'emoji',
|
||||
name: item.name,
|
||||
html: item.code_decimal,
|
||||
}
|
||||
})
|
||||
} else if (this.type === 'emoticon') {
|
||||
const data = this.emoticonList.find(({path}) => path === this.emoticonPath)
|
||||
if (data) {
|
||||
return data.list;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
},
|
||||
emoticonList() {
|
||||
if ($A.isArray(window.emoticonData)) {
|
||||
let baseUrl = $A.apiUrl("../images/emoticon")
|
||||
return window.emoticonData.map(data => {
|
||||
data.src = `${baseUrl}/${data.path}/${data.icon}`
|
||||
data.list = data.list.map(item => {
|
||||
item.type = `emoticon`
|
||||
item.asset = `images/emoticon/${data.path}/${item.path}`
|
||||
item.src = `${baseUrl}/${data.path}/${item.path}`
|
||||
return item
|
||||
})
|
||||
return data;
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onEmoticon(path) {
|
||||
this.type = 'emoticon';
|
||||
this.emoticonPath = path;
|
||||
},
|
||||
|
||||
onSelect(item) {
|
||||
this.$emit('on-select', item)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -4,26 +4,39 @@
|
||||
<div class="chat-input-toolbar">
|
||||
<slot name="toolbarBefore"/>
|
||||
|
||||
<ETooltip placement="top" :content="$L('表情')"><i class="taskfont" @click="onToolbar('emoji')"></i></ETooltip>
|
||||
<ETooltip placement="top" :content="$L('选择会员')"><i class="taskfont" @click="onToolbar('user')"></i></ETooltip>
|
||||
<ETooltip placement="top" :content="$L('选择任务')"><i class="taskfont" @click="onToolbar('task')"></i></ETooltip>
|
||||
<EPopover
|
||||
v-model="showEmoji"
|
||||
:visibleArrow="false"
|
||||
popperClass="chat-input-emoji-popover">
|
||||
<ETooltip slot="reference" :disabled="showEmoji" placement="top" :content="$L('表情')">
|
||||
<i class="taskfont" @click="onToolbar('emoji')"></i>
|
||||
</ETooltip>
|
||||
<ChatEmoji @on-select="onSelectEmoji"/>
|
||||
</EPopover>
|
||||
|
||||
<EDropdown
|
||||
trigger="hover"
|
||||
placement="top"
|
||||
@command="onToolbar">
|
||||
<i class="taskfont"></i>
|
||||
<EDropdownMenu slot="dropdown" class="chat-input-dropdown-menu">
|
||||
<EDropdownItem command="image">
|
||||
<i class="taskfont"></i>
|
||||
{{$L('图片')}}
|
||||
</EDropdownItem>
|
||||
<EDropdownItem command="file">
|
||||
<i class="taskfont"></i>
|
||||
{{$L('文件')}}
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</EDropdown>
|
||||
<ETooltip placement="top" :content="$L('选择会员')">
|
||||
<i class="taskfont" @click="onToolbar('user')"></i>
|
||||
</ETooltip>
|
||||
<ETooltip placement="top" :content="$L('选择任务')">
|
||||
<i class="taskfont" @click="onToolbar('task')"></i>
|
||||
</ETooltip>
|
||||
|
||||
<EPopover
|
||||
v-model="showMore"
|
||||
:visibleArrow="false"
|
||||
popperClass="chat-input-more-popover">
|
||||
<ETooltip slot="reference" :disabled="showMore" placement="top" :content="$L('展开')">
|
||||
<i class="taskfont"></i>
|
||||
</ETooltip>
|
||||
<div class="chat-input-popover-item" @click="onToolbar('image')">
|
||||
<i class="taskfont"></i>
|
||||
{{$L('图片')}}
|
||||
</div>
|
||||
<div class="chat-input-popover-item" @click="onToolbar('file')">
|
||||
<i class="taskfont"></i>
|
||||
{{$L('文件')}}
|
||||
</div>
|
||||
</EPopover>
|
||||
|
||||
<div class="toolbar-spacing"></div>
|
||||
|
||||
@ -40,9 +53,11 @@ import {mapGetters, mapState} from "vuex";
|
||||
|
||||
import Quill from 'quill';
|
||||
import "quill-mention";
|
||||
import ChatEmoji from "./emoji";
|
||||
|
||||
export default {
|
||||
name: 'ChatInput',
|
||||
components: {ChatEmoji},
|
||||
props: {
|
||||
dialogId: {
|
||||
type: Number,
|
||||
@ -94,6 +109,9 @@ export default {
|
||||
|
||||
userList: null,
|
||||
taskList: null,
|
||||
|
||||
showMore: false,
|
||||
showEmoji: false,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
@ -266,7 +284,22 @@ export default {
|
||||
},
|
||||
|
||||
send() {
|
||||
this.$emit('on-send', this.quill)
|
||||
this.$emit('on-send')
|
||||
},
|
||||
|
||||
onSelectEmoji(item) {
|
||||
if (!this.quill) {
|
||||
return;
|
||||
}
|
||||
if (item.type === 'emoji') {
|
||||
let element = document.createElement('span');
|
||||
element.innerHTML = item.html;
|
||||
this.quill.insertText(this.quill.getSelection(true).index, element.innerHTML);
|
||||
element = null;
|
||||
} else if (item.type === 'emoticon') {
|
||||
this.$emit('on-send', `<img class="emoticon" data-asset="${item.asset}" data-name="${item.name}" src="${item.src}"/>`)
|
||||
}
|
||||
this.showEmoji = false;
|
||||
},
|
||||
|
||||
onToolbar(action) {
|
||||
@ -286,6 +319,10 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
onMoreVisibleChange(v) {
|
||||
this.showMore = v;
|
||||
},
|
||||
|
||||
openMenu(char) {
|
||||
if (!this.quill) {
|
||||
return;
|
||||
@ -302,6 +339,26 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
getProjectId() {
|
||||
let object = null;
|
||||
if (this.dialogId > 0) {
|
||||
object = this.cacheProjects.find(({dialog_id}) => dialog_id == this.dialogId);
|
||||
if (object) {
|
||||
return object.id;
|
||||
}
|
||||
object = this.cacheTasks.find(({dialog_id}) => dialog_id == this.dialogId);
|
||||
if (object) {
|
||||
return object.project_id;
|
||||
}
|
||||
} else if (this.taskId > 0) {
|
||||
object = this.cacheTasks.find(({id}) => id == this.taskId);
|
||||
if (object) {
|
||||
return object.project_id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
getSource(mentionChar) {
|
||||
return new Promise(resolve => {
|
||||
switch (mentionChar) {
|
||||
@ -448,26 +505,6 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getProjectId() {
|
||||
let object = null;
|
||||
if (this.dialogId > 0) {
|
||||
object = this.cacheProjects.find(({dialog_id}) => dialog_id == this.dialogId);
|
||||
if (object) {
|
||||
return object.id;
|
||||
}
|
||||
object = this.cacheTasks.find(({dialog_id}) => dialog_id == this.dialogId);
|
||||
if (object) {
|
||||
return object.project_id;
|
||||
}
|
||||
} else if (this.taskId > 0) {
|
||||
object = this.cacheTasks.find(({id}) => id == this.taskId);
|
||||
if (object) {
|
||||
return object.project_id;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -225,10 +225,21 @@ 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")));
|
||||
switch (target.nodeName) {
|
||||
case "IMG":
|
||||
if (target.classList.contains('browse')) {
|
||||
this.viewPicture(target.currentSrc);
|
||||
} else {
|
||||
this.$store.state.previewImageIndex = 0;
|
||||
this.$store.state.previewImageList = [target.currentSrc];
|
||||
}
|
||||
break;
|
||||
|
||||
case "SPAN":
|
||||
if (target.classList.contains('mention') && target.classList.contains('task')) {
|
||||
this.$store.dispatch("openTask", $A.runNum(target.getAttribute("data-id")));
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -264,7 +275,7 @@ export default {
|
||||
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 item.msg.text.match(/<img\s+class="browse"[^>]*?>/);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -277,9 +288,10 @@ export default {
|
||||
if (type === 'file') {
|
||||
list.push(msg.path)
|
||||
} else if (type === 'text') {
|
||||
const array = msg.text.match(/<img src="(.*?)"\/>/g);
|
||||
const baseUrl = $A.apiUrl('../');
|
||||
const array = msg.text.match(/<img\s+class="browse"[^>]*?src="(.*?)"[^>]*?>/g);
|
||||
array.some(res => {
|
||||
list.push(res.match(/<img src="(.*?)"\/>/)[1].replace(/\{\{RemoteURL\}\}/g, $A.apiUrl('../')))
|
||||
list.push(res.match(/<img\s+class="browse"[^>]*?src="(.*?)"[^>]*?>/)[1].replace(/\{\{RemoteURL\}\}/g, baseUrl))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@ -317,14 +317,18 @@ export default {
|
||||
|
||||
methods: {
|
||||
sendMsg(text) {
|
||||
let msgText;
|
||||
if (typeof text === "string" && text) {
|
||||
this.msgText = text;
|
||||
this.$refs.input.focus();
|
||||
msgText = text;
|
||||
} else {
|
||||
msgText = this.msgText;
|
||||
this.msgText = '';
|
||||
}
|
||||
if (this.msgText == '') {
|
||||
if (msgText == '' && this.isDesktop) {
|
||||
this.$refs.input.focus();
|
||||
return;
|
||||
}
|
||||
this.msgText = this.msgText.replace(/<\/span> <\/p>$/, "</span></p>")
|
||||
msgText = msgText.replace(/<\/span> <\/p>$/, "</span></p>")
|
||||
//
|
||||
let tempId = $A.randomString(16);
|
||||
this.tempMsgs.push({
|
||||
@ -333,7 +337,7 @@ export default {
|
||||
type: 'text',
|
||||
userid: this.userId,
|
||||
msg: {
|
||||
text: this.msgText,
|
||||
text: msgText,
|
||||
},
|
||||
});
|
||||
if (!this.isDesktop) {
|
||||
@ -346,7 +350,7 @@ export default {
|
||||
url: 'dialog/msg/sendtext',
|
||||
data: {
|
||||
dialog_id: this.dialogId,
|
||||
text: this.msgText,
|
||||
text: msgText,
|
||||
},
|
||||
method: 'post'
|
||||
}).then(({data}) => {
|
||||
@ -356,8 +360,6 @@ export default {
|
||||
$A.modalError(msg);
|
||||
this.tempMsgs = this.tempMsgs.filter(({id}) => id != tempId)
|
||||
});
|
||||
//
|
||||
this.msgText = '';
|
||||
},
|
||||
|
||||
sendFileMsg(files) {
|
||||
|
||||
@ -404,10 +404,7 @@ export default {
|
||||
if ($A.isJson(data)) {
|
||||
switch (data.type) {
|
||||
case 'text':
|
||||
let text = data.msg.text;
|
||||
text = text.replace(/<img src=".*?"\/>/g, `[${this.$L('图片')}]`)
|
||||
text = text.replace(/<[^>]+>/g,"")
|
||||
return text
|
||||
return $A.getMsgTextPreview(data.msg.text)
|
||||
case 'file':
|
||||
if (data.msg.type == 'img') {
|
||||
return `[${this.$L('图片')}]`
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
float: left;
|
||||
max-width: 100%;
|
||||
min-width: calc(100% - 175px);
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
|
||||
.ql-editor {
|
||||
padding: 4px 7px;
|
||||
@ -203,9 +204,11 @@
|
||||
background-color: #cccccc;
|
||||
}
|
||||
> i {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
&.disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@ -213,22 +216,118 @@
|
||||
margin-right: -5px;
|
||||
}
|
||||
}
|
||||
.el-dropdown {
|
||||
.el-tooltip.taskfont {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 0 5px;
|
||||
> i {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
}
|
||||
font-size: 20px;
|
||||
line-height: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-input-dropdown-menu {
|
||||
> li {
|
||||
|
||||
.chat-input-emoji-popover {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chat-input-more-popover {
|
||||
min-width: 100px;
|
||||
padding: 8px;
|
||||
.chat-input-popover-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
line-height: 36px;
|
||||
padding: 0 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background-color: #ecf5ff;
|
||||
}
|
||||
> i {
|
||||
font-size: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chat-emoji-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.chat-emoji-box {
|
||||
width: 360px;
|
||||
height: 280px;
|
||||
padding: 8px;
|
||||
overflow-x: hidden;
|
||||
word-break: break-all;
|
||||
box-sizing: content-box;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
|
||||
> li {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-size: 22px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: transform 0.3s;
|
||||
> img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
&:hover {
|
||||
transform: scale(1.4);
|
||||
}
|
||||
}
|
||||
|
||||
&.emoticon {
|
||||
> li {
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.chat-emoji-menu {
|
||||
width: 376px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
background-color: #f2f4f7;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
> li {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
|
||||
&.active {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
> span {
|
||||
padding: 0 13px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
> img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0 12px;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
opacity: .2;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
padding-right: 52px;
|
||||
}
|
||||
@ -48,6 +49,7 @@
|
||||
.dialog-avatar {
|
||||
flex-shrink: 0;
|
||||
margin-right: 12px;
|
||||
|
||||
.user-avatar,
|
||||
.icon-avatar {
|
||||
width: 42px;
|
||||
@ -56,6 +58,7 @@
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.icon-avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -64,9 +67,11 @@
|
||||
font-size: 26px;
|
||||
background-color: #61B2F9;
|
||||
color: #ffffff;
|
||||
|
||||
&.project {
|
||||
background-color: #6E99EB;
|
||||
}
|
||||
|
||||
&.task {
|
||||
background-color: #9B96DF;
|
||||
font-size: 24px;
|
||||
@ -226,7 +231,6 @@
|
||||
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 {
|
||||
@ -237,19 +241,30 @@
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
max-width: 220px;
|
||||
max-height: 220px;
|
||||
vertical-align: bottom;
|
||||
|
||||
&.emoticon {
|
||||
max-width: 150px;
|
||||
max-height: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
.mention {
|
||||
color: $flow-status-end-color;
|
||||
background-color: transparent;
|
||||
user-select: auto;
|
||||
margin-right: 0;
|
||||
|
||||
> span {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.task {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -553,6 +568,7 @@
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.chat-input-wrapper {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
@ -178,6 +178,8 @@
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
||||
|
||||
.common-avatar,
|
||||
.last-self {
|
||||
flex-shrink: 0;
|
||||
|
||||
BIN
resources/assets/statics/public/images/emoticon/01/01.gif
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/02.gif
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/03.gif
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/04.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/05.gif
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/06.gif
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/07.gif
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/08.gif
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/09.gif
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/10.gif
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/11.gif
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/12.gif
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/13.gif
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/14.gif
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/15.gif
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/16.gif
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/17.gif
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/18.gif
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/19.gif
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/20.gif
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/21.gif
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/22.gif
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/23.gif
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/24.gif
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
resources/assets/statics/public/images/emoticon/01/icon.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/01.gif
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/02.gif
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/03.gif
Normal file
|
After Width: | Height: | Size: 262 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/04.gif
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/05.gif
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/06.gif
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/07.gif
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/08.gif
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/09.gif
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/10.gif
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/11.gif
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/12.gif
Normal file
|
After Width: | Height: | Size: 295 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/13.gif
Normal file
|
After Width: | Height: | Size: 415 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/14.gif
Normal file
|
After Width: | Height: | Size: 277 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/15.gif
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/16.gif
Normal file
|
After Width: | Height: | Size: 203 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/17.gif
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/18.gif
Normal file
|
After Width: | Height: | Size: 350 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/19.gif
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/20.gif
Normal file
|
After Width: | Height: | Size: 375 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/21.gif
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/22.gif
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/23.gif
Normal file
|
After Width: | Height: | Size: 415 KiB |
BIN
resources/assets/statics/public/images/emoticon/02/icon.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/01.gif
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/02.gif
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/03.gif
Normal file
|
After Width: | Height: | Size: 44 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/04.gif
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/05.gif
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/06.gif
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/07.gif
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/08.gif
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/09.gif
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/10.gif
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/11.gif
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/12.gif
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/13.gif
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/14.gif
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/15.gif
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/16.gif
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/17.gif
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/18.gif
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/19.gif
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/20.gif
Normal file
|
After Width: | Height: | Size: 88 KiB |
BIN
resources/assets/statics/public/images/emoticon/03/icon.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/01.gif
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/02.gif
Normal file
|
After Width: | Height: | Size: 144 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/03.gif
Normal file
|
After Width: | Height: | Size: 217 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/04.gif
Normal file
|
After Width: | Height: | Size: 150 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/05.gif
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/06.gif
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/07.gif
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/08.gif
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/09.gif
Normal file
|
After Width: | Height: | Size: 181 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/10.gif
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/11.gif
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/12.gif
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/13.gif
Normal file
|
After Width: | Height: | Size: 111 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/14.gif
Normal file
|
After Width: | Height: | Size: 202 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/15.gif
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/16.gif
Normal file
|
After Width: | Height: | Size: 288 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/17.gif
Normal file
|
After Width: | Height: | Size: 186 KiB |
BIN
resources/assets/statics/public/images/emoticon/04/18.gif
Normal file
|
After Width: | Height: | Size: 88 KiB |