Commit c168a435 authored by yuwenwen's avatar yuwenwen

修改BUG,添加表情文件

parent 4c74a506
...@@ -62,7 +62,19 @@ ...@@ -62,7 +62,19 @@
<div class="username">{{ item.nickName }}:</div> <div class="username">{{ item.nickName }}:</div>
<div class="datetime">{{ item.createTime }}</div> <div class="datetime">{{ item.createTime }}</div>
</div> </div>
<div class="content">{{ item.content }}</div> <div class="content">
<div class="text" v-if="!item.replyNickName" >
{{item.content}}
</div>
<div class="text" v-else>
回复<span style="color: #0058B6;">{{item.replyNickName}}:</span>{{item.content}}
</div>
<div class="operation-text">
<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>
</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">
加载更多 加载更多
...@@ -116,6 +128,10 @@ export default { ...@@ -116,6 +128,10 @@ export default {
this.queryParams.pageNum += 1; this.queryParams.pageNum += 1;
this.getComments() this.getComments()
}, },
// 删除评论
handleDelete(){
}
} }
} }
...@@ -353,9 +369,28 @@ export default { ...@@ -353,9 +369,28 @@ export default {
} }
} }
.content { .content{
color: black; color: black;
margin: 5px 0; margin: 5px 0;
display: flex;
.text {
width: calc(100% - 90px);
}
.operation-text {
width:90px;
text-align: right;
font-size: 12px;
display: flex;
align-items: center;
justify-content: flex-end;
}
.mr10{
margin-right: 6px;
}
.add-text {
color: #0058B6;
}
} }
.tips { .tips {
......
...@@ -56,7 +56,9 @@ export default { ...@@ -56,7 +56,9 @@ export default {
this.upload.open = false; this.upload.open = false;
this.upload.isUploading = false; this.upload.isUploading = false;
this.$refs.upload.clearFiles(); this.$refs.upload.clearFiles();
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }); console.log(response)
let msg = `总共:${response.data.totalCount}条,成功:${response.data.successCount},失败:${response.data.failCount}`
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true });
this.$emit('handleOk') this.$emit('handleOk')
}, },
// 提交上传文件 // 提交上传文件
......
...@@ -13,5 +13,6 @@ ...@@ -13,5 +13,6 @@
</script> </script>
<style> <style>
@import '/static/iconfont/iconfont.css'
/*每个页面公共css */ /*每个页面公共css */
</style> </style>
...@@ -26,8 +26,9 @@ ...@@ -26,8 +26,9 @@
@click="handleFeatured(item)">加入精选</view> @click="handleFeatured(item)">加入精选</view>
<view class="mr10" v-if="form.isSelf==1&&activeIndex==1 &&item.isFeatured==1&&form.isEnableFeaturedComment==1" @click="handleFeatured(item)"> <view class="mr10" v-if="form.isSelf==1&&activeIndex==1 &&item.isFeatured==1&&form.isEnableFeaturedComment==1" @click="handleFeatured(item)">
取消精选</view> 取消精选</view>
<view v-if="form.isSelf==1&&activeIndex==1" @click="handleDelete(item)">删除</view> <view v-if="activeIndex==0&&item.isFeatured==1" style="color: #F2AC39;margin-right: 10rpx;">精选</view>
<view v-if="activeIndex==0&&item.isFeatured==1" style="color: #F2AC39;">精选</view> <view v-if="item.isSelf==1" @click.stop="handleDelete(item)">删除</view>
</view> </view>
</view> </view>
</view> </view>
...@@ -246,7 +247,7 @@ ...@@ -246,7 +247,7 @@
.operation-text { .operation-text {
width: 180rpx; width: 180rpx;
text-align: right; text-align: right;
font-size: 28rpx; font-size: 24rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
<image v-if="deleteable" class="more-icon" @click.stop="handleDelDynamics" <image v-if="deleteable" class="more-icon" @click.stop="handleDelDynamics"
src="/static/images/more-icon.png"></image> src="/static/images/more-icon.png"></image>
<!-- 删除按钮 --> <!-- 删除按钮 -->
<view class="del-btn" v-if="showDelBtn" @click.stop="handleDel" :style="'left:' + clientX + 'rpx;' +'top:' + clientY + 'rpx'"> <view class="del-btn" v-if="showDelBtn" @click.stop="handleDel"
:style="'left:' + clientX + 'rpx;' +'top:' + clientY + 'rpx'">
删除动态</view> 删除动态</view>
</view> </view>
<view class="topics-box" v-if="form.topicNames && form.topicNames.length >0"> <view class="topics-box" v-if="form.topicNames && form.topicNames.length >0">
...@@ -16,8 +17,9 @@ ...@@ -16,8 +17,9 @@
<view class="topic-box-common" @click.stop="toTopicDetailPage(name,index)"># {{name}}</view> <view class="topic-box-common" @click.stop="toTopicDetailPage(name,index)"># {{name}}</view>
</template> </template>
</view> </view>
<view class="dynamic-content-box"> <view class="dynamic-content-box" >
<view class="text">{{form.content}}</view>
<rich-text v-if="preNodes.length > 0" :nodes="preNodes"></rich-text>
<view class="imgs" v-if="form.type=='IMAGE'&&form.attachments && form.attachments.length > 0"> <view 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">
<image class="item" :src="item.url" @click.stop="preview(item.url)"></image> <image class="item" :src="item.url" @click.stop="preview(item.url)"></image>
...@@ -25,7 +27,8 @@ ...@@ -25,7 +27,8 @@
</view> </view>
<view class="imgs" v-if="form.type=='VIDEO'&&form.attachments && form.attachments.length > 0"> <view class="imgs" v-if="form.type=='VIDEO'&&form.attachments && form.attachments.length > 0">
<template v-for="(item,index) in form.attachments"> <template v-for="(item,index) in form.attachments">
<video class="item" :src="item.url"></video> <video class="item" :src="item.url" :show-fullscreen-btn="false" :show-center-play-btn="false"
@click.stop="videoPreview(item.url)"></video>
</template> </template>
</view> </view>
</view> </view>
...@@ -79,10 +82,12 @@ ...@@ -79,10 +82,12 @@
</view> </view>
</view> </view>
<view class="pk-results"> <view class="pk-results">
<view class="left" :style="'flex:' + form.voteOptions[0].voteCount" @click.stop="toPKDetailPage(0)"> <view class="left" :style="'flex:' + form.voteOptions[0].voteCount"
@click.stop="toPKDetailPage(0)">
<view class="results-item left-item"></view> <view class="results-item left-item"></view>
</view> </view>
<view class="right" :style="'flex:' + form.voteOptions[1].voteCount" @click.stop="toPKDetailPage(1)"> <view class="right" :style="'flex:' + form.voteOptions[1].voteCount"
@click.stop="toPKDetailPage(1)">
<view class="results-item right-item"></view> <view class="results-item right-item"></view>
</view> </view>
</view> </view>
...@@ -100,20 +105,27 @@ ...@@ -100,20 +105,27 @@
<view class="username">{{item.nickName}}:</view> <view class="username">{{item.nickName}}:</view>
<view class="datetime">2025-07-01 04:21:21</view> <view class="datetime">2025-07-01 04:21:21</view>
</view> </view>
<view class="content" v-if="!item.replyNickName" @click.stop="handleReplayComment(item)"> <view class="content">
{{item.content}}</view> <view class="text" v-if="!item.replyNickName" @click.stop="handleReplayComment(item)">
<view class="content" v-else @click.stop="handleReplayComment(item)"> {{item.content}}
回复<span style="color: #0058B6;">{{item.replyNickName}}:</span>:{{item.content}} </view>
<view class="text" v-else @click.stop="handleReplayComment(item)">
回复<span style="color: #0058B6;">{{item.replyNickName}}:</span>{{item.content}}
</view>
<view class="operation-text">
<view v-if="item.isFeatured==1" style="color: #F2AC39;margin-right: 10rpx;">精选</view>
<view v-if="item.isSelf==1" @click.stop="handleDelete(item)">删除</view>
</view>
</view> </view>
<!-- <view class="tips">未精选,仅自己可见</view> -->
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 发布评论区 --> <!-- 发布评论区 -->
<publish-comment :form="form" ref="publishCommentRef" @refresh="$emit('refresh')"></publish-comment> <publish-comment :form="form" ref="publishCommentRef" @refresh="$emit('refresh')"></publish-comment>
<!-- 视频预览 -->
<video-preview ref="videoPreviewRef"></video-preview>
</view> </view>
</template> </template>
...@@ -121,23 +133,29 @@ ...@@ -121,23 +133,29 @@
import { import {
dynamicLikeUnlike, dynamicLikeUnlike,
delMonment, delMonment,
dynamicVote dynamicVote,
delComment
} from '@/api/api.js' } from '@/api/api.js'
import PublishComment from './PublishComment.vue'; import PublishComment from './PublishComment.vue';
import VideoPreview from './VideoPreview.vue';
import emotions from '@/utils/emjo';
export default { export default {
name: "Dynamic-Item", name: "Dynamic-Item",
data() { data() {
return { return {
commentList: [{}, {}], commentList: [],
showComment: false, showComment: false,
commentContent: '', commentContent: '',
clientX: 0, clientX: 0,
clientY: 0, clientY: 0,
showDelBtn: false showDelBtn: false,
preNodes: [],
emotions
}; };
}, },
components: { components: {
PublishComment PublishComment,
VideoPreview
}, },
props: { props: {
form: { form: {
...@@ -149,6 +167,19 @@ ...@@ -149,6 +167,19 @@
default: false default: false
} }
}, },
watch: {
// 当内容变化时自动更新预览
"form.content": {
immediate: true,
handler(val, oldVal) {
if (val === oldVal) {
return;
}
this.preNodes = this.formatContent(val)
}
}
},
methods: { methods: {
// 点赞/取消点赞 // 点赞/取消点赞
handleUpdateLikeStatus(likeStatus) { handleUpdateLikeStatus(likeStatus) {
...@@ -156,11 +187,11 @@ ...@@ -156,11 +187,11 @@
momentId: this.form.id, momentId: this.form.id,
likeStatus likeStatus
} }
if(likeStatus == '1'){ if (likeStatus == '1') {
this.form.likeCount = this.form.likeCount + 1 this.form.likeCount = this.form.likeCount + 1
this.form.isLike = 1 this.form.isLike = 1
} }
if(likeStatus == '0'){ if (likeStatus == '0') {
this.form.likeCount = this.form.likeCount - 1 this.form.likeCount = this.form.likeCount - 1
this.form.isLike = 0 this.form.isLike = 0
} }
...@@ -171,6 +202,60 @@ ...@@ -171,6 +202,60 @@
}) })
}, },
formatContent(content) {
const nodes = [];
const emotionMap = {};
// 创建表情符号到iconfont的映射
this.emotions.forEach(emotion => {
emotionMap[emotion.symbol] = emotion.code;
});
// 提取所有表情符号并按长度排序
const emotionSymbols = Object.keys(emotionMap).sort((a, b) => b.length - a.length);
while (content.length > 0) {
let found = false;
// 查找是否有表情符号
for (const symbol of emotionSymbols) {
if (content.startsWith(symbol)) {
// 添加表情节点
nodes.push({
name: 'span',
attrs: {
class: `iconfont ${emotionMap[symbol]} emotion-icon`
},
});
content = content.slice(symbol.length);
found = true;
break;
}
}
// 如果没有找到表情,提取普通文本
if (!found) {
// 找到下一个表情的位置
let nextEmotionIndex = content.length;
for (const symbol of emotionSymbols) {
const index = content.indexOf(symbol);
if (index !== -1 && index < nextEmotionIndex) {
nextEmotionIndex = index;
}
}
// 提取文本
const text = content.slice(0, nextEmotionIndex);
nodes.push({
type: 'text',
text: text
});
content = content.slice(nextEmotionIndex);
}
}
return nodes;
},
// 打开评论区 // 打开评论区
handleOpenComment() { handleOpenComment() {
// this.showComment = true // this.showComment = true
...@@ -188,17 +273,17 @@ ...@@ -188,17 +273,17 @@
this.clientY = ((e.target.offsetTop * 2) + 34); this.clientY = ((e.target.offsetTop * 2) + 34);
}, },
// 删除动态 // 删除动态
handleDel(){ handleDel() {
let _this = this; let _this = this;
uni.showModal({ uni.showModal({
title: '提示', title: '提示',
content: '是否确认删除动态?', content: '是否确认删除动态?',
success: function (res) { success: function(res) {
if (res.confirm) { if (res.confirm) {
delMonment(_this.form.id).then(res=>{ delMonment(_this.form.id).then(res => {
if(res.code == 200){ if (res.code == 200) {
uni.showToast({ uni.showToast({
title:'删除成功', title: '删除成功',
}) })
_this.$emit('refresh'); _this.$emit('refresh');
uni.$emit('hanldeDynamicRefresh') uni.$emit('hanldeDynamicRefresh')
...@@ -226,12 +311,39 @@ ...@@ -226,12 +311,39 @@
} }
}) })
}, },
// 预览 // 删除评论
handleDelete(item) {
let _this = this;
uni.showModal({
title: '提示',
content: `是否确认删除评论:${item.content}?`,
success: function(res) {
if (res.confirm) {
delComment(item.id).then(res => {
if (res.code == 200) {
uni.showToast({
title: `删除成功`
})
_this.$emit('refresh');
}
})
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
// 预览图片
preview(url) { preview(url) {
uni.previewImage({ uni.previewImage({
urls: [url] urls: [url]
}); });
}, },
//预览视频
videoPreview(url) {
this.$refs.videoPreviewRef.openModal(url)
},
toDynamicDetailPage() { toDynamicDetailPage() {
let pathName = window.location.pathname let pathName = window.location.pathname
if (pathName.indexOf('/pages/dynamic-detail/dynamic-detail') > -1) { if (pathName.indexOf('/pages/dynamic-detail/dynamic-detail') > -1) {
...@@ -273,4 +385,11 @@ ...@@ -273,4 +385,11 @@
text-align: center; text-align: center;
box-shadow: 0px 2px 12rpx 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 2px 12rpx 0px rgba(0, 0, 0, 0.2);
} }
.emotion-icon {
font-size: 22px;
margin: 0 2px;
vertical-align: middle;
color: #333;
}
</style> </style>
\ No newline at end of file
...@@ -4,12 +4,12 @@ ...@@ -4,12 +4,12 @@
<block v-if="fileList && fileList.length > 0"> <block v-if="fileList && fileList.length > 0">
<view class="pic-list-item" v-for="(img, i) in fileList" :key="i"> <view class="pic-list-item" v-for="(img, i) in fileList" :key="i">
<block v-if="isVideo"> <block v-if="isVideo">
<video @click.stop :src="img.url" controls class="pic" <video @click.stop="videoPreview(img.url)" :src="img.url" controls class="pic"
:style="'width:'+width+'rpx;'+'height:'+height+'rpx'"></video> :style="'width:'+width+'rpx;'+'height:'+height+'rpx'"></video>
</block> </block>
<block v-else> <block v-else>
<image class="pic" :style="'width:'+width+'rpx;'+'height:'+height+'rpx'" :src="img.url" mode="" <image class="pic" :style="'width:'+width+'rpx;'+'height:'+height+'rpx'" :src="img.url" mode=""
@error="(e) => imgError(e, img)" @click="preview(img.url)"></image> @error="(e) => imgError(e, img)" @click.stop="preview(img.url)"></image>
<view v-if="img.error" class="pic-error">加载失败</view> <view v-if="img.error" class="pic-error">加载失败</view>
</block> </block>
<icon @click="handleRemove(i)" class="clear-icon" type="clear" size="20" /> <icon @click="handleRemove(i)" class="clear-icon" type="clear" size="20" />
...@@ -35,7 +35,17 @@ ...@@ -35,7 +35,17 @@
v-if="!isImg"></image> v-if="!isImg"></image>
<image src="/static/images/publish/video-disabled-icon.png" class="icons" v-else></image> <image src="/static/images/publish/video-disabled-icon.png" class="icons" v-else></image>
<!-- 表情 --> <!-- 表情 -->
<image src="/static/images/publish/face-icon.png" class="icons"></image> <image src="/static/images/publish/face-icon.png" class="icons" @click="handleShowEmjo"></image>
<!-- 表情展示区 -->
<view class="emjo-box" v-if="showEmjo" :style="'left:' + clientX + 'rpx;' +'top:' + clientY + 'rpx'">
<view class="emotion-list">
<view class="emotion-item" v-for="(emotion, index) in emotions" :key="index"
:title="emotion.name" @click="handleSelectEmjo(emotion)">
<text class="iconfont" :class="emotion.code"></text>
</view>
</view>
</view>
<!-- 话题 --> <!-- 话题 -->
<image src="/static/images/publish/topic-icon.png" class="icons" @click="handleOpenTopicSelection"> <image src="/static/images/publish/topic-icon.png" class="icons" @click="handleOpenTopicSelection">
</image> </image>
...@@ -44,6 +54,11 @@ ...@@ -44,6 +54,11 @@
<!-- @ --> <!-- @ -->
<!-- <image src="/static/images/publish/important-icon.png" class="icons"></image> --> <!-- <image src="/static/images/publish/important-icon.png" class="icons"></image> -->
</view> </view>
<!-- 视频预览 -->
<video-preview ref="videoPreviewRef"></video-preview>
</view> </view>
</template> </template>
...@@ -57,6 +72,7 @@ ...@@ -57,6 +72,7 @@
getToken getToken
} from '@/utils/auth.js'; } from '@/utils/auth.js';
import $modal from '@/utils/modal.js' import $modal from '@/utils/modal.js'
import VideoPreview from './VideoPreview.vue';
export default { export default {
name: 'BatchImageUpload', name: 'BatchImageUpload',
props: { props: {
...@@ -88,6 +104,9 @@ ...@@ -88,6 +104,9 @@
default: 200 default: 200
} }
}, },
components: {
VideoPreview
},
data() { data() {
return { return {
uploadUrl: '/bbs/mobile/common/upload', //上传地址 uploadUrl: '/bbs/mobile/common/upload', //上传地址
...@@ -96,7 +115,71 @@ ...@@ -96,7 +115,71 @@
fileList: [], fileList: [],
isVideo: false, isVideo: false,
isImg: false, isImg: false,
limiData: undefined limiData: undefined,
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: '[哭脸]'
},
],
showEmjo: false,
clientX: 0,
clientY: 0
}; };
}, },
computed: { computed: {
...@@ -161,7 +244,7 @@ ...@@ -161,7 +244,7 @@
} }
_this.fileList = newlist; _this.fileList = newlist;
this.limiData = this.limit - newlist.length this.limiData = this.limit - newlist.length
_this.$emit('componentsType', _this.isVideo ? 'VIDEO':'IMAGE') _this.$emit('componentsType', _this.isVideo ? 'VIDEO' : 'IMAGE')
}, },
immediate: true immediate: true
} }
...@@ -357,9 +440,25 @@ ...@@ -357,9 +440,25 @@
urls: [url] urls: [url]
}); });
}, },
//预览视频
videoPreview(url) {
this.$refs.videoPreviewRef.openModal(url)
},
// 选择话题 // 选择话题
handleOpenTopicSelection() { handleOpenTopicSelection() {
this.showEmjo = false
this.$emit('handleTopic') this.$emit('handleTopic')
},
// 打开表情选择
handleShowEmjo(e) {
this.showEmjo = !this.showEmjo
this.clientX = (e.target.offsetLeft * 2 - 158);
this.clientY = ((e.target.offsetTop * 2) + 34);
},
// 选择表情
handleSelectEmjo(emotion){
this.showEmjo = false
this.$emit('handleEmjo',emotion)
} }
} }
}; };
...@@ -367,8 +466,6 @@ ...@@ -367,8 +466,6 @@
<style scoped lang="scss"> <style scoped lang="scss">
.ImagesUpload { .ImagesUpload {
.pic-box { .pic-box {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
...@@ -434,4 +531,35 @@ ...@@ -434,4 +531,35 @@
} }
} }
} }
.emjo-box {
position: fixed;
width: 90vw;
min-height: 100rpx;
background-color: white;
box-shadow: 0px 2px 12rpx 0px rgba(0, 0, 0, 0.2);
border-radius: 10rpx;
z-index: 999;
.emotion-list {
display: flex;
flex-wrap: wrap;
padding: 10px;
overflow-y: auto;
}
.emotion-item {
width: 20%;
height:80rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 26px;
color: #333;
}
}
</style> </style>
\ No newline at end of file
<template>
<view class="video-preview-shadow" v-if="visible">
<div class="preview-box">
<view class="title">预览</view>
<video :src="url" class="video" :autoplay="autoplay"></video>
<view class="btn" @click="visible=false">关闭</view>
</div>
</view>
</template>
<script>
export default {
name: "VideoPreview",
data() {
return {
visible: false,
url: '',
autoplay:false
};
},
methods: {
openModal(url) {
this.visible = true
this.$nextTick(() => {
this.url = url;
this.autoplay = true
})
}
}
}
</script>
<style lang="scss" scoped>
.video-preview-shadow {
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.3);
z-index: 999;
position: fixed;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
.preview-box {
width: 90vw;
height: 1200rpx;
background-color: white;
border-radius: 20rpx;
.title{
height: 100rpx;
line-height: 100rpx;
text-align: center;
font-size: 32rpx;
font-weight: bold;
}
.video{
width: 100%;
height:calc(100% - 220rpx);
display: flex;
align-items: center;
justify-content: center;
}
.btn{
height: 120rpx;
line-height: 120rpx;
text-align: center;
font-weight: bold;
}
}
}
</style>
\ No newline at end of file
<template> <template>
<view class="page-container"> <view class="page-container">
<view class="search-box-common"> <view class="search-box-common">
<image src="/static/images/search-icon.png" class="search-icon"></image> <image src="/static/images/search-icon.png" class="search-icon" @click="refreshContentList"></image>
<input placeholder="搜索" placeholder-class="placeholder-class" /> <input placeholder="搜索" style="width: 100%;" v-model="queryParams.content" @keypress.enter="refreshContentList" placeholder-class="placeholder-class" />
</view> </view>
<scroll-view class="scroll-view-index" scroll-y :show-scrollbar="false" v-if="list.length>0" @scrolltolower="loadMore"> <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"> <template v-for="(item,index) in list">
<dynamic-item :form="item" @refresh="getList"></dynamic-item> <dynamic-item :form="item" @refresh="refreshContentList"></dynamic-item>
</template> </template>
</scroll-view> </scroll-view>
<scroll-view class="scroll-view-index" scroll-y :show-scrollbar="false" v-else> <scroll-view class="scroll-view-index" scroll-y :show-scrollbar="false" v-else>
...@@ -26,6 +27,7 @@ ...@@ -26,6 +27,7 @@
<script> <script>
import DynamicItem from '@/components/Dynamic-Item.vue' import DynamicItem from '@/components/Dynamic-Item.vue'
import ListEmpty from '@/components/ListEmpty.vue'; import ListEmpty from '@/components/ListEmpty.vue';
import emotions from '@/utils/emjo';
import { import {
dynamicList dynamicList
} from '@/api/api.js' } from '@/api/api.js'
...@@ -41,7 +43,8 @@ ...@@ -41,7 +43,8 @@
area: { area: {
x: 330, x: 330,
y: 600 y: 600
} },
emotions
} }
}, },
components: { components: {
...@@ -62,24 +65,27 @@ ...@@ -62,24 +65,27 @@
}, },
onPullDownRefresh() { onPullDownRefresh() {
this.refreshContentList() this.refreshContentList()
setTimeout(()=>{ setTimeout(() => {
uni.stopPullDownRefresh(); uni.stopPullDownRefresh();
}, 1000) }, 1000)
}, },
methods: { methods: {
getList() { getList() {
let _this = this;
uni.showLoading({ uni.showLoading({
title:'加载中...' title: '加载中...'
}) })
dynamicList(this.queryParams).then(res => { dynamicList(this.queryParams).then(res => {
this.list = [...this.list,...res.rows]; this.list = [...this.list, ...res.rows]
this.total = res.total this.total = res.total
}).finally(()=>{ }).finally(() => {
uni.hideLoading() uni.hideLoading()
}) })
}, },
loadMore() { loadMore() {
if(this.list.length < this.total){ if (this.list.length < this.total) {
this.queryParams.pageNum += 1; this.queryParams.pageNum += 1;
this.getList() this.getList()
} }
...@@ -115,10 +121,11 @@ ...@@ -115,10 +121,11 @@
position: fixed; position: fixed;
height: 100%; height: 100%;
width: 100%; width: 100%;
z-index: 999; z-index: 998;
pointer-events: none; pointer-events: none;
left: 0; left: 0;
top: 0; top: 0;
.move-button { .move-button {
pointer-events: auto; pointer-events: auto;
display: flex; display: flex;
......
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
<textarea class="textarea" v-model="form.content" placeholder="分享有趣事~" <textarea class="textarea" v-model="form.content" placeholder="分享有趣事~"
placeholder-class="placeholder-class" /> placeholder-class="placeholder-class" />
<image-upload v-model="form.attachments" :limit="9" :showIcons="true" <image-upload v-model="form.attachments" :limit="9" :showIcons="true"
@componentsType="handleSetComponentsType" @handleTopic="handleOpenTopicSelection"></image-upload> @componentsType="handleSetComponentsType" @handleTopic="handleOpenTopicSelection"
@handleEmjo="handleAddEmjo"></image-upload>
</view> </view>
<view class="permission-box"> <view class="permission-box">
<view class="item"> <view class="item">
...@@ -32,7 +33,7 @@ ...@@ -32,7 +33,7 @@
<!-- pk数据编辑 --> <!-- pk数据编辑 -->
<view class="pk-edit-box" v-if="form.isEnableVote==1"> <view class="pk-edit-box" v-if="form.isEnableVote==1">
<view class="textarea-box"> <view class="textarea-box">
<textarea class="textarea" v-model="form.voteTitle" placeholder="请输入PK标题~(0/12)" <textarea class="textarea" v-model="form.voteTitle" maxlength="12" placeholder="请输入PK标题~(0/12)"
placeholder-class="placeholder-class" /> placeholder-class="placeholder-class" />
</view> </view>
<view class="pk-type-box"> <view class="pk-type-box">
...@@ -60,11 +61,13 @@ ...@@ -60,11 +61,13 @@
<view class="choice-box" v-if="form.voteOptionType=='TEXT'"> <view class="choice-box" v-if="form.voteOptionType=='TEXT'">
<view class="choice-item text-item"> <view class="choice-item text-item">
<view class="label">选项1</view> <view class="label">选项1</view>
<input class="text" maxlength="4" v-model="form.voteOptions[0].name" placeholder="请输入选项1(4字以内)" /> <input class="text" maxlength="4" v-model="form.voteOptions[0].name"
placeholder="请输入选项1(4字以内)" />
</view> </view>
<view class="choice-item text-item"> <view class="choice-item text-item">
<view class="label">选项2</view> <view class="label">选项2</view>
<input class="text" maxlength="4" v-model="form.voteOptions[1].name" placeholder="请输入选项2(4字以内)" /> <input class="text" maxlength="4" v-model="form.voteOptions[1].name"
placeholder="请输入选项2(4字以内)" />
</view> </view>
</view> </view>
</view> </view>
...@@ -116,6 +119,7 @@ ...@@ -116,6 +119,7 @@
crateNewDynamic crateNewDynamic
} from '@/api/api.js'; } from '@/api/api.js';
import ImageUpload from '@/components/ImageUpload.vue' import ImageUpload from '@/components/ImageUpload.vue'
import emotions from '@/utils/emjo';
export default { export default {
data() { data() {
return { return {
...@@ -149,7 +153,8 @@ ...@@ -149,7 +153,8 @@
}], }],
}, },
voteOptionsAffirmative: [], voteOptionsAffirmative: [],
voteOptionsOpposing: [] voteOptionsOpposing: [],
emotions
} }
}, },
components: { components: {
...@@ -168,6 +173,28 @@ ...@@ -168,6 +173,28 @@
}) })
} }
}, },
// 当内容变化时自动更新预览
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;
}
}
}
}
}
},
methods: { methods: {
// 允许评论,开启精选等操作 // 允许评论,开启精选等操作
handleChange(e, field) { handleChange(e, field) {
...@@ -180,7 +207,7 @@ ...@@ -180,7 +207,7 @@
this.form.voteOptionType = e.detail.value this.form.voteOptionType = e.detail.value
}, },
handleSetComponentsType(type) { handleSetComponentsType(type) {
if (type && this.form.attachments.length > 0) { if (type && this.form.attachments && this.form.attachments.length > 0) {
this.form.type = type this.form.type = type
} else { } else {
this.form.type = 'TEXT' this.form.type = 'TEXT'
...@@ -211,7 +238,7 @@ ...@@ -211,7 +238,7 @@
this.$set(this.form.voteOptions[0], 'imageUrl', this.voteOptionsAffirmative[0].url); this.$set(this.form.voteOptions[0], 'imageUrl', this.voteOptionsAffirmative[0].url);
this.$set(this.form.voteOptions[1], 'imageUrl', this.voteOptionsOpposing[0].url); this.$set(this.form.voteOptions[1], 'imageUrl', this.voteOptionsOpposing[0].url);
} }
if(!this.form.voteTitle){ if (!this.form.voteTitle) {
uni.showToast({ uni.showToast({
title: '请输入PK标题', title: '请输入PK标题',
icon: 'error' icon: 'error'
...@@ -290,6 +317,35 @@ ...@@ -290,6 +317,35 @@
} }
}); });
},
// 添加表情
handleAddEmjo(emotion) {
console.log(emotion)
this.form.content = this.form.content + emotion.symbol
},
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);
}
} }
} }
} }
......
@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: 40rpx;
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";
}
...@@ -252,6 +252,25 @@ ...@@ -252,6 +252,25 @@
.content{ .content{
color: black; color: black;
margin: 10rpx 0; margin: 10rpx 0;
display: flex;
.text {
width: calc(100% - 180rpx);
}
.operation-text {
width: 180rpx;
text-align: right;
font-size: 24rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
.mr10{
margin-right: 12rpx;
}
.add-text {
color: #0058B6;
}
} }
.tips{ .tips{
font-size: 24rpx; font-size: 24rpx;
......
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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment