Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
safe-campus-bbs
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
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
万成波
safe-campus-bbs
Commits
dc7417ed
Commit
dc7417ed
authored
Sep 24, 2025
by
yuwenwen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
修改BUG,PC端添加表情展示
parent
e7445cb8
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
342 additions
and
50 deletions
+342
-50
safe-campus-bbs-ui/public/iconfont/iconfont.css
safe-campus-bbs-ui/public/iconfont/iconfont.css
+63
-0
safe-campus-bbs-ui/public/iconfont/iconfont.ttf
safe-campus-bbs-ui/public/iconfont/iconfont.ttf
+0
-0
safe-campus-bbs-ui/public/iconfont/iconfont.woff
safe-campus-bbs-ui/public/iconfont/iconfont.woff
+0
-0
safe-campus-bbs-ui/public/iconfont/iconfont.woff2
safe-campus-bbs-ui/public/iconfont/iconfont.woff2
+0
-0
safe-campus-bbs-ui/src/main.js
safe-campus-bbs-ui/src/main.js
+1
-0
safe-campus-bbs-ui/src/utils/emjo.js
safe-campus-bbs-ui/src/utils/emjo.js
+64
-0
safe-campus-bbs-ui/src/views/moments/DetailDialog.vue
safe-campus-bbs-ui/src/views/moments/DetailDialog.vue
+129
-42
safe-campus-bbs-ui/src/views/moments/index.vue
safe-campus-bbs-ui/src/views/moments/index.vue
+85
-8
No files found.
safe-campus-bbs-ui/public/iconfont/iconfont.css
0 → 100644
View file @
dc7417ed
@font-face
{
font-family
:
"iconfont"
;
/* Project id 5028537 */
src
:
url('iconfont.woff2?t=1758609551078')
format
(
'woff2'
),
url('iconfont.woff?t=1758609551078')
format
(
'woff'
),
url('iconfont.ttf?t=1758609551078')
format
(
'truetype'
);
}
.iconfont
{
font-family
:
"iconfont"
!important
;
font-size
:
40
rpx
;
font-style
:
normal
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
}
.icon-chijing
:before
{
content
:
"\e600"
;
}
.icon-dai
:before
{
content
:
"\e601"
;
}
.icon-mogui
:before
{
content
:
"\e602"
;
}
.icon-ganga
:before
{
content
:
"\e603"
;
}
.icon-qin
:before
{
content
:
"\e604"
;
}
.icon-nu
:before
{
content
:
"\e605"
;
}
.icon-shengqi
:before
{
content
:
"\e606"
;
}
.icon-ma
:before
{
content
:
"\e607"
;
}
.icon-bishi
:before
{
content
:
"\e608"
;
}
.icon-maimeng
:before
{
content
:
"\e609"
;
}
.icon-jingdai
:before
{
content
:
"\e60a"
;
}
.icon-kulian
:before
{
content
:
"\e60b"
;
}
safe-campus-bbs-ui/public/iconfont/iconfont.ttf
0 → 100644
View file @
dc7417ed
File added
safe-campus-bbs-ui/public/iconfont/iconfont.woff
0 → 100644
View file @
dc7417ed
File added
safe-campus-bbs-ui/public/iconfont/iconfont.woff2
0 → 100644
View file @
dc7417ed
File added
safe-campus-bbs-ui/src/main.js
View file @
dc7417ed
...
@@ -7,6 +7,7 @@ import './assets/styles/element-variables.scss'
...
@@ -7,6 +7,7 @@ import './assets/styles/element-variables.scss'
import
'
@/assets/styles/index.scss
'
// global css
import
'
@/assets/styles/index.scss
'
// global css
import
'
@/assets/styles/ruoyi.scss
'
// ruoyi css
import
'
@/assets/styles/ruoyi.scss
'
// ruoyi css
import
'
../public/iconfont/iconfont.css
'
import
App
from
'
./App
'
import
App
from
'
./App
'
import
store
from
'
./store
'
import
store
from
'
./store
'
import
router
from
'
./router
'
import
router
from
'
./router
'
...
...
safe-campus-bbs-ui/src/utils/emjo.js
0 → 100644
View file @
dc7417ed
const
emotions
=
[{
code
:
'
icon-chijing
'
,
name
:
'
吃惊
'
,
symbol
:
'
[吃惊]
'
},
{
code
:
'
icon-dai
'
,
name
:
'
呆
'
,
symbol
:
'
[呆]
'
},
{
code
:
'
icon-mogui
'
,
name
:
'
魔鬼
'
,
symbol
:
'
[魔鬼]
'
},
{
code
:
'
icon-ganga
'
,
name
:
'
尴尬
'
,
symbol
:
'
[尴尬]
'
},
{
code
:
'
icon-qin
'
,
name
:
'
亲
'
,
symbol
:
'
[亲]
'
},
{
code
:
'
icon-nu
'
,
name
:
'
怒
'
,
symbol
:
'
[怒]
'
},
{
code
:
'
icon-shengqi
'
,
name
:
'
生气
'
,
symbol
:
'
[生气]
'
},
{
code
:
'
icon-ma
'
,
name
:
'
骂
'
,
symbol
:
'
[骂]
'
},
{
code
:
'
icon-bishi
'
,
name
:
'
鄙视
'
,
symbol
:
'
[鄙视]
'
},
{
code
:
'
icon-maimeng
'
,
name
:
'
卖萌
'
,
symbol
:
'
[卖萌]
'
},
{
code
:
'
icon-jingdai
'
,
name
:
'
惊呆
'
,
symbol
:
'
[惊呆]
'
},
{
code
:
'
icon-kulian
'
,
name
:
'
哭脸
'
,
symbol
:
'
[哭脸]
'
},
]
export
default
emotions
;
\ No newline at end of file
safe-campus-bbs-ui/src/views/moments/DetailDialog.vue
View file @
dc7417ed
...
@@ -12,7 +12,7 @@
...
@@ -12,7 +12,7 @@
</
template
>
</
template
>
</div>
</div>
<div
class=
"dynamic-content-box"
>
<div
class=
"dynamic-content-box"
>
<div
class=
"text"
>
{{ form.content }}
</div>
<div
class=
"text"
v-html=
"formatContent(form.content)"
>
</div>
<div
class=
"imgs"
v-if=
"form.type == 'IMAGE' && form.attachments && form.attachments.length > 0"
>
<div
class=
"imgs"
v-if=
"form.type == 'IMAGE' && form.attachments && form.attachments.length > 0"
>
<
template
v-for=
"(item, index) in form.attachments"
>
<
template
v-for=
"(item, index) in form.attachments"
>
<el-image
class=
"item"
:src=
"item.url"
:preview-src-list=
"[item.url]"
></el-image>
<el-image
class=
"item"
:src=
"item.url"
:preview-src-list=
"[item.url]"
></el-image>
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
<img
src=
"@/assets/images/favorite-active.png"
v-if=
"form.isLike == 1"
class=
"icon"
></img>
<img
src=
"@/assets/images/favorite-active.png"
v-if=
"form.isLike == 1"
class=
"icon"
></img>
<div
class=
"num"
>
{{ form.likeCount }}
</div>
<div
class=
"num"
>
{{ form.likeCount }}
</div>
</div>
</div>
<div
class=
"comment-box"
>
<div
class=
"comment-box"
style=
"border-top: 0;"
>
<img
class=
"icon"
src=
"@/assets/images/comment-icon.png"
></img>
<img
class=
"icon"
src=
"@/assets/images/comment-icon.png"
></img>
<div
class=
"text"
>
评论
</div>
<div
class=
"text"
>
评论
</div>
</div>
</div>
...
@@ -63,18 +63,18 @@
...
@@ -63,18 +63,18 @@
<div
class=
"datetime"
>
{{ item.createTime }}
</div>
<div
class=
"datetime"
>
{{ item.createTime }}
</div>
</div>
</div>
<div
class=
"content"
>
<div
class=
"content"
>
<div
class=
"text"
v-if=
"!item.replyNickName"
>
<div
class=
"text"
v-if=
"!item.replyNickName"
>
{{item.content
}}
{{ item.content
}}
</div>
</div>
<div
class=
"text"
v-else
>
<div
class=
"text"
v-else
>
回复
<span
style=
"color: #0058B6;"
>
{{item.replyNickName}}:
</span>
{{item.content
}}
回复
<span
style=
"color: #0058B6;"
>
{{ item.replyNickName }}:
</span>
{{ item.content
}}
</div>
</div>
<div
class=
"operation-text"
>
<div
class=
"operation-text"
>
<div
v-if=
"item.isFeatured==
1"
style=
"color: #F2AC39;margin-right: 10rpx;"
>
精选
</div>
<div
v-if=
"item.isFeatured ==
1"
style=
"color: #F2AC39;margin-right: 10rpx;"
>
精选
</div>
<div
v-if=
"item.isSelf==1"
@
click.stop=
"handleDelete(item)"
>
删除
</div>
<div
@
click.stop=
"handleDelete(item)"
>
删除
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class=
"show-more-box"
v-if=
"commentList.length < total"
@
click=
"loadMore"
>
<div
class=
"show-more-box"
v-if=
"commentList.length < total"
@
click=
"loadMore"
>
加载更多
加载更多
...
@@ -86,6 +86,8 @@
...
@@ -86,6 +86,8 @@
</template>
</template>
<
script
>
<
script
>
import
{
detailData
,
getMomentComments
}
from
'
@/api/moments
'
import
{
detailData
,
getMomentComments
}
from
'
@/api/moments
'
import
{
delData
}
from
'
@/api/comment
'
;
import
emotions
from
'
@/utils/emjo
'
;
export
default
{
export
default
{
data
()
{
data
()
{
return
{
return
{
...
@@ -97,14 +99,21 @@ export default {
...
@@ -97,14 +99,21 @@ export default {
},
},
commentList
:
[],
commentList
:
[],
total
:
0
,
total
:
0
,
currentRow
:{}
currentRow
:
{},
emotions
,
// 预创建表情符号到iconfont的映射表,提高性能
emotionMap
:
{}
}
}
},
},
methods
:
{
methods
:
{
openModal
(
row
)
{
openModal
(
row
)
{
this
.
visible
=
true
;
this
.
visible
=
true
;
this
.
currentRow
=
{
...
row
}
this
.
currentRow
=
{
...
row
}
this
.
queryParams
.
pageNum
=
1
;
this
.
queryParams
.
pageNum
=
1
;
// 初始化表情映射表
this
.
emotions
.
forEach
(
emotion
=>
{
this
.
emotionMap
[
emotion
.
symbol
]
=
emotion
.
code
;
});
this
.
commentList
=
[];
this
.
commentList
=
[];
this
.
getData
();
this
.
getData
();
this
.
getComments
()
this
.
getComments
()
...
@@ -128,9 +137,83 @@ export default {
...
@@ -128,9 +137,83 @@ export default {
this
.
queryParams
.
pageNum
+=
1
;
this
.
queryParams
.
pageNum
+=
1
;
this
.
getComments
()
this
.
getComments
()
},
},
// 删除评论
// 删除
handleDelete
(){
handleDelete
(
row
)
{
this
.
$modal
.
confirm
(
'
确认要删除评论内容为:
'
+
row
.
content
+
'
的数据吗?
'
).
then
(
function
()
{
return
delData
(
row
.
id
);
}).
then
(()
=>
{
this
.
$modal
.
msgSuccess
(
"
删除成功
"
);
this
.
commentList
=
[];
this
.
getComments
()
this
.
$emit
(
'
refresh
'
)
})
},
/**
* 将内容中的表情符号转换为iconfont标签
* @param {string} content - 原始内容
* @returns {string} 转换后的HTML字符串
*/
formatContent
(
content
)
{
if
(
!
content
)
return
''
;
let
result
=
''
;
let
remainingContent
=
content
;
// 提取所有表情符号并按长度排序(长表情优先匹配)
const
emotionSymbols
=
Object
.
keys
(
this
.
emotionMap
).
sort
((
a
,
b
)
=>
b
.
length
-
a
.
length
);
while
(
remainingContent
.
length
>
0
)
{
let
found
=
false
;
// 查找是否有表情符号
for
(
const
symbol
of
emotionSymbols
)
{
if
(
remainingContent
.
startsWith
(
symbol
))
{
// 添加表情标签
result
+=
`<i class="iconfont
${
this
.
emotionMap
[
symbol
]}
emotion-icon"></i>`
;
remainingContent
=
remainingContent
.
slice
(
symbol
.
length
);
found
=
true
;
break
;
}
}
// 如果没有找到表情,提取普通文本
if
(
!
found
)
{
// 找到下一个表情的位置
let
nextEmotionIndex
=
remainingContent
.
length
;
for
(
const
symbol
of
emotionSymbols
)
{
const
index
=
remainingContent
.
indexOf
(
symbol
);
if
(
index
!==
-
1
&&
index
<
nextEmotionIndex
)
{
nextEmotionIndex
=
index
;
}
}
// 提取文本并进行HTML转义,防止XSS
const
text
=
this
.
escapeHtml
(
remainingContent
.
slice
(
0
,
nextEmotionIndex
));
result
+=
text
;
remainingContent
=
remainingContent
.
slice
(
nextEmotionIndex
);
}
}
return
result
;
},
/**
* HTML转义处理,防止XSS攻击
* @param {string} str - 需要转义的字符串
* @returns {string} 转义后的字符串
*/
escapeHtml
(
str
)
{
if
(
!
str
)
return
''
;
return
str
.
replace
(
/
[
&<>"'
]
/g
,
char
=>
{
const
entities
=
{
'
&
'
:
'
&
'
,
'
<
'
:
'
<
'
,
'
>
'
:
'
>
'
,
'
"
'
:
'
"
'
,
"
'
"
:
'
'
'
};
return
entities
[
char
]
||
char
;
});
}
}
}
}
...
@@ -369,29 +452,33 @@ export default {
...
@@ -369,29 +452,33 @@ export default {
}
}
}
}
.content
{
.content
{
color
:
black
;
color
:
black
;
margin
:
5px
0
;
margin
:
5px
0
;
display
:
flex
;
display
:
flex
;
.text
{
width
:
calc
(
100%
-
90px
);
.text
{
}
width
:
calc
(
100%
-
90px
);
}
.operation-text
{
width
:
90px
;
.operation-text
{
text-align
:
right
;
width
:
90px
;
font-size
:
12px
;
text-align
:
right
;
display
:
flex
;
font-size
:
12px
;
align-items
:
center
;
display
:
flex
;
justify-content
:
flex-end
;
align-items
:
center
;
}
justify-content
:
flex-end
;
.mr10
{
cursor
:
pointer
;
margin-right
:
6px
;
}
}
.add-text
{
.mr10
{
color
:
#0058B6
;
margin-right
:
6px
;
}
}
}
.add-text
{
color
:
#0058B6
;
}
}
.tips
{
.tips
{
font-size
:
12px
;
font-size
:
12px
;
...
...
safe-campus-bbs-ui/src/views/moments/index.vue
View file @
dc7417ed
...
@@ -8,8 +8,8 @@
...
@@ -8,8 +8,8 @@
</el-form-item>
</el-form-item>
<el-form-item
label=
"创建时间"
>
<el-form-item
label=
"创建时间"
>
<el-date-picker
placeholder=
"请选择"
type=
"daterange"
format=
"yyyy-MM-dd"
value-format=
"yyyy-MM-dd"
<el-date-picker
placeholder=
"请选择"
type=
"daterange"
format=
"yyyy-MM-dd"
value-format=
"yyyy-MM-dd"
v-model=
"dateRange"
range-separator=
"至"
start-placeholder=
"开始时间"
v-model=
"dateRange"
range-separator=
"至"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
end-placeholder=
"结束时间"
@
change=
"dateChange"
></el-date-picker>
@
change=
"dateChange"
></el-date-picker>
</el-form-item>
</el-form-item>
<el-form-item>
<el-form-item>
<el-button
type=
"primary"
@
click=
"handleQuery"
>
查询
</el-button>
<el-button
type=
"primary"
@
click=
"handleQuery"
>
查询
</el-button>
...
@@ -21,7 +21,11 @@
...
@@ -21,7 +21,11 @@
</el-row>
</el-row>
<el-table
:data=
"tableList"
>
<el-table
:data=
"tableList"
>
<el-table-column
label=
"序号"
width=
"55"
type=
"index"
align=
"center"
></el-table-column>
<el-table-column
label=
"序号"
width=
"55"
type=
"index"
align=
"center"
></el-table-column>
<el-table-column
label=
"动态内容"
prop=
"content"
align=
"center"
></el-table-column>
<el-table-column
label=
"动态内容"
prop=
"content"
align=
"center"
>
<template
#default
="
{ row }">
<div
v-html=
"formatContent(row.content)"
class=
"content-container"
></div>
</
template
>
</el-table-column>
<el-table-column
label=
"话题"
align=
"center"
prop=
"topicNames"
width=
"240"
></el-table-column>
<el-table-column
label=
"话题"
align=
"center"
prop=
"topicNames"
width=
"240"
></el-table-column>
<el-table-column
label=
"帐号"
prop=
"userName"
align=
"center"
width=
"140"
></el-table-column>
<el-table-column
label=
"帐号"
prop=
"userName"
align=
"center"
width=
"140"
></el-table-column>
<el-table-column
label=
"姓名"
prop=
"nickName"
align=
"center"
width=
"120"
></el-table-column>
<el-table-column
label=
"姓名"
prop=
"nickName"
align=
"center"
width=
"120"
></el-table-column>
...
@@ -39,13 +43,14 @@
...
@@ -39,13 +43,14 @@
:limit.sync=
"queryParams.pageSize"
@
pagination=
"getList"
/>
:limit.sync=
"queryParams.pageSize"
@
pagination=
"getList"
/>
</div>
</div>
<!-- 动态详情 -->
<!-- 动态详情 -->
<detail-dialog
ref=
"detailDialogRef"
></detail-dialog>
<detail-dialog
ref=
"detailDialogRef"
@
refresh=
"getList"
></detail-dialog>
</div>
</div>
</template>
</template>
<
script
>
<
script
>
import
{
listData
,
delData
}
from
'
@/api/moments
'
;
import
{
listData
,
delData
}
from
'
@/api/moments
'
;
import
DetailDialog
from
'
./DetailDialog.vue
'
;
import
DetailDialog
from
'
./DetailDialog.vue
'
;
import
emotions
from
'
@/utils/emjo
'
;
export
default
{
export
default
{
name
:
'
Moments
'
,
name
:
'
Moments
'
,
data
()
{
data
()
{
...
@@ -57,13 +62,19 @@ export default {
...
@@ -57,13 +62,19 @@ export default {
tableList
:
[],
tableList
:
[],
total
:
0
,
total
:
0
,
dateRange
:
[],
dateRange
:
[],
emotions
,
// 预创建表情符号到iconfont的映射表,提高性能
emotionMap
:
{}
}
}
},
},
components
:
{
components
:
{
DetailDialog
DetailDialog
},
},
created
()
{
created
()
{
// 初始化表情映射表
this
.
emotions
.
forEach
(
emotion
=>
{
this
.
emotionMap
[
emotion
.
symbol
]
=
emotion
.
code
;
});
},
},
mounted
()
{
mounted
()
{
this
.
getList
()
this
.
getList
()
...
@@ -77,7 +88,6 @@ export default {
...
@@ -77,7 +88,6 @@ export default {
this
.
total
=
res
.
total
this
.
total
=
res
.
total
})
})
},
},
// 新增
// 新增
handleDetail
(
row
)
{
handleDetail
(
row
)
{
this
.
$refs
.
detailDialogRef
.
openModal
(
row
)
this
.
$refs
.
detailDialogRef
.
openModal
(
row
)
...
@@ -91,8 +101,8 @@ export default {
...
@@ -91,8 +101,8 @@ export default {
this
.
getList
()
this
.
getList
()
})
})
},
},
dateChange
(
val
){
dateChange
(
val
)
{
if
(
val
.
length
>
0
)
{
if
(
val
.
length
>
0
)
{
this
.
queryParams
[
'
params[startTime]
'
]
=
val
[
0
]
this
.
queryParams
[
'
params[startTime]
'
]
=
val
[
0
]
this
.
queryParams
[
'
params[endTime]
'
]
=
val
[
1
]
this
.
queryParams
[
'
params[endTime]
'
]
=
val
[
1
]
}
}
...
@@ -110,6 +120,73 @@ export default {
...
@@ -110,6 +120,73 @@ export default {
}
}
this
.
dateRange
=
[]
this
.
dateRange
=
[]
this
.
getList
()
this
.
getList
()
},
/**
* 将内容中的表情符号转换为iconfont标签
* @param {string} content - 原始内容
* @returns {string} 转换后的HTML字符串
*/
formatContent
(
content
)
{
if
(
!
content
)
return
''
;
let
result
=
''
;
let
remainingContent
=
content
;
// 提取所有表情符号并按长度排序(长表情优先匹配)
const
emotionSymbols
=
Object
.
keys
(
this
.
emotionMap
).
sort
((
a
,
b
)
=>
b
.
length
-
a
.
length
);
while
(
remainingContent
.
length
>
0
)
{
let
found
=
false
;
// 查找是否有表情符号
for
(
const
symbol
of
emotionSymbols
)
{
if
(
remainingContent
.
startsWith
(
symbol
))
{
// 添加表情标签
result
+=
`<i class="iconfont
${
this
.
emotionMap
[
symbol
]}
emotion-icon"></i>`
;
remainingContent
=
remainingContent
.
slice
(
symbol
.
length
);
found
=
true
;
break
;
}
}
// 如果没有找到表情,提取普通文本
if
(
!
found
)
{
// 找到下一个表情的位置
let
nextEmotionIndex
=
remainingContent
.
length
;
for
(
const
symbol
of
emotionSymbols
)
{
const
index
=
remainingContent
.
indexOf
(
symbol
);
if
(
index
!==
-
1
&&
index
<
nextEmotionIndex
)
{
nextEmotionIndex
=
index
;
}
}
// 提取文本并进行HTML转义,防止XSS
const
text
=
this
.
escapeHtml
(
remainingContent
.
slice
(
0
,
nextEmotionIndex
));
result
+=
text
;
remainingContent
=
remainingContent
.
slice
(
nextEmotionIndex
);
}
}
return
result
;
},
/**
* HTML转义处理,防止XSS攻击
* @param {string} str - 需要转义的字符串
* @returns {string} 转义后的字符串
*/
escapeHtml
(
str
)
{
if
(
!
str
)
return
''
;
return
str
.
replace
(
/
[
&<>"'
]
/g
,
char
=>
{
const
entities
=
{
'
&
'
:
'
&
'
,
'
<
'
:
'
<
'
,
'
>
'
:
'
>
'
,
'
"
'
:
'
"
'
,
"
'
"
:
'
'
'
};
return
entities
[
char
]
||
char
;
});
}
}
}
}
}
}
...
...
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