uniapp 微信小程序仿抖音评论区功能,支持展开收起

最近需要写一个评论区功能,所以打算仿照抖音做一个评论功能,支持展开和收起,

首先我们需要对功能做一个拆解,评论区功能,两个模块,一个是发表评论模块,一个是评论展示区。接下来对这两个模块进行详细描述。

使用到的技术 uniapp  uview2.0   文章最后我会贴上全部源码

一、发表评论模块

这个模块使用uview的两个组件来完成分别是u-popup弹出层和u-input输入框

下面是代码和展示图:

<u-popup :show="talkShow" mode="bottom" :customStyle="{'width':'100%','border-radius':'8rpx'}" @close="popclosed" @open="keyboard=true" :safeAreaInsetBottom="true">
			<view class="flex justify-between align-center" style="padding: 32rpx;">
				<div class="cirbOX padding-left padding-right-sm">
					<u--form labelPosition="left" :model="talkData" :rules="Rules" ref="Form" :borderBottom="false">
						<u-form-item label=" " prop="txt" :borderBottom="false" ref="item1" labelWidth='0'>
							<u--input :focus="keyboard" v-model="talkData.txt" cursorSpacing="30" maxlength="100" :placeholder="pinglunHolder" border="none" clearable></u--input>
						</u-form-item>
					</u--form>
				</div>
				<div class="submitpinglun" @click="submit">发布</div>
			</view>
		</u-popup>

这部分需要注意两点

1.input组件的focus属性的设置:

在弹出层弹出的时候 在open事件中对input的focus属性布尔值设置为true,close时候设置focus为false。这样做的目的是在弹出输入评论的弹窗时会拉起小键盘,这个交互方式是模仿的微信朋友圈发布评论的形式。

2.input的cursorSpacing属性(输入框聚焦时底部与键盘的距离)设置:

当键盘拉起时候整个输入框因为设置了cursorSpacing="30",故整体页面会被小键盘托起。 当收起小键盘时候,输入框有回归到手机底部,因为我们popup设置的是底部的弹出层。这样是和微信朋友圈发布评论是对标的。

二、展示评论区的功能

这一部分我封装成了组件,因为需求的要求需要下拉加载评论故在组件外部循环一级评论,组件内部展示一级评论和二级评论,其中二级评论是在组件内部去循环,

循环一级评论的时候需要注意,因为后续要获取pinglun组件的实例,所以在ref的设置上面起初我按照for循环提供的index来拼的字符串,这也导致后续bug的出现埋下伏笔,所以我后续调整了,选择了id这个唯一值作为组件实例的ref名字,这个很关键!

<div v-for="(item,index) in onePagePinglunList" :key="item.id" class="margin-bottom">
				<pinglun :ref="`pinglun-${item.levelOneCommentVo.id}`" :caseIdData="caseId" :data="item" :indexxx="index" @comment="goComment" @noLogin="sonNoLogin"></pinglun>
			</div>

组件代码:

<template>
	<div>
		<!-- 一级评论 -->
		<div class="flex justify-start align-start margin-bottom-sm">
			<div class="margin-right-xs">
				<d-image :dSrc="onePageList.levelOneCommentVo.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image>
			</div>
			<div class="flex-sub">
				<div class="flex justify-start align-center">
					<div class="name margin-right-sm">{{onePageList.levelOneCommentVo.userName}}</div>
					<div class="zuozhe flex justify-center align-center" v-if="onePageList.levelOneCommentVo.belongAuthor===1">作者</div>
				</div>
				<div class="flex justify-between align-center" @click="goPinglun(1,onePageList.levelOneCommentVo.id,onePageList.levelOneCommentVo.userName,onePageList.levelOneCommentVo.id)">
					<div class="content flex-sub">{{onePageList.levelOneCommentVo.content}}</div>
					<div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(1,'',onePageList.levelOneCommentVo.id)">
						<div class="margin-bottom-xs">
							<div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===0">
								<u-icon name="heart" color="#667286" size="34rpx"></u-icon>
							</div>
							<div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===1">
								<u-icon name="heart-fill" color="red" size="34rpx"></u-icon>
							</div>
						</div>
						<div class="likeNum">{{onePageList.levelOneCommentVo.likeCount}}</div>
					</div>
				</div>
				<div class="time">{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}</div>
			</div>
		</div>
		<!-- 二级评论 -->
		<div class="erpinglunBox" :style="{'height':`${pingjiaBoxMaxHeight}px`,'opacity':pinglunOpcity,}">
			<div class="pinglunDom">
				<div v-for="(item,index) in onePageList.twoLevelpinglun" :key="item.id" class="margin-bottom-sm">
					<div class="flex justify-start align-start">
						<div class="margin-right-xs">
							<d-image :dSrc="item.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image>
						</div>
						<div class="flex-sub">
							<div class="flex justify-start align-center">
								<div class="name margin-right-sm">{{item.userName}}</div>
								<div class="zuozhe flex justify-center align-center margin-right-sm" v-if="item.belongAuthor===1">作者</div>
								<div class="name" v-if="item.isReplayTwoComment===1">回复 {{item.replayLevelTwoCommentUser.userName}}</div>
							</div>
							<div class="flex justify-between align-center" @click="goPinglun(2,item.id,item.userName,onePageList.levelOneCommentVo.id)">
								<div class="content flex-sub">{{item.content}}</div>
								<div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(2,index,item.id)">
									<div class="margin-bottom-xs">
										<div v-show="item.isCurrentUserLike===0">
											<u-icon name="heart" color="#667286" size="34rpx"></u-icon>
										</div>
										<div v-show="item.isCurrentUserLike===1">
											<u-icon name="heart-fill" color="red" size="34rpx"></u-icon>
										</div>
									</div>
									<div class="likeNum">{{item.likeCount}}</div>
								</div>
							</div>
							<div class="time">{{ $u.timeFrom(new Date(item.createTime).getTime())}}</div>
						</div>
					</div>
				</div>
			</div>
		</div>
		<!-- 展开和收起按钮 -->
		<div class="flex justify-start align-center" style="padding-left: 84rpx;">
			<div class="seeMore padding-top-sm padding-bottom flex align-center" v-if="onePageList.levelTwoCommentCount > 0&&params.current <= totalPage" @click="$u.throttle(getTwoLevelPinglun, 1000,true)">
				<div class="margin-right-xs">查看更多回复</div>
				<u-icon name="arrow-down" color="#00875A" size="28rpx" :bold="true"></u-icon>
			</div>
			<div class="seeMore retract padding-top-sm padding-bottom margin-left flex justify-center align-center" v-if="params.current > 1" @click="$u.throttle(retract, 1000,true)">
				<div class="margin-right-xs">收起</div>
				<u-icon name="arrow-up" color="#00875A" size="28rpx" :bold="true"></u-icon>
			</div>
		</div>
	</div>
</template>

感觉唯一的难点在于因为展开收缩使用的过渡动画,大家应该都知道,想使用这个过渡必须设置有效值,也就是说比如我给高度写过渡动画,从一个高度到一个高度,都需要是具体的值,atuo这种被内容撑开的高度是不作数的。

