明树Git Lab
Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
J
jt_front
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
jt_front
Commits
9bb75707
Commit
9bb75707
authored
May 18, 2026
by
zhanghan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
消息模块完成
parent
d2c0f73b
Pipeline
#111532
passed with stage
in 20 seconds
Changes
4
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
787 additions
and
9 deletions
+787
-9
MainLayout.vue
src/layouts/MainLayout.vue
+5
-8
routes.js
src/router/routes.js
+1
-1
message.js
src/stores/message.js
+19
-0
newMessage.vue
src/views/systemManage/newMessage.vue
+762
-0
No files found.
src/layouts/MainLayout.vue
View file @
9bb75707
...
@@ -82,12 +82,14 @@
...
@@ -82,12 +82,14 @@
import
{
computed
,
ref
,
onMounted
,
getCurrentInstance
,
watch
}
from
"vue"
;
import
{
computed
,
ref
,
onMounted
,
getCurrentInstance
,
watch
}
from
"vue"
;
import
{
useRouter
,
useRoute
}
from
"vue-router"
;
import
{
useRouter
,
useRoute
}
from
"vue-router"
;
import
{
useUserStore
}
from
"@/stores/user.js"
;
import
{
useUserStore
}
from
"@/stores/user.js"
;
import
{
useMessageStore
}
from
"@/stores/message.js"
;
import
windowConfig
from
"@/window"
;
import
windowConfig
from
"@/window"
;
import
LeftMenu
from
"./leftMenu.vue"
;
import
LeftMenu
from
"./leftMenu.vue"
;
import
axios
from
"axios"
;
import
axios
from
"axios"
;
import
{
Bell
,
Avatar
,
ArrowUp
,
ArrowDown
}
from
"@element-plus/icons-vue"
;
// 补充导入图标
import
{
Bell
,
Avatar
,
ArrowUp
,
ArrowDown
}
from
"@element-plus/icons-vue"
;
const
userStore
=
useUserStore
();
const
userStore
=
useUserStore
();
const
messageStore
=
useMessageStore
();
const
proxyRef
=
ref
(
null
);
const
proxyRef
=
ref
(
null
);
const
{
proxy
}
=
getCurrentInstance
();
const
{
proxy
}
=
getCurrentInstance
();
const
excludeTabs
=
[
"/homePage"
];
const
excludeTabs
=
[
"/homePage"
];
...
@@ -223,14 +225,9 @@ const getResourceData = () => {
...
@@ -223,14 +225,9 @@ const getResourceData = () => {
};
};
// 获取未读消息数量
// 获取未读消息数量
let
messageCount
=
ref
(
0
);
const
messageCount
=
computed
(()
=>
messageStore
.
messageCount
);
const
getMessageCount
=
()
=>
{
const
getMessageCount
=
()
=>
{
axios
messageStore
.
fetchMessageCount
();
.
post
(
windowConfig
.
baseUrl
+
"/api/message/getMesCount"
,
{})
.
then
((
res
)
=>
{
messageCount
.
value
=
res
.
data
.
count
||
0
;
// 增加默认值
})
.
catch
((
err
)
=>
console
.
error
(
"获取消息数量失败:"
,
err
));
// 增加错误处理
};
};
// 跳转消息列表页
// 跳转消息列表页
...
...
src/router/routes.js
View file @
9bb75707
...
@@ -26,7 +26,7 @@ const routes = [
...
@@ -26,7 +26,7 @@ const routes = [
name
:
"message"
,
name
:
"message"
,
title
:
"消息中心"
,
title
:
"消息中心"
,
meta
:
{
title
:
"消息中心"
},
meta
:
{
title
:
"消息中心"
},
component
:
()
=>
import
(
"@/views/systemManage/
m
essage.vue"
),
component
:
()
=>
import
(
"@/views/systemManage/
newM
essage.vue"
),
},
},
{
{
path
:
"/homePage"
,
path
:
"/homePage"
,
...
...
src/stores/message.js
0 → 100644
View file @
9bb75707
import
{
defineStore
}
from
"pinia"
;
import
axios
from
"axios"
;
import
windowConfig
from
"@/window"
;
export
const
useMessageStore
=
defineStore
(
"message"
,
{
state
:
()
=>
({
messageCount
:
0
,
}),
actions
:
{
fetchMessageCount
()
{
axios
.
post
(
windowConfig
.
baseUrl
+
"/api/message/getMesCount"
,
{})
.
then
((
res
)
=>
{
this
.
messageCount
=
res
.
data
.
count
||
0
;
})
.
catch
(()
=>
{});
},
},
});
src/views/systemManage/newMessage.vue
0 → 100644
View file @
9bb75707
<
template
>
<div
class=
"manage-container"
>
<div
class=
"manage-wrap message-page"
>
<!-- 分类卡片 -->
<div
class=
"message-cards"
v-loading=
"loading"
>
<div
v-for=
"card in categoryCards"
:key=
"card.key"
class=
"message-card"
:class=
"
{ 'is-active': activeKey === card.key }"
:style="{ '--card-color': card.color, '--card-bg': card.bg }"
@click="activeKey = card.key"
>
<div
class=
"card-icon-wrap"
>
<el-icon
:size=
"26"
><component
:is=
"card.icon"
/></el-icon>
</div>
<div
class=
"card-info"
>
<div
class=
"card-name"
>
{{
card
.
name
}}
</div>
<div
class=
"card-nums"
>
<span
class=
"card-total"
>
{{
card
.
total
}}
条
</span>
<span
class=
"card-divider"
>
/
</span>
<span
class=
"card-unread"
v-if=
"card.unread > 0"
>
{{
card
.
unread
}}
条未读
</span
>
<span
class=
"card-read"
v-else
>
全部已读
</span>
</div>
</div>
<div
class=
"card-badge"
v-if=
"card.unread > 0"
>
{{
card
.
unread
}}
</div>
</div>
</div>
<!-- 下方左右两栏 -->
<div
class=
"message-panels"
>
<!-- 左侧:最近消息时间线 -->
<div
class=
"panel panel-recent"
>
<div
class=
"panel-header"
>
<span
class=
"panel-title"
>
最近消息
</span>
</div>
<div
class=
"panel-body"
>
<div
v-if=
"recentMessages.length === 0"
class=
"panel-empty"
>
暂无消息
</div>
<div
v-for=
"(msg, idx) in recentMessages"
:key=
"msg.id"
class=
"recent-item"
@
click=
"handlePreview(msg)"
>
<div
class=
"recent-dot-line"
>
<span
class=
"recent-dot"
:class=
"
{ 'dot-unread': !msg.isRead }"
:style="{ '--dot-color': getTypeColor(msg.type) }"
>
</span>
<span
class=
"recent-line"
v-if=
"idx
<
recentMessages
.
length
-
1
"
></span>
</div>
<div
class=
"recent-content"
>
<div
class=
"recent-top"
>
<span
class=
"recent-title"
:class=
"
{ 'is-unread': !msg.isRead }"
>
{{
msg
.
title
}}
</span
>
<el-tag
:type=
"getTypeTagColor(msg.type)"
size=
"small"
effect=
"light"
disable-transitions
>
{{
getTypeName
(
msg
.
type
)
}}
</el-tag>
</div>
<div
class=
"recent-bottom"
>
<span
class=
"recent-time"
>
{{
relativeTime
(
msg
.
createdAt
)
}}
</span>
<el-tag
v-if=
"!msg.isRead"
type=
"danger"
size=
"small"
effect=
"plain"
disable-transitions
>
未读
</el-tag
>
</div>
</div>
</div>
</div>
</div>
<!-- 右侧:分类列表 -->
<div
class=
"panel panel-list"
>
<div
class=
"panel-header"
>
<span
class=
"panel-title"
>
{{
currentCard
.
name
}}
</span>
<span
class=
"panel-count"
>
共
{{
filteredMessages
.
length
}}
条
</span>
</div>
<div
class=
"panel-body panel-body-table"
>
<el-table
:data=
"filteredMessages"
style=
"width: 100%"
:header-cell-style=
"
{
background: '#fafafa',
color: '#333',
fontWeight: 600,
}"
empty-text="暂无消息"
:row-class-name="tableRowClass"
@row-click="handlePreview"
class="message-table"
>
<el-table-column
label=
"标题"
min-width=
"280px"
show-overflow-tooltip
>
<template
#
default=
"
{ row }">
<div
class=
"msg-title-cell"
>
<span
class=
"unread-dot"
v-if=
"!row.isRead"
></span>
<span
class=
"read-dot"
v-else
></span>
<span
class=
"msg-title-text"
:class=
"
{ 'is-unread': !row.isRead }"
>
{{
row
.
title
}}
</span
>
</div>
</
template
>
</el-table-column>
<el-table-column
label=
"类型"
width=
"140"
align=
"center"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"getTypeTagColor(row.type)"
size=
"small"
effect=
"light"
disable-transitions
>
{{
getTypeName
(
row
.
type
)
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"状态"
width=
"80"
align=
"center"
>
<
template
#
default=
"{ row }"
>
<el-tag
:type=
"row.isRead ? 'info' : 'danger'"
size=
"small"
effect=
"plain"
disable-transitions
>
{{
row
.
isRead
?
"已读"
:
"未读"
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"时间"
width=
"220"
align=
"center"
>
<
template
#
default=
"{ row }"
>
{{
formatTime
(
row
.
createdAt
)
}}
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"120"
align=
"center"
fixed=
"right"
>
<
template
#
default=
"{ row }"
>
<el-button
link
type=
"primary"
size=
"small"
@
click
.
stop=
"handlePreview(row)"
>
查看
</el-button
>
<el-button
link
type=
"primary"
size=
"small"
@
click
.
stop=
"handleDelete(row)"
>
删除
</el-button
>
</
template
>
</el-table-column>
</el-table>
</div>
</div>
</div>
<!-- 消息详情弹窗 -->
<el-dialog
v-model=
"detailDialogVisible"
width=
"560"
align-center
:close-on-click-modal=
"false"
@
close=
"closeDetail"
>
<
template
#
header
>
<div
class=
"msg-dialog-header"
>
<el-tag
:type=
"getTypeTagColor(messageInfo.type)"
size=
"small"
effect=
"light"
disable-transitions
>
{{
getTypeName
(
messageInfo
.
type
)
}}
</el-tag>
<span
class=
"msg-dialog-time"
>
{{
formatTime
(
messageInfo
.
createdAt
)
}}
</span>
</div>
</
template
>
<div
class=
"msg-dialog-body"
>
<h3
class=
"msg-dialog-title"
>
{{ messageInfo.title }}
</h3>
<div
class=
"msg-dialog-content"
>
{{ messageInfo.content }}
</div>
</div>
<
template
#
footer
>
<el-button
@
click=
"closeDetail"
>
关闭
</el-button>
<el-button
type=
"primary"
@
click=
"toProjectPage"
>
去处理
</el-button>
</
template
>
</el-dialog>
</div>
</div>
</template>
<
script
setup
>
import
{
ref
,
onMounted
,
getCurrentInstance
,
computed
}
from
"vue"
;
import
{
ElMessage
,
ElMessageBox
}
from
"element-plus"
;
import
{
Message
,
Bell
,
Edit
,
Stamp
}
from
"@element-plus/icons-vue"
;
import
{
useRouter
}
from
"vue-router"
;
import
{
useMessageStore
}
from
"@/stores/message.js"
;
const
router
=
useRouter
();
const
{
proxy
}
=
getCurrentInstance
();
const
messageStore
=
useMessageStore
();
const
loading
=
ref
(
false
);
const
allMessages
=
ref
([]);
const
activeKey
=
ref
(
"all"
);
const
getTypeName
=
(
type
)
=>
{
if
(
type
===
2
)
return
"项目初步审核"
;
if
(
type
===
3
)
return
"项目终审"
;
return
"系统消息"
;
};
const
getTypeTagColor
=
(
type
)
=>
{
if
(
type
===
2
)
return
"warning"
;
if
(
type
===
3
)
return
"danger"
;
return
"success"
;
};
const
getTypeColor
=
(
type
)
=>
{
if
(
type
===
2
)
return
"#e6a23c"
;
if
(
type
===
3
)
return
"#f56c6c"
;
return
"#67c23a"
;
};
const
formatTime
=
(
time
)
=>
{
if
(
!
time
)
return
""
;
return
proxy
.
moment
(
time
).
format
(
"YYYY-MM-DD HH:mm:ss"
);
};
const
relativeTime
=
(
time
)
=>
{
if
(
!
time
)
return
""
;
const
m
=
proxy
.
moment
(
time
);
const
now
=
proxy
.
moment
();
const
diffMin
=
now
.
diff
(
m
,
"minutes"
);
if
(
diffMin
<
1
)
return
"刚刚"
;
if
(
diffMin
<
60
)
return
diffMin
+
" 分钟前"
;
const
diffHour
=
now
.
diff
(
m
,
"hours"
);
if
(
diffHour
<
24
)
return
diffHour
+
" 小时前"
;
const
diffDay
=
now
.
diff
(
m
,
"days"
);
if
(
diffDay
<
7
)
return
diffDay
+
" 天前"
;
return
m
.
format
(
"MM-DD HH:mm"
);
};
// 分类定义
const
categoryCards
=
computed
(()
=>
{
const
msgs
=
allMessages
.
value
;
const
sys
=
msgs
.
filter
((
m
)
=>
m
.
type
!==
2
&&
m
.
type
!==
3
);
const
chubu
=
msgs
.
filter
((
m
)
=>
m
.
type
===
2
);
const
zhongshen
=
msgs
.
filter
((
m
)
=>
m
.
type
===
3
);
return
[
{
key
:
"all"
,
name
:
"全部消息"
,
icon
:
Message
,
color
:
"#409eff"
,
bg
:
"rgba(64,158,255,0.06)"
,
total
:
msgs
.
length
,
unread
:
msgs
.
filter
((
m
)
=>
!
m
.
isRead
).
length
,
},
{
key
:
"system"
,
name
:
"系统消息"
,
icon
:
Bell
,
color
:
"#67c23a"
,
bg
:
"rgba(103,194,58,0.06)"
,
total
:
sys
.
length
,
unread
:
sys
.
filter
((
m
)
=>
!
m
.
isRead
).
length
,
},
{
key
:
"chubu"
,
name
:
"项目初步审核"
,
icon
:
Edit
,
color
:
"#e6a23c"
,
bg
:
"rgba(230,162,60,0.06)"
,
total
:
chubu
.
length
,
unread
:
chubu
.
filter
((
m
)
=>
!
m
.
isRead
).
length
,
},
{
key
:
"zhongshen"
,
name
:
"项目终审"
,
icon
:
Stamp
,
color
:
"#f56c6c"
,
bg
:
"rgba(245,108,108,0.06)"
,
total
:
zhongshen
.
length
,
unread
:
zhongshen
.
filter
((
m
)
=>
!
m
.
isRead
).
length
,
},
];
});
const
currentCard
=
computed
(()
=>
{
return
(
categoryCards
.
value
.
find
((
c
)
=>
c
.
key
===
activeKey
.
value
)
||
categoryCards
.
value
[
0
]
);
});
const
filteredMessages
=
computed
(()
=>
{
const
msgs
=
allMessages
.
value
;
if
(
activeKey
.
value
===
"all"
)
return
msgs
;
if
(
activeKey
.
value
===
"system"
)
return
msgs
.
filter
((
m
)
=>
m
.
type
!==
2
&&
m
.
type
!==
3
);
if
(
activeKey
.
value
===
"chubu"
)
return
msgs
.
filter
((
m
)
=>
m
.
type
===
2
);
if
(
activeKey
.
value
===
"zhongshen"
)
return
msgs
.
filter
((
m
)
=>
m
.
type
===
3
);
return
msgs
;
});
const
recentMessages
=
computed
(()
=>
{
return
[...
filteredMessages
.
value
]
.
sort
((
a
,
b
)
=>
new
Date
(
b
.
createdAt
)
-
new
Date
(
a
.
createdAt
))
.
slice
(
0
,
10
);
});
const
tableRowClass
=
({
row
})
=>
{
return
row
.
isRead
?
"row-read"
:
"row-unread"
;
};
// 数据加载
const
loadAllMessages
=
()
=>
{
loading
.
value
=
true
;
proxy
.
$post
({
url
:
"/api/message/getUserMessages"
,
data
:
{
page
:
1
,
pageSize
:
9999
},
callback
:
(
data
)
=>
{
allMessages
.
value
=
data
.
rows
||
[];
loading
.
value
=
false
;
},
error
:
()
=>
{
loading
.
value
=
false
;
ElMessage
.
error
(
"加载数据失败"
);
},
});
};
onMounted
(()
=>
{
loadAllMessages
();
});
// 消息详情
const
detailDialogVisible
=
ref
(
false
);
const
messageInfo
=
ref
({});
const
handlePreview
=
(
row
)
=>
{
proxy
.
$post
({
url
:
"/api/message/getMessageInfo"
,
data
:
{
id
:
row
.
id
},
callback
:
(
data
)
=>
{
detailDialogVisible
.
value
=
true
;
messageInfo
.
value
=
data
;
if
(
!
row
.
isRead
)
{
row
.
isRead
=
true
;
messageStore
.
fetchMessageCount
();
}
},
error
:
()
=>
{
ElMessage
.
error
(
"加载数据失败"
);
},
});
};
const
closeDetail
=
()
=>
{
messageInfo
.
value
=
{};
detailDialogVisible
.
value
=
false
;
};
const
toProjectPage
=
()
=>
{
router
.
push
({
name
:
"addProject"
,
query
:
{
projectId
:
messageInfo
.
value
.
projectId
,
isPreview
:
true
},
});
};
const
handleDelete
=
(
row
)
=>
{
ElMessageBox
.
confirm
(
"确定删除该条消息?"
,
"提示"
,
{
confirmButtonText
:
"确定"
,
cancelButtonText
:
"取消"
,
type
:
"warning"
,
}).
then
(()
=>
{
proxy
.
$post
({
url
:
"/api/message/deleteMessage"
,
data
:
{
id
:
row
.
id
},
callback
:
()
=>
{
ElMessage
.
success
(
"删除成功"
);
loadAllMessages
();
messageStore
.
fetchMessageCount
();
},
error
:
()
=>
{
ElMessage
.
error
(
"删除失败"
);
},
});
});
};
</
script
>
<
style
lang=
"less"
scoped
>
.message-page {
padding: 12px;
overflow-y: auto;
margin-bottom: 18px;
}
.message-page-header {
margin-bottom: 16px;
}
.message-page-title {
font-size: 18px;
font-weight: 600;
color: #1d2129;
}
/* ========== 分类卡片 ========== */
.message-cards {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 14px;
margin-bottom: 16px;
}
.message-card {
position: relative;
background: #fff;
border-radius: 8px;
padding: 18px 16px;
display: flex;
align-items: center;
gap: 14px;
cursor: pointer;
transition: all 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
border: 2px solid transparent;
user-select: none;
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
&.is-active {
border-color: var(--card-color);
background: var(--card-bg);
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.08);
}
}
.card-icon-wrap {
width: 48px;
height: 48px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
background: var(--card-color);
color: #fff;
flex-shrink: 0;
}
.card-info {
flex: 1;
min-width: 0;
}
.card-name {
font-size: 14px;
font-weight: 600;
color: #1d2129;
margin-bottom: 4px;
}
.card-nums {
font-size: 12px;
color: #86909c;
display: flex;
align-items: center;
gap: 4px;
}
.card-divider {
color: #dcdfe6;
}
.card-unread {
color: #f56c6c;
font-weight: 500;
}
.card-read {
color: #67c23a;
}
.card-badge {
position: absolute;
top: 8px;
right: 10px;
min-width: 18px;
height: 18px;
line-height: 18px;
text-align: center;
padding: 0 5px;
border-radius: 9px;
background: #f56c6c;
color: #fff;
font-size: 11px;
font-weight: 500;
}
/* ========== 下方两栏 ========== */
.message-panels {
display: grid;
grid-template-columns: 340px 1fr;
gap: 14px;
flex: 1;
min-height: 0;
}
.panel {
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
display: flex;
flex-direction: column;
min-height: 0;
}
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 18px 12px;
border-bottom: 1px solid #f2f3f5;
flex-shrink: 0;
}
.panel-title {
font-size: 15px;
font-weight: 600;
color: #1d2129;
}
.panel-count {
font-size: 13px;
color: #86909c;
}
.panel-body {
flex: 1;
overflow-y: auto;
padding: 10px 18px 16px;
}
.panel-body-table {
padding: 0;
}
.panel-empty {
text-align: center;
color: #c0c4cc;
font-size: 14px;
padding: 48px 0;
}
/* 左侧时间线 */
.recent-item {
display: flex;
gap: 12px;
cursor: pointer;
&:hover .recent-title {
color: #409eff;
}
}
.recent-dot-line {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 6px;
width: 12px;
flex-shrink: 0;
}
.recent-dot {
width: 10px;
height: 10px;
min-height: 10px;
border-radius: 50%;
background: var(--dot-color, #dcdfe6);
flex-shrink: 0;
opacity: 0.45;
&.dot-unread {
opacity: 1;
box-shadow: 0 0 0 3px rgba(245, 108, 108, 0.15);
}
}
.recent-line {
width: 1px;
flex: 1;
background: #e8e8e8;
margin: 4px 0;
}
.recent-content {
flex: 1;
min-width: 0;
padding-bottom: 12px;
border-bottom: 1px solid #f7f7f7;
}
.recent-item:last-child .recent-content {
border-bottom: none;
padding-bottom: 0;
}
.recent-top {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 4px;
}
.recent-title {
flex: 1;
min-width: 0;
font-size: 13px;
color: #4e5969;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
transition: color 0.2s;
&.is-unread {
font-weight: 600;
color: #1d2129;
}
}
.recent-bottom {
display: flex;
align-items: center;
gap: 8px;
}
.recent-time {
font-size: 12px;
color: #c0c4cc;
}
/* 右侧表格 */
.message-table {
flex: 1;
}
:deep(.message-table) {
.el-table__row {
cursor: pointer;
transition: background 0.15s;
}
.row-unread td {
background: #f0f7ff !important;
}
.el-table__row:hover > td {
background: #ecf5ff !important;
}
}
.msg-title-cell {
display: flex;
align-items: center;
gap: 8px;
}
.unread-dot {
width: 8px;
height: 8px;
min-width: 8px;
border-radius: 50%;
background: #f56c6c;
}
.read-dot {
width: 8px;
height: 8px;
min-width: 8px;
border-radius: 50%;
background: #dcdfe6;
}
.msg-title-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.is-unread {
font-weight: 600;
color: #1d2129;
}
/* ========== 详情弹窗 ========== */
.msg-dialog-header {
display: flex;
align-items: center;
gap: 12px;
}
.msg-dialog-time {
font-size: 13px;
color: #86909c;
}
.msg-dialog-body {
padding: 4px 0 12px;
}
.msg-dialog-title {
font-size: 17px;
font-weight: 600;
color: #1d2129;
margin: 0 0 16px;
line-height: 1.5;
}
.msg-dialog-content {
font-size: 14px;
color: #4e5969;
line-height: 1.8;
background: #f7f8fa;
border-radius: 6px;
padding: 14px 16px;
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment