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
40bad449
Commit
40bad449
authored
Dec 02, 2025
by
yuwenwen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
移动端调整
parent
28d41209
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
517 additions
and
154 deletions
+517
-154
safe-campus-bbs-uniapp/.gitignore
safe-campus-bbs-uniapp/.gitignore
+24
-0
safe-campus-bbs-uniapp/components/Comment-Item.vue
safe-campus-bbs-uniapp/components/Comment-Item.vue
+314
-42
safe-campus-bbs-uniapp/components/Dynamic-Item.vue
safe-campus-bbs-uniapp/components/Dynamic-Item.vue
+56
-21
safe-campus-bbs-uniapp/config/index.config.js
safe-campus-bbs-uniapp/config/index.config.js
+9
-3
safe-campus-bbs-uniapp/pages/dynamic-detail/dynamic-detail.vue
...campus-bbs-uniapp/pages/dynamic-detail/dynamic-detail.vue
+1
-1
safe-campus-bbs-uniapp/pages/index/index.vue
safe-campus-bbs-uniapp/pages/index/index.vue
+1
-8
safe-campus-bbs-uniapp/pages/publish/publish.vue
safe-campus-bbs-uniapp/pages/publish/publish.vue
+58
-54
safe-campus-bbs-uniapp/static/images/comment.png
safe-campus-bbs-uniapp/static/images/comment.png
+0
-0
safe-campus-bbs-uniapp/static/images/is-featured.png
safe-campus-bbs-uniapp/static/images/is-featured.png
+0
-0
safe-campus-bbs-uniapp/static/images/is-top.png
safe-campus-bbs-uniapp/static/images/is-top.png
+0
-0
safe-campus-bbs-uniapp/static/styles/common.scss
safe-campus-bbs-uniapp/static/styles/common.scss
+6
-5
safe-campus-bbs-uniapp/static/styles/index.scss
safe-campus-bbs-uniapp/static/styles/index.scss
+22
-17
safe-campus-bbs-uniapp/static/styles/publish.scss
safe-campus-bbs-uniapp/static/styles/publish.scss
+7
-3
safe-campus-bbs-uniapp/utils/common.js
safe-campus-bbs-uniapp/utils/common.js
+19
-0
No files found.
safe-campus-bbs-uniapp/.gitignore
0 → 100644
View file @
40bad449
.DS_Store
node_modules/
unpackage/
dist/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
**/*.log
tests/**/coverage/
tests/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
package-lock.json
yarn.lock
safe-campus-bbs-uniapp/components/Comment-Item.vue
View file @
40bad449
...
...
@@ -9,53 +9,155 @@
<image
src=
"/static/images/empty.png"
class=
"icon"
></image>
<view
class=
"text"
>
期待您的经常评论~
</view>
</view>
<view
class=
"comment-display-box"
v-else
>
<view
class=
"comment-item"
v-for=
"(item,index) in commentList"
>
<view
class=
"user-info"
>
<view
style=
"display: flex;align-items: center;"
>
<view
class=
"username"
>
{{
item
.
nickName
}}
</view>
<view
class=
"datetime"
>
{{
item
.
createTime
}}
</view>
</view>
<view
class=
"operation-text"
>
<view
class=
"add-text mr10"
v-if=
"form.isSelf==1&&activeIndex==1 &&item.isFeatured==0 &&form.isEnableFeaturedComment==1"
@
click=
"handleFeatured(item)"
>
加入精选
</view>
<view
class=
"mr10"
v-if=
"form.isSelf==1&&activeIndex==1 &&item.isFeatured==1&&form.isEnableFeaturedComment==1"
@
click=
"handleFeatured(item)"
>
取消精选
</view>
<view
v-if=
"activeIndex==0&&item.isFeatured==1"
style=
"color: #F2AC39;margin-right: 10rpx;"
>
精选
<view
class=
"comment-item-new"
v-for=
"(item,index) in commentList"
>
<block
v-if=
"activeIndex==0"
>
<!-- PK评论展示红蓝方 -->
<block
v-if=
"form.isEnableVote == 1"
>
<!-- 红方 -->
<view
class=
"user-info"
v-if=
"item.voteOptionCode=='1'"
>
<view
class=
"flex-layout"
>
<!-- 是否精选 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isFeatured"
>
<image
src=
"/static/images/is-featured.png"
class=
"icon"
></image>
</view>
<!-- 是否置顶 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isTop"
>
<image
src=
"/static/images/is-top.png"
class=
"icon"
></image>
</view>
<view
class=
"tag red-tag"
>
红
</view>
<view
class=
"username ml-10"
>
{{
item
.
nickName
}}
</view>
</view>
<view
class=
"flex-layout"
>
<view
class=
"datetime"
>
{{
item
.
createTime
}}
</view>
<image
src=
"/static/images/more-icon.png"
class=
"more ml-10"
@
click.stop=
"(e)=>handleOperationDynamics(e,item)"
></image>
</view>
</view>
<view
class=
"user-info"
v-else
>
<view
class=
"flex-layout"
>
<image
src=
"/static/images/more-icon.png"
class=
"more mr-10"
@
click.stop=
"(e)=>handleOperationDynamics(e,item)"
></image>
<view
class=
"datetime"
>
{{
item
.
createTime
}}
</view>
</view>
<view
class=
"flex-layout"
>
<view
class=
"username mr-10"
>
{{
item
.
nickName
}}
</view>
<view
class=
"tag blue-tag"
>
蓝
</view>
<!-- 是否精选 -->
<view
class=
"tag rmark-icon ml-10"
v-if=
"item.isFeatured"
>
<image
src=
"/static/images/is-featured.png"
class=
"icon"
></image>
</view>
<!-- 是否置顶 -->
<view
class=
"tag rmark-icon ml-10"
v-if=
"item.isTop"
>
<image
src=
"/static/images/is-top.png"
class=
"icon"
></image>
</view>
</view>
</view>
<view
class=
"content"
v-if=
"item.voteOptionCode=='1'"
>
<view
class=
"text "
@
click.stop=
"handleReplayComment(item)"
>
{{
item
.
content
}}
</view>
<view
class=
"replay-content"
v-if=
"item.replyNickName"
@
click.stop=
"handleReplayComment(item)"
>
<span>
{{
item
.
replyNickName
}}
:
</span>
{{
item
.
replyContent
}}
</view>
</view>
<view
class=
"content"
v-if=
"item.voteOptionCode=='2'"
>
<view
class=
"text text-blue"
@
click.stop=
"handleReplayComment(item)"
>
{{
item
.
content
}}
</view>
<view
class=
"blue-content"
>
<view
class=
"replay-content"
v-if=
"item.replyNickName"
@
click.stop=
"handleReplayComment(item)"
>
<span>
{{
item
.
replyNickName
}}
:
</span>
{{
item
.
replyContent
}}
</view>
</view>
<view
v-if=
"activeIndex==0&&form.isSelf==1 && item.isTop==0"
class=
"add-text mr10"
@
click=
"handleIsTop(item,1)"
>
置顶
</view>
<view
class=
"add-text mr10"
v-if=
"form.isSelf==1&&activeIndex==0 && item.isTop==1"
@
click=
"handleIsTop(item,0)"
>
取消置顶
</view>
<view
style=
"color: #bbb;margin-left: 10rpx;"
v-if=
"item.isSelf==1 || userInfo.bbsAdmin"
@
click.stop=
"handleDelete(item)"
>
删除
</view>
</view>
</view>
<view
class=
"content"
>
<view
class=
"text"
v-if=
"!item.replyNickName"
@
click.stop=
"handleReplayComment(item)"
>
{{
item
.
content
}}
</view>
</block>
<!-- 非PK评论正常展示 -->
<block
v-else
>
<view
class=
"user-info"
>
<view
class=
"flex-layout"
>
<!-- 是否精选 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isFeatured"
>
<image
src=
"/static/images/is-featured.png"
class=
"icon"
></image>
</view>
<!-- 是否置顶 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isTop"
>
<image
src=
"/static/images/is-top.png"
class=
"icon"
></image>
</view>
<view
class=
"username ml-10"
>
{{
item
.
nickName
}}
</view>
</view>
<view
class=
"flex-layout"
>
<view
class=
"datetime"
>
{{
item
.
createTime
}}
</view>
<image
src=
"/static/images/more-icon.png"
class=
"more ml-10"
@
click.stop=
"(e)=>handleOperationDynamics(e,item)"
>
</image>
</view>
</view>
<view
class=
"content"
>
<view
class=
"text"
@
click.stop=
"handleReplayComment(item)"
>
{{
item
.
content
}}
</view>
<view
class=
"replay-content"
v-if=
"item.replyNickName"
@
click.stop=
"handleReplayComment(item)"
>
<span>
{{
item
.
replyNickName
}}
:
</span>
{{
item
.
replyContent
}}
</view>
</view>
</block>
</block>
<block
v-if=
"activeIndex==1"
>
<view
class=
"user-info"
>
<view
class=
"flex-layout"
>
<!-- 是否精选 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isFeatured"
>
<image
src=
"/static/images/is-featured.png"
class=
"icon"
></image>
</view>
<!-- 是否置顶 -->
<view
class=
"tag rmark-icon mr-10"
v-if=
"item.isTop"
>
<image
src=
"/static/images/is-top.png"
class=
"icon"
></image>
</view>
<view
class=
"tag red-tag"
v-if=
"item.voteOptionCode=='1'"
>
红
</view>
<view
class=
"tag blue-tag"
v-if=
"item.voteOptionCode=='2'"
>
蓝
</view>
<view
class=
"username ml-10"
>
{{
item
.
nickName
}}
</view>
</view>
<view
class=
"flex-layout"
>
<view
class=
"datetime"
>
{{
item
.
createTime
}}
</view>
<image
src=
"/static/images/more-icon.png"
class=
"more ml-10"
@
click.stop=
"(e)=>handleOperationDynamics(e,item)"
></image>
</view>
</view>
<view
class=
"text"
v-else
@
click.stop=
"handleReplayComment(item)"
>
回复
<span
style=
"color: #0058B6;"
>
{{
item
.
replyNickName
}}
</span>
{{
item
.
content
}}
<view
class=
"content"
>
<view
class=
"text"
@
click.stop=
"handleReplayComment(item)"
>
{{
item
.
content
}}
</view>
<view
class=
"replay-content"
v-if=
"item.replyNickName"
@
click.stop=
"handleReplayComment(item)"
>
<span>
{{
item
.
replyNickName
}}
:
</span>
{{
item
.
replyContent
}}
</view>
</view>
</block>
<view
class=
"show-more-box"
v-if=
"commentList.length
<
total
"
@
click=
"loadMore"
>
加载更多
<image
src=
"/static/images/down.png"
class=
"icon"
></image>
</view>
</view>
<view
class=
"show-more-box"
v-if=
"commentList.length
<
total
"
@
click=
"loadMore"
>
加载更多
<image
src=
"/static/images/down.png"
class=
"icon"
></image>
<!-- 操作按钮 -->
<view
class=
"operation-box"
v-if=
"showOperationBtn"
:style=
"'left:' + clientX + 'rpx;' +'top:' + clientY + 'rpx'"
>
<view
class=
"item del-item"
v-if=
"operationItem.isSelf==1 || userInfo.bbsAdmin"
@
click.stop=
"handleDelete(operationItem)"
>
删除
</view>
<view
class=
"item"
v-if=
"activeIndex==1 && operationItem.isTop==0"
@
click=
"handleIsTop(operationItem,1)"
>
置顶
</view>
<view
class=
"item"
v-if=
"activeIndex==1 && operationItem.isTop==1"
@
click=
"handleIsTop(operationItem,0)"
>
取消置顶
</view>
<view
class=
"item"
v-if=
"activeIndex==1 &&operationItem.isFeatured==0 &&form.isEnableFeaturedComment==1"
@
click=
"handleFeatured(operationItem)"
>
加入精选
</view>
<view
class=
"item"
v-if=
"activeIndex==1 &&operationItem.isFeatured==1&&form.isEnableFeaturedComment==1"
@
click=
"handleFeatured(operationItem)"
>
取消精选
</view>
</view>
</view>
<!-- 打开评论 -->
<publish-comment
:form=
"form"
ref=
"publishCommentRef"
@
refresh=
"handleRefresh"
></publish-comment>
</view>
...
...
@@ -84,7 +186,11 @@
momentId
:
''
},
total
:
0
,
userInfo
:
{}
userInfo
:
{},
showOperationBtn
:
false
,
clientX
:
0
,
clientY
:
0
,
operationItem
:
{}
};
},
components
:
{
...
...
@@ -115,6 +221,7 @@
methods
:
{
handleChange
(
index
)
{
this
.
activeIndex
=
index
this
.
showOperationBtn
=
false
},
handleRefresh
()
{
this
.
queryParams
.
pageNum
=
1
;
...
...
@@ -154,10 +261,12 @@
uni
.
showToast
({
title
:
`
${
text
}
成功`
})
_this
.
showOperationBtn
=
false
_this
.
handleRefresh
()
}
})
}
else
if
(
res
.
cancel
)
{
_this
.
showOperationBtn
=
false
console
.
log
(
'
用户点击取消
'
);
}
}
...
...
@@ -175,10 +284,12 @@
uni
.
showToast
({
title
:
`删除成功`
})
_this
.
showOperationBtn
=
false
_this
.
handleRefresh
()
}
})
}
else
if
(
res
.
cancel
)
{
_this
.
showOperationBtn
=
false
console
.
log
(
'
用户点击取消
'
);
}
}
...
...
@@ -190,7 +301,7 @@
let
data
=
{
isTop
,
commentId
:
item
.
id
,
momentId
:
this
.
form
.
id
,
momentId
:
this
.
form
.
id
,
}
let
msg
=
`确认要
${
text
}
评论内容为:
${
item
.
content
}
的数据吗?`
uni
.
showModal
({
...
...
@@ -203,15 +314,32 @@
uni
.
showToast
({
title
:
`
${
text
}
成功`
})
_this
.
showOperationBtn
=
false
_this
.
handleRefresh
()
}
})
}
else
if
(
res
.
cancel
)
{
_this
.
showOperationBtn
=
false
console
.
log
(
'
用户点击取消
'
);
}
}
});
}
},
// 展示删除动态按钮
handleOperationDynamics
(
e
,
item
)
{
this
.
showOperationBtn
=
!
this
.
showOperationBtn
this
.
operationItem
=
{
...
item
}
if
(
e
.
target
.
offsetLeft
<
100
)
{
this
.
clientX
=
(
e
.
target
.
offsetLeft
*
2
);
this
.
clientY
=
((
e
.
target
.
offsetTop
*
2
)
+
14
);
}
else
{
this
.
clientX
=
(
e
.
target
.
offsetLeft
*
2
-
148
);
this
.
clientY
=
((
e
.
target
.
offsetTop
*
2
)
+
34
);
}
},
}
}
</
script
>
...
...
@@ -267,6 +395,126 @@
margin-top
:
32rpx
;
padding
:
24rpx
20rpx
;
box-sizing
:
border-box
;
position
:
relative
;
.comment-item-new
{
font-size
:
28rpx
;
.user-info
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
.flex-layout
{
display
:
flex
;
align-items
:
center
;
height
:
100%
;
}
.flex-end
{
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-end
;
}
.tag
{
width
:
40rpx
;
height
:
40rpx
;
border-radius
:
6rpx
;
font-size
:
24rpx
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
font-weight
:
bold
;
}
.red-tag
{
background-color
:
rgba
(
255
,
100
,
95
,
0
.1
);
color
:
rgba
(
255
,
100
,
95
,
1
);
}
.blue-tag
{
background-color
:
rgba
(
52
,
132
,
253
,
0
.1
);
color
:
rgba
(
52
,
132
,
253
,
1
);
}
.rmark-icon
{
background-color
:
rgba
(
242
,
172
,
57
,
0
.1
);
color
:
rgba
(
255
,
100
,
95
,
1
);
.icon
{
width
:
24rpx
;
height
:
24rpx
;
}
}
.username
{
color
:
black
;
color
:
#0058B6
;
}
.ml-10
{
margin-left
:
10rpx
;
}
.mr-10
{
margin-right
:
10rpx
;
}
.datetime
{
margin-left
:
16rpx
;
color
:
#999999
;
font-size
:
24rpx
;
}
.more
{
width
:
32rpx
;
height
:
32rpx
;
}
}
.blue-content
{
display
:
flex
;
align-items
:
center
;
justify-content
:
flex-end
;
}
.content
{
color
:
black
;
margin
:
10rpx
0
;
.text
{
width
:
100%
;
word-wrap
:
break-word
;
word-break
:
break-all
;
padding
:
0
10rpx
;
box-sizing
:
border-box
;
}
.text-blue
{
text-align
:
right
;
}
.mr10
{
margin-right
:
12rpx
;
}
.add-text
{
color
:
#0058B6
;
}
}
.replay-content
{
padding
:
6rpx
12rpx
;
box-sizing
:
border-box
;
background-color
:
rgba
(
238
,
238
,
238
,
1
);
width
:
fit-content
;
margin-top
:
8rpx
;
}
}
.comment-item
{
.user-info
{
...
...
@@ -299,7 +547,7 @@
display
:
flex
;
.text
{
width
:
calc
(
100%
-
180rpx
)
;
width
:
100%
;
word-wrap
:
break-word
;
word-break
:
break-all
;
}
...
...
@@ -330,4 +578,28 @@
height
:
32rpx
;
}
}
.operation-box
{
position
:
absolute
;
width
:
152rpx
;
border-radius
:
6rpx
;
background-color
:
rgba
(
255
,
255
,
255
,
1
);
color
:
rgba
(
102
,
102
,
102
,
1
);
font-size
:
26rpx
;
text-align
:
center
;
box-shadow
:
0px
2px
12rpx
0px
rgba
(
0
,
0
,
0
,
0
.2
);
padding
:
10rpx
0
;
color
:
rgba
(
16
,
16
,
16
,
1
);
.item
{
height
:
56rpx
;
line-height
:
56rpx
;
}
.del-item
{
color
:
#ff645f
;
}
}
</
style
>
\ No newline at end of file
safe-campus-bbs-uniapp/components/Dynamic-Item.vue
View file @
40bad449
...
...
@@ -2,8 +2,8 @@
<view>
<view
class=
"dynamic-item"
@
click=
"toDynamicDetailPage"
>
<view
class=
"user-info-box"
style=
"position: relative;"
>
<image
class=
"avatar"
v-if=
"form.
avatar"
:src=
"form.avatar
"
></image>
<
image
class=
"avatar"
v-else
src=
"/static/images/default-avatar.png"
></image
>
<image
class=
"avatar"
v-if=
"form.
faceImg"
:src=
"form.faceImg"
@
error=
"imgLoadFail
"
></image>
<
!--
<image
class=
"avatar"
v-else
src=
"/static/images/default-avatar.png"
></image>
--
>
<view
class=
"user-name"
>
{{
form
.
nickName
}}
</view>
<image
v-if=
"deleteable || userInfo.bbsAdmin || form.isSelf==1"
class=
"more-icon"
@
click.stop=
"handleDelDynamics"
src=
"/static/images/more-icon.png"
></image>
...
...
@@ -35,14 +35,20 @@
</view>
<view
class=
"datetime-box"
>
{{form.createTime}}
</view>
<view
class=
"operation-box"
>
<view
class=
"favorite-box"
>
<image
src=
"/static/images/favorite.png"
v-if=
"form.isLike==0"
class=
"icon"
@
click.stop=
"handleUpdateLikeStatus(1)"
></image>
<image
src=
"/static/images/favorite-active.png"
v-if=
"form.isLike==1"
@
click.stop=
"handleUpdateLikeStatus(0)"
class=
"icon"
></image>
<view
class=
"num"
>
{{form.likeCount}}
</view>
<view
class=
"flex-layout"
>
<view
class=
"favorite-box"
>
<image
src=
"/static/images/favorite.png"
v-if=
"form.isLike==0"
class=
"icon"
@
click.stop=
"handleUpdateLikeStatus(1)"
></image>
<image
src=
"/static/images/favorite-active.png"
v-if=
"form.isLike==1"
@
click.stop=
"handleUpdateLikeStatus(0)"
class=
"icon"
></image>
<view
class=
"num"
>
{{form.likeCount}}
</view>
</view>
<view
class=
"favorite-box ml-10"
>
<image
src=
"/static/images/comment.png"
class=
"icon"
></image>
<view
class=
"num"
>
{{form.commentCount}}
</view>
</view>
</view>
<view
class=
"comment-box"
@
click.stop=
"handleOpenComment"
>
<view
class=
"comment-box"
v-if=
"displayComment"
@
click.stop=
"handleOpenComment"
>
<image
class=
"icon"
src=
"/static/images/comment-icon.png"
></image>
<view
class=
"text"
>
评论
</view>
</view>
...
...
@@ -53,14 +59,14 @@
<image
src=
"/static/images/pk-icon.png"
class=
"pk-icon"
></image>
<view
class=
"pk-title-text"
>
{{form.voteTitle}}
</view>
</view>
<view
class=
"pk-imgs"
v-if=
"form.voteOptionType=='IMAGE'
&&
form.voteOptions.length>0 "
>
<view
class=
"pk-imgs"
v-if=
"form.voteOptionType=='IMAGE'
&&form.voteOptions&&
form.voteOptions.length>0 "
>
<
template
v-for=
"(item,index) in form.voteOptions"
>
<image
:src=
"item.imageUrl"
@
click.stop=
"preview(form.voteOptions,index)"
class=
"img"
></image>
</
template
>
</view>
<!-- 未投票 -->
<view
v-if=
"form.isVote==0"
>
<view
class=
"pk-btns"
v-if=
"form.voteOptions.length>0 "
>
<view
class=
"pk-btns"
v-if=
"form.voteOptions
&&form.voteOptions&&form.voteOptions
.length>0 "
>
<view
class=
"btns red-btn"
@
click.stop=
"handleVote(form.voteOptions[0])"
>
{{form.voteOptions[0].name}}
</view>
...
...
@@ -77,17 +83,18 @@
<view
class=
"left"
@
click.stop=
"toPKDetailPage(0)"
>
<view
class=
"left-num"
>
{{form.voteOptions[0].name}} {{form.voteOptions[0].voteCount}}
</view>
</view>
<view
class=
"
right"
@
click.stop=
"toPKDetailPage(1)"
>
<view
class=
"right-num"
>
{{form.voteOptions[1].name}} {{form.voteOptions[1].voteCount}}
</view>
<view
class=
"
left"
:style=
"'width:' + ((form.voteOptions[0].voteCount/(form.voteOptions[0].voteCount+form.voteOptions[1].voteCount))*100)+'%'"
@
click.stop=
"toPKDetailPage(0)"
>
<
view
class=
"results-item left-item"
><
/view>
</view>
</view>
<view
class=
"pk-results"
>
<view
class=
"
left"
:style=
"'flex:' + form.voteOptions[0].voteCount"
@
click.stop=
"toPKDetailPage(0)"
>
<
view
class=
"results-item left-item"
><
/view>
<view
class=
"
right"
@
click.stop=
"toPKDetailPage(1)"
>
<view
class=
"right-num"
>
{{form.voteOptions[1].name}} {{form.voteOptions[1].voteCount}}
</view>
</view>
<view
class=
"right"
:style=
"'
flex:' + form.voteOptions[1].voteCount
"
<view
class=
"right"
:style=
"'
width:' + ((form.voteOptions[1].voteCount/(form.voteOptions[0].voteCount+form.voteOptions[1].voteCount))*100)+'%'
"
@
click.stop=
"toPKDetailPage(1)"
>
<view
class=
"results-item right-item"
></view>
</view>
...
...
@@ -99,7 +106,7 @@
</view>
</view>
<!-- 评论区 -->
<view
class=
"comment-box"
v-if=
"form.isEnableComment==1"
>
<
!-- <
view class="comment-box" v-if="form.isEnableComment==1">
<view class="comment-display-box" v-if="form.comments&& form.comments.length>0">
<view class="comment-item" v-for="(item,index) in form.comments">
<view class="user-info">
...
...
@@ -124,7 +131,7 @@
</view>
</view>
</view>
</view>
</view>
-->
</view>
<!-- 发布评论区 -->
<publish-comment
:form=
"form"
ref=
"publishCommentRef"
@
refresh=
"$emit('refresh')"
></publish-comment>
...
...
@@ -143,9 +150,11 @@
import
PublishComment
from
'
./PublishComment.vue
'
;
import
VideoPreview
from
'
./VideoPreview.vue
'
;
import
emotions
from
'
@/utils/emjo
'
;
import
defalutAvatar
from
'
/static/images/default-avatar.png
'
import
{
getUserInfo
}
from
'
@/utils/auth
'
;
import
{
generateSignature
}
from
'
@/utils/common.js
'
;
export
default
{
name
:
"
Dynamic-Item
"
,
data
()
{
...
...
@@ -173,6 +182,10 @@
deleteable
:
{
type
:
Boolean
,
default
:
false
},
displayComment
:{
type
:
Boolean
,
default
:
true
}
},
watch
:
{
...
...
@@ -184,6 +197,7 @@
return
;
}
this
.
userInfo
=
JSON
.
parse
(
JSON
.
parse
(
getUserInfo
()))
this
.
form
.
faceImg
=
generateSignature
(
this
.
userInfo
.
userName
)
this
.
preNodes
=
this
.
formatContent
(
val
)
}
}
...
...
@@ -282,7 +296,24 @@
// 打开评论区
handleOpenComment
()
{
// this.showComment = true
this
.
$refs
.
publishCommentRef
.
openModal
()
const
{
isEnableVote
,
isVote
}
=
this
.
form
;
// 如果开启pk,则必须先已经投票才可以评论
if
(
isEnableVote
==
1
){
if
(
isVote
==
1
){
this
.
$refs
.
publishCommentRef
.
openModal
()
}
else
{
uni
.
showToast
({
title
:
'
请先点击上方PK按钮,选择你的观点后才可进行评论
'
,
icon
:
'
none
'
,
duration
:
3000
})
return
;
}
}
else
{
this
.
$refs
.
publishCommentRef
.
openModal
()
}
},
// 回复评论
handleReplayComment
(
item
)
{
...
...
@@ -330,6 +361,7 @@
uni
.
showToast
({
title
:
'
投票成功
'
})
uni
.
$emit
(
'
hanldeDynamicRefresh
'
)
this
.
$emit
(
'
refreshCurrent
'
,
this
.
form
.
id
)
}
})
...
...
@@ -369,6 +401,9 @@
});
}
},
imgLoadFail
()
{
this
.
userInfo
.
faceImg
=
defalutAvatar
},
//预览视频
videoPreview
(
url
)
{
this
.
$refs
.
videoPreviewRef
.
openModal
(
url
)
...
...
safe-campus-bbs-uniapp/config/index.config.js
View file @
40bad449
...
...
@@ -4,16 +4,22 @@ const CONFIG = {
debug
:
true
,
platformName
:
'
社区
'
,
requestUrl
:
'
http://192.168.5.177:8089
'
,
videoLimitSize
:
10
videoLimitSize
:
10
,
secret
:
'
775d4e98-49d8-86d7-48c9-c93b5f7c0c16
'
,
appId
:
'
jfsq
'
,
faceBaseUrl
:
'
https://photo.jift.edu.cn/preview/main/
'
},
//生产环境配置
production
:
{
debug
:
false
,
platformName
:
'
社区
'
,
requestUrl
:
'
/bbs/prod-api
'
,
videoLimitSize
:
10
videoLimitSize
:
10
,
secret
:
'
775d4e98-49d8-86d7-48c9-c93b5f7c0c16
'
,
appId
:
'
jfsq
'
,
faceBaseUrl
:
'
https://photo.jift.edu.cn/preview/main/
'
}
}
export
default
CONFIG
[
process
.
env
.
NODE_ENV
];
export
default
CONFIG
[
process
.
env
.
NODE_ENV
];
\ No newline at end of file
safe-campus-bbs-uniapp/pages/dynamic-detail/dynamic-detail.vue
View file @
40bad449
<
template
>
<view
class=
"detail-page-container"
>
<dynamic-item
:form=
"form"
@
refresh=
"handleRefresh"
@
deleteSuccess=
"deleteSuccess"
></dynamic-item>
<dynamic-item
:form=
"form"
@
refresh=
"handleRefresh"
@
refreshCurrent=
"handleRefresh"
@
deleteSuccess=
"deleteSuccess"
></dynamic-item>
<!-- 评论管理区 -->
<comment-item
:form=
"form"
></comment-item>
</view>
...
...
safe-campus-bbs-uniapp/pages/index/index.vue
View file @
40bad449
...
...
@@ -11,20 +11,13 @@
<scroll-view
class=
"scroll-view-index"
scroll-y
:show-scrollbar=
"false"
v-if=
"list.length>0"
@
scrolltolower=
"loadMore"
>
<template
v-for=
"(item,index) in list"
>
<dynamic-item
:form=
"item"
@
refresh=
"refreshContentList"
<dynamic-item
:form=
"item"
:displayComment=
"false"
@
refresh=
"refreshContentList"
@
refreshCurrent=
"refreshCurrent"
></dynamic-item>
</
template
>
</scroll-view>
<scroll-view
class=
"scroll-view-index"
scroll-y
:show-scrollbar=
"false"
v-else
>
<list-empty></list-empty>
</scroll-view>
<!-- 发布按钮 -->
<!-- <movable-area class="movable-area">
<movable-view class="add-dynamic-box move-button" :x="area.x+'rpx'" :y="area.y + 'rpx'" direction="all"
@change="onChange" damping="30" @click="toPublishPage">
<image class="icon" src="/static/images/publish-icon.png"></image>
</movable-view>
</movable-area> -->
<!-- 发布按钮 -->
<view
class=
"add-dynamic-box"
@
click=
"toPublishPage"
:style=
"{ left: iconLeft + 'px', top: iconTop + 'px' }"
...
...
safe-campus-bbs-uniapp/pages/publish/publish.vue
View file @
40bad449
...
...
@@ -6,8 +6,8 @@
</view>
</view>
<view
class=
"publish-box"
>
<textarea
class=
"textarea"
v-model=
"form.content"
placeholder=
"分享有趣事~"
placeholder-class=
"placeholder-class"
@
focus=
"handleFocus"
/>
<textarea
class=
"textarea"
v-model=
"form.content"
placeholder=
"分享有趣事~"
placeholder-class=
"placeholder-class"
@
focus=
"handleFocus"
/>
<image-upload
v-model=
"form.attachments"
ref=
"uploadRef"
:limit=
"9"
:showEmjo=
"showEmjo"
:showIcons=
"true"
@
componentsType=
"handleSetComponentsType"
@
handleTopic=
"handleOpenTopicSelection"
@
handleEmjo=
"handleAddEmjo"
></image-upload>
...
...
@@ -33,7 +33,7 @@
<!-- pk数据编辑 -->
<view
class=
"pk-edit-box"
v-if=
"form.isEnableVote==1"
>
<view
class=
"textarea-box"
>
<textarea
class=
"textarea"
v-model=
"form.voteTitle"
maxlength=
"
12"
placeholder=
"请输入PK标题~(0/12
)"
<textarea
class=
"textarea"
v-model=
"form.voteTitle"
maxlength=
"
50"
placeholder=
"请输入PK标题~(0/50
)"
placeholder-class=
"placeholder-class"
/>
</view>
<view
class=
"pk-type-box"
>
...
...
@@ -41,7 +41,7 @@
<label
class=
"radio"
style=
"margin-right: 40rpx;"
>
<radio
value=
"TEXT"
:checked=
"form.voteOptionType=='TEXT'"
/>
文字PK
</label>
<label
class=
"radio"
>
<label
class=
"radio"
>
<radio
value=
"IMAGE"
:checked=
"form.voteOptionType=='IMAGE'"
/>
图片PK
</label>
</radio-group>
...
...
@@ -50,24 +50,26 @@
<view
class=
"choice-item"
>
<image-upload
v-model=
"voteOptionsAffirmative"
:limit=
"1"
:width=
"120"
:height=
"120"
:showIcons=
"false"
></image-upload>
<input
class=
"text"
v-model=
"form.voteOptions[0].name"
placeholder=
"请输入选项1(4字以内)"
/>
<input
class=
"text"
maxlength=
"16"
v-model=
"form.voteOptions[0].name"
placeholder=
"请输入选项1(16字以内)"
/>
</view>
<view
class=
"choice-item"
>
<image-upload
v-model=
"voteOptionsOpposing"
:limit=
"1"
:width=
"120"
:height=
"120"
:showIcons=
"false"
></image-upload>
<input
class=
"text"
v-model=
"form.voteOptions[1].name"
placeholder=
"请输入选项2(4字以内)"
/>
<input
class=
"text"
maxlength=
"16"
v-model=
"form.voteOptions[1].name"
placeholder=
"请输入选项2(16字以内)"
/>
</view>
</view>
<view
class=
"choice-box"
v-if=
"form.voteOptionType=='TEXT'"
>
<view
class=
"choice-item text-item"
>
<view
class=
"label"
>
选项1
</view>
<input
class=
"text"
maxlength=
"
4
"
v-model=
"form.voteOptions[0].name"
placeholder=
"请输入选项1(
4
字以内)"
/>
<input
class=
"text"
maxlength=
"
16
"
v-model=
"form.voteOptions[0].name"
placeholder=
"请输入选项1(
16
字以内)"
/>
</view>
<view
class=
"choice-item text-item"
>
<view
class=
"label"
>
选项2
</view>
<input
class=
"text"
maxlength=
"
4
"
v-model=
"form.voteOptions[1].name"
placeholder=
"请输入选项2(
4
字以内)"
/>
<input
class=
"text"
maxlength=
"
16
"
v-model=
"form.voteOptions[1].name"
placeholder=
"请输入选项2(
16
字以内)"
/>
</view>
</view>
</view>
...
...
@@ -155,7 +157,7 @@
voteOptionsAffirmative
:
[],
voteOptionsOpposing
:
[],
emotions
,
showEmjo
:
false
showEmjo
:
false
}
},
components
:
{
...
...
@@ -176,25 +178,25 @@
},
// 当内容变化时自动更新预览
watch
:
{
"
form.content
"
:
{
immediate
:
true
,
handler
(
val
,
oldVal
)
{
if
(
val
===
oldVal
)
return
;
if
(
val
&&
val
.
length
<
oldVal
.
length
)
{
// 计算删除的字符长度(正常退格删1个,表情需要删N个)
const
deleteLen
=
oldVal
.
length
-
val
.
length
;
// 检查删除前的末尾是否是表情,且删除长度不够(比如表情是4个字符,只删了1个)
const
sortedEmojis
=
[...
this
.
emotions
].
sort
((
a
,
b
)
=>
b
.
symbol
.
length
-
a
.
symbol
.
length
);
for
(
const
emoji
of
sortedEmojis
)
{
if
(
oldVal
.
endsWith
(
emoji
.
symbol
)
&&
deleteLen
<
emoji
.
symbol
.
length
)
{
// 补删剩余的表情字符(比如表情4个字符,已删1个,再删3个)
this
.
form
.
content
=
oldVal
.
slice
(
0
,
-
emoji
.
symbol
.
length
);
break
;
}
}
}
}
}
"
form.content
"
:
{
immediate
:
true
,
handler
(
val
,
oldVal
)
{
if
(
val
===
oldVal
)
return
;
if
(
val
&&
val
.
length
<
oldVal
.
length
)
{
// 计算删除的字符长度(正常退格删1个,表情需要删N个)
const
deleteLen
=
oldVal
.
length
-
val
.
length
;
// 检查删除前的末尾是否是表情,且删除长度不够(比如表情是4个字符,只删了1个)
const
sortedEmojis
=
[...
this
.
emotions
].
sort
((
a
,
b
)
=>
b
.
symbol
.
length
-
a
.
symbol
.
length
);
for
(
const
emoji
of
sortedEmojis
)
{
if
(
oldVal
.
endsWith
(
emoji
.
symbol
)
&&
deleteLen
<
emoji
.
symbol
.
length
)
{
// 补删剩余的表情字符(比如表情4个字符,已删1个,再删3个)
this
.
form
.
content
=
oldVal
.
slice
(
0
,
-
emoji
.
symbol
.
length
);
break
;
}
}
}
}
}
},
methods
:
{
// 允许评论,开启精选等操作
...
...
@@ -274,6 +276,7 @@
handleCloseTopicSelection
()
{
this
.
showTopicSelection
=
false
,
this
.
topicResultList
=
undefined
this
.
topicParams
.
name
=
''
},
// 搜索话题
handleSearchTopic
()
{
...
...
@@ -306,12 +309,13 @@
},
// 删除话题
handleDeleteTopic
(
index
)
{
let
_this
=
this
;
uni
.
showModal
({
title
:
'
提示
'
,
content
:
'
是否取消选择话题
'
,
success
:
function
(
res
)
{
if
(
res
.
confirm
)
{
this
.
topicList
.
splice
(
index
,
1
)
_
this
.
topicList
.
splice
(
index
,
1
)
}
else
if
(
res
.
cancel
)
{
console
.
log
(
'
用户点击取消
'
);
}
...
...
@@ -320,7 +324,7 @@
},
// textarea聚焦时关闭表情窗口
handleFocus
(){
handleFocus
()
{
this
.
$refs
.
uploadRef
.
closeEmjo
()
},
// 添加表情
...
...
@@ -330,28 +334,28 @@
},
// 删除表情
deleteContent
()
{
// 1. 处理 form.content 为空的情况,直接返回避免报错
if
(
!
this
.
form
.
content
||
this
.
form
.
content
.
trim
()
===
''
)
{
return
;
}
let
deleted
=
false
;
// 2. 按表情符号长度排序(长符号优先,避免短符号误匹配)
const
sortedEmojis
=
[...
this
.
emotions
].
sort
((
a
,
b
)
=>
b
.
symbol
.
length
-
a
.
symbol
.
length
);
let
lastIndex
=
-
1
;
// 3. 检查内容是否以某个表情符号结尾,记录最后一个表情符号的位置
for
(
const
emoji
of
sortedEmojis
)
{
if
(
this
.
form
.
content
.
endsWith
(
emoji
.
symbol
))
{
lastIndex
=
this
.
form
.
content
.
lastIndexOf
(
emoji
.
symbol
);
deleted
=
true
;
}
}
// 4. 若找到表情符号,删除所有匹配的表情符号
if
(
deleted
)
{
this
.
form
.
content
=
this
.
form
.
content
.
slice
(
0
,
lastIndex
);
}
else
{
// 5. 若未匹配到表情,删除最后一个普通字符
this
.
form
.
content
=
this
.
form
.
content
.
slice
(
0
,
-
1
);
}
// 1. 处理 form.content 为空的情况,直接返回避免报错
if
(
!
this
.
form
.
content
||
this
.
form
.
content
.
trim
()
===
''
)
{
return
;
}
let
deleted
=
false
;
// 2. 按表情符号长度排序(长符号优先,避免短符号误匹配)
const
sortedEmojis
=
[...
this
.
emotions
].
sort
((
a
,
b
)
=>
b
.
symbol
.
length
-
a
.
symbol
.
length
);
let
lastIndex
=
-
1
;
// 3. 检查内容是否以某个表情符号结尾,记录最后一个表情符号的位置
for
(
const
emoji
of
sortedEmojis
)
{
if
(
this
.
form
.
content
.
endsWith
(
emoji
.
symbol
))
{
lastIndex
=
this
.
form
.
content
.
lastIndexOf
(
emoji
.
symbol
);
deleted
=
true
;
}
}
// 4. 若找到表情符号,删除所有匹配的表情符号
if
(
deleted
)
{
this
.
form
.
content
=
this
.
form
.
content
.
slice
(
0
,
lastIndex
);
}
else
{
// 5. 若未匹配到表情,删除最后一个普通字符
this
.
form
.
content
=
this
.
form
.
content
.
slice
(
0
,
-
1
);
}
}
}
}
...
...
safe-campus-bbs-uniapp/static/images/comment.png
0 → 100644
View file @
40bad449
835 Bytes
safe-campus-bbs-uniapp/static/images/is-featured.png
0 → 100644
View file @
40bad449
695 Bytes
safe-campus-bbs-uniapp/static/images/is-top.png
0 → 100644
View file @
40bad449
430 Bytes
safe-campus-bbs-uniapp/static/styles/common.scss
View file @
40bad449
...
...
@@ -31,16 +31,17 @@ $common-width:94vw;
// 话题容器样式
.topic-box-common
{
height
:
52rpx
;
padding
:
0
20rpx
;
// height: 52rpx;
background-color
:
rgba
(
0
,
123
,
255
,
0
.1
);
color
:
$color-main-blue
;
border-radius
:
26rpx
;
line-height
:
52rpx
;
margin-right
:
20rpx
;
font-size
:
26rpx
;
/* 基准字体大小 */
padding
:
10rpx
16px
;
/* 只左右内边距,高度由line-height决定 */
border-radius
:
2em
;
/* 1em = 16px = 高度32px的50% */
height
:
fit-content
;
margin-bottom
:
10rpx
;
}
.search-box-common
{
height
:
76rpx
;
width
:
$common-width
;
...
...
safe-campus-bbs-uniapp/static/styles/index.scss
View file @
40bad449
...
...
@@ -70,6 +70,10 @@
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
.flex-layout
{
display
:
flex
;
align-items
:
center
;
}
.favorite-box
{
width
:
112rpx
;
height
:
60rpx
;
...
...
@@ -90,6 +94,9 @@
color
:
rgba
(
245
,
166
,
35
,
1
);
}
}
.ml-10
{
margin-left
:
20rpx
;
}
.comment-box
{
display
:
flex
;
...
...
@@ -122,6 +129,7 @@
.pk-title-text
{
color
:
rgba
(
16
,
16
,
16
,
1
);
font-size
:
24rpx
;
width
:
calc
(
100%
-
50rpx
);
}
}
...
...
@@ -139,10 +147,11 @@
.pk-btns
{
margin
:
20rpx
0
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
.btns
{
width
:
208
rpx
;
width
:
520
rpx
;
height
:
76rpx
;
line-height
:
76rpx
;
color
:
rgba
(
255
,
255
,
255
,
1
);
...
...
@@ -150,11 +159,11 @@
text-align
:
center
;
}
.red-btn
{
border-radius
:
38rpx
6rpx
6rpx
38rpx
;
border-radius
:
38rpx
;
background-color
:
rgba
(
255
,
100
,
95
,
1
);
}
.blue-btn
{
border-radius
:
6rpx
38rpx
38rpx
6
rpx
;
border-radius
:
38
rpx
;
background-color
:
rgba
(
52
,
132
,
253
,
1
);
}
...
...
@@ -175,43 +184,39 @@
.pk-results
{
margin-top
:
20rpx
;
margin-bottom
:
10rpx
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
//
display: flex;
//
align-items: center;
//
justify-content: space-between;
font-size
:
24rpx
;
.left
{
width
:
100%
;
flex
:
1
;
.left-num
{
color
:
rgba
(
255
,
100
,
95
,
1
);
margin-bottom
:
10rpx
;
}
}
.right
{
width
:
100%
;
flex
:
1
;
text-align
:
right
;
.right-num
{
color
:
rgba
(
52
,
132
,
253
,
1
);
margin-bottom
:
10rpx
;
}
}
.results-item
{
width
:
100%
;
height
:
12rpx
;
color
:
rgba
(
255
,
255
,
255
,
1
);
font-size
:
28rpx
;
}
.left-item
{
border-radius
:
6rpx
0
0
6rpx
;
m
argin-right
:
10rpx
;
border-radius
:
6rpx
;
m
in-width
:
10rpx
;
background-color
:
rgba
(
255
,
100
,
95
,
1
);
}
.right-item
{
border-radius
:
0
6rpx
6rpx
0
;
m
argin-left
:
10rpx
;
border-radius
:
6rpx
;
m
in-width
:
10rpx
;
background-color
:
rgba
(
52
,
132
,
253
,
1
);
}
...
...
safe-campus-bbs-uniapp/static/styles/publish.scss
View file @
40bad449
...
...
@@ -95,6 +95,7 @@
color
:
rgba
(
187
,
187
,
187
,
1
);
font-size
:
32rpx
;
margin-left
:
32rpx
;
width
:
calc
(
100%
-
140rpx
);
}
.label
{
color
:
rgba
(
16
,
16
,
16
,
1
);
...
...
@@ -176,6 +177,7 @@
}
.input
{
margin-left
:
20rpx
;
width
:
calc
(
100%
-
50rpx
);
}
.input-class
{
font-size
:
14px
;
...
...
@@ -185,11 +187,13 @@
.topic-result-list
{
margin-top
:
32rpx
;
.list-item
{
height
:
64
rpx
;
padding
:
10rpx
16
rpx
;
border-radius
:
32rpx
;
background-color
:
rgba
(
245
,
248
,
250
,
1
);
font-size
:
26rpx
;
padding
:
0
20rpx
;
font-size
:
26rpx
;
/* 基准字体大小 */
border-radius
:
2em
;
/* 1em = 16px = 高度32px的50% */
box-sizing
:
border-box
;
display
:
flex
;
align-items
:
center
;
...
...
safe-campus-bbs-uniapp/utils/common.js
View file @
40bad449
...
...
@@ -170,4 +170,23 @@ export function getQuery(name) {
}
else
return
decodeURIComponent
(
r
[
2
]);
}
return
null
;
}
import
md5
from
'
js-md5
'
;
import
config
from
'
@/config/index.config.js
'
export
function
generateSignature
(
userName
)
{
if
(
!
userName
||
typeof
userName
!==
'
string
'
)
{
throw
new
Error
(
'
用户名/学工号不能为空,且必须是字符串类型
'
);
}
const
timestamp
=
Date
.
now
();
const
appSecret
=
config
.
secret
;
const
appId
=
config
.
appId
;
const
baseUrl
=
config
.
faceBaseUrl
;
const
rawStr
=
userName
+
timestamp
.
toString
()
+
appSecret
;
const
signature
=
md5
(
rawStr
);
return
baseUrl
+
userName
+
"
?appid=
"
+
appId
+
"
×tamp=
"
+
timestamp
.
toString
()
+
"
&signature=
"
+
signature
;
}
\ No newline at end of file
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