这里拿高度,需要注意的是需要等待渲染完毕再去获取高度,不然拿到的值就是不准确的。

下面是我写的获取高度的函数。如果一个nexttick也获取不到准确高度,那么就再加个延时器,就差不多可以获取到准确高度了。

	updatHeight() {
				let that = this
				this.$nextTick(() => {
					// this.timer = setTimeout(() => {
					this.createSelectorQuery().select(".pinglunDom").boundingClientRect(function(rect) {
						// console.log(rect);
						that.pingjiaBoxMaxHeight = rect.height
						that.pinglunOpcity = 1
					}).exec();
					// }, 0)
				})
			},

还有一个需要注意的点,就是在一级评论发布之后,需要拿到所有pinglu组件的实例去调用这个方法,重置所有二级评论的高度。调用这个方法的前提也必须是一级评论的渲染完毕,不然还是不起作用

以下是代码:

this.$forceUpdate();
	this.$nextTick(() => {
		for (let i = 0; i < this.onePagePinglunList.length; i++) {
			this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].updatHeight() 
			if (this.onePagePinglunList[i].twoLevelpinglun.length === 0) {
	        this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].params.current = 1
			}
		}
	}) 

至此应该就没什么需要注意的地方了

可能也是第一次写这个功能,还有很多可以优化的地方。希望对各位有所帮助,接下来我把评论功能所有源码贴在下面。

因为我的评论功能是在案例详情里面的,所以有两个文件,一个是案例详情,一个就是封装的评论组件 

案例详情:

<template>
	<div :style="{'padding-bottom':`${(safeAreaBottom*2)+144}`+'rpx'}">
		<div style="padding: 32rpx 32rpx 50rpx;">
			<div class="margin-bottom-sm txt-1">成功蜕变历程</div>
			<div class="toplicheng flex justify-center align-center margin-bottom-sm">
				<div class="flex flex-direction align-center">
					<div class="flex align-center">
						<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/caseDetailIcON2.png" dMode="aspectFit" dWidth="32rpx" dHeight="32rpx"></d-image>
						<div class="toptxt1 margin-left-xs">体重</div>
					</div>
					<div class="toptxt2 margin-top-xs">{{topweightcha||0}}kg</div>
				</div>
				<div class="midBox flex flex-direction align-center">
					<div class="xmonth flex justify-center align-center margin-bottom-xs">逆糖3个月</div>
					<div class="topshuxian"></div>
				</div>
				<div class="flex flex-direction align-center">
					<div class="flex align-center">
						<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/caseDetailIcON1.png" dMode="aspectFit" dWidth="32rpx" dHeight="32rpx"></d-image>
						<div class="toptxt1 margin-left-xs">空腹血糖</div>
					</div>
					<div class="toptxt2 margin-top-xs">{{topxuetangcha||0}}mmol/L</div>
				</div>
			</div>
			<!-- 案例信息 -->
			<div class="caseBox">
				<div class="case-head-box flex justify-between align-center">
					<div class="head-left-box flex">
						<div class="avatarBox">
							<u-avatar :src="detailData.userInfoVo.userAvatar || 'https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/healthy.png'" size="72rpx" mode="aspectFill"></u-avatar>
						</div>
						<div>
							<div class="txt-1 margin-bottom-xs">{{detailData.userInfoVo.userName||'暂无昵称'}}</div>
							<div class="txt-2">{{detailData.isExistServicePack?detailData.servicePackVo.servicePackName:'暂无服务包'}}</div>
						</div>
					</div>
					<div class=" flex justify-center align-center" style="width: 80rpx;height: 80rpx;">
						<u-icon name="share-square" color="" size="34rpx"></u-icon>
					</div>
				</div>
				<div class="caseBoxContentBox">
					<u-row justify="space-start">
						<u-col span="4">
							<view class="txt-4 margin-bottom">项目</view>
						</u-col>
						<u-col span="4">
							<view class="txt-4 margin-bottom">管理前</view>
						</u-col>
						<u-col span="4">
							<view class="txt-4 margin-bottom">管理后</view>
						</u-col>
					</u-row>
					<u-row justify="space-start">
						<u-col span="4">
							<view>
								<div class="txt-3">服务时间</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="startTime">
									{{detailData.managementInfoVo.managementStartTime||'--'}}
								</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="endTime">
									{{detailData.managementInfoVo.managementEndTime||'--'}}
								</div>
							</view>
						</u-col>
					</u-row>
					<div class="line"></div>
					<u-row justify="space-start">
						<u-col span="4">
							<view>
								<div class="txt-3">体重</div>
								<div class="txt-7">kg</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="yellow-box flex justify-center align-center" style="position: relative;">
									{{detailData.managementInfoVo.beforeManagementWeight||'--'}}
									<div class="jiantou" v-if="detailData.managementInfoVo.beforeManagementFastingSugarBloodTrend===3">
										<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/redUp.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image>
									</div>
									<div class="jiantou" v-else-if="detailData.managementInfoVo.beforeManagementFastingSugarBloodTrend===1">
										<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/greenDown.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image>
									</div>
								</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="green-box flex justify-center align-center">{{detailData.managementInfoVo.afterManagementWeight||'--'}}</div>
							</view>
						</u-col>
					</u-row>
					<div class="line"></div>
					<u-row justify="space-start">
						<u-col span="4">
							<view>
								<div class="txt-3">空腹血糖</div>
								<div class="txt-7">mmol/L</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="yellow-box flex justify-center align-center" style="position: relative;">
									{{detailData.managementInfoVo.beforeManagementFastingSugarBlood||'--'}}
									<div class="jiantou"
										v-if="detailData.managementInfoVo.beforeManagementWeightTrend===3||detailData.managementInfoVo.beforeManagementWeightTrend===4||detailData.managementInfoVo.beforeManagementWeightTrend===5">
										<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/redUp.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image>
									</div>
									<div class="jiantou" v-else-if="detailData.managementInfoVo.beforeManagementWeightTrend===1">
										<d-image dSrc="https://tj-data.oss-cn-hangzhou.aliyuncs.com/uploadFiles/wx/mzkHomeland/greenDown.png" dMode="aspectFit" dWidth="24rpx" dHeight="24rpx"></d-image>
									</div>
								</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="green-box flex justify-center align-center">
									{{detailData.managementInfoVo.afterManagementFastingSugarBlood||'--'}}
								</div>
							</view>
						</u-col>
					</u-row>
					<div class="line"></div>
					<u-row justify="space-start">
						<u-col span="4">
							<view>
								<div class="txt-3">用药数量</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="yellow-box flex justify-center align-center">
									{{detailData.managementInfoVo.beforeManagementMedicationCount||'0'}}
								</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="green-box flex justify-center align-center">
									{{detailData.managementInfoVo.afterManagementMedicationCount||'0'}}
								</div>
							</view>
						</u-col>
					</u-row>
					<div class="line"></div>
					<u-row justify="space-start">
						<u-col span="4">
							<view>
								<div class="txt-3">对比照片</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="margin-bottom-sm">
									<div>
										<div v-if="detailData.managementInfoVo.beforeManagementImagePhoto===''" class="noPicBox flex justify-center align-center">暂无</div>
										<div v-else>
											<d-image :dSrc="detailData.managementInfoVo.beforeManagementImagePhoto" dMode="aspectFit" dWidth="140rpx" dHeight="140rpx">
											</d-image>
										</div>
									</div>
								</div>
							</view>
						</u-col>
						<u-col span="4">
							<view>
								<div class="margin-bottom-sm">
									<div>
										<div v-if="detailData.managementInfoVo.afterManagementImagePhoto===''" class="noPicBox flex justify-center align-center">暂无</div>
										<div v-else>
											<d-image :dSrc="detailData.managementInfoVo.afterManagementImagePhoto" dMode="aspectFit" dWidth="140rpx" dHeight="140rpx">
											</d-image>
										</div>
									</div>
								</div>
							</view>
						</u-col>
					</u-row>
				</div>
			</div>
			<!-- 评价 -->
			<div class="evaluateBox margin-top-sm margin-bottom-sm">
				<div class="margin-bottom-sm txt-1">健康评价</div>
				<div class="margin-top-sm flex flex-wrap pingjiaBox">
					<view class="pingjiaDom">
						<div v-for="(item,index) in defaultPingjia" :key="item.id" class="flex ">
							<div class="tag margin-right-sm flex align-center margin-bottom-sm" :style="{'background':item.styleBg}">
								<div style="height: 100%; " class="flex align-start margin-right-sm">
									<d-image :dSrc="item.styleIcon" dMode="aspectFit" dWidth="26rpx" dHeight="26rpx">
									</d-image>
								</div>
								<text :style="{'max-width': '544rpx','word-break': 'break-all','color':item.styleColor}">{{item.content}}</text>
							</div>
						</div>
					</view>
				</div>
			</div>
			<!-- echart -->
			<!-- 	<div class="margin-bottom-sm" style="position: relative;overflow: hidden;" v-for="(item,index) in echartList" :key="index">
				<detailChart :echarType="item"></detailChart>
			</div> -->
		</div>
		<!-- 评论 -->
		<div style="padding: 0 32rpx 56rpx;background: #FFFFFF;">
			<div class="flex justify-between align-center">
				<div class="pingluntitle">{{detailData.interActionVo.commentCount||'0'}} 评论</div>
				<div></div>
			</div>
			<div v-for="(item,index) in onePagePinglunList" :key="item.id" class="margin-bottom">
				<pinglun :ref="`pinglun-${item.levelOneCommentVo.id}`" :caseIdData="caseId" :data="item" :indexxx="index" @comment="goComment" @noLogin="sonNoLogin" @shouqi="shouqiTwoPinglun"></pinglun>
			</div>
		</div>
		<div class="contentB">- 让每个人都能从知识中获得健康 -</div>
		<!-- 底部评价评论点赞收藏 -->
		<div class="pingjialikeBox flex justify-between align-center" :style="{'bottom':`${(safeAreaBottom*2)}`+'rpx'}">
			<div class="talksomething flex justify-center align-center" @click="openPinglun">说点什么吧</div>
			<div class="flex justify-around" style="width: 428rpx;">
				<div class="flex align-center btn" @click="$u.throttle(clickLike, 500,true)">
					<div v-show="detailData.interActionVo.isCurrentUserLike===0">
						<u-icon name="heart" color="" size="34rpx"></u-icon>
					</div>
					<div v-show="detailData.interActionVo.isCurrentUserLike===1">
						<u-icon name="heart-fill" color="red" size="34rpx"></u-icon>
					</div>
					<text class="margin-left-xs">{{detailData.interActionVo.likeCount||'0'}}</text>
				</div>
				<div class="flex align-center btn" @click="$u.throttle(clickCollect, 500,true)">
					<div v-show="detailData.interActionVo.isCurrentUserCollection===0">
						<u-icon name="star" color="" size="34rpx"></u-icon>
					</div>
					<div v-show="detailData.interActionVo.isCurrentUserCollection===1">
						<u-icon name="star-fill" color="#ff991f" size="34rpx"></u-icon>
					</div>
					<text class="margin-left-xs">{{detailData.interActionVo.collectionCount||'0'}}</text>
				</div>
				<div class=" flex align-center btn">
					<u-icon name="chat" color="" size="34rpx"></u-icon>
					<text class="margin-left-xs">{{detailData.interActionVo.commentCount||'0'}}</text>
				</div>
			</div>
		</div>
		<u-popup :show="talkShow" mode="bottom" :customStyle="{'width':'100%','border-radius':'8rpx'}" @close="popclosed" @open="keyboard=true" :safeAreaInsetBottom="true">
			<view class="flex justify-between align-center" style="padding: 32rpx;">
				<div class="cirbOX padding-left padding-right-sm">
					<u--form labelPosition="left" :model="talkData" :rules="Rules" ref="Form" :borderBottom="false">
						<u-form-item label=" " prop="txt" :borderBottom="false" ref="item1" labelWidth='0'>
							<u--input :focus="keyboard" v-model="talkData.txt" cursorSpacing="30" maxlength="100" :placeholder="pinglunHolder" border="none" clearable></u--input>
						</u-form-item>
					</u--form>
				</div>
				<div class="submitpinglun" @click="submit">发布</div>
			</view>
		</u-popup>
		<u-modal title="确认登录" :show="show1" width="608rpx" content="为了您的良好体验,建议您先确认登录 ~" :closeOnClickOverlay="true" @close="show1=false">
			<u-button slot="confirmButton" text="确定" shape="circle" color="#00875A" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber" :customStyle="{'width':'264rpx','height':'68rpx'}"></u-button>
		</u-modal>
		<u-toast ref="uToast"></u-toast>
	</div>
</template>

<script>
	import { mapState } from 'vuex';
	import detailChart from "./detailEchart.vue"
	import pinglun from "./pinglun.vue"
	import { sub } from '@/utils/tool.js'
	import { getDetail, getCurveModule, collection, like, savecomment, getLevelOnePage } from '@/api/case/case.js'
	export default {
		data() {
			return {
				show1: false,
				keyboard: false,
				pinglunHolder: '说点什么吧',
				Rules: {
					'txt': [{
							required: true,
							type: 'any',
							message: '评论不能为空',
							trigger: ['blur', 'change']
						},
						{
							validator: (rule, value, callback) => {
								return value.length < 100;
							},
							message: '您评论的字数超过100,请调整您的字数~',
							trigger: ['blur', 'change']
						}
					],
				},
				talkShow: false,
				talkData: { //弹框form值 评论
					txt: ""
				},
				caseId: null,
				echartList: [],
				detailData: {},
				defaultPingjia: [],
				topweightcha: null,
				topxuetangcha: null,
				pinglunForm: { //接口参数
					caseId: null,
					caseLevelOneCommentId: '', //对一级评论进行回复时不可为空
					caseLevelTwoCommentId: '', //对二级评论进行回复时不可为空
					content: null,
					userId: null,
				},
				params: {
					current: 1,
					limit: 5,
					likeSort: 2, //点赞数排序 1:升序 2:降序
					timeSort: 2, //创建时间排序 1:升序 2:降序
				},
				totalPage: 1,
				onePagePinglunList: [],
				pinglunType: null, //判断用户评论的类型是案例评论(3)还是一级评论(1)还是二级评论(2)
				erpinglunIndex: 0, //暂存二级评论发送给父级组件给的一级评论的index
			}
		},
		components: { detailChart, pinglun },
		computed: {
			...mapState(["hasLogin", "safeAreaBottom", "userInfo", ])
		},
		// 发送给朋友
		onShareAppMessage(res) {
			return {
				title: '妙智健康案例',
				path: `/pages-caseStory/caseDetail/index?caseId=${this.caseId}&title=${this.detailData.userInfoVo.userName}`
			}
		},
		//分享到朋友圈
		onShareTimeline(res) {
			return {
				title: '妙智健康案例',
				query: `caseId=${this.caseId}&title=${this.detailData.userInfoVo.userName}`,
				path: `/pages-caseStory/caseDetail/index` //自定义路径拼参数会导致接收参数会失败
			}
		},
		onReady() {},
		onLoad(option) {
			this.$refs.Form.setRules(this.Rules)
			this.caseId = option?.caseId
			uni.setNavigationBarTitle({
				title: `${option.title||''}案例`
			});
			this.getdetailData()
			this.getLevelOnePageData()
		},
		onUnload() {
			// this.$store.commit('set_caseShareEchartPicList', [])
		},
		onShow() {

		},
		methods: {
			sub,
			async getPhoneNumber(e) {
				// console.log("获取手机号code", e) //获取手机号已经不需要先进行wx.login(最新文档)
				if (!e.detail.code) {
					uni.showToast({
						title: '登录需要获取您的手机号',
						icon: 'none',
						duration: 2500
					})
					return
				}
				let resss = await this.$store.dispatch("loginFn", e) //能同步拿到vux中mutaion的resolve,然后给fourDataNum赋值(登录后数据更新)
				console.log(resss);
				if (resss.state === 1) { //登录成功
					this.show1 = false
				}
			},
			async getdetailData() {
				uni.showLoading({
					title: '加载中...'
				})
				try {
					let res = await getDetail({
						caseId: this.caseId,
						userId: this.hasLogin ? this.userInfo?.userId : ''
					})

					let echarRes = await getCurveModule({
						caseId: this.caseId,
					})
					if (res.state === 1) {
						this.detailData = res.content
						this.defaultPingjia = res.content.personnelEvaluationVoList
						this.topweightcha = this.sub(this.detailData.managementInfoVo.afterManagementWeight, this.detailData.managementInfoVo.beforeManagementWeight)
						this.topxuetangcha = this.sub(this.detailData.managementInfoVo.afterManagementFastingSugarBlood, this.detailData.managementInfoVo.beforeManagementFastingSugarBlood)
					}
					if (echarRes.state === 1) {
						this.echartList = echarRes.content.map(item => {
							let obj = {
								title: item.caseCurveType === 1 ? '硅基' : (item.caseCurveType === 2 ? "微策" : "体重"),
								defaultTime: item.caseCurveType === 1 ? item.curveStartDate : [item.curveStartDate, item.curveEndDate],
								userId: res.content.userInfoVo.userId
							}
							return obj
						})
					}
					uni.hideLoading();
				} catch (e) {
					uni.hideLoading();
					uni.$u.toast(e)
				}
			},
			async clickLike(item, index) {
				if (!this.hasLogin) {
					this.show1 = true
					return
				}
				try {
					let res = await like({
						userId: this.userInfo?.userId,
						caseId: this.caseId,
					})
					if (res.state === 1) {
						if (this.detailData.interActionVo.isCurrentUserLike === 1) {
							this.detailData.interActionVo.isCurrentUserLike = 0
							this.detailData.interActionVo.likeCount--
						} else if (this.detailData.interActionVo.isCurrentUserLike === 0) {
							this.detailData.interActionVo.isCurrentUserLike = 1
							this.detailData.interActionVo.likeCount++
						}
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			async clickCollect(item) {
				if (!this.hasLogin) {
					this.show1 = true
					return
				}
				try {
					let res = await collection({
						userId: this.userInfo?.userId,
						caseId: this.caseId,
					})
					if (res.state === 1) {
						if (this.detailData.interActionVo.isCurrentUserCollection === 1) {
							this.detailData.interActionVo.isCurrentUserCollection = 0
							this.detailData.interActionVo.collectionCount--
						} else if (this.detailData.interActionVo.isCurrentUserCollection === 0) {
							this.detailData.interActionVo.isCurrentUserCollection = 1
							this.detailData.interActionVo.collectionCount++
						}
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			popclosed() {
				this.talkData.txt = ''
				this.keyboard = false
				this.talkShow = false
				console.log(this.keyboard);
			},
			async getLevelOnePageData() {
				uni.showLoading({
					title: '加载中...'
				})
				try {
					let res = await getLevelOnePage({ userId: this.hasLogin ? this.userInfo?.userId : '', caseId: Number(this.caseId), ...this.params })

					if (res.state === 1) {
						for (let i = 0; i < res.content.records.length; i++) {
							res.content.records[i].twoLevelpinglun = []
							if (this.onePagePinglunList.some(item => item.levelOneCommentVo.id === res.content.records[i].levelOneCommentVo.id)) { //删除重复项
								res.content.records.splice(i, 1)
							}
						}
						this.onePagePinglunList = [...this.onePagePinglunList, ...res.content.records]
						this.totalPage = Math.ceil(res.content.total / this.params.limit) //总页数=总数量/每页数量
					}
					uni.hideLoading();
				} catch (e) {
					uni.hideLoading();
					uni.$u.toast(e)
				}
			},
			openPinglun() {
				if (!this.hasLogin) {
					this.show1 = true
					return
				}
				this.pinglunType = 3 //案例评论
				this.pinglunHolder = '说点什么吧'
				this.pinglunForm.caseLevelOneCommentId = '' //不回复一二级评论时候置空该字段
				this.pinglunForm.caseLevelTwoCommentId = '' //不回复一二级评论时候置空该字段

				this.talkShow = true
				// this.keyboard = true
			},
			goComment(e) { //处理回复一级二级评论  案例的顶级评论在openPinglun()函数中
				console.log(e);
				this.pinglunType = e.type //评论类型
				console.log('this.pinglunType', this.pinglunType);
				if (e.type === 1) { //一级评论
					this.pinglunForm.caseLevelOneCommentId = e.id
					this.erpinglunIndex = e.index
					this.pinglunHolder = `回复 @${e.replyName}`
				} else if (e.type === 2) { //二级评论
					this.pinglunForm.caseLevelTwoCommentId = e.id
					this.erpinglunIndex = e.index
					this.pinglunHolder = `回复 @${e.replyName}`
				}
				console.log("点击的item", this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList);
				this.talkShow = true
				// this.keyboard = true
				console.log(this.keyboard);
			},
			async submit() {
				this.pinglunForm.userId = this.userInfo.userId
				this.pinglunForm.content = this.talkData.txt
				this.pinglunForm.caseId = this.caseId
				// let form = {
				// 	caseId: this.caseId,
				// 	caseLevelOneCommentId: '', //对一级评论进行回复时不可为空
				// 	caseLevelTwoCommentId: '', //对二级评论进行回复时不可为空
				// 	content: this.talkData.txt,
				// 	userId: this.userInfo.userId,
				// }
				try {
					let res = await savecomment(this.pinglunForm)
					if (res.state === 1) {

						if (this.pinglunType === 3) { //案例评论
							this.onePagePinglunList.unshift({
								twoLevelpinglun: [],
								...res.content.caseCommentHomeVo
							})
							this.$forceUpdate();
							this.$nextTick(() => {
								for (let i = 0; i < this.onePagePinglunList.length; i++) {
									this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].updatHeight() //重置子组件内部height 不管新增一级还是二级都需要全部重置高度不然会出现bug
									if (this.onePagePinglunList[i].twoLevelpinglun.length === 0) {
										this.$refs[`pinglun-${this.onePagePinglunList[i].levelOneCommentVo.id}`][0].params.current = 1
									}
								}
								console.log(this.$refs[`pinglun-${127}`][0].onePageList);
							})
							this.$forceUpdate();
						} else if (this.pinglunType === 1 || this.pinglunType === 2) { //回复一级评论或二级评论  push完需要注意的是在获取分页数据时候去重,因为这个push操作是模拟更新数据,后端并不知晓所以后端未做去重
							console.log(this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun);
							this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun.push({
								...res.content.caseLevelTwoCommentVo
							})
							console.log(this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun);
							let indxx;
							for (let i = 0; i < this.onePagePinglunList.length; i++) {
								if (this.onePagePinglunList[i].levelOneCommentVo.id === this.erpinglunIndex) {
									indxx = i
									break
								}
							}
							// 目的是防止发表一级评论之后父级向下重新注入数据,会触发pinglun组件内部的watch,导致会重置组件内部的twoLevelpinglun为[],
							this.onePagePinglunList[indxx].twoLevelpinglun = this.$refs[`pinglun-${this.erpinglunIndex}`][0].onePageList.twoLevelpinglun
							this.onePagePinglunList[indxx].levelTwoCommentCount++

							this.$refs[`pinglun-${this.erpinglunIndex}`][0].updatHeight() //重置子组件内部height

						}
						this.talkData.txt = '' //重置评论
						this.keyboard = false //自动聚焦设为false
						this.talkShow = false //关闭弹窗
						this.updatePinglunNum() //更新评论数量
						console.log(this.keyboard);
						this.$refs.uToast.show({
							type: 'success',
							message: "已发送评论~",
							duration: 1200,
						})
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			sonNoLogin(e) {
				console.log(e);
				if (!this.hasLogin) {
					this.show1 = true
					return
				}
			},
			async updatePinglunNum() {
				try {
					let res = await getDetail({
						caseId: this.caseId,
						userId: this.hasLogin ? this.userInfo?.userId : ''
					})
					if (res.state === 1) {
						this.detailData = res.content
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			//因为每次发表二级评论都会往父级的twoLevelpinglun添加属性,也就是submit函数里面的565行代码,会导致一个bug 就是发布二级评论后,
			// 因为同时给父级也赋值了,故收起二级评论后,再发表一级评论,重置了了渲染,会将父级被赋值的twoLevelpinglun同步到二级评论的twoLevelpinglun,相当于之前收起操作白重置了twoLevelpinglun
			shouqiTwoPinglun(index) {
				let indxx;
				for (let i = 0; i < this.onePagePinglunList.length; i++) {
					if (this.onePagePinglunList[i].levelOneCommentVo.id === index) {
						indxx = i
						break
					}
				}
				this.onePagePinglunList[indxx].twoLevelpinglun = []
			},
		},
		// 上拉加载
		async onReachBottom() {
			if (this.params.current > this.totalPage) {
				this.$refs.uToast.show({
					type: 'warning',
					message: "已经到底啦~",
					duration: 1200,
				})
				return
			}
			this.params.current += 1
			await this.getLevelOnePageData()
			uni.stopPullDownRefresh() //停止上拉加载
		},
		// 下拉刷新触发
		async onPullDownRefresh() {
			this.params.current = 1 //重置页码
			this.onePagePinglunList = []
			await this.getLevelOnePageData()
			this.$refs.uToast.show({
				type: 'success',
				message: "刷新成功",
				duration: 1200,
			})
			uni.stopPullDownRefresh() //停止下拉刷新
		},

	}
</script>

<style lang="scss" scoped>
	@import '@/pages-caseStory/style/caseCommon.scss';

	.pingluntitle {
		font-size: 28rpx;
		font-family: PingFangSC;
		color: #1F3253;
		height: 90rpx;
		line-height: 90rpx;
	}

	.contentB {
		margin: 42rpx 0;
		font-size: 24rpx;
		font-weight: 400;
		color: #667286;
		text-align: center;
	}

	.pingjialikeBox {
		padding: 32rpx;
		width: 100%;
		height: 144rpx;
		background: #FFFFFF;
		position: fixed;
		left: 0;

		.btn {
			height: 70rpx;
			width: 78rpx;
		}
	}

	.toplicheng {
		height: 160rpx;
		background: linear-gradient(47deg, rgba(23, 144, 109, 0.84) 0%, #5DC063 100%);
		border-radius: 12rpx;
	}

	.topshuxian {
		width: 1rpx;
		height: 80rpx;
		opacity: 0.5;
		border: 2rpx solid #FFFFFF;
	}

	.xmonth {
		width: 156rpx;
		height: 47rpx;
		background: #FFFFFF;
		border-radius: 0rpx 0rpx 14rpx 14rpx;
		opacity: 0.8;
		font-size: 24rpx;
		font-weight: 400;
		color: #00875A;
	}

	.toptxt1 {
		font-size: 28rpx;
		font-weight: 400;
		color: #FFFFFF;
	}

	.toptxt2 {
		font-size: 36rpx;
		font-weight: bold;
		color: #E2FFF5;
	}

	.midBox {
		width: 156rpx;
		height: 160rpx;
		margin-left: 70rpx;
		margin-right: 23rpx;
	}

	.noPicBox {
		width: 140rpx;
		height: 140rpx;
		background: #E7EFF6;
	}

	.jiantou {
		position: absolute;
		top: 0;
		right: 0;
	}

	.evaluateBox {
		background: #FFFFFF;
		border-radius: 12rpx;
		padding: 40rpx 32rpx 78rpx;

		.tag {
			background: #FFF6E9;
			border-radius: 30rpx;
			padding: 20rpx 30rpx 20rpx 20rpx;
			vertical-align: center;

		}
	}

	.talksomething {
		width: 248rpx;
		height: 80rpx;
		background: #F4F5F7;
		border-radius: 40rpx;
		font-size: 28rpx;
		font-weight: 400;
		color: #697588;
	}

	.cirbOX {
		width: 600rpx;
		height: 80rpx;
		background: #F4F5F7;
		border-radius: 40rpx;
	}

	.submitpinglun {
		height: 80rpx;
		width: 64rpx;
		font-size: 32rpx;
		font-weight: 500;
		color: #00875A;
		line-height: 80rpx;
	}
</style>

pinglun组件:

<template>
	<div>
		<!-- 一级评论 -->
		<div class="flex justify-start align-start margin-bottom-sm">
			<div class="margin-right-xs">
				<d-image :dSrc="onePageList.levelOneCommentVo.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image>
			</div>
			<div class="flex-sub">
				<div class="flex justify-start align-center">
					<div class="name margin-right-sm">{{onePageList.levelOneCommentVo.userName}}</div>
					<div class="zuozhe flex justify-center align-center" v-if="onePageList.levelOneCommentVo.belongAuthor===1">作者</div>
				</div>
				<div class="flex justify-between align-center" @click="goPinglun(1,onePageList.levelOneCommentVo.id,onePageList.levelOneCommentVo.userName,onePageList.levelOneCommentVo.id)">
					<div class="content flex-sub">{{onePageList.levelOneCommentVo.content}}</div>
					<div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(1,'',onePageList.levelOneCommentVo.id)">
						<div class="margin-bottom-xs">
							<div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===0">
								<u-icon name="heart" color="#667286" size="34rpx"></u-icon>
							</div>
							<div v-show="onePageList.levelOneCommentVo.isCurrentUserLike===1">
								<u-icon name="heart-fill" color="red" size="34rpx"></u-icon>
							</div>
						</div>
						<div class="likeNum">{{onePageList.levelOneCommentVo.likeCount}}</div>
					</div>
				</div>
				<div class="time">{{ $u.timeFrom(new Date(onePageList.levelOneCommentVo.createTime).getTime())}}</div>
			</div>
		</div>
		<!-- 二级评论 -->
		<div class="erpinglunBox" :style="{'height':`${pingjiaBoxMaxHeight}px`,'opacity':pinglunOpcity,}">
			<div class="pinglunDom">
				<div v-for="(item,index) in onePageList.twoLevelpinglun" :key="item.id" class="margin-bottom-sm">
					<div class="flex justify-start align-start">
						<div class="margin-right-xs">
							<d-image :dSrc="item.userAvatar" dMode="aspectFit" dWidth="72rpx" dHeight="72rpx"></d-image>
						</div>
						<div class="flex-sub">
							<div class="flex justify-start align-center">
								<div class="name margin-right-sm">{{item.userName}}</div>
								<div class="zuozhe flex justify-center align-center margin-right-sm" v-if="item.belongAuthor===1">作者</div>
								<div class="name" v-if="item.isReplayTwoComment===1">回复 {{item.replayLevelTwoCommentUser.userName}}</div>
							</div>
							<div class="flex justify-between align-center" @click="goPinglun(2,item.id,item.userName,onePageList.levelOneCommentVo.id)">
								<div class="content flex-sub">{{item.content}}</div>
								<div class="flex flex-direction align-center" style="width: 68rpx;" @click.stop="likepinglun(2,index,item.id)">
									<div class="margin-bottom-xs">
										<div v-show="item.isCurrentUserLike===0">
											<u-icon name="heart" color="#667286" size="34rpx"></u-icon>
										</div>
										<div v-show="item.isCurrentUserLike===1">
											<u-icon name="heart-fill" color="red" size="34rpx"></u-icon>
										</div>
									</div>
									<div class="likeNum">{{item.likeCount}}</div>
								</div>
							</div>
							<div class="time">{{ $u.timeFrom(new Date(item.createTime).getTime())}}</div>
						</div>
					</div>
				</div>
			</div>
		</div>
		<!-- 展开和收起按钮 -->
		<div class="flex justify-start align-center" style="padding-left: 84rpx;">
			<div class="seeMore padding-top-sm padding-bottom flex align-center" v-if="onePageList.levelTwoCommentCount > 0&&params.current <= totalPage" @click="$u.throttle(getTwoLevelPinglun, 1000,true)">
				<div class="margin-right-xs">查看更多回复</div>
				<u-icon name="arrow-down" color="#00875A" size="28rpx" :bold="true"></u-icon>
			</div>
			<div class="seeMore retract padding-top-sm padding-bottom margin-left flex justify-center align-center" v-if="params.current > 1" @click="$u.throttle(retract, 1000,true)">
				<div class="margin-right-xs">收起</div>
				<u-icon name="arrow-up" color="#00875A" size="28rpx" :bold="true"></u-icon>
			</div>
		</div>
	</div>
</template>

<script>
	import { mapState } from 'vuex';
	import { commentlike, getLevelOnePage, getLevelTwoPage } from '@/api/case/case.js'
	export default {
		data() {
			return {
				caseId: null,
				indexxxx: null, //一级评论的index
				params: {
					current: 1,
					limit: 5,
					timeSort: 1, //创建时间排序 1:升序 2:降序
				},
				totalPage: 1,
				onePageList: {},
				pingjiaBoxMaxHeight: 0,
				pinglunOpcity: 0,
				timer: null,
				timer1: null,
			}
		},
		props: {
			caseIdData: {
				type: Number,
				// 定义是否必须传
				required: true,
				// 定义默认值
				default: 0
			},
			data: {
				type: Object,
				// 定义是否必须传
				required: true,
				// 定义默认值
				default: {}
			},
			indexxx: {
				type: Number,
				// 定义是否必须传
				required: true,
				// 定义默认值
				default: 0
			}
		},
		watch: {
			caseIdData: {
				immediate: true,
				handler(val) {
					this.caseId = val;
				}
			},
			data: {
				immediate: true,
				handler(val) {
					this.onePageList = val;
				}
			},
			indexxx: {
				immediate: true,
				handler(val) {
					this.indexxxx = val;
				}
			}
		},
		components: {},
		computed: {
			...mapState(["hasLogin", "userInfo"])
		},
		mounted() {},
		beforeDestroy() {
			clearTimeout(this.timer)
			clearTimeout(this.timer1)
		},
		methods: {
			async likepinglun(type, index, id) {
				if (!this.hasLogin) {
					this.$emit('noLogin', '一二级评论点赞未登录')
					return
				}

				let form = {};
				if (type === 1) {
					form.caseLevelOneCommentId = id
				} else if (type === 2) {
					form.caseLevelTwoCommentId = id
				}
				try {
					let res = await commentlike({ ...form, userId: this.userInfo?.userId })
					if (res.state === 1) { //如果接口回调成功
						if (type === 1) { //如果点击的是一级评论的点赞
							if (this.onePageList.levelOneCommentVo.isCurrentUserLike === 0) { //判断点赞之前是0还是1 然后取反  并且对应点赞数量同步加减
								this.onePageList.levelOneCommentVo.isCurrentUserLike = 1
								this.onePageList.levelOneCommentVo.likeCount++
							} else if (this.onePageList.levelOneCommentVo.isCurrentUserLike === 1) {
								this.onePageList.levelOneCommentVo.isCurrentUserLike = 0
								this.onePageList.levelOneCommentVo.likeCount--
							}
						} else if (type === 2) { //如果点击的是二级评论的点赞
							if (this.onePageList.twoLevelpinglun[index].isCurrentUserLike === 0) {
								this.onePageList.twoLevelpinglun[index].isCurrentUserLike = 1
								this.onePageList.twoLevelpinglun[index].likeCount++
							} else if (this.onePageList.twoLevelpinglun[index].isCurrentUserLike === 1) {
								this.onePageList.twoLevelpinglun[index].isCurrentUserLike = 0
								this.onePageList.twoLevelpinglun[index].likeCount--
							}
						}
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			goPinglun(e, id, name, indexx) {
				if (e === 1) { //一级评论
					this.$emit('comment', {
						type: e,
						id: id,
						// index: this.indexxxx,
						index: indexx,
						replyName: name, //点击的谁的评论进行回复,用于在输入框的placeholder回显
					})
				} else if (e === 2) { //二级评论
					this.$emit('comment', {
						type: e,
						id: id,
						// index: this.indexxxx,
						index: indexx,
						replyName: name, //点击的谁的评论进行回复,用于在输入框的placeholder回显
					})
				}
			},
			async getTwoLevelPinglun() {
				try {
					let res = await getLevelTwoPage({ userId: this.hasLogin ? this.userInfo?.userId : '', caseLevelOneCommentId: this.onePageList.levelOneCommentVo.id, ...this.params })
					if (res.state === 1) {
						for (let i = 0; i < res.content.records.length; i++) {
							res.content.records[i].twoLevelpinglun = []
							if (this.onePageList.twoLevelpinglun.some(item => item.id === res.content.records[i].id)) { //删除重复项
								res.content.records.splice(i, 1)
								console.log("发现重复项,删除他!!!");
							}
						}

						this.onePageList.twoLevelpinglun = [...this.onePageList.twoLevelpinglun, ...res.content.records]
						this.totalPage = Math.ceil(res.content.total / this.params.limit) //总页数=总数量/每页数量
						this.params.current += 1
						this.updatHeight()
					}
				} catch (e) {
					uni.$u.toast(e)
				}
			},
			retract() {
				this.pingjiaBoxMaxHeight = 0
				this.pinglunOpcity = 0
				this.params.current = 1
				this.onePageList.twoLevelpinglun = []
				this.timer1 = setTimeout(() => { //因为展开动画需要1s 故 在收起的时候延迟置空数组,
					console.log(this.onePageList);
					this.$emit('shouqi', this.onePageList.levelOneCommentVo.id)
				}, 800)
			},
			updatHeight() {
				let that = this
				this.$nextTick(() => {
					// this.timer = setTimeout(() => {
					this.createSelectorQuery().select(".pinglunDom").boundingClientRect(function(rect) {
						// console.log(rect);
						that.pingjiaBoxMaxHeight = rect.height
						that.pinglunOpcity = 1
					}).exec();
					// }, 0)
				})
			},
		}
	}
</script>

<style lang="scss" scoped>
	.name {
		font-size: 24rpx;
		font-weight: 400;
		color: #667286;
	}

	.content {
		font-size: 28rpx;
		font-weight: 400;
		color: #1F3253;
	}

	.time {
		font-size: 20rpx;
		font-weight: 400;
		color: #AFAFAF;
	}

	.likeNum {
		font-size: 20rpx;
		font-weight: 400;
		color: #667286;
	}

	.zuozhe {
		width: 60rpx;
		height: 28rpx;
		background: #FFFFFF;
		border-radius: 18rpx;
		border: 1rpx solid #00875A;
		font-size: 20rpx;
		font-weight: 400;
		color: #00875A;
	}

	.seeMore {
		font-size: 24rpx;
		font-weight: 400;
		color: #00875A;
	}

	.retract {
		width: 150rpx;
		text-align: center;
	}

	.erpinglunBox {
		padding-left: 84rpx;
		transition: height 1s, opacity 2s;
		overflow: hidden;
	}
</style>

案例详情引入的scss文件:

	.font-20 {
		font-size: 20rpx;
		font-weight: 400;
	}

	.font-24 {
		font-size: 24rpx;
		font-weight: 400;
	}


	.txt-1 {
		font-size: 28rpx;
		font-weight: 500;
		color: #0F2C50;
	}

	.txt-2 {
		@extend .font-20;
		color: #667286;
	}

	.txt-3 {
		@extend .font-24;
		color: #667286;
	}

	.txt-4 {
		font-size: 24rpx;
		font-weight: 500;
		color: #667286;
	}

	.txt-5 {
		font-size: 36rpx;
		font-weight: bold;
	}

	.txt-6 {
		@extend .font-24;
		color: #9CADC6;
	}

	.txt-7 {
		@extend .font-20;
		color: #B7BCC3;
	}

	.txt-8 {
		@extend .font-24;
		color: #fff;
	}
	.txt-9 {
		@extend .font-24;
		color: #0F2C50;
	}
	.txt-10 {
		font-size: 28rpx;
		font-weight: 400;
		color: #667286;
	}

	.yell-green-base {
		width: 140rpx;
		height: 52rpx;
		border-radius: 2rpx;
		font-size: 36rpx;
		font-weight: bold;
	}

	.yellow-box {
		@extend .yell-green-base;
		background-color: #FFF4CD;
		color: #FF991F;
	}

	.green-box {
		@extend .yell-green-base;
		background: #E2FFEE;
		color: #00875A;
	}
	.timeFont{
		font-size: 32rpx;
		font-family: DINAlternate-Bold, DINAlternate;
		font-weight: bold;
	}
  .startTime{
		@extend .timeFont;
		color: #FF991F;
  }
  .endTime{
		@extend .timeFont;
		color: #00875A;
  }
	.line {
		height: 1rpx;
		border: 1rpx solid #E6E6E6;
		margin: 16rpx 0;
	}
.caseBox {
		background: #FFFFFF;
		border-radius: 12rpx;
		margin-top: 20rpx;
		padding: 0 32rpx;

		.case-head-box {
			height: 140rpx;
		}

		.avatarBox {
			width: 72rpx;
			height: 72rpx;
			margin-right: 16rpx;
		}

		.caseDetailBtn {
			width: 100rpx;
			height: 44rpx;
			background: #00875A;
			border-radius: 22rpx;
		}

		.rateBox {
			height: 80rpx;
		}

		.mar-80 {
			margin-right: 80rpx;
		}
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/102198.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

最新ChatGPT程序源码+AI系统+详细图文部署教程/支持GPT4.0/支持Midjourney绘画/Prompt知识库

一、AI系统 如何搭建部署人工智能源码、AI创作系统、ChatGPT系统呢&#xff1f;小编这里写一个详细图文教程吧&#xff01;SparkAi使用Nestjs和Vue3框架技术&#xff0c;持续集成AI能力到AIGC系统&#xff01; 1.1 程序核心功能 程序已支持ChatGPT3.5/GPT-4提问、AI绘画、Mi…

Kubernetes技术--使用kubeadm搭建高可用的K8s集群(贴近实际环境)

1.高可用k8s集群架构(多master) 2.安装硬件要求 一台或多台机器,操作系统 CentOS7.x-86_x64 硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多 注: 这里属于教学环境,所以使用三台虚拟机模拟实现。 3.部署规划 4.部署前准备 (1).关闭防火墙 systemctl stop fi…

数据结构|栈和队列以及实现

栈和队列 一、栈1.1栈的概念及结构1.2栈的实现 二、队列2.1队列的概念及结构2.2队列的实现 一、栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和数据删除的一端称为栈顶&#xff0c;另一端称为栈…

深度学习入门(Python)学习笔记1

第1章 Python入门 1.1python是什么 Python是一个简单、易读、易记的编程语言&#xff0c;而且是开源的&#xff0c;可以免费地自由使用。 使用Python不仅可以写出可读性高的代码&#xff0c;还可以写出性能高&#xff08;处理速度快&#xff09;的代码。 再者&#xff0c;在…

7.2 项目2 学生通讯录管理:文本文件增删改查(C 版本)(自顶向下设计+断点调试) (A)

C自学精简教程 目录(必读) 该作业是 作业 学生通讯录管理&#xff1a;文本文件增删改查&#xff08;C版本&#xff09; 的C 语言版本。 具体的作业题目描述&#xff0c;要求&#xff0c;可以参考 学生通讯录管理&#xff1a;文本文件增删改查&#xff08;C版本&#xff09;。…

Windows下Redis的安装和配置

文章目录 一,Redis介绍二,Redis下载三,Redis安装-解压四,Redis配置五,Redis启动和关闭(通过terminal操作)六,Redis连接七,Redis使用 一,Redis介绍 远程字典服务,一个开源的,键值对形式的在线服务框架,值支持多数据结构,本文介绍windows下Redis的安装,配置相关,官网默认下载的是…

iTOP-RK3588开发板Android12 设置系统默认不休眠

修改文件&#xff1a; device/rockchip/rk3588/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults. xml 文件&#xff0c;如下图所示&#xff1a; - <integer name"def_screen_off_timeout">60000</integer> <integer name&q…

卡特兰数和算法

在组合数学中&#xff0c;卡特兰数是一系列自然数&#xff0c;出现在各种组合计数问题中&#xff0c;通常涉及递归定义的对象。它们以比利时数学家尤金查尔斯卡特兰&#xff08;Eugne Charles Catalan&#xff09;的名字命名。 卡特兰数序列是1, 1, 2, 5, 14, 42......&#xf…

传承精神 缅怀伟人——湖南多链优品科技有限公司赴韶山开展红色主题活动

8月27日上午&#xff0c; 湖南多链优品科技有限公司全体员工怀着崇敬之情&#xff0c;以红色文化为引领&#xff0c;参加了毛泽东同志诞辰130周年的纪念活动。以董事长程小明为核心的公司班子成员以及全国优秀代表近70人一行专赴韶山&#xff0c;缅怀伟人毛泽东同志的丰功伟绩。…

230902-部署Gradio到已有FastAPI及服务器中

1. 官方例子 run.py from fastapi import FastAPI import gradio as grCUSTOM_PATH "/gradio"app FastAPI()app.get("/") def read_main():return {"message": "This is your main app"}io gr.Interface(lambda x: "Hello, …

基于硬件隔离增强risc-v调试安全1_问题描述

安全之安全(security)博客目录导读 2023 RISC-V中国峰会 安全相关议题汇总 说明&#xff1a;本文参考RISC-V 2023中国峰会如下议题&#xff0c;版权归原作者所有。

CCF HPC China2023|澎峰科技:使能先进计算,赋能行业应用

CCF HPC China2023圆满落幕&#xff01; 桂秋八月&#xff0c;为期三天的中国高性能计算领域最高规格盛会——2023CCF全球高性能计算学术年会&#xff08;HPC China&#xff09;在青岛红岛国际展览中心圆满落幕。行业超算大咖、顶级学界精英、先锋企业领袖参会者齐聚山东青岛&a…

tableau基础学习2:时间序列数据预处理与绘图

文章目录 数据预处理1. 原始数据2. 合并数据集2. 创建计算字段 绘图分析1. 趋势分析2. 计算字段趋势分析 这一部分&#xff0c;我们记录一些分析时序趋势的分析步骤 数据预处理 1. 原始数据 原始数据是excel表格&#xff0c;其中包含三个Sheet页&#xff0c; 这里我们选择两…

Matlab——二维绘图(最为详细,附上相关实例)

为了帮助各位同学备战数学建模和学习Matlab的使用&#xff0c;今天我们来聊一聊 Matlab 中的绘图技巧吧&#xff01;对于 Matlab 这样的科学计算软件来说&#xff0c;绘图是非常重要的一项功能。在数据处理和分析时&#xff0c;良好的绘图技巧能够更直观地呈现数据&#xff0c;…

git在linux情况下设置git 命令高亮

只需要执行下面这个命令&#xff0c;这样就可以在查看git status明亮的时候高亮显示。 git config --global color.status auto未设置前 谁知之后

python基础爬虫反爬破解

文章目录 爬虫初识1. HTTP协议与WEB开发&#xff08;1&#xff09;简介&#xff08;2&#xff09;socket套接字&#xff08;3&#xff09;请求协议与响应协议 2. requests&反爬破解&#xff08;1&#xff09;UA反爬&#xff08;2&#xff09;referer反爬&#xff08;3&…

微信小程序echart导出图片

echarts版本5.1.0 用到的echarts组件是uni插件市场的echart组件 <div style"overflow: hidden;"><dCanvas class"uni-ec-canvass" id"uni-ec-canvas" ref"canvas" canvas-id"mychart-gauge" :ec"ec"&g…

IIS搭建本地电脑服务器:通过内网穿透技术实现公网访问的步骤指南

1.前言 在网上各种教程和介绍中&#xff0c;搭建网页都会借助各种软件的帮助&#xff0c;比如网页运行的Apache和Nginx、数据库软件MySQL和MSSQL之类&#xff0c;为方便用户使用&#xff0c;还出现了XAMPP、PHPStudy、宝塔面板等等一系列集成服务&#xff0c;都是为了方便我们…

Nginx高级配置

目录 一、Nginx 第三方模块 1.1ehco 模块 二、变量 2.1 内置 2.2 自定义变量 三、nginx压缩功能 ​编辑四、https功能 一、Nginx 第三方模块 1.1ehco 模块 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-…

企业应用系统 PHP项目支持管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页

一、源码特点 PHP 项目支持管理系统是一套完善的web设计系统 应用于企业项目管理&#xff0c;从企业内部的各个业务环境总体掌握&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 php项目支撑管理系统2 二、功能介绍 (1)权限管理&#xff1…