Browse Source

添加社区模块

xiaoxin 2 years ago
parent
commit
1838560c40
49 changed files with 4764 additions and 522 deletions
  1. 122 0
      components/commentChild3.vue
  2. 24 0
      pages.json
  3. 57 20
      pages/addPlace/addPlace.vue
  4. 111 31
      pages/community/community.vue
  5. 1 2
      pages/complaint/complaint.vue
  6. 46 88
      pages/detail/detail.vue
  7. 1 2
      pages/evaluate/evaluate.vue
  8. 1 1
      pages/home/home.vue
  9. 111 38
      pages/home3/home3.vue
  10. 50 39
      pages/likeList/likeList.vue
  11. 10 4
      pages/my/my.vue
  12. 202 78
      pages/myHome/myHome.vue
  13. 48 0
      pages/newsDetail/newsDetail.vue
  14. 194 0
      pages/newsList/newsList.vue
  15. 19 7
      pages/orderManage/orderManage.vue
  16. 358 0
      pages/rimDetail/rimDetail.vue
  17. 63 0
      pages/rimInfo/rimInfo.vue
  18. 66 16
      pages/send/send.vue
  19. 8 0
      pages/set/set.vue
  20. 423 190
      pages/tweetDetail/tweetDetail.vue
  21. BIN
      static/index/dianzan.png
  22. BIN
      static/index/down.png
  23. BIN
      static/index/look.png
  24. BIN
      static/index/msg.png
  25. BIN
      static/index/notice.png
  26. BIN
      static/index/phone3.png
  27. BIN
      static/index/upvote-active.png
  28. BIN
      static/index/upvote.png
  29. BIN
      static/index/video.png
  30. 193 0
      uni_modules/mp-html/README.md
  31. 129 0
      uni_modules/mp-html/changelog.md
  32. 498 0
      uni_modules/mp-html/components/mp-html/mp-html.vue
  33. 576 0
      uni_modules/mp-html/components/mp-html/node/node.vue
  34. 1335 0
      uni_modules/mp-html/components/mp-html/parser.js
  35. 76 0
      uni_modules/mp-html/package.json
  36. 1 0
      uni_modules/mp-html/static/app-plus/mp-html/js/handler.js
  37. 1 0
      uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js
  38. 1 0
      uni_modules/mp-html/static/app-plus/mp-html/local.html
  39. 2 0
      uni_modules/uv-image/changelog.md
  40. 3 1
      uni_modules/uv-image/components/uv-image/uv-image.vue
  41. 1 1
      uni_modules/uv-image/package.json
  42. 4 0
      uni_modules/uv-transition/changelog.md
  43. 5 0
      uni_modules/uv-transition/components/uv-transition/uv-transition.vue
  44. 1 1
      uni_modules/uv-transition/package.json
  45. 6 0
      uni_modules/uv-ui-tools/changelog.md
  46. 2 2
      uni_modules/uv-ui-tools/libs/config/config.js
  47. 13 0
      uni_modules/uv-ui-tools/libs/mixin/mixin.js
  48. 1 1
      uni_modules/uv-ui-tools/package.json
  49. 1 0
      util/api.js

+ 122 - 0
components/commentChild3.vue

@@ -0,0 +1,122 @@
+<template>
+	<view class="item_child">
+		<view class="child_box" v-for="item in list" :key="item.id" @click.stop="handleComment(item)">
+			<view class="box_user">
+				<img mode="aspectFill" :src="item.image" @click.stop="handleGoMyHome(item.userId)" />
+				<view class="user_info">
+					{{ item.userName }}
+				</view>
+			</view>
+			<view class="box_content">
+				<text class="content_key">回复{{ item.parentName }}:</text>
+				{{ item.content }}
+				<view class="content_bottom">
+					{{ item.date.slice(0, 19) }}
+				</view>
+			</view>
+
+			<view>
+				<Child v-if="item.childrens" :list="item.childrens" :commentParentId="commentParentId"></Child>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+var dayjs = require('dayjs')
+// uniapp不兼容递归组件,需要重新引入注册使用
+import Child from '@/components/commentChild3.vue'
+export default {
+	components: { Child },
+	props: {
+		list: Array,
+		commentParentId: String
+	},
+	methods: {
+		handleComment(item) {
+			uni.showModal({
+				title: '请输入评论',
+				editable: true,
+				success: async (res) => {
+					if (res.confirm) {
+						const result = res.content
+						if (!res.content) {
+							uni.showToast({
+								title: '评论内容不能为空',
+								icon: 'none',
+								mask: true
+							})
+							setTimeout(() => {
+								this.handleComment()
+							}, 1500)
+						} else {
+							const res = await this.$myRequest({
+								url: '/mhotel/articlecommentArticle.action',
+								method: 'post',
+								data: {
+									articleId: this.commentParentId,
+									parentId: item.id,
+									userId: uni.getStorageSync('userInfo').id,
+									content: result
+								}
+							})
+							// console.log(res);
+							if (res.code === 200) {
+								uni.$emit('getReset')
+							}
+						}
+					}
+				}
+			})
+		},
+		handleGoMyHome(userId) {
+			uni.navigateTo({
+				url: `/pages/myHome/myHome?userId=${userId}`
+			})
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.item_child {
+	// margin-left: 50rpx;
+
+	.child_box {
+		margin-bottom: 10rpx;
+		.box_user {
+			display: flex;
+			align-items: center;
+			height: 70rpx;
+
+			img {
+				width: 70rpx;
+				height: 70rpx;
+				border-radius: 50%;
+			}
+
+			.user_info {
+				display: flex;
+				align-items: center;
+				margin-left: 18rpx;
+				height: 70rpx;
+				font-size: 28rpx;
+			}
+		}
+
+		.box_content {
+			margin-left: 80rpx;
+			font-size: 24rpx;
+
+			.content_key {
+				color: #808080;
+			}
+
+			.content_bottom {
+				margin: 10rpx 0;
+				color: #808080;
+			}
+		}
+	}
+}
+</style>

+ 24 - 0
pages.json

@@ -285,6 +285,30 @@
 				"navigationBarTitleText": "点赞过的用户",
 				"navigationBarTitleText": "点赞过的用户",
 				"enablePullDownRefresh": false
 				"enablePullDownRefresh": false
 			}
 			}
+		}, {
+			"path": "pages/rimDetail/rimDetail",
+			"style": {
+				"navigationBarTitleText": "周边详情",
+				"enablePullDownRefresh": false
+			}
+		}, {
+			"path": "pages/rimInfo/rimInfo",
+			"style": {
+				"navigationBarTitleText": "简介",
+				"enablePullDownRefresh": false
+			}
+		}, {
+			"path": "pages/newsDetail/newsDetail",
+			"style": {
+				"navigationBarTitleText": "资讯详情",
+				"enablePullDownRefresh": false
+			}
+		}, {
+			"path": "pages/newsList/newsList",
+			"style": {
+				"navigationBarTitleText": "招商资讯",
+				"enablePullDownRefresh": false
+			}
 		}
 		}
 	],
 	],
 	"tabBar": {
 	"tabBar": {

+ 57 - 20
pages/addPlace/addPlace.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-	<view class="container" v-if="townList.length && hotelList.length">
+	<view class="container" v-if="townList.length">
 		<view class="title">选择乡镇</view>
 		<view class="title">选择乡镇</view>
 		<!-- 乡镇列表区域 -->
 		<!-- 乡镇列表区域 -->
 		<view class="town_list">
 		<view class="town_list">
@@ -9,21 +9,27 @@
 		</view>
 		</view>
 		<view class="title2">关联民宿</view>
 		<view class="title2">关联民宿</view>
 		<!-- 民宿列表区域 -->
 		<!-- 民宿列表区域 -->
-		<view class="hotel_list">
+		<view class="hotel_list" v-if="hotelList.length">
 			<!-- 每一个民宿 -->
 			<!-- 每一个民宿 -->
 			<view class="hotel_box" v-for="item in hotelList" :key="item.id">
 			<view class="hotel_box" v-for="item in hotelList" :key="item.id">
 				<view class="box_radio">
 				<view class="box_radio">
-					<radio style="transform:scale(1.2)" color="#096562" :checked="item.is_collect_hotel"
+					<radio style="transform:scale(1.2)" color="#096562" :checked="item.isCheck"
 						@click="handleClickRadio(item)" /></label>
 						@click="handleClickRadio(item)" /></label>
 				</view>
 				</view>
 				<view class="box_info">
 				<view class="box_info">
 					<img mode="aspectFill" :src="item.coverImg">
 					<img mode="aspectFill" :src="item.coverImg">
 					<view class="info_detail">
 					<view class="info_detail">
 						<view class="detail_name">
 						<view class="detail_name">
-							{{item.hotel_name}}
+							{{item.name}}
 						</view>
 						</view>
-						<view class="detail_leave">
-							{{item.hTypeName}}
+						<view class="detail_leave" v-if="item.type===1">
+							银宿级
+						</view>
+						<view class="detail_leave" v-if="item.type===2">
+							金宿级
+						</view>
+						<view class="detail_leave" v-if="item.type===3">
+							白金级
 						</view>
 						</view>
 						<view class="detail_rate">
 						<view class="detail_rate">
 							{{item.score.toFixed(1)}}分
 							{{item.score.toFixed(1)}}分
@@ -32,6 +38,12 @@
 				</view>
 				</view>
 			</view>
 			</view>
 		</view>
 		</view>
+		
+		<!-- 没有数据时展示的区域 -->
+		<view class="noData" v-else>
+			<img src="../../static/images/noData.png" />
+			暂无数据
+		</view>
 
 
 		<!-- 确定按钮区域 -->
 		<!-- 确定按钮区域 -->
 		<view class="btn" @click="handleClickBtn">
 		<view class="btn" @click="handleClickBtn">
@@ -50,46 +62,55 @@
 				hotelList: [],
 				hotelList: [],
 				// 当前高亮索引
 				// 当前高亮索引
 				activeIndex: 0,
 				activeIndex: 0,
-				// 已经选中的数组
-				oldList:[]
+				// 之前选中的数组
+				oldList:[],
+				// 之前选中的城镇id
+				oldTownId:''
 			}
 			}
 		},
 		},
 		onLoad(options) {
 		onLoad(options) {
 			this.oldList = JSON.parse(options.list)
 			this.oldList = JSON.parse(options.list)
-			console.log(this.oldList);
+			this.oldTownId = options.townId
 			this.getTownList()
 			this.getTownList()
-			this.getHotelList()
 		},
 		},
 		methods: {
 		methods: {
 			// 获取乡镇列表数组
 			// 获取乡镇列表数组
 			async getTownList() {
 			async getTownList() {
 				const res = await this.$myRequest({
 				const res = await this.$myRequest({
-					url: '/mhotel/ahpgetResidueCount.action'
+					url: '/mhotel/articletownShips.action'
 				})
 				})
 				// console.log(res)
 				// console.log(res)
 				if (res.code === 200) {
 				if (res.code === 200) {
 					this.townList = res.data
 					this.townList = res.data
+					this.townList.forEach((ele,index)=>{
+						if(ele.id == this.oldTownId){
+							this.activeIndex = index
+						}
+					})
+					this.getHotelList()
 				}
 				}
 			},
 			},
 			// 获取民宿列表数组
 			// 获取民宿列表数组
 			async getHotelList() {
 			async getHotelList() {
 				const res = await this.$myRequest({
 				const res = await this.$myRequest({
-					url: '/mhotel/ahphomePage.action',
+					url: '/mhotel/articlehotelByid.action',
 					data: {
 					data: {
+						townId:this.townList[this.activeIndex].id,
 						page: 1,
 						page: 1,
-						rows: 4,
-						type: 3,
-						userId: uni.getStorageSync('userInfo') ? uni.getStorageSync('userInfo').id : ''
+						rows: 999,
 					}
 					}
 				})
 				})
-				
 				// console.log(res)
 				// console.log(res)
 				if (res.code === 200) {
 				if (res.code === 200) {
 					this.hotelList = res.data.pageList
 					this.hotelList = res.data.pageList
+					// 添加isCheck属性
+					this.hotelList.forEach(ele=>{
+						this.$set(ele,'isCheck',false)
+					})
 					this.hotelList.forEach((ele)=>{
 					this.hotelList.forEach((ele)=>{
 				         this.oldList.forEach((item)=>{
 				         this.oldList.forEach((item)=>{
 				         	if(item.id ===ele.id){
 				         	if(item.id ===ele.id){
-								ele.is_collect_hotel = true
+								ele.isCheck = true
 							}
 							}
 				         })
 				         })
 					})
 					})
@@ -98,17 +119,19 @@
 			// 切换乡镇回调
 			// 切换乡镇回调
 			handleChange(index) {
 			handleChange(index) {
 				this.activeIndex = index
 				this.activeIndex = index
+				this.getHotelList()
 			},
 			},
 			// 点击radio回调
 			// 点击radio回调
 			handleClickRadio(item) {
 			handleClickRadio(item) {
-				item.is_collect_hotel = !item.is_collect_hotel
+				item.isCheck = !item.isCheck
 			},
 			},
 			// 确定按钮点击回调
 			// 确定按钮点击回调
 			handleClickBtn() {
 			handleClickBtn() {
-				let temList = this.hotelList.filter(ele => ele.is_collect_hotel)
+				let temList = this.hotelList.filter(ele => ele.isCheck)
 				if (temList.length) {
 				if (temList.length) {
 					uni.$emit('add', {
 					uni.$emit('add', {
-						list: temList
+						list: temList,
+						townId:this.townList[this.activeIndex].id
 					})
 					})
 					uni.navigateBack(1)
 					uni.navigateBack(1)
 				} else {
 				} else {
@@ -125,6 +148,7 @@
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 	.container {
 	.container {
+		box-sizing: border-box;
 		padding: 0 19rpx 80rpx;
 		padding: 0 19rpx 80rpx;
 		min-height: 100vh;
 		min-height: 100vh;
 		background-color: #fff;
 		background-color: #fff;
@@ -220,6 +244,19 @@
 				}
 				}
 			}
 			}
 		}
 		}
+		
+		.noData {
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+		
+			img {
+				margin-top: 60rpx;
+				width: 400rpx;
+				height: 400rpx;
+			}
+		}
 
 
 		.btn {
 		.btn {
 			display: flex;
 			display: flex;

+ 111 - 31
pages/community/community.vue

@@ -33,17 +33,20 @@
 					<!-- 为了磨平部分平台的BUG,必须套一层view -->
 					<!-- 为了磨平部分平台的BUG,必须套一层view -->
 					<view>
 					<view>
 						<view v-for="(item, index) in list1" :key="item.id" class="waterfall_item" @click="goPageDetail(item)">
 						<view v-for="(item, index) in list1" :key="item.id" class="waterfall_item" @click="goPageDetail(item)">
-							<img mode="aspectFill" class="item_cover" :src="item.coverImg" />
-							<view class="item_desc">{{ item.hposition }}</view>
+							<img v-if="item.image" mode="aspectFill" class="item_cover" :src="item.image" />
+							<video v-if="item.video" class="item_cover" :src="item.video" :show-center-play-btn="false" :show-fullscreen-btn="false" :show-play-btn="false"></video>
+							<view class="item_town" v-if="item.townName">{{ item.townName }}</view>
+							<img v-if="item.video" class="item_play" src="../../static/index/video.png" />
+							<view class="item_desc">{{ item.title }}</view>
 							<view class="item_info">
 							<view class="item_info">
-								<img mode="aspectFill" :src="item.coverImg" />
-								<view class="text">{{ item.hotel_name }}</view>
+								<img mode="aspectFill" :src="item.userPhoto" />
+								<view class="text">{{ item.userName }}</view>
 								<img
 								<img
 									class="img"
 									class="img"
-									:src="item.is_collect_hotel ? '../../static/index/like-active.png' : '../../static/index/like.png'"
+									:src="item.isCollect === 1 ? '../../static/index/like-active.png' : '../../static/index/like.png'"
 									@click.stop="handleClickLike(item)"
 									@click.stop="handleClickLike(item)"
 								/>
 								/>
-								<view class="count">{{ item.roomNumber }}</view>
+								<view class="count">{{ item.collectNum }}</view>
 							</view>
 							</view>
 						</view>
 						</view>
 					</view>
 					</view>
@@ -53,17 +56,20 @@
 					<!-- 为了磨平部分平台的BUG,必须套一层view -->
 					<!-- 为了磨平部分平台的BUG,必须套一层view -->
 					<view>
 					<view>
 						<view v-for="(item, index) in list2" :key="item.id" class="waterfall_item" @click="goPageDetail(item)">
 						<view v-for="(item, index) in list2" :key="item.id" class="waterfall_item" @click="goPageDetail(item)">
-							<img mode="aspectFill" class="item_cover" :src="item.coverImg" />
-							<view class="item_desc">{{ item.hposition }}</view>
+							<img v-if="item.image" mode="aspectFill" class="item_cover" :src="item.image" />
+							<video v-if="item.video" class="item_cover" :src="item.video" :show-center-play-btn="false" :show-fullscreen-btn="false" :show-play-btn="false"></video>
+							<view class="item_town" v-if="item.townName">{{ item.townName }}</view>
+							<img v-if="item.video" class="item_play" src="../../static/index/video.png" />
+							<view class="item_desc">{{ item.title }}</view>
 							<view class="item_info">
 							<view class="item_info">
-								<img mode="aspectFill" :src="item.coverImg" />
-								<view class="text">{{ item.hotel_name }}</view>
+								<img mode="aspectFill" :src="item.userPhoto" />
+								<view class="text">{{ item.userName }}</view>
 								<img
 								<img
 									class="img"
 									class="img"
-									:src="item.is_collect_hotel ? '../../static/index/like-active.png' : '../../static/index/like.png'"
+									:src="item.isCollect === 1 ? '../../static/index/like-active.png' : '../../static/index/like.png'"
 									@click.stop="handleClickLike(item)"
 									@click.stop="handleClickLike(item)"
 								/>
 								/>
-								<view class="count">{{ item.roomNumber }}</view>
+								<view class="count">{{ item.collectNum }}</view>
 							</view>
 							</view>
 						</view>
 						</view>
 					</view>
 					</view>
@@ -93,6 +99,8 @@ export default {
 			keywords: '',
 			keywords: '',
 			// 当前选择地区索引
 			// 当前选择地区索引
 			placeIndex: 0,
 			placeIndex: 0,
+			// 当前选择地区的id
+			placeId: '',
 			// 地区数组
 			// 地区数组
 			placeList: [
 			placeList: [
 				{
 				{
@@ -117,19 +125,57 @@ export default {
 			list2: []
 			list2: []
 		}
 		}
 	},
 	},
-	onLoad() {
-		this.getHotelList()
+	onShow() {
+		let userInfo = uni.getStorageSync('userInfo')
+		if (!userInfo) {
+			uni.showModal({
+				title: '提示',
+				content: '您当前未登录,请授权登录查看社区信息',
+				showCancel: false,
+				success: (res) => {
+					if (res.confirm) {
+						uni.navigateTo({
+							url: '/pages/login/login'
+						})
+					}
+				}
+			})
+		} else {
+			this.placeList = [
+				{
+					name: '靖安县'
+				}
+			]
+			this.list = []
+			this.list1 = []
+			this.list2 = []
+			this.page = 1
+			this.getTownList()
+			this.getHotelList()
+		}
 	},
 	},
 	methods: {
 	methods: {
-		// 获取列表数组
+		// 获取乡镇列表数组
+		async getTownList() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articletownShips.action'
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.placeList = [...this.placeList, ...res.data]
+			}
+		},
+		// 获取推文列表数组
 		async getHotelList() {
 		async getHotelList() {
 			const res = await this.$myRequest({
 			const res = await this.$myRequest({
-				url: '/mhotel/ahphomePage.action',
+				url: '/mhotel/articlequeryArticlePage.action',
 				data: {
 				data: {
 					page: this.page,
 					page: this.page,
 					rows: this.rows,
 					rows: this.rows,
-					type: 3,
-					userId: uni.getStorageSync('userInfo') ? uni.getStorageSync('userInfo').id : ''
+					townId: this.placeId,
+					type: this.current,
+					keyWord: this.keywords,
+					userId: uni.getStorageSync('userInfo').id
 				}
 				}
 			})
 			})
 			// console.log(res)
 			// console.log(res)
@@ -146,8 +192,18 @@ export default {
 			}
 			}
 		},
 		},
 		// 点击爱心回调
 		// 点击爱心回调
-		handleClickLike(item) {
-			item.is_collect_hotel = !item.is_collect_hotel
+		async handleClickLike(item) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlecollectArticle.action',
+				data: {
+					id: item.id,
+					userId: uni.getStorageSync('userInfo').id
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				item.isCollect === 1 ? ((item.isCollect = 0), (item.collectNum -= 1)) : ((item.isCollect = 1), (item.collectNum += 1))
+			}
 		},
 		},
 		// 点击悬浮按钮回调
 		// 点击悬浮按钮回调
 		handleClickBtn() {
 		handleClickBtn() {
@@ -156,22 +212,24 @@ export default {
 			})
 			})
 		},
 		},
 		// 搜索按钮点击回调
 		// 搜索按钮点击回调
-		searchHandler() {},
+		searchHandler() {
+			this.list = []
+			this.$refs.waterfall.clear()
+			this.list1 = []
+			this.list2 = []
+			this.page = 1
+			this.getHotelList()
+		},
 		// 选择地区时的回调
 		// 选择地区时的回调
 		bindPickerChange(e) {
 		bindPickerChange(e) {
 			this.placeIndex = e.detail.value
 			this.placeIndex = e.detail.value
+			this.placeId = this.placeList[this.placeIndex].id || ''
+			this.searchHandler()
 		},
 		},
 		// 分段器切换回调
 		// 分段器切换回调
 		onClickItem(e) {
 		onClickItem(e) {
 			this.current = e.currentIndex
 			this.current = e.currentIndex
-			this.list = []
-			this.$refs.waterfall.clear()
-			this.list1 = []
-			this.list2 = []
-			this.page = 1
-			if (this.current === 0) {
-				this.getHotelList()
-			}
+			this.searchHandler()
 		},
 		},
 		// 页面触底回调
 		// 页面触底回调
 		handleTolower() {
 		handleTolower() {
@@ -189,7 +247,7 @@ export default {
 		// 点击每一个推文回调
 		// 点击每一个推文回调
 		goPageDetail(item) {
 		goPageDetail(item) {
 			uni.navigateTo({
 			uni.navigateTo({
-				url: `/pages/tweetDetail/tweetDetail?id=${item.id}`
+				url: `/pages/tweetDetail/tweetDetail?id=${item.id}&townId=${item.townId}`
 			})
 			})
 		}
 		}
 	}
 	}
@@ -291,6 +349,7 @@ export default {
 		height: calc(100vh - 220rpx);
 		height: calc(100vh - 220rpx);
 
 
 		.waterfall_item {
 		.waterfall_item {
+			position: relative;
 			overflow: hidden;
 			overflow: hidden;
 			margin-bottom: 20rpx;
 			margin-bottom: 20rpx;
 			width: 335rpx;
 			width: 335rpx;
@@ -303,6 +362,27 @@ export default {
 				border: 10rpx 10rpx 0 0;
 				border: 10rpx 10rpx 0 0;
 			}
 			}
 
 
+			.item_town {
+				position: absolute;
+				top: 404rpx;
+				left: 22rpx;
+				padding: 0 20rpx;
+				line-height: 43rpx;
+				text-align: center;
+				font-size: 20rpx;
+				color: #fff;
+				border-radius: 42rpx;
+				background-color: rgba(0, 0, 0, 0.5);
+			}
+
+			.item_play {
+				position: absolute;
+				top: 20rpx;
+				right: 20rpx;
+				width: 50rpx;
+				height: 50rpx;
+			}
+
 			.item_desc {
 			.item_desc {
 				padding: 0 22rpx;
 				padding: 0 22rpx;
 				font-size: 28rpx;
 				font-size: 28rpx;
@@ -312,7 +392,7 @@ export default {
 			.item_info {
 			.item_info {
 				padding: 15rpx 22rpx;
 				padding: 15rpx 22rpx;
 				display: flex;
 				display: flex;
-				align-items: center;
+				// align-items: center;
 				color: #666666;
 				color: #666666;
 				font-size: 20rpx;
 				font-size: 20rpx;
 
 

+ 1 - 2
pages/complaint/complaint.vue

@@ -199,8 +199,7 @@ export default {
 				title: '上传中'
 				title: '上传中'
 			})
 			})
 			uni.uploadFile({
 			uni.uploadFile({
-				// url: `https://chtech.ncjti.edu.cn/hotelReservation/mhotel/mhotel/uploadhimage.action`,
-				url: `https://chtech.ncjti.edu.cn/homestay/file/cos/upload`,
+				url: `https://chtech.ncjti.edu.cn/hotelReservation/file/cos/upload`,
 				filePath: ele.tempFilePath,
 				filePath: ele.tempFilePath,
 				// name: 'myFile',
 				// name: 'myFile',
 				name: 'files',
 				name: 'files',

+ 46 - 88
pages/detail/detail.vue

@@ -290,14 +290,20 @@
 			</view>
 			</view>
 		</view>
 		</view>
 
 
-		<!-- 周边民宿区域 -->
+		<!-- 周边区域 -->
 		<view class="rim">
 		<view class="rim">
 			<!-- 标题区域 -->
 			<!-- 标题区域 -->
-			<view class="rim_title">周边民宿</view>
-			<!-- 周边民宿列表区域 -->
+			<view class="rim_title">周边</view>
+			<!-- 周边分段器区域 -->
+			<view class="rim_control">
+				<span class="control_box" v-for="(item, index) in rimHeaderList" :key="index" @click="onClickItemRim(index)">
+					<text class="text" :class="{ active: rimActiveIndex === index }">{{ item }}</text>
+				</span>
+			</view>
+			<!-- 周边列表区域 -->
 			<view class="rim_body">
 			<view class="rim_body">
-				<!-- 每一个民宿区域 -->
-				<view class="rim_box" v-for="item in rimList" :key="item.id" @click="testGo(item)">
+				<!-- 每一个盒子区域 -->
+				<view class="rim_box" v-for="item in rimList" :key="item.id" @click="GoRimDetail">
 					<img mode="aspectFill" :src="item.url" />
 					<img mode="aspectFill" :src="item.url" />
 					<view class="box_info">
 					<view class="box_info">
 						<view class="info_top">{{ item.name }}</view>
 						<view class="info_top">{{ item.name }}</view>
@@ -319,36 +325,6 @@
 				<img src="../../static/index/right.png" />
 				<img src="../../static/index/right.png" />
 			</view>
 			</view>
 		</view>
 		</view>
-
-		<!-- 周边景点区域 -->
-		<view class="scenicSpot">
-			<!-- 标题区域 -->
-			<view class="scenicSpot_title">周边景点</view>
-			<!-- 周边景点列表区域 -->
-			<view class="scenicSpot_body">
-				<!-- 每一个景点区域 -->
-				<view class="scenicSpot_box" v-for="item in scenicSpotList" :key="item.id">
-					<img mode="aspectFill" :src="item.url" />
-					<view class="box_info">
-						<view class="info_top">{{ item.name }}</view>
-						<view class="info_center">距您查询酒店直线{{ item.distance }}km</view>
-						<view class="info_bottom">
-							<view class="bottom_rate">{{ item.rate }}分</view>
-							<view class="bottom_num">{{ item.num }}条评论</view>
-							<view class="bottom_price">
-								¥{{ item.price }}
-								<text>起</text>
-							</view>
-						</view>
-					</view>
-				</view>
-			</view>
-			<!-- 查看全部 -->
-			<view class="scenicSpot_more" @click="test">
-				查看全部
-				<img src="../../static/index/right.png" />
-			</view>
-		</view>
 	</view>
 	</view>
 </template>
 </template>
 
 
@@ -410,6 +386,7 @@ export default {
 			videoContext: null,
 			videoContext: null,
 			// 是否是全屏状态
 			// 是否是全屏状态
 			isFullScreen: false,
 			isFullScreen: false,
+			// 周边列表数组
 			rimList: [
 			rimList: [
 				{
 				{
 					id: 1726150980,
 					id: 1726150980,
@@ -448,44 +425,10 @@ export default {
 					price: 650
 					price: 650
 				}
 				}
 			],
 			],
-			scenicSpotList: [
-				{
-					id: 1,
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230922113014_c1d59da5595928a4d865418eeae861b.png',
-					name: '九仙君澜水上乐园',
-					distance: 1.3,
-					rate: 4.8,
-					num: 69,
-					price: 160
-				},
-				{
-					id: 2,
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230922112928_113d3f4c04eda11cea9051d516613aa.png',
-					name: '九仙君澜温泉',
-					distance: 1.5,
-					rate: 4.5,
-					num: 11,
-					price: 880
-				},
-				{
-					id: 3,
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230922112955_639270c554d315e5a845d6c26ad8548.png',
-					name: '白沙坪度假村',
-					distance: 3,
-					rate: 4.6,
-					num: 89,
-					price: 388
-				},
-				{
-					id: 4,
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230922112850_1bba201e62087a806240c668d0f2bf8.png',
-					name: '百丈山萝卜潭',
-					distance: 3.5,
-					rate: 4.7,
-					num: 81,
-					price: 550
-				}
-			]
+			// 周边分段器当前索引
+			rimActiveIndex: 0,
+			// 周边分段器数组
+			rimHeaderList: ['民宿', '美食', '景点', '洗浴', '健身', 'KTV', '电影院', '酒店']
 		}
 		}
 	},
 	},
 	mounted() {
 	mounted() {
@@ -539,21 +482,10 @@ export default {
 				mask: true
 				mask: true
 			})
 			})
 		},
 		},
-		testGo(item) {
-			this.info = null
-			this.activeIndex = 0
-			this.score = ''
-			this.scoreFw = ''
-			this.scoreSs = ''
-			this.scoreWs = ''
-			this.scoreWz = ''
-			this.commentList = []
-			this.getHotelInfo(item.id)
-			this.getEvaData(item.id)
-			uni.pageScrollTo({
-				scrollTop: 0
+		GoRimDetail() {
+			uni.navigateTo({
+				url: '/pages/rimDetail/rimDetail'
 			})
 			})
-			// this.queryDom = null
 		},
 		},
 		// 进入全屏和退出全屏时触发的回调
 		// 进入全屏和退出全屏时触发的回调
 		fullscreenchange(e) {
 		fullscreenchange(e) {
@@ -663,6 +595,9 @@ export default {
 				})
 				})
 			}
 			}
 		},
 		},
+		onClickItemRim(index) {
+			this.rimActiveIndex = index
+		},
 		monthSwitch(e) {
 		monthSwitch(e) {
 			let time = e.year + '-' + e.month.toString().padStart(2, 0) + '-01'
 			let time = e.year + '-' + e.month.toString().padStart(2, 0) + '-01'
 			this.handleOpen(time)
 			this.handleOpen(time)
@@ -1583,11 +1518,34 @@ export default {
 		background-color: #f2f3f5;
 		background-color: #f2f3f5;
 
 
 		.rim_title {
 		.rim_title {
-			line-height: 83rpx;
+			line-height: 80rpx;
 			font-size: 32rpx;
 			font-size: 32rpx;
 			font-weight: bold;
 			font-weight: bold;
 		}
 		}
 
 
+		.rim_control {
+			margin-bottom: 10rpx;
+			line-height: 85rpx;
+			font-size: 28rpx;
+			color: #808080;
+			white-space: nowrap;
+			overflow-x: auto;
+			background-color: #fff;
+
+			.control_box {
+				padding: 0 15rpx 0 20rpx;
+
+				.text {
+					padding-bottom: 5rpx;
+				}
+
+				.active {
+					color: #096562;
+					border-bottom: 5rpx solid #096562;
+				}
+			}
+		}
+
 		.rim_body {
 		.rim_body {
 			.rim_box {
 			.rim_box {
 				display: flex;
 				display: flex;

+ 1 - 2
pages/evaluate/evaluate.vue

@@ -335,8 +335,7 @@ export default {
 				title: '上传中'
 				title: '上传中'
 			})
 			})
 			uni.uploadFile({
 			uni.uploadFile({
-				// url: `https://chtech.ncjti.edu.cn/hotelReservation/mhotel/mhotel/uploadhimage.action`,
-				url: `https://chtech.ncjti.edu.cn/homestay/file/cos/upload`,
+				url: `https://chtech.ncjti.edu.cn/hotelReservation/file/cos/upload`,
 				filePath: ele.tempFilePath,
 				filePath: ele.tempFilePath,
 				// name: 'myFile',
 				// name: 'myFile',
 				name: 'files',
 				name: 'files',

+ 1 - 1
pages/home/home.vue

@@ -171,7 +171,7 @@ export default {
 		}
 		}
 	},
 	},
 	onLoad(options) {
 	onLoad(options) {
-		// console.log(options)
+		console.log(options)
 		this.keywords = options.keywords
 		this.keywords = options.keywords
 		if (!options.level || options.level === '白金') {
 		if (!options.level || options.level === '白金') {
 			this.current = 0
 			this.current = 0

+ 111 - 38
pages/home3/home3.vue

@@ -106,17 +106,23 @@
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 					</view>
 					</view>
 				</view>
 				</view>
-				<view class="body_strategy" @click="handleGoDetail">
-					<img mode="aspectfill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
+				<view class="body_strategy" @click="handleGoDetail(bestNewsInfo)">
+					<img v-if="bestNewsInfo.image" class="strategy_cover" mode="aspectfill" :src="bestNewsInfo.image" />
+					<video
+						v-if="bestNewsInfo.video"
+						class="strategy_cover"
+						:src="bestNewsInfo.video"
+						:show-center-play-btn="false"
+						:show-fullscreen-btn="false"
+						:show-play-btn="false"
+					></video>
 					<view class="strategy_info">
 					<view class="strategy_info">
-						<view class="info_title">这里不是瑞士!是江西靖安!</view>
+						<view class="info_title">{{ bestNewsInfo.title }}</view>
 						<view class="info_tags">
 						<view class="info_tags">
-							<view class="tag">南昌周边游</view>
-							<view class="tag">江西旅游</view>
-							<view class="tag">靖安民宿</view>
+							<view class="tag">{{ bestNewsInfo.townName }}</view>
 						</view>
 						</view>
 						<view class="info_desc">
 						<view class="info_desc">
-							南昌周边度假的宝藏民宿🏠享受山野间森呼吸🌿很适合逃离城市奔向大自然的快乐躺平☁️阴雨绵绵也抵挡不住它的美☔心向山野 尽请赴约 🍃一房一景 设计独特
+							{{ bestNewsInfo.content }}
 						</view>
 						</view>
 					</view>
 					</view>
 				</view>
 				</view>
@@ -127,29 +133,20 @@
 					<view class="circle color"></view>
 					<view class="circle color"></view>
 					<view class="top_title">招商资讯 .</view>
 					<view class="top_title">招商资讯 .</view>
 					<view class="top_msg">以招商引资,推动镇域经济</view>
 					<view class="top_msg">以招商引资,推动镇域经济</view>
-					<view class="top_more" @click="handleTest">
+					<view class="top_more" @click="handleGoNewsList">
 						更多
 						更多
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 					</view>
 					</view>
 				</view>
 				</view>
 
 
-				<view class="body_strategy">
-					<img mode="aspectfill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
+				<view v-for="item in newsList" :key="item.id" class="body_strategy" @click="handleGoNews(item)">
+					<uv-image width="253rpx" height="190rpx" radius="8rpx" mode="aspectFill" :src="item.url" />
 					<view class="strategy_info">
 					<view class="strategy_info">
-						<view class="info_title2">以招商引资,推动镇域经济!以招商引资,推动镇域经济以招商引资,推动镇域经济!</view>
+						<view class="info_title2">{{ item.title ? item.title : '无标题' }}</view>
 						<view class="info_desc">
 						<view class="info_desc">
-							南昌周边度假的宝藏民宿🏠享受山野间森呼吸🌿很适合逃离城市奔向大自然的快乐躺平☁️阴雨绵绵也抵挡不住它的美☔心向山野 尽请赴约 🍃一房一景 设计独特
-						</view>
-					</view>
-				</view>
-
-				<view class="body_strategy">
-					<img mode="aspectfill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
-					<view class="strategy_info">
-						<view class="info_title2">以招商引资,推动镇域经济!以招商引资,推动镇域经济以招商引资,推动镇域经济!</view>
-						<view class="info_desc">
-							南昌周边度假的宝藏民宿🏠享受山野间森呼吸🌿很适合逃离城市奔向大自然的快乐躺平☁️阴雨绵绵也抵挡不住它的美☔心向山野 尽请赴约 🍃一房一景 设计独特
+							{{ item.desc }}
 						</view>
 						</view>
+						<mp-html v-if="item.showHtml" @load="htmlLoad(item)" :ref="item.id + 'html'" :content="item.content" />
 					</view>
 					</view>
 				</view>
 				</view>
 
 
@@ -159,7 +156,7 @@
 					<view class="circle color"></view>
 					<view class="circle color"></view>
 					<view class="top_title">精选推荐 .</view>
 					<view class="top_title">精选推荐 .</view>
 					<view class="top_msg">线上订民宿,住着玩个遍</view>
 					<view class="top_msg">线上订民宿,住着玩个遍</view>
-					<view class="top_more" @click="handleTest">
+					<view class="top_more" @click="handleGoHome">
 						更多
 						更多
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 						<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/13.png" />
 					</view>
 					</view>
@@ -266,13 +263,20 @@ export default {
 			hotelList: [],
 			hotelList: [],
 			// 当前乡镇
 			// 当前乡镇
 			town: '',
 			town: '',
+			// 民宿级别
 			level: '',
 			level: '',
+			// 乡镇列表
 			townList: [],
 			townList: [],
+			// 顶部导航栏显示隐藏控制
 			headerType: false,
 			headerType: false,
 			// 状态栏高度
 			// 状态栏高度
 			statusBarH: 0,
 			statusBarH: 0,
 			// 胶囊按钮栏高度
 			// 胶囊按钮栏高度
-			customBarH: 0
+			customBarH: 0,
+			// 招商资讯列表
+			newsList: [],
+			// 精选攻略数据
+			bestNewsInfo: {}
 		}
 		}
 	},
 	},
 	created() {
 	created() {
@@ -322,10 +326,41 @@ export default {
 		}, 1000)
 		}, 1000)
 	},
 	},
 	onLoad() {
 	onLoad() {
+		// 获取乡镇列表
 		this.getResidueCount()
 		this.getResidueCount()
+		// 获取精选攻略
+		this.getBestNews()
+		// 获取招商资讯列表
+		this.getNews()
+		// 获取定位
 		this.getLocation()
 		this.getLocation()
 	},
 	},
 	methods: {
 	methods: {
+		async getBestNews() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryMaxArticleLike.action'
+			})
+			// console.log(res)
+			if (res.code == 200) {
+				this.bestNewsInfo = res.data
+			}
+		},
+		async getNews() {
+			const res = await this.$myRequest({
+				url: '/mhotel/appnewlist.action',
+				data: {
+					page: 1,
+					rows: 2
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.newsList = res.rows
+				this.newsList.forEach((ele) => {
+					this.$set(ele, 'showHtml', true)
+				})
+			}
+		},
 		// 获取用户当前位置
 		// 获取用户当前位置
 		getLocation() {
 		getLocation() {
 			uni.getSetting({
 			uni.getSetting({
@@ -391,10 +426,24 @@ export default {
 				}
 				}
 			})
 			})
 		},
 		},
-		handleGoDetail() {
-			uni.navigateTo({
-				url: `/pages/strategyDetatil/strategyDetatil`
-			})
+		handleGoDetail(info) {
+			let openid = uni.getStorageSync('openid')
+			if (openid) {
+				uni.navigateTo({
+					url: `/pages/tweetDetail/tweetDetail?id=${info.id}&townId=${info.townId}`
+				})
+			} else {
+				uni.showToast({
+					title: '请先登录',
+					icon: 'none',
+					mask: true
+				})
+				setTimeout(() => {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				}, 1500)
+			}
 		},
 		},
 		// 获取民宿列表
 		// 获取民宿列表
 		async getHotelList() {
 		async getHotelList() {
@@ -427,7 +476,6 @@ export default {
 		},
 		},
 		handleOpen() {
 		handleOpen() {
 			this.$refs.popup.open()
 			this.$refs.popup.open()
-			// this.getResidueCount()
 		},
 		},
 		// 获取乡镇
 		// 获取乡镇
 		async getResidueCount() {
 		async getResidueCount() {
@@ -488,13 +536,6 @@ export default {
 				url: `/pages/home/home?town=${this.town}&keywords=${this.keywords}&level=${this.level}`
 				url: `/pages/home/home?town=${this.town}&keywords=${this.keywords}&level=${this.level}`
 			})
 			})
 		},
 		},
-		handleTest() {
-			uni.showToast({
-				title: '功能开发中',
-				icon: 'none',
-				mask: true
-			})
-		},
 		handleGoSetMeal() {
 		handleGoSetMeal() {
 			uni.navigateTo({
 			uni.navigateTo({
 				url: '/pages/setMeal/setMeal'
 				url: '/pages/setMeal/setMeal'
@@ -532,6 +573,38 @@ export default {
 			uni.switchTab({
 			uni.switchTab({
 				url: '/pages/community/community'
 				url: '/pages/community/community'
 			})
 			})
+		},
+		handleGoNews(item) {
+			let info = encodeURIComponent(JSON.stringify(item))
+			uni.navigateTo({
+				url: `/pages/newsDetail/newsDetail?info=${info}`
+			})
+		},
+		handleGoNewsList() {
+			uni.navigateTo({
+				url: '/pages/newsList/newsList'
+			})
+		},
+		htmlLoad(item) {
+			let id = item.id + 'html'
+			let ctx = this.$refs[id][0]
+			let text = ctx.getText()
+			let imgs = ctx.imgList[0]
+			item.showHtml = false
+			item.desc = text
+			item.url = imgs
+		},
+		handleGoHome() {
+			uni.navigateTo({
+				url: '/pages/home/home'
+			})
+		},
+		handleTest() {
+			uni.showToast({
+				title: '功能开发中',
+				icon: 'none',
+				mask: true
+			})
 		}
 		}
 	}
 	}
 }
 }
@@ -860,7 +933,7 @@ export default {
 				border-radius: 12rpx;
 				border-radius: 12rpx;
 				background-color: #fff;
 				background-color: #fff;
 
 
-				img {
+				.strategy_cover {
 					width: 253rpx;
 					width: 253rpx;
 					height: 190rpx;
 					height: 190rpx;
 					border-radius: 7rpx;
 					border-radius: 7rpx;
@@ -1136,4 +1209,4 @@ export default {
 		}
 		}
 	}
 	}
 }
 }
-</style>
+</style>

+ 50 - 39
pages/likeList/likeList.vue

@@ -3,12 +3,12 @@
 		<view class="list">
 		<view class="list">
 			<!-- 每一个用户区域 -->
 			<!-- 每一个用户区域 -->
 			<view class="list_box" v-for="item in list" :key="item.id">
 			<view class="list_box" v-for="item in list" :key="item.id">
-				<img mode="aspectFill" :src="item.url" />
+				<img mode="aspectFill" :src="item.image" @click="handleGoMyHome(item)" />
 				<view class="box_info">
 				<view class="box_info">
 					<view class="info_name">{{ item.name }}</view>
 					<view class="info_name">{{ item.name }}</view>
 					<view class="info_num">
 					<view class="info_num">
-						<view class="num_article">{{ item.count }}篇推文</view>
-						<view class="num_fans">{{ item.fans }}粉丝</view>
+						<view class="num_article">{{ item.articleNumber }}篇推文</view>
+						<view class="num_fans">{{ item.fansNumber }}粉丝</view>
 					</view>
 					</view>
 				</view>
 				</view>
 			</view>
 			</view>
@@ -20,43 +20,54 @@
 export default {
 export default {
 	data() {
 	data() {
 		return {
 		return {
-			list: [
-				{
-					id: 1,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-					name: '鸣人',
-					count: 6,
-					fans: 10
-				},
-				{
-					id: 2,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-					name: '路飞',
-					count: 6,
-					fans: 10
-				},
-				{
-					id: 3,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-					name: '黑崎一护',
-					count: 6,
-					fans: 10
-				},
-				{
-					id: 4,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-					name: '灰太狼',
-					count: 6,
-					fans: 10
-				},
-				{
-					id: 5,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-					name: '哆啦A梦',
-					count: 6,
-					fans: 10
+			// 推文id
+			tweetId: null,
+			// 列表数组
+			list: [],
+			// 当前页
+			page: 1,
+			// 每页多少条
+			rows: 20,
+			// 总条数
+			total: null
+		}
+	},
+	onLoad(options) {
+		this.tweetId = options.id
+		this.getData()
+	},
+	onReachBottom() {
+		if (this.list.length < this.total) {
+			this.page++
+			this.getData()
+		} else {
+			uni.showToast({
+				title: '没有更多数据了',
+				icon: 'none',
+				mask: true
+			})
+		}
+	},
+	methods: {
+		async getData() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryLikes.action',
+				data: {
+					id: this.tweetId,
+					page: this.page,
+					rows: this.rows
 				}
 				}
-			]
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.list = [...this.list, ...res.data.pageList]
+				this.total = res.data.total
+			}
+		},
+		handleGoMyHome(item) {
+			uni.navigateTo({
+				url: `/pages/myHome/myHome?userId=${item.id}`
+			})
 		}
 		}
 	}
 	}
 }
 }

+ 10 - 4
pages/my/my.vue

@@ -9,12 +9,12 @@
 		<view class="header">
 		<view class="header">
 			<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/18.png" />
 			<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/18.png" />
 			<!-- 头像区域 -->
 			<!-- 头像区域 -->
-			<img class="img" mode="aspectFill" v-if="flag" :src="userInfo.headPhoto" @click="handleGoPage('/pages/myHome/myHome')" />
-			<img class="img" v-else src="../../static/my/portrait.png" @click="handleGoPage('/pages/myHome/myHome')" />
+			<img class="img" mode="aspectFill" v-if="flag" :src="userInfo.headPhoto" @click="handleGoPageHome" />
+			<img class="img" v-else src="../../static/my/portrait.png" @click="handleGoPageHome" />
 			<!-- 姓名区域 -->
 			<!-- 姓名区域 -->
-			<view class="name" v-if="flag" @click="handleGoPage('/pages/myHome/myHome')">{{ userInfo.user_name }}</view>
+			<view class="name" v-if="flag" @click="handleGoPageHome">{{ userInfo.user_name }}</view>
 			<!-- 用户id区域 -->
 			<!-- 用户id区域 -->
-			<view class="number" v-if="flag" @click="handleGoPage('/pages/myHome/myHome')">ID:{{ userInfo.id }}</view>
+			<view class="number" v-if="flag" @click="handleGoPageHome">ID:{{ userInfo.id }}</view>
 			<!-- 是否实名认证区域 -->
 			<!-- 是否实名认证区域 -->
 			<!-- <view class="real" v-if="userInfo.card_number">
 			<!-- <view class="real" v-if="userInfo.card_number">
 				<img src="../../static/my/true.png" />
 				<img src="../../static/my/true.png" />
@@ -164,6 +164,12 @@ export default {
 					})
 					})
 				}, 1500)
 				}, 1500)
 			}
 			}
+		},
+		handleGoPageHome() {
+			let userId = uni.getStorageSync('userInfo').id
+			uni.navigateTo({
+				url: `/pages/myHome/myHome?userId=${userId}`
+			})
 		}
 		}
 	}
 	}
 }
 }

+ 202 - 78
pages/myHome/myHome.vue

@@ -1,5 +1,5 @@
 <template>
 <template>
-	<view class="container">
+	<view class="container" v-if="userInfo !== null">
 		<!-- 页面标题 -->
 		<!-- 页面标题 -->
 		<view class="title" :style="{ height: customBarH * 2 + 'rpx', top: statusBarH * 2 + 'rpx' }" v-if="!headerType">个人主页</view>
 		<view class="title" :style="{ height: customBarH * 2 + 'rpx', top: statusBarH * 2 + 'rpx' }" v-if="!headerType">个人主页</view>
 
 
@@ -19,31 +19,32 @@
 		<view class="header">
 		<view class="header">
 			<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/18.png" />
 			<img src="https://chtech.ncjti.edu.cn/hotelReservation/image/18.png" />
 			<!-- 头像区域 -->
 			<!-- 头像区域 -->
-			<img class="img" mode="aspectFill" :src="userInfo.headPhoto || '../../static/my/portrait.png'" />
+			<img class="img" mode="aspectFill" :src="userInfo.image || '../../static/my/portrait.png'" />
 			<!-- 姓名区域 -->
 			<!-- 姓名区域 -->
-			<view class="name">{{ userInfo.user_name }}</view>
+			<view class="name">{{ userInfo.userName }}</view>
+			<view class="follow" v-if="userInfo.isFollow !== 2" @click="handleFollow">{{ info.isFollow === 0 ? '关注' : '已关注' }}</view>
 			<!-- 用户id区域 -->
 			<!-- 用户id区域 -->
 			<view class="number">ID:{{ userInfo.id }}</view>
 			<view class="number">ID:{{ userInfo.id }}</view>
 			<!-- 简介区域 -->
 			<!-- 简介区域 -->
-			<view class="desc" v-if="!showInput" @click="showInput = true">点击这里,填写简介</view>
+			<view class="desc" v-if="!showInput" @click="handleClickInput">{{ userInfo.descript }}</view>
 			<view class="desc_input" v-else>
 			<view class="desc_input" v-else>
-				<input type="text" auto-focus placeholder-style="color:#ccc" placeholder="请输入简介" @blur="handleBlur" @confirm="handleClickDesc" />
+				<input type="text" confirm-type="done" auto-focus placeholder-style="color:#ccc" placeholder="请输入简介" @blur="handleBlur" @confirm="handleClickDesc" />
 			</view>
 			</view>
 			<!-- 粉丝 关注 获赞 区域 -->
 			<!-- 粉丝 关注 获赞 区域 -->
 			<view class="info">
 			<view class="info">
 				<!-- 粉丝区域 -->
 				<!-- 粉丝区域 -->
 				<view class="info_box">
 				<view class="info_box">
-					<view class="box_num">17</view>
+					<view class="box_num">{{ userInfo.fansNum }}</view>
 					<view class="box_key">粉丝</view>
 					<view class="box_key">粉丝</view>
 				</view>
 				</view>
 				<!-- 关注区域 -->
 				<!-- 关注区域 -->
 				<view class="info_box">
 				<view class="info_box">
-					<view class="box_num">18</view>
+					<view class="box_num">{{ userInfo.followNum }}</view>
 					<view class="box_key">关注</view>
 					<view class="box_key">关注</view>
 				</view>
 				</view>
 				<!-- 获赞区域 -->
 				<!-- 获赞区域 -->
 				<view class="info_box">
 				<view class="info_box">
-					<view class="box_num">12</view>
+					<view class="box_num">{{ userInfo.likeNum }}</view>
 					<view class="box_key">获赞</view>
 					<view class="box_key">获赞</view>
 				</view>
 				</view>
 			</view>
 			</view>
@@ -57,46 +58,52 @@
 			</view>
 			</view>
 
 
 			<!-- 推文列表区域 -->
 			<!-- 推文列表区域 -->
-			<view class="list">
+			<view class="list" v-if="list.length">
 				<!-- 每一个推文区域 -->
 				<!-- 每一个推文区域 -->
-				<view class="item_box" v-for="item in list" :key="item.id">
+				<view class="item_box" v-for="item in list" :key="item.id" @click="handleGoDetail(item)">
 					<!-- 视频推文 -->
 					<!-- 视频推文 -->
-					<view class="box_video" v-if="item.type === 'video'">
+					<view class="box_video" v-if="item.video">
 						<!-- :show-play-btn="false" -->
 						<!-- :show-play-btn="false" -->
 						<video
 						<video
 							:id="'id' + item.id"
 							:id="'id' + item.id"
 							:show-fullscreen-btn="false"
 							:show-fullscreen-btn="false"
 							:direction="0"
 							:direction="0"
-							:src="item.url"
+							:src="item.video"
 							@fullscreenchange="fullscreenchange"
 							@fullscreenchange="fullscreenchange"
-							@click="handleClickVideo('id' + item.id)"
+							@click.stop="handleClickVideo('id' + item.id)"
 						></video>
 						></video>
 					</view>
 					</view>
 
 
 					<!-- 图片推文 -->
 					<!-- 图片推文 -->
-					<view class="box_image" v-if="item.type === 'image'">
-						<view class="image_box" v-for="(ele, index) in item.url" :key="index">
-							<img mode="acpectFill" :src="ele" />
+					<view class="box_image" v-if="item.images">
+						<view class="image_box" v-for="(ele, index) in item.images" :key="index">
+							<img mode="aspectFill" :src="ele" @click.stop="handleLookImg(item.images, index)" />
 						</view>
 						</view>
 					</view>
 					</view>
 					<!-- 标题区域 -->
 					<!-- 标题区域 -->
 					<view class="box_title">{{ item.title }}</view>
 					<view class="box_title">{{ item.title }}</view>
 					<view class="box_info">
 					<view class="box_info">
-						<view class="info_time">{{ item.time }}</view>
-						<view class="info_town">{{ item.town }}</view>
-						<img class="img" src="../../static/index/upvote.png" />
-						<view class="info_like">{{ item.like }}</view>
+						<view class="info_time">{{ item.date.slice(0, 19) }}</view>
+						<view class="info_town">{{ item.townName }}</view>
+						<img class="img" :src="item.isLike === 0 ? '../../static/index/upvote.png' : '../../static/index/upvote-active.png'" @click.stop="handleClickLike(item)" />
+						<view class="info_like">{{ item.likeNum }}</view>
 						<img class="img2" src="../../static/index/comment.png" />
 						<img class="img2" src="../../static/index/comment.png" />
 
 
-						<view class="info_comment">{{ item.comment }}</view>
+						<view class="info_comment">{{ item.commentNum }}</view>
 
 
 						<!-- 审核中印章区域 -->
 						<!-- 审核中印章区域 -->
-						<img v-if="current === 1" class="box_audit" src="../../static/index/audit.png" />
+						<img v-if="item.approve === 1" class="box_audit" src="../../static/index/audit.png" />
 						<!-- 已驳回印章区域 -->
 						<!-- 已驳回印章区域 -->
-						<img v-if="current === 2" class="box_rejected" src="../../static/index/rejected.png" />
+						<img v-if="item.approve === 3" class="box_rejected" src="../../static/index/rejected.png" />
 					</view>
 					</view>
 				</view>
 				</view>
 			</view>
 			</view>
+
+			<!-- 没有数据时展示的区域 -->
+			<view class="noData" v-else>
+				<img src="../../static/images/noData.png" />
+				暂无数据
+			</view>
 		</view>
 		</view>
 	</view>
 	</view>
 </template>
 </template>
@@ -105,8 +112,10 @@
 export default {
 export default {
 	data() {
 	data() {
 		return {
 		return {
+			// 是否是本人
+			isSelf: true,
 			// 用户信息
 			// 用户信息
-			userInfo: {},
+			userInfo: null,
 			// 状态栏高度
 			// 状态栏高度
 			statusBarH: 0,
 			statusBarH: 0,
 			// 胶囊按钮栏高度
 			// 胶囊按钮栏高度
@@ -115,61 +124,24 @@ export default {
 			headerType: false,
 			headerType: false,
 			// 简介输入框显示隐藏控制
 			// 简介输入框显示隐藏控制
 			showInput: false,
 			showInput: false,
+			// 分段器当前索引
 			current: 0,
 			current: 0,
+			// 分段器数组
 			items: ['全部推文', '审核中', '驳回'],
 			items: ['全部推文', '审核中', '驳回'],
-			list: [
-				{
-					id: 1,
-					title: '靖安最美的景色,绝对值得来',
-					time: '09-20',
-					town: '双溪镇',
-					like: 99,
-					comment: 24,
-					type: 'image',
-					url: [
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg',
-						'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg'
-					]
-				},
-				{
-					id: 2,
-					title: '靖安最美的景色,绝对值得来',
-					time: '09-20',
-					town: '双溪镇',
-					like: 66,
-					comment: 26,
-					type: 'video',
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230927113127_ytGv5IurFspj2d102676797c75b76ac4d13238401c8f.mp4'
-				},
-				{
-					id: 3,
-					title: '靖安最美的景色,绝对值得来',
-					time: '09-20',
-					town: '双溪镇',
-					like: 66,
-					comment: 26,
-					type: 'video',
-					url: 'https://jinganminsu-1320402385.cos.ap-nanjing.myqcloud.com/static//20230927113127_ytGv5IurFspj2d102676797c75b76ac4d13238401c8f.mp4'
-				},
-				{
-					id: 4,
-					title: '靖安最美的景色,绝对值得来',
-					time: '09-20',
-					town: '双溪镇',
-					like: 99,
-					comment: 24,
-					type: 'image',
-					url: ['https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg']
-				}
-			],
+			// 推文列表数组
+			list: [],
 			// video 上下文 videoContext 对象
 			// video 上下文 videoContext 对象
 			videoContext: null,
 			videoContext: null,
 			// 是否是全屏状态
 			// 是否是全屏状态
-			isFullScreen: false
+			isFullScreen: false,
+			// 当前用户id
+			userId: '',
+			// 当前页
+			page: 1,
+			// 每页多少条
+			rows: 6,
+			// 总条数
+			total: null
 		}
 		}
 	},
 	},
 	created() {
 	created() {
@@ -191,10 +163,79 @@ export default {
 			this.headerType = false
 			this.headerType = false
 		}
 		}
 	},
 	},
-	onShow() {
-		this.userInfo = uni.getStorageSync('userInfo')
+	onLoad(options) {
+		let id = uni.getStorageSync('userInfo').id
+		this.userId = options.userId
+		if (id != this.userId) {
+			this.isSelf = false
+			this.items = ['全部推文']
+		}
+		this.getUserInfo()
+		this.getTweetList()
+	},
+	onReachBottom() {
+		if (this.list.length < this.total) {
+			this.page++
+			this.getTweetList()
+		} else {
+			uni.showToast({
+				title: '没有更多数据了',
+				icon: 'none'
+			})
+		}
 	},
 	},
 	methods: {
 	methods: {
+		// 获取个人信息
+		async getUserInfo() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryUserInfo.action',
+				data: {
+					userId: this.userId
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.userInfo = res.data
+			}
+		},
+		// 获取推文列表数组
+		async getTweetList() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryOwnerArticlePage.action',
+				data: {
+					userId: this.userId,
+					type: this.current,
+					page: this.page,
+					rows: this.rows
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.list = [...this.list, ...res.data.pageList]
+				this.total = res.data.total
+			}
+		},
+		// 关注或者取消关注请求
+		async handleFollow() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlefollowAuthor.action',
+				data: {
+					authorId: this.userInfo.id,
+					userId: uni.getStorageSync('userInfo').id
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.userInfo.isFollow === 0 ? (this.userInfo.isFollow = 1) : (this.userInfo.isFollow = 0)
+			}
+		},
+		handleGoDetail(item) {
+			if (item.approve === 2) {
+				uni.navigateTo({
+					url: `/pages/tweetDetail/tweetDetail?id=${item.id}&townId=${item.townId}`
+				})
+			}
+		},
 		// 进入全屏和退出全屏时触发的回调
 		// 进入全屏和退出全屏时触发的回调
 		fullscreenchange(e) {
 		fullscreenchange(e) {
 			this.isFullScreen = e.detail.fullScreen
 			this.isFullScreen = e.detail.fullScreen
@@ -210,18 +251,76 @@ export default {
 				this.videoContext.play()
 				this.videoContext.play()
 			}
 			}
 		},
 		},
+		// 左上角返回按钮回调
 		handleBack() {
 		handleBack() {
 			uni.navigateBack(1)
 			uni.navigateBack(1)
 		},
 		},
-		handleClickDesc(e) {
-			console.log(e.detail)
+		handleClickInput() {
+			if (this.isSelf) {
+				this.showInput = true
+			}
+		},
+		async handleClickDesc(e) {
 			this.showInput = false
 			this.showInput = false
+			if (e.detail.value.length > 12) {
+				uni.showToast({
+					title: '简介不能超过12个字,请重新输入',
+					icon: 'none',
+					mask: true
+				})
+				return
+			}
+			let id = uni.getStorageSync('userInfo').id
+			const res = await this.$myRequest({
+				url: '/mhotel/articleupdateDescript.action',
+				data: {
+					descript: e.detail.value,
+					authorId: id,
+					userId: id
+				}
+			})
+			// console.log(res);
+
+			if (res.code === 200) {
+				uni.showToast({
+					title: res.message,
+					icon: 'success',
+					mask: true
+				})
+				setTimeout(() => {
+					this.getUserInfo()
+				}, 1500)
+			}
 		},
 		},
 		handleBlur() {
 		handleBlur() {
 			this.showInput = false
 			this.showInput = false
 		},
 		},
+		// 分段器切换回调
 		onClickItem(e) {
 		onClickItem(e) {
 			this.current = e.currentIndex
 			this.current = e.currentIndex
+			this.list = []
+			this.page = 1
+			this.getTweetList()
+		},
+		// 点击图片回调
+		handleLookImg(urls, current) {
+			uni.previewImage({
+				urls,
+				current
+			})
+		},
+		async handleClickLike(item) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlelikeArticle.action',
+				data: {
+					id: item.id,
+					userId: this.userId
+				}
+			})
+			// console.log(res);
+			if (res.code === 200) {
+				item.isLike === 1 ? ((item.isLike = 0), (item.likeNum -= 1)) : ((item.isLike = 1), (item.likeNum += 1))
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -284,6 +383,18 @@ export default {
 			font-weight: bold;
 			font-weight: bold;
 		}
 		}
 
 
+		.follow {
+			position: absolute;
+			top: 206rpx;
+			left: 580rpx;
+			display: flex;
+			align-items: center;
+			padding: 0 30rpx;
+			font-size: 28rpx;
+			border-radius: 70rpx;
+			border: 1rpx solid #fff;
+		}
+
 		.number {
 		.number {
 			position: absolute;
 			position: absolute;
 			top: 265rpx;
 			top: 265rpx;
@@ -452,6 +563,19 @@ export default {
 				}
 				}
 			}
 			}
 		}
 		}
+
+		.noData {
+			display: flex;
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+
+			img {
+				margin-top: 60rpx;
+				width: 400rpx;
+				height: 400rpx;
+			}
+		}
 	}
 	}
 }
 }
 </style>
 </style>

+ 48 - 0
pages/newsDetail/newsDetail.vue

@@ -0,0 +1,48 @@
+<template>
+	<view class="container" v-if="info !== null">
+		<!-- 标题区域 -->
+		<view class="title">{{ info.title }}</view>
+
+		<!-- 发布时间区域 -->
+		<view class="time">{{ info.update_time }}</view>
+
+		<!-- 内容区域 -->
+		<mp-html :content="info.content" />
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			info: null
+		}
+	},
+	onLoad(options) {
+		this.info = JSON.parse(decodeURIComponent(options.info))
+		// this.info.content = this.info.content.replace(/data-src/g, 'src')
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+	padding: 0 30rpx;
+	min-height: 100vh;
+	background-color: #fff;
+
+	.title {
+		padding-top: 30rpx;
+		text-align: center;
+		font-size: 32rpx;
+		font-weight: bold;
+	}
+
+	.time {
+		margin-top: 20rpx;
+		text-align: center;
+		color: #666666;
+		font-size: 24rpx;
+	}
+}
+</style>

+ 194 - 0
pages/newsList/newsList.vue

@@ -0,0 +1,194 @@
+<template>
+	<view class="container">
+		<!-- 搜索框区域 -->
+		<view class="search">
+			<view class="add">
+				<image class="img" src="../../static/index/search.png" mode="aspectFit"></image>
+			</view>
+			<input class="inp" type="text" v-model="keywords" placeholder="请输入关键字" />
+			<view class="btnSearch" @click="searchHandler">搜索</view>
+		</view>
+
+		<!-- 资讯列表区域 -->
+		<scroll-view class="list" scroll-y @scrolltolower="handleLower">
+			<!-- 每一条资讯区域 -->
+			<view class="box" v-for="item in list" :key="item.id" @click="handleGoDetail(item)">
+				<uv-image width="253rpx" height="190rpx" radius="8rpx" mode="aspectFill" :src="item.url" />
+				<view class="box_detail">
+					<view class="detail_title">{{ item.title ? item.title : '无标题' }}</view>
+					<view class="detail_time">{{ item.update_time }}</view>
+				</view>
+				<!-- 富文本区域 -->
+				<mp-html v-if="item.showHtml" @load="htmlLoad(item)" :ref="item.id + 'html'" :content="item.content" />
+			</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			// 搜索框绑定数据
+			keywords: '',
+			// 资讯列表
+			list: [],
+			// 当前页
+			pageNews: 1,
+			// 每页多少条
+			rowsNews: 8,
+			// 总条数
+			totalNews: null
+		}
+	},
+	onLoad() {
+		this.getNews()
+	},
+	methods: {
+		// 获取资讯列表
+		async getNews() {
+			const res = await this.$myRequest({
+				url: '/mhotel/appnewlist.action',
+				data: {
+					page: this.pageNews,
+					rows: this.rowsNews,
+					title: this.keywords
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.list = [...this.list, ...res.rows]
+				this.list.forEach((ele) => {
+					this.$set(ele, 'showHtml', true)
+				})
+				this.totalNews = res.total
+			}
+		},
+		// 点击搜索按钮回调
+		searchHandler() {
+			;(this.list = []), (this.pageNews = 1)
+			this.getNews()
+		},
+		// 页面到底触发回调
+		handleLower() {
+			if (this.list.length < this.totalNews) {
+				this.pageNews++
+				this.getNews()
+			} else {
+				uni.showToast({
+					title: '没有更多数据了',
+					icon: 'none'
+				})
+			}
+		},
+		// 跳转资讯详情回调
+		handleGoDetail(item) {
+			let info = encodeURIComponent(JSON.stringify(item))
+			uni.navigateTo({
+				url: `/pages/newsDetail/newsDetail?info=${info}`
+			})
+		},
+		// 获取富文本信息回调
+		htmlLoad(item) {
+			let id = item.id + 'html'
+			let ctx = this.$refs[id][0]
+			let imgs = ctx.imgList[0]
+			item.showHtml = false
+			item.url = imgs
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+	box-sizing: border-box;
+	padding: 20rpx;
+	height: 100vh;
+	background-color: #f2f2f2;
+
+	.search {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		height: 80rpx;
+		opacity: 1;
+		border-radius: 70px;
+		background-color: #fff;
+
+		.add {
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			margin-left: 10rpx;
+			width: 60rpx;
+			height: 60rpx;
+
+			.img {
+				width: 30rpx;
+				height: 30rpx;
+			}
+		}
+
+		.inp {
+			height: 60rpx;
+			line-height: 60rpx;
+			flex-grow: 1;
+			font-size: 28rpx;
+		}
+
+		.btnSearch {
+			margin-right: 10rpx;
+			width: 100rpx;
+			height: 60rpx;
+			line-height: 60rpx;
+			text-align: center;
+			opacity: 1;
+			font-size: 28rpx;
+			color: #096562;
+		}
+	}
+
+	.list {
+		height: calc(100vh - 140rpx);
+		padding: 20rpx 0;
+
+		.box {
+			box-sizing: border-box;
+			padding: 20rpx 30rpx 20rpx 20rpx;
+			margin-bottom: 20rpx;
+			display: flex;
+			width: 710rpx;
+			height: 230rpx;
+			background-color: #fff;
+
+			// .box_img {
+			// 	width: 253rpx;
+			// 	height: 190rpx;
+			// 	border-radius: 8rpx;
+			// }
+
+			.box_detail {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				justify-content: space-between;
+				margin-left: 20rpx;
+
+				.detail_title {
+					font-size: 32rpx;
+					font-weight: bold;
+					display: -webkit-box;
+					-webkit-box-orient: vertical;
+					-webkit-line-clamp: 2;
+					overflow: hidden;
+				}
+				.detail_time {
+					color: #666666;
+					font-size: 24rpx;
+				}
+			}
+		}
+	}
+}
+</style>

+ 19 - 7
pages/orderManage/orderManage.vue

@@ -80,9 +80,7 @@ export default {
 			deleteList: []
 			deleteList: []
 		}
 		}
 	},
 	},
-	onLoad() {
-		// this.getLocation()
-	},
+	onLoad() {},
 	onUnload() {
 	onUnload() {
 		this.handleDeleteList()
 		this.handleDeleteList()
 	},
 	},
@@ -90,10 +88,24 @@ export default {
 		this.handleDeleteList()
 		this.handleDeleteList()
 	},
 	},
 	onShow() {
 	onShow() {
-		this.total = null
-		this.page = 1
-		this.orderList = []
-		this.getLocation()
+		let openid = uni.getStorageSync('openid')
+		if (openid) {
+			this.total = null
+			this.page = 1
+			this.orderList = []
+			this.getLocation()
+		} else {
+			uni.showToast({
+				title: '请先登录',
+				icon: 'none',
+				mask: true
+			})
+			setTimeout(() => {
+				uni.navigateTo({
+					url: '/pages/login/login'
+				})
+			}, 1500)
+		}
 	},
 	},
 	// 下拉刷新
 	// 下拉刷新
 	onPullDownRefresh() {
 	onPullDownRefresh() {

+ 358 - 0
pages/rimDetail/rimDetail.vue

@@ -0,0 +1,358 @@
+<template>
+	<view class="container" :style="'overflow:' + (showPage ? 'hidden' : 'visible')">
+		<!-- 顶部轮播图区域 -->
+		<swiper class="swiper" indicator-dots indicator-color="rgba(255, 255, 255, 0.5)" indicator-active-color="#fff" autoplay :interval="3000">
+			<swiper-item>
+				<view class="swiper-item">
+					<img class="img" mode="aspectFill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
+				</view>
+			</swiper-item>
+			<swiper-item>
+				<view class="swiper-item">
+					<img class="img" mode="aspectFill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
+				</view>
+			</swiper-item>
+		</swiper>
+
+		<!-- 周边信息区域 -->
+		<view class="info">
+			<view class="info_name">周边名称周边名称周边名称</view>
+			<view class="info_score">
+				<view class="score_left">5.0</view>
+				<view class="score_right">超棒</view>
+				<view class="score_msg" @click="goPageInfo">简介</view>
+				<img class="score_icon" src="../../static/index/right.png" @click="goPageInfo" />
+			</view>
+			<view class="info_address">
+				<img class="address_icon" src="../../static/index/address.png" />
+				江西省南昌市西湖区九州大街南昌动物园西门
+			</view>
+		</view>
+
+		<!-- 周边产品区域 -->
+		<view class="goods">
+			<view class="goods_title">周边产品</view>
+			<!-- 列表区域 -->
+			<view class="goods_list">
+				<!-- 每一个产品区域 -->
+				<view class="item_box" v-for="item in goodList" :key="item.id" @click="handleLookDetail">
+					<view class="box_left">
+						<view class="left_name">{{ item.name }}</view>
+						<view class="left_info">产品简介 ></view>
+						<view class="left_price">¥{{ item.price }}</view>
+					</view>
+					<view class="box_right">
+						<view class="right_btn">预定</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<!-- 查看更多区域 -->
+		<view class="more">
+			查看更多
+			<img class="more_icon" src="../../static/index/down.png" />
+		</view>
+
+		<!-- 弹窗区域 -->
+		<uv-popup ref="popup" bgColor="none" :safeAreaInsetBottom="false">
+			<view class="body_pop">
+				<img class="pop_img" mode="aspectFill" src="https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1933617026前台.jpg" />
+				<!-- 弹窗关闭图标区域 -->
+				<img class="pop_icon" src="../../static/index/close.png" @click="handleClosePop" />
+				<view class="pop_name">门票+观光车+竹筏</view>
+				<view class="pop_title">
+					<img class="title_img" src="../../static/index/notice.png" />
+					购票须知
+				</view>
+				<view class="pop_content">16:00点前可订今日,预订后立即可用平均2秒出票凭[入园码先换票再入园</view>
+				<view class="pop_content">未使用可随时由请全额退款</view>
+				<view class="pop_content">使用日期后1天经核实未使用系统将自动发起退款申请</view>
+				<view class="pop_content">换票后,不支持退款</view>
+				<view class="pop_content">下单后不支持改期使用说明:</view>
+				<view class="pop_content">换票时间:08:00-16:00 换票地址:游客中心取票入园</view>
+				<view class="pop_content">费用说明费用包含三爪仑观音岩-[成人票]门票- 1张</view>
+				<view class="pop_content">其它说明</view>
+				<view class="pop_content">比产品由商家开具发票,若需要发票,请在消费前和商家联系确认开票方法</view>
+
+				<view class="pop_title">
+					<img class="title_img" src="../../static/index/phone3.png" />
+					联系电话
+				</view>
+
+				<view class="pop_phone">13677988964</view>
+			</view>
+		</uv-popup>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			// 滚动穿透控制
+			showPage: false,
+			goodList: [
+				{
+					id: 1,
+					name: '门票+观光车+竹筏',
+					price: 120
+				},
+				{
+					id: 2,
+					name: '门票',
+					price: 20
+				},
+				{
+					id: 3,
+					name: '观光车+竹筏',
+					price: 80
+				}
+			]
+		}
+	},
+	methods: {
+		goPageInfo() {
+			uni.navigateTo({
+				url: '/pages/rimInfo/rimInfo'
+			})
+		},
+		handleLookDetail() {
+			this.showPage = true
+			this.$refs.popup.open('bottom')
+		},
+		// 点击弹窗关闭图标回调
+		handleClosePop() {
+			this.showPage = false
+			this.$refs.popup.close()
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.container {
+	min-height: 100vh;
+	background-color: #fff;
+
+	.swiper {
+		height: 423rpx;
+
+		.swiper-item {
+			width: 100%;
+			height: 100%;
+
+			.img {
+				width: 100%;
+				height: 100%;
+			}
+		}
+	}
+
+	.info {
+		margin-top: 20rpx;
+		padding: 0 20rpx;
+
+		.info_name {
+			font-size: 34rpx;
+			font-weight: bold;
+			color: #000000;
+		}
+
+		.info_score {
+			display: flex;
+			align-items: center;
+			margin-top: 22rpx;
+			font-size: 24rpx;
+
+			.score_left {
+				padding: 0 10rpx 0 12rpx;
+				line-height: 36rpx;
+				color: #fff;
+				text-align: center;
+				font-weight: bold;
+				border-radius: 32rpx 0 0 32rpx;
+				background-color: #096562;
+			}
+			.score_right {
+				padding: 0 12rpx 0 10rpx;
+				line-height: 36rpx;
+				color: #096562;
+				text-align: center;
+				font-weight: bold;
+				border-radius: 0 32rpx 32rpx 0;
+				background-color: #dff2f2;
+			}
+			.score_msg {
+				margin-left: 42rpx;
+				color: #096562;
+			}
+
+			.score_icon {
+				margin-top: 5rpx;
+				margin-left: 13rpx;
+				width: 10rpx;
+				height: 20rpx;
+			}
+		}
+
+		.info_address {
+			display: flex;
+			align-items: center;
+			margin-top: 24rpx;
+			height: 83rpx;
+			font-size: 28rpx;
+			border-top: 1rpx solid #e6e6e6;
+
+			.address_icon {
+				margin-right: 8rpx;
+				width: 30rpx;
+				height: 30rpx;
+			}
+		}
+	}
+
+	.goods {
+		padding: 0 20rpx;
+		border-top: 1rpx solid #cccccc;
+
+		.goods_title {
+			margin-top: 30rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+		}
+
+		.goods_list {
+			margin-top: 17rpx;
+
+			.item_box {
+				display: flex;
+				margin-bottom: 20rpx;
+				padding: 0 32rpx 0 24rpx;
+				height: 170rpx;
+				border-radius: 10rpx;
+				background-color: #f2f2f2;
+
+				.box_left {
+					flex: 2;
+					display: flex;
+					flex-direction: column;
+					justify-content: space-evenly;
+					overflow: hidden;
+
+					.left_name {
+						font-size: 28rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+
+					.left_info {
+						color: #808080;
+						font-size: 24rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+					}
+
+					.left_price {
+						color: #ff5733;
+						font-size: 24rpx;
+					}
+				}
+
+				.box_right {
+					flex: 1;
+					display: flex;
+					justify-content: flex-end;
+					align-items: center;
+
+					.right_btn {
+						display: flex;
+						justify-content: center;
+						align-items: center;
+						width: 115rpx;
+						height: 60rpx;
+						color: #fff;
+						font-size: 28rpx;
+						border-radius: 10rpx;
+						background-color: #ff5733;
+					}
+				}
+			}
+		}
+	}
+
+	.more {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		padding: 20rpx 0 30rpx 0;
+		color: #096663;
+		font-size: 24rpx;
+
+		.more_icon {
+			width: 38rpx;
+			height: 48rpx;
+		}
+	}
+
+	.body_pop {
+		position: relative;
+		width: 750rpx;
+		height: 85vh;
+		border-radius: 22rpx 22rpx 0 0;
+		background-color: #fff;
+		overflow-y: auto;
+
+		.pop_img {
+			width: 100%;
+			height: 423rpx;
+			border-radius: 20rpx 20rpx 0 0;
+		}
+
+		.pop_icon {
+			position: absolute;
+			top: 20rpx;
+			right: 30rpx;
+			width: 58rpx;
+			height: 58rpx;
+		}
+
+		.pop_name {
+			padding: 0 20rpx;
+			line-height: 90rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+		}
+
+		.pop_title {
+			display: flex;
+			align-items: center;
+			padding: 12rpx 20rpx 13rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+
+			.title_img {
+				margin-right: 15rpx;
+				width: 38rpx;
+				height: 38rpx;
+			}
+		}
+
+		.pop_content {
+			padding: 0 20rpx;
+			line-height: 40rpx;
+			color: #666666;
+			font-size: 24rpx;
+		}
+
+		.pop_phone {
+			margin-left: 50rpx;
+			padding-bottom: 50rpx;
+			color: #096562;
+			font-size: 24rpx;
+		}
+	}
+}
+</style>

File diff suppressed because it is too large
+ 63 - 0
pages/rimInfo/rimInfo.vue


+ 66 - 16
pages/send/send.vue

@@ -48,7 +48,7 @@
 
 
 		<!-- 标题输入区域 -->
 		<!-- 标题输入区域 -->
 		<view class="title">
 		<view class="title">
-			<input class="input" type="text" placeholder-style="color:#B3B3B3" placeholder="请输入标题" v-model="titleValue" />
+			<input class="input" type="text" placeholder-style="color:#B3B3B3" placeholder="请输入标题" maxlength="30" v-model="titleValue" />
 		</view>
 		</view>
 
 
 		<!-- 推文内容输入区域 -->
 		<!-- 推文内容输入区域 -->
@@ -73,7 +73,7 @@
 		<!-- 关联民宿列表区域 -->
 		<!-- 关联民宿列表区域 -->
 		<view class="and_list">
 		<view class="and_list">
 			<!-- 每一个民宿区域 -->
 			<!-- 每一个民宿区域 -->
-			<view class="and_box" :class="{ active: item.is_collect_hotel }" v-for="item in andList" :key="item.id" @click="handleChange(item)">{{ item.hotel_name }}</view>
+			<view class="and_box" :class="{ active: item.isCheck }" v-for="item in andList" :key="item.id" @click="handleChange(item)">{{ item.name }}</view>
 		</view>
 		</view>
 
 
 		<!-- 发布按钮区域 -->
 		<!-- 发布按钮区域 -->
@@ -132,7 +132,8 @@ export default {
 			// video 上下文 videoContext 对象
 			// video 上下文 videoContext 对象
 			videoContext: null,
 			videoContext: null,
 			// 是否是全屏状态
 			// 是否是全屏状态
-			isFullScreen: false
+			isFullScreen: false,
+			townId: null
 		}
 		}
 	},
 	},
 	created() {
 	created() {
@@ -160,7 +161,7 @@ export default {
 	methods: {
 	methods: {
 		// 切换关联民宿回调
 		// 切换关联民宿回调
 		handleChange(item) {
 		handleChange(item) {
-			item.is_collect_hotel = !item.is_collect_hotel
+			item.isCheck = !item.isCheck
 		},
 		},
 		// 点击添加图片回调
 		// 点击添加图片回调
 		handleImage() {
 		handleImage() {
@@ -227,7 +228,7 @@ export default {
 				title: '上传中'
 				title: '上传中'
 			})
 			})
 			uni.uploadFile({
 			uni.uploadFile({
-				url: `https://chtech.ncjti.edu.cn/homestay/file/cos/upload`,
+				url: `https://chtech.ncjti.edu.cn/hotelReservation/file/cos/upload`,
 				filePath: ele,
 				filePath: ele,
 				name: 'files',
 				name: 'files',
 				success: (uploadFileRes) => {
 				success: (uploadFileRes) => {
@@ -287,18 +288,19 @@ export default {
 		},
 		},
 		// 点击添加地点回调
 		// 点击添加地点回调
 		handleGoPage() {
 		handleGoPage() {
-			this.andList = this.andList.filter((ele) => ele.is_collect_hotel)
+			this.andList = this.andList.filter((ele) => ele.isCheck)
 			const list = JSON.stringify(this.andList)
 			const list = JSON.stringify(this.andList)
 			uni.navigateTo({
 			uni.navigateTo({
-				url: `/pages/addPlace/addPlace?list=${list}`
+				url: `/pages/addPlace/addPlace?list=${list}&townId=${this.townId}`
 			})
 			})
 		},
 		},
 		// 全局自定义事件
 		// 全局自定义事件
 		add(e) {
 		add(e) {
 			this.andList = e.list
 			this.andList = e.list
+			this.townId = e.townId
 		},
 		},
 		// 点击发布按钮回调
 		// 点击发布按钮回调
-		handleClickSub() {
+		async handleClickSub() {
 			if (!this.subImgList.length && !this.subVideo) {
 			if (!this.subImgList.length && !this.subVideo) {
 				uni.showToast({
 				uni.showToast({
 					title: '请上传图片或者视频',
 					title: '请上传图片或者视频',
@@ -324,17 +326,53 @@ export default {
 				})
 				})
 				return
 				return
 			}
 			}
-			let temList = this.andList.filter((ele) => ele.is_collect_hotel)
-			console.log(temList)
-			console.log(this.subImgList)
-			console.log(this.subVideo)
-			console.log(this.titleValue)
-			console.log(this.contentValue)
-			this.$refs.popup.open()
+			if (!this.andList.length) {
+				uni.showToast({
+					title: '请添加地点关联相关民宿',
+					icon: 'none',
+					mask: true
+				})
+				return
+			}
+			if (!this.andList.some((ele) => ele.isCheck)) {
+				uni.showToast({
+					title: '请关联至少一个民宿',
+					icon: 'none',
+					mask: true
+				})
+				return
+			}
+			let temList = []
+			this.andList.forEach((ele) => {
+				if (ele.isCheck) {
+					temList.push(ele.id)
+				}
+			})
+			const res = await this.$myRequest({
+				url: '/mhotel/articleinsertArticleTweet.action',
+				method: 'post',
+				data: {
+					images: this.subImgList,
+					video: this.subVideo,
+					townId: this.townId,
+					hotelIds: temList,
+					title: this.titleValue,
+					content: this.contentValue,
+					createId: uni.getStorageSync('userInfo').id
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.$refs.popup.open()
+			}
 		},
 		},
 		// 点击弹窗查看推文按钮回调
 		// 点击弹窗查看推文按钮回调
 		handleClickLook() {
 		handleClickLook() {
 			this.$refs.popup.close()
 			this.$refs.popup.close()
+			let userId = uni.getStorageSync('userInfo').id
+			uni.redirectTo({
+				url: `/pages/myHome/myHome?userId=${userId}`
+			})
 		},
 		},
 		// 点击图片回调
 		// 点击图片回调
 		handleLookImg(urls, current) {
 		handleLookImg(urls, current) {
@@ -344,7 +382,19 @@ export default {
 			})
 			})
 		},
 		},
 		handleBack() {
 		handleBack() {
-			uni.navigateBack(1)
+			uni.showModal({
+				content: '确认退出吗,已编辑的内容将不保存',
+				cancelText: '退出',
+				cancelColor: '#808080',
+				confirmText: '继续发布',
+				confirmColor: '#000000',
+				success: (res) => {
+					if (res.confirm) {
+					} else if (res.cancel) {
+						uni.navigateBack(1)
+					}
+				}
+			})
 		}
 		}
 	}
 	}
 }
 }

+ 8 - 0
pages/set/set.vue

@@ -139,6 +139,14 @@ export default {
 							setTimeout(() => {
 							setTimeout(() => {
 								this.changeName()
 								this.changeName()
 							}, 1500)
 							}, 1500)
+						} else if (res.content.length > 8) {
+							uni.showToast({
+								title: '账号名最多8位',
+								icon: 'none'
+							})
+							setTimeout(() => {
+								this.changeName()
+							}, 1500)
 						} else {
 						} else {
 							const result = await this.$myRequest({
 							const result = await this.$myRequest({
 								url: '/mhotel/ampupdateUserInfo.action',
 								url: '/mhotel/ampupdateUserInfo.action',

+ 423 - 190
pages/tweetDetail/tweetDetail.vue

@@ -2,41 +2,52 @@
 	<view class="container" :style="'overflow:' + (showPage ? 'hidden' : 'visible')" v-if="info">
 	<view class="container" :style="'overflow:' + (showPage ? 'hidden' : 'visible')" v-if="info">
 		<!-- 作者信息区域 -->
 		<!-- 作者信息区域 -->
 		<view class="author">
 		<view class="author">
-			<img mode="aspectFill" :src="info.coverImg" />
-			<view class="author_name">{{ info.hotel_name }}</view>
-			<view class="author_btn">关注</view>
+			<img mode="aspectFill" :src="info.userPhoto" @click="handleGoMyHome(info.userId)" />
+			<view class="author_name">{{ info.userName }}</view>
+			<view class="author_btn" v-if="info.isFollow !== 2" @click="handleFollow">{{ info.isFollow === 0 ? '关注' : '已关注' }}</view>
 		</view>
 		</view>
 
 
 		<!-- 轮播图区域 -->
 		<!-- 轮播图区域 -->
-		<swiper indicator-color="#ccc" indicator-active-color="#096562" indicator-dots autoplay circular class="swiper">
-			<swiper-item class="swiper_item" v-for="(item, current) in info.hotelFileInfoList" :key="item.id" @click="handleClickSwiper(info.hotelFileInfoList, current)">
-				<img mode="aspectFill" class="img" :src="item.url" />
+		<swiper indicator-color="#ccc" indicator-active-color="#096562" indicator-dots autoplay circular class="swiper" v-if="info.images">
+			<swiper-item class="swiper_item" v-for="(item, current) in info.images" :key="current" @click="handleClickSwiper(info.images, current)">
+				<img mode="aspectFill" class="img" :src="item" />
 			</swiper-item>
 			</swiper-item>
 		</swiper>
 		</swiper>
 
 
+		<video
+			v-if="info.video"
+			class="swiper"
+			:src="info.video"
+			id="myVideo"
+			:show-fullscreen-btn="false"
+			:direction="0"
+			@fullscreenchange="fullscreenchange"
+			@click="handleClickVideo('myVideo')"
+		></video>
+
 		<!-- 推文信息区域 -->
 		<!-- 推文信息区域 -->
 		<view class="tweet">
 		<view class="tweet">
-			<view class="tweet_title">{{ info.hposition }}</view>
-			<view class="tweet_msg">{{ info.remark }}</view>
-			<view class="tweet_info">{{ info.openTime.slice(5, 10) }} {{ info.hotelTownshipName }}</view>
+			<view class="tweet_title">{{ info.title }}</view>
+			<view class="tweet_msg">{{ info.content }}</view>
+			<view class="tweet_info">{{ info.dateStr }} {{ info.townName }}</view>
 		</view>
 		</view>
 
 
 		<!-- 关联民宿区域 -->
 		<!-- 关联民宿区域 -->
 		<view class="and">
 		<view class="and">
 			<!-- 每一个关联民宿区域 -->
 			<!-- 每一个关联民宿区域 -->
-			<view class="and_box" v-for="item in info.houseList.slice(0, 2)" :key="item.id">
-				<img mode="aspectFill" :src="item.fileInfoList[0].url" />
+			<view class="and_box" v-for="item in info.hotels" :key="item.id" @click="goHotelDetail(item)">
+				<img mode="aspectFill" :src="item.coverImg" />
 				<view class="box_detail">
 				<view class="box_detail">
 					<view class="detail_name">
 					<view class="detail_name">
-						{{ item.hName }}
-						<img class="img" src="../../static/index/like.png" />
-					</view>
-					<view class="detail_leave">
-						{{ item.hName }}
+						{{ item.name }}
+						<img class="img" :src="item.isCollect === 0 ? '../../static/index/like.png' : '../../static/index/like-active.png'" @click.stop="handleLikeHotel(item)" />
 					</view>
 					</view>
+					<view class="detail_leave" v-if="item.type === 1">银宿级</view>
+					<view class="detail_leave" v-if="item.type === 2">金宿级</view>
+					<view class="detail_leave" v-if="item.type === 3">白金级</view>
 					<view class="detail_num">
 					<view class="detail_num">
-						<view class="num_rate">{{ item.number.toFixed(1) }}分</view>
-						<view class="num_comment">{{ item.number }}条评论</view>
+						<view class="num_rate">{{ item.score.toFixed(1) }}分</view>
+						<view class="num_comment">{{ item.comment }}条评论</view>
 						<view class="num_price">
 						<view class="num_price">
 							¥{{ item.price }}
 							¥{{ item.price }}
 							<text>起</text>
 							<text>起</text>
@@ -50,30 +61,30 @@
 		</view>
 		</view>
 
 
 		<!-- 点赞人数区域 -->
 		<!-- 点赞人数区域 -->
-		<view class="like">
-			<uv-avatar-group :urls="info.hotelFileInfoList" keyName="url" size="30" gap="0.3" maxCount="10"></uv-avatar-group>
-			<view class="like_text" @click="handleGoPage('/pages/likeList/likeList')">{{ info.roomNumber }}人已赞</view>
+		<view class="like" v-if="info.likes.length !== 0">
+			<uv-avatar-group mode="aspectFill" :urls="info.likes" size="30" gap="0.3" maxCount="10"></uv-avatar-group>
+			<view class="like_text" @click="handleGoPageLike">{{ info.likeNum }}人已赞</view>
 		</view>
 		</view>
 
 
 		<!-- 评论总条数区域 -->
 		<!-- 评论总条数区域 -->
-		<view class="total">共15条评论</view>
+		<view class="total" v-if="info.commentNum">共{{ info.commentNum }}条评论</view>
 
 
 		<!-- 评论输入框区域 -->
 		<!-- 评论输入框区域 -->
 		<view class="input_box">
 		<view class="input_box">
-			<input type="text" confirm-type="send" placeholder="爱评论的人运气都不差" @confirm="handleInput" />
+			<input type="text" confirm-type="send" placeholder="爱评论的人运气都不差" v-model="commentsValue" @confirm="handleInput" />
 		</view>
 		</view>
 
 
 		<!-- 评论列表区域 -->
 		<!-- 评论列表区域 -->
-		<view class="comment_list">
+		<view class="comment_list" v-if="info.comments">
 			<!-- 每一个评论区域 -->
 			<!-- 每一个评论区域 -->
-			<view class="comment_box" v-for="item in info.houseList.slice(0, 3)" :key="item.id">
+			<view class="comment_box" v-for="item in info.comments" :key="item.id">
 				<view class="box_left">
 				<view class="box_left">
-					<img mode="aspectFill" :src="item.fileInfoList[0].url" />
+					<img mode="aspectFill" :src="item.image" @click="handleGoMyHome(item.userId)" />
 				</view>
 				</view>
 				<view class="box_right">
 				<view class="box_right">
-					<view class="right_name">{{ item.hName }}</view>
-					<view class="right_content">{{ item.hConfig }}</view>
-					<view class="right_time">{{ item.createDate.slice(6, 11) }}</view>
+					<view class="right_name">{{ item.userName }}</view>
+					<view class="right_content">{{ item.content }}</view>
+					<view class="right_time">{{ item.date.slice(0, 19) }}</view>
 				</view>
 				</view>
 			</view>
 			</view>
 
 
@@ -82,22 +93,30 @@
 		</view>
 		</view>
 
 
 		<!-- 相关推文区域 -->
 		<!-- 相关推文区域 -->
-		<view class="related" v-if="info.houseList.length">
+		<view class="related" v-if="bindTweetList.length !== 0">
 			<view class="related_title">相关推文</view>
 			<view class="related_title">相关推文</view>
 			<!-- 相关推文列表区域 -->
 			<!-- 相关推文列表区域 -->
 			<view class="related_list">
 			<view class="related_list">
 				<!-- 每一个推文区域 -->
 				<!-- 每一个推文区域 -->
-				<view class="related_box" v-for="item in info.houseList.slice(0, 2)" :key="item.id">
-					<img mode="aspectFill" :src="item.fileInfoList[0].url" />
-					<view class="box_content">{{ item.hConfig }}</view>
+				<view class="related_box" v-for="item in bindTweetList" :key="item.id" @click="handleGoBind(item)">
+					<img class="box_cover" v-if="item.image" mode="aspectFill" :src="item.image" />
+					<video class="box_cover" v-if="item.video" :src="item.video" :show-center-play-btn="false" :show-fullscreen-btn="false" :show-play-btn="false"></video>
+					<view class="box_content">{{ item.title }}</view>
 					<view class="box_info">
 					<view class="box_info">
-						<img class="img" mode="aspectFill" :src="item.fileInfoList[0].url" />
-						<view class="info_name">{{ item.hName }}</view>
-						<img class="img2" mode="aspectFill" src="../../static/index/like.png" />
-						<view class="info_count">{{ item.number }}</view>
+						<img class="img" mode="aspectFill" :src="item.userPhoto" />
+						<view class="info_name">{{ item.userName }}</view>
+						<img
+							class="img2"
+							mode="aspectFill"
+							:src="item.isCollect === 0 ? '../../static/index/like.png' : '../../static/index/like-active.png'"
+							@click.stop="handleClickLike(item)"
+						/>
+						<view class="info_count">{{ item.collectNum }}</view>
 					</view>
 					</view>
 					<!-- 乡镇信息区域 -->
 					<!-- 乡镇信息区域 -->
-					<view class="box_town">{{ item.hName }}</view>
+					<view class="box_town">{{ item.townName }}</view>
+					<!-- 视频图标 -->
+					<img v-if="item.video" class="box_play" src="../../static/index/video.png" />
 				</view>
 				</view>
 			</view>
 			</view>
 		</view>
 		</view>
@@ -106,37 +125,37 @@
 		<view class="tab">
 		<view class="tab">
 			<!-- 点赞 -->
 			<!-- 点赞 -->
 			<view class="tab_box">
 			<view class="tab_box">
-				<img class="img" src="../../static/index/upvote.png" />
-				123
+				<img class="img" :src="info.isLike === 0 ? '../../static/index/upvote.png' : '../../static/index/upvote-active.png'" @click="clickBtnLike" />
+				{{ info.likeNum }}
 			</view>
 			</view>
 			<!-- 评论 -->
 			<!-- 评论 -->
 			<view class="tab_box" @click="handleClickComment">
 			<view class="tab_box" @click="handleClickComment">
 				<img class="img2" src="../../static/index/comment.png" />
 				<img class="img2" src="../../static/index/comment.png" />
-				123
+				{{ info.commentNum }}
 			</view>
 			</view>
 			<!-- 收藏 -->
 			<!-- 收藏 -->
 			<view class="tab_box">
 			<view class="tab_box">
-				<img class="img" src="../../static/index/like.png" />
-				123
+				<img class="img" :src="info.isCollect === 0 ? '../../static/index/like.png' : '../../static/index/like-active.png'" @click="handleClickLike(info)" />
+				{{ info.collectNum }}
 			</view>
 			</view>
 		</view>
 		</view>
 
 
 		<!-- 点击评论弹窗区域 -->
 		<!-- 点击评论弹窗区域 -->
-		<uv-popup ref="popup" bgColor="none" :safeAreaInsetBottom="false">
-			<view class="body_pop">
+		<uv-popup ref="popup" bgColor="none" :safeAreaInsetBottom="false" :closeOnClickOverlay="false">
+			<view class="body_pop" v-if="commentList.length">
 				<!-- 评论总数区域 -->
 				<!-- 评论总数区域 -->
 				<view class="pop_title">
 				<view class="pop_title">
-					共25条评论
+					共{{ totalComment }}条评论
 					<img class="pop_icon" src="../../static/index/close3.png" @click="handleClosePop" />
 					<img class="pop_icon" src="../../static/index/close3.png" @click="handleClosePop" />
 				</view>
 				</view>
 
 
 				<!-- 评论列表区域 -->
 				<!-- 评论列表区域 -->
-				<view class="pop_list" v-if="commentList.length">
+				<scroll-view class="pop_list" scroll-y @scrolltolower="handleTolowerComment">
 					<!-- 每一条评论区域 -->
 					<!-- 每一条评论区域 -->
 					<view class="pop_item" v-for="item in commentList" :key="item.id">
 					<view class="pop_item" v-for="item in commentList" :key="item.id">
 						<!-- 用户区域 -->
 						<!-- 用户区域 -->
 						<view class="item_user" @click="handleComment(item)">
 						<view class="item_user" @click="handleComment(item)">
-							<img mode="aspectFill" :src="item.headPhoto" />
+							<img mode="aspectFill" :src="item.image" @click.stop="handleGoMyHome(item.userId)" />
 							<view class="user_info">
 							<view class="user_info">
 								{{ item.userName }}
 								{{ item.userName }}
 							</view>
 							</view>
@@ -147,28 +166,28 @@
 								{{ item.content }}
 								{{ item.content }}
 							</view>
 							</view>
 							<view class="content_bottom">
 							<view class="content_bottom">
-								{{ item.dateTime }}
+								{{ item.date.slice(0, 19) }}
 							</view>
 							</view>
 						</view>
 						</view>
 
 
 						<!-- 二级评论区域 -->
 						<!-- 二级评论区域 -->
 						<view class="item_child">
 						<view class="item_child">
-							<CommentChild v-if="item.commentVoList" :list="item.commentVoList" :commentParentId="info.id" />
+							<CommentChild3 v-if="item.childrens" :list="item.childrens" :commentParentId="tweetId" />
 						</view>
 						</view>
 					</view>
 					</view>
-				</view>
+				</scroll-view>
 			</view>
 			</view>
 
 
 			<!-- 评论输入框区域 -->
 			<!-- 评论输入框区域 -->
-			<view class="body_input">
+			<view class="body_input" v-if="commentList.length">
 				<view class="input_box">
 				<view class="input_box">
-					<input type="text" placeholder="说点什么呢~" @confirm="handleInputPop" />
+					<input type="text" confirm-type="send" placeholder="说点什么呢~" v-model="popInputValue" @confirm="handleInputPop" />
 				</view>
 				</view>
 			</view>
 			</view>
 		</uv-popup>
 		</uv-popup>
 
 
 		<!-- 点击关联民宿弹窗区域 -->
 		<!-- 点击关联民宿弹窗区域 -->
-		<uv-popup ref="popup_bind" bgColor="none" :safeAreaInsetBottom="false">
+		<uv-popup ref="popup_bind" bgColor="none" :safeAreaInsetBottom="false" :closeOnClickOverlay="false">
 			<view class="body_pop">
 			<view class="body_pop">
 				<!-- 评论总数区域 -->
 				<!-- 评论总数区域 -->
 				<view class="pop_title">
 				<view class="pop_title">
@@ -177,21 +196,25 @@
 				</view>
 				</view>
 
 
 				<!-- 关联民宿列表区域 -->
 				<!-- 关联民宿列表区域 -->
-				<view class="pop_list" v-if="bindList.length">
+				<scroll-view class="pop_list" v-if="bindList.length" scroll-y @scrolltolower="handleTolower">
 					<!-- 每一个民宿区域 -->
 					<!-- 每一个民宿区域 -->
-					<view class="pop_item_bind" v-for="item in bindList" :key="item.id">
-						<img mode="aspectFill" :src="item.url" />
+					<view class="pop_item_bind" v-for="item in bindList" :key="item.id" @click="goHotelDetail(item)">
+						<img mode="aspectFill" :src="item.coverImg" />
 						<view class="box_detail">
 						<view class="box_detail">
 							<view class="detail_name">
 							<view class="detail_name">
-								{{ item.hName }}
-								<img class="img" src="../../static/index/like.png" />
-							</view>
-							<view class="detail_leave">
-								{{ item.hName }}
+								{{ item.name }}
+								<img
+									class="img"
+									:src="item.isCollect === 0 ? '../../static/index/like.png' : '../../static/index/like-active.png'"
+									@click.stop="handleLikeHotel(item)"
+								/>
 							</view>
 							</view>
+							<view class="detail_leave" v-if="item.type === 1">银宿级</view>
+							<view class="detail_leave" v-if="item.type === 2">金宿级</view>
+							<view class="detail_leave" v-if="item.type === 3">白金级</view>
 							<view class="detail_num">
 							<view class="detail_num">
-								<view class="num_rate">{{ item.number.toFixed(1) }}分</view>
-								<view class="num_comment">{{ item.number }}条评论</view>
+								<view class="num_rate">{{ item.score.toFixed(1) }}分</view>
+								<view class="num_comment">{{ item.comment }}条评论</view>
 								<view class="num_price">
 								<view class="num_price">
 									¥{{ item.price }}
 									¥{{ item.price }}
 									<text>起</text>
 									<text>起</text>
@@ -199,150 +222,225 @@
 							</view>
 							</view>
 						</view>
 						</view>
 					</view>
 					</view>
-				</view>
+				</scroll-view>
 			</view>
 			</view>
 		</uv-popup>
 		</uv-popup>
 	</view>
 	</view>
 </template>
 </template>
 
 
 <script>
 <script>
-import CommentChild from '@/components/commentChild2.vue'
+import CommentChild3 from '@/components/commentChild3.vue'
 export default {
 export default {
-	components: { CommentChild },
+	components: { CommentChild3 },
 	data() {
 	data() {
 		return {
 		return {
 			// 滚动穿透控制
 			// 滚动穿透控制
 			showPage: false,
 			showPage: false,
-			hotelId: '',
-			startTime: '',
-			endTime: '',
+			// 推文id
+			tweetId: '',
+			// 乡镇id
+			townId: '',
+			// 用户id
+			userId: '',
+			// 推文信息
 			info: null,
 			info: null,
-			commentList: [
-				{
-					id: 1,
-					headPhoto: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1374205869tmp_ec40ba855cc6003b2a47877a654dceaf9fc74230a8e9cf25.jpg',
-					userName: '张三',
-					dateTime: '2023-09-22 16:54:38',
-					content: '策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬',
-					commentVoList: [
-						{
-							id: 11,
-							headPhoto: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1374205869tmp_ec40ba855cc6003b2a47877a654dceaf9fc74230a8e9cf25.jpg',
-							userName: '小王',
-							commentName: '老六',
-							dateTime: '2023-09-22 16:54:38',
-							content: '策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬',
-							commentVoList: [
-								{
-									id: 111,
-									headPhoto: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1374205869tmp_ec40ba855cc6003b2a47877a654dceaf9fc74230a8e9cf25.jpg',
-									userName: '小王',
-									commentName: '老六',
-									dateTime: '2023-09-22 16:54:38',
-									content: '策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬',
-									commentVoList: []
-								}
-							]
-						}
-					]
-				},
-				{
-					id: 2,
-					headPhoto: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/1374205869tmp_ec40ba855cc6003b2a47877a654dceaf9fc74230a8e9cf25.jpg',
-					userName: '李四',
-					dateTime: '2023-09-22 16:54:38',
-					content: '呜呜呜呜呜呜吾问无为谓策划斯哈斯是回家哦啊好啦干哈会离开是尴尬尬',
-					commentVoList: []
-				}
-			],
-			bindList: [
-				{
-					id: 1,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '开心',
-					number: 5,
-					price: 166
-				},
-				{
-					id: 2,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '健康',
-					number: 6,
-					price: 186
-				},
-				{
-					id: 3,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '幸福',
-					number: 9,
-					price: 126
-				},
-				{
-					id: 4,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '开心',
-					number: 5,
-					price: 166
-				},
-				{
-					id: 5,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '健康',
-					number: 6,
-					price: 186
-				},
-				{
-					id: 6,
-					url: 'https://chtech.ncjti.edu.cn/hotelReservation/fileload/download/14479079250812_2.jpg',
-					hName: '幸福',
-					number: 9,
-					price: 126
-				}
-			]
+			// 相关推文列表数组
+			bindTweetList: [],
+			// 弹窗评论列表当前页
+			pageComment: 1,
+			// 弹窗评论列表每页多少条
+			rowsComment: 10,
+			// 弹窗评论列表总条数
+			totalComment: null,
+			// 弹窗评论列表
+			commentList: [],
+			// 弹窗关联民宿列表
+			bindList: [],
+			// 弹窗关联民宿当前页
+			pageBind: 1,
+			// 弹窗关联民宿每页多少条
+			rowsBind: 10,
+			// 弹窗关联民宿总条数
+			totalBind: null,
+			// 一级评论框绑定数值
+			commentsValue: '',
+			// 评论弹窗评论框绑定数值
+			popInputValue: '',
+			// 相关推文当前页
+			pageTweet: 1,
+			// 相关推文每页多少条
+			rowsTweet: 10,
+			// 相关推文总条数
+			totalTweet: null,
+			// video 上下文 videoContext 对象
+			videoContext: null,
+			// 是否是全屏状态
+			isFullScreen: false
 		}
 		}
 	},
 	},
 	onLoad(options) {
 	onLoad(options) {
-		this.hotelId = options.id
-		this.getTimes()
-		this.getHotelInfo()
+		this.userId = uni.getStorageSync('userInfo').id
+		this.tweetId = options.id
+		this.townId = options.townId
+		this.getTweetInfo()
+		this.getBindTweet()
+		uni.$on('getReset', this.getReset)
+	},
+	onReachBottom() {
+		if (this.bindTweetList.length < this.totalTweet) {
+			this.pageTweet++
+			this.getBindTweet()
+		} else {
+			uni.showToast({
+				title: '没有更多数据了',
+				icon: 'none'
+			})
+		}
 	},
 	},
 	methods: {
 	methods: {
-		// 获取民宿信息
-		async getHotelInfo(id) {
+		// 获取推文详细信息
+		async getTweetInfo(id) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryDetail.action',
+				data: {
+					id: id ? id : this.tweetId,
+					userId: this.userId
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.info = res.data
+			}
+		},
+		// 获取相关推文数组
+		async getBindTweet() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlerelatedTweets.action',
+				data: {
+					id: this.tweetId,
+					townId: this.townId,
+					userId: this.userId,
+					page: this.pageTweet,
+					rows: this.rowsTweet
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.bindTweetList = res.data.pageList
+				this.totalTweet = res.data.total
+			}
+		},
+		// 关注或者取消关注请求
+		async handleFollow() {
 			const res = await this.$myRequest({
 			const res = await this.$myRequest({
-				url: '/mhotel/ahpgetHouseByHotelId.action',
+				url: '/mhotel/articlefollowAuthor.action',
 				data: {
 				data: {
-					hotelId: id ? id : this.hotelId,
-					userId: uni.getStorageSync('userInfo').id,
-					queryStartTime: this.startTime,
-					queryEndTime: this.endTime
+					authorId: this.info.userId,
+					userId: this.userId
 				}
 				}
 			})
 			})
 			// console.log(res)
 			// console.log(res)
 			if (res.code === 200) {
 			if (res.code === 200) {
-				this.info = res.data.data
+				this.info.isFollow === 0 ? (this.info.isFollow = 1) : (this.info.isFollow = 0)
 			}
 			}
 		},
 		},
+		// 点击关联民宿爱心图标回调
+		async handleLikeHotel(item) {
+			const res = await this.$myRequest({
+				url: item.isCollect === 0 ? '/mhotel/ahpcollectHotel.action' : '/mhotel/ahpdelCollectHotel.action',
+				data: {
+					hotelId: item.id,
+					userId: this.userId
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				item.isCollect === 0 ? (item.isCollect = 1) : (item.isCollect = 0)
+				this.getTweetInfo()
+			}
+		},
+		// 点击民宿前往民宿详情回调
+		goHotelDetail(item) {
+			this.showPage = false
+			this.$refs.popup_bind.close()
+			uni.navigateTo({
+				url: `/pages/detail/detail?id=${item.id}`
+			})
+		},
 		// 点击轮播图图片回调
 		// 点击轮播图图片回调
 		handleClickSwiper(urls, current) {
 		handleClickSwiper(urls, current) {
-			const temList = urls.map((ele) => ele.url)
 			uni.previewImage({
 			uni.previewImage({
-				urls: temList,
+				urls,
 				current
 				current
 			})
 			})
 		},
 		},
-		handleInput(e) {
-			console.log(e)
-			console.log(999)
+		// 一级评论框确定输入回调
+		async handleInput(e) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlecommentArticle.action',
+				method: 'post',
+				data: {
+					articleId: this.tweetId,
+					parentId: 0,
+					userId: this.userId,
+					content: e.detail.value
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.commentsValue = ''
+				this.getTweetInfo()
+			}
 		},
 		},
 		// 评论弹窗输入框回调
 		// 评论弹窗输入框回调
-		handleInputPop(e) {
-			console.log(e)
+		async handleInputPop(e) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlecommentArticle.action',
+				method: 'post',
+				data: {
+					articleId: this.tweetId,
+					parentId: 0,
+					userId: this.userId,
+					content: e.detail.value
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.popInputValue = ''
+				this.commentList = []
+				this.pageComment = 1
+				this.handleClickCommentReq()
+				this.getTweetInfo()
+			}
 		},
 		},
 		// 点击底部tab评论按钮回调
 		// 点击底部tab评论按钮回调
 		handleClickComment() {
 		handleClickComment() {
-			this.showPage = true
-			this.$refs.popup.open('bottom')
+			if (this.info.comments) {
+				this.commentList = []
+				this.showPage = true
+				this.$refs.popup.open('bottom')
+				this.handleClickCommentReq()
+			} else {
+				uni.showToast({
+					title: '暂无评论',
+					icon: 'none'
+				})
+			}
+		},
+		async handleClickCommentReq() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryCommentList.action',
+				data: {
+					id: this.tweetId,
+					page: this.pageComment,
+					rows: this.rowsComment
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.commentList = [...this.commentList, ...res.data.pageList]
+				this.totalComment = res.data.total
+			}
 		},
 		},
 		// 点击评论弹窗关闭图标回调
 		// 点击评论弹窗关闭图标回调
 		handleClosePop() {
 		handleClosePop() {
@@ -351,30 +449,155 @@ export default {
 		},
 		},
 		// 点击关联民宿查看全部按钮回调
 		// 点击关联民宿查看全部按钮回调
 		handleClickALL() {
 		handleClickALL() {
+			this.bindList = []
 			this.showPage = true
 			this.showPage = true
 			this.$refs.popup_bind.open('bottom')
 			this.$refs.popup_bind.open('bottom')
+			this.handleClickALLReq()
+		},
+		async handleClickALLReq() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlequeryHotelList.action',
+				data: {
+					id: this.tweetId,
+					userId: this.userId,
+					page: this.pageBind,
+					rows: this.rowsBind
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.bindList = [...this.bindList, ...res.data.pageList]
+				this.totalBind = res.data.total
+			}
 		},
 		},
 		// 点击关联民宿弹窗关闭图标回调
 		// 点击关联民宿弹窗关闭图标回调
 		handleClosePopBind() {
 		handleClosePopBind() {
 			this.showPage = false
 			this.showPage = false
 			this.$refs.popup_bind.close()
 			this.$refs.popup_bind.close()
 		},
 		},
-		handleGoPage(url) {
+		handleGoPageLike() {
 			uni.navigateTo({
 			uni.navigateTo({
-				url
+				url: `/pages/likeList/likeList?id=${this.info.id}`
+			})
+		},
+		// 相关推文点击爱心回调
+		async handleClickLike(item) {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlecollectArticle.action',
+				data: {
+					id: item.id,
+					userId: this.userId
+				}
+			})
+			// console.log(res)
+			if (res.code === 200) {
+				item.isCollect === 1 ? ((item.isCollect = 0), (item.collectNum -= 1)) : ((item.isCollect = 1), (item.collectNum += 1))
+			}
+		},
+		// 点击底部点赞按钮回调
+		async clickBtnLike() {
+			const res = await this.$myRequest({
+				url: '/mhotel/articlelikeArticle.action',
+				data: {
+					id: this.tweetId,
+					userId: this.userId
+				}
 			})
 			})
+			// console.log(res)
+			if (res.code === 200) {
+				this.getTweetInfo()
+			}
+		},
+		handleGoBind(item) {
+			this.tweetId = item.id
+			this.townId = item.townId
+			this.bindTweetList = []
+			this.info = null
+			this.getTweetInfo()
+			this.getBindTweet()
 		},
 		},
-		handleComment() {},
-		// 获取今明两天的日期 YYYY-MM-DD
-		getTimes() {
-			// 今天
-			let today = new Date()
-			// 明天
-			let tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000)
-			let late = new Date(today.getTime() + 24 * 60 * 60 * 1000 * 14)
-
-			this.startTime = `${today.getFullYear()}-${(today.getMonth() + 1).toString().padStart(2, 0)}-${today.getDate().toString().padStart(2, 0)}`
-			this.endTime = `${tomorrow.getFullYear()}-${(tomorrow.getMonth() + 1).toString().padStart(2, 0)}-${tomorrow.getDate().toString().padStart(2, 0)}`
+		handleComment(item) {
+			uni.showModal({
+				title: '请输入评论',
+				editable: true,
+				success: async (res) => {
+					if (res.confirm) {
+						const result = res.content
+						if (!res.content) {
+							uni.showToast({
+								title: '评论内容不能为空',
+								icon: 'none',
+								mask: true
+							})
+							setTimeout(() => {
+								this.handleComment()
+							}, 1500)
+						} else {
+							const res = await this.$myRequest({
+								url: '/mhotel/articlecommentArticle.action',
+								method: 'post',
+								data: {
+									articleId: this.tweetId,
+									parentId: item.id,
+									userId: this.userId,
+									content: result
+								}
+							})
+							// console.log(res);
+							if (res.code === 200) {
+								this.getReset()
+							}
+						}
+					}
+				}
+			})
+		},
+		getReset() {
+			this.commentList = []
+			this.pageComment = 1
+			this.handleClickCommentReq()
+		},
+		handleTolower() {
+			if (this.bindList.length < this.totalBind) {
+				this.pageBind++
+				this.handleClickALLReq()
+			} else {
+				uni.showToast({
+					title: '没有更多数据了',
+					icon: 'none'
+				})
+			}
+		},
+		handleTolowerComment() {
+			if (this.commentList.length < this.totalComment) {
+				this.pageComment++
+				this.handleClickCommentReq()
+			} else {
+				uni.showToast({
+					title: '没有更多数据了',
+					icon: 'none'
+				})
+			}
+		},
+		// 进入全屏和退出全屏时触发的回调
+		fullscreenchange(e) {
+			this.isFullScreen = e.detail.fullScreen
+		},
+		// 点击视频控件时触发的回调
+		handleClickVideo(id) {
+			this.videoContext = uni.createVideoContext(id)
+			if (this.isFullScreen) {
+				this.videoContext.pause()
+				this.videoContext.exitFullScreen()
+			} else {
+				this.videoContext.requestFullScreen()
+				this.videoContext.play()
+			}
+		},
+		handleGoMyHome(userId) {
+			uni.navigateTo({
+				url: `/pages/myHome/myHome?userId=${userId}`
+			})
 		}
 		}
 	}
 	}
 }
 }
@@ -382,6 +605,7 @@ export default {
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
 .container {
 .container {
+	padding-bottom: 130rpx;
 	min-height: 100vh;
 	min-height: 100vh;
 	background-color: #fff;
 	background-color: #fff;
 
 
@@ -418,6 +642,7 @@ export default {
 	}
 	}
 
 
 	.swiper {
 	.swiper {
+		width: 100%;
 		height: 495rpx;
 		height: 495rpx;
 
 
 		.swiper_item {
 		.swiper_item {
@@ -567,7 +792,7 @@ export default {
 	}
 	}
 
 
 	.input_box {
 	.input_box {
-		margin: auto;
+		margin: 10rpx auto 0;
 		width: 710rpx;
 		width: 710rpx;
 		height: 66rpx;
 		height: 66rpx;
 		font-size: 24rpx;
 		font-size: 24rpx;
@@ -635,7 +860,6 @@ export default {
 
 
 	.related {
 	.related {
 		margin: auto;
 		margin: auto;
-		padding-bottom: 130rpx;
 		width: 710rpx;
 		width: 710rpx;
 
 
 		.related_title {
 		.related_title {
@@ -654,7 +878,7 @@ export default {
 				width: 335rpx;
 				width: 335rpx;
 				background-color: #f7f7f7;
 				background-color: #f7f7f7;
 
 
-				img {
+				.box_cover {
 					width: 335rpx;
 					width: 335rpx;
 					height: 463rpx;
 					height: 463rpx;
 					border-radius: 10rpx 10rpx 0 0;
 					border-radius: 10rpx 10rpx 0 0;
@@ -713,6 +937,14 @@ export default {
 					border-radius: 42rpx;
 					border-radius: 42rpx;
 					background-color: rgba(0, 0, 0, 0.3);
 					background-color: rgba(0, 0, 0, 0.3);
 				}
 				}
+
+				.box_play {
+					position: absolute;
+					top: 20rpx;
+					right: 20rpx;
+					width: 50rpx;
+					height: 50rpx;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -752,10 +984,9 @@ export default {
 
 
 	.body_pop {
 	.body_pop {
 		position: relative;
 		position: relative;
-		max-height: 955rpx;
+		height: 955rpx;
 		border-radius: 22rpx 22rpx 0 0;
 		border-radius: 22rpx 22rpx 0 0;
 		background-color: #fff;
 		background-color: #fff;
-		overflow-y: auto;
 
 
 		.pop_title {
 		.pop_title {
 			position: fixed;
 			position: fixed;
@@ -779,7 +1010,9 @@ export default {
 		}
 		}
 
 
 		.pop_list {
 		.pop_list {
+			box-sizing: border-box;
 			padding: 110rpx 20rpx 30rpx;
 			padding: 110rpx 20rpx 30rpx;
+			height: 955rpx;
 
 
 			.pop_item {
 			.pop_item {
 				margin-bottom: 10rpx;
 				margin-bottom: 10rpx;

BIN
static/index/dianzan.png


BIN
static/index/down.png


BIN
static/index/look.png


BIN
static/index/msg.png


BIN
static/index/notice.png


BIN
static/index/phone3.png


BIN
static/index/upvote-active.png


BIN
static/index/upvote.png


BIN
static/index/video.png


+ 193 - 0
uni_modules/mp-html/README.md

@@ -0,0 +1,193 @@
+## 为减小组件包的大小,默认组件包中不包含编辑、latex 公式等扩展功能,需要使用扩展功能的请参考下方的 插件扩展 栏的说明
+
+## 功能介绍
+- 全端支持(含 `v3、NVUE`)
+- 支持丰富的标签(包括 `table`、`video`、`svg` 等)
+- 支持丰富的事件效果(自动预览图片、链接处理等)
+- 支持设置占位图(加载中、出错时、预览时)
+- 支持锚点跳转、长按复制等丰富功能
+- 支持大部分 *html* 实体
+- 丰富的插件(关键词搜索、内容编辑、`latex` 公式等)
+- 效率高、容错性强且轻量化
+
+查看 [功能介绍](https://jin-yufeng.gitee.io/mp-html/#/overview/feature) 了解更多
+
+## 使用方法
+- `uni_modules` 方式  
+  1. 点击右上角的 `使用 HBuilder X 导入插件` 按钮直接导入项目或点击 `下载插件 ZIP` 按钮下载插件包并解压到项目的 `uni_modules/mp-html` 目录下  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <!-- 不需要引入,可直接使用 -->
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     export default {
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时在 `HBuilder X` 中右键 `uni_modules/mp-html` 目录选择 `从插件市场更新` 即可  
+
+- 源码方式  
+  1. 从 [github](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 或 [gitee](https://gitee.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 下载源码  
+     插件市场的 **非 uni_modules 版本** 无法更新,不建议从插件市场获取  
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from '@/components/mp-html/mp-html'
+     export default {
+       // HBuilderX 2.5.5+ 可以通过 easycom 自动引入
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+
+- npm 方式  
+  1. 在项目根目录下执行  
+     ```bash
+     npm install mp-html
+     ```
+  2. 在需要使用页面的 `(n)vue` 文件中添加  
+     ```html
+     <mp-html :content="html" />
+     ```
+     ```javascript
+     import mpHtml from 'mp-html/dist/uni-app/components/mp-html/mp-html'
+     export default {
+       // 不可省略
+       components: {
+         mpHtml
+       },
+       data() {
+         return {
+           html: '<div>Hello World!</div>'
+         }
+       }
+     }
+     ```
+  3. 需要更新版本时执行以下命令即可  
+     ```bash
+     npm update mp-html
+     ```
+  
+  使用 *cli* 方式运行的项目,通过 *npm* 方式引入时,需要在 *vue.config.js* 中配置 *transpileDependencies*,详情可见 [#330](https://github.com/jin-yufeng/mp-html/issues/330#issuecomment-913617687)  
+  如果在 **nvue** 中使用还要将 `dist/uni-app/static` 目录下的内容拷贝到项目的 `static` 目录下,否则无法运行  
+
+查看 [快速开始](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart) 了解更多
+
+## 组件属性
+
+| 属性 | 类型 | 默认值 | 说明 |
+|:---:|:---:|:---:|---|
+| container-style | String |  | 容器的样式([2.1.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v210)) |
+| content | String |  | 用于渲染的 html 字符串 |
+| copy-link | Boolean | true | 是否允许外部链接被点击时自动复制 |
+| domain | String |  | 主域名(用于链接拼接) |
+| error-img | String |  | 图片出错时的占位图链接 |
+| lazy-load | Boolean | false | 是否开启图片懒加载 |
+| loading-img | String |  | 图片加载过程中的占位图链接 |
+| pause-video | Boolean | true | 是否在播放一个视频时自动暂停其他视频 |
+| preview-img | Boolean | true | 是否允许图片被点击时自动预览 |
+| scroll-table | Boolean | false | 是否给每个表格添加一个滚动层使其能单独横向滚动 |
+| selectable | Boolean | false | 是否开启文本长按复制 |
+| set-title | Boolean | true | 是否将 title 标签的内容设置到页面标题 |
+| show-img-menu | Boolean | true | 是否允许图片被长按时显示菜单 |
+| tag-style | Object |  | 设置标签的默认样式 |
+| use-anchor | Boolean | false | 是否使用锚点链接 |
+
+查看 [属性](https://jin-yufeng.gitee.io/mp-html/#/basic/prop) 了解更多
+
+## 组件事件
+
+| 名称 | 触发时机 |
+|:---:|---|
+| load | dom 树加载完毕时 |
+| ready | 图片加载完毕时 |
+| error | 发生渲染错误时 |
+| imgtap | 图片被点击时 |
+| linktap | 链接被点击时 |
+| play | 音视频播放时 |
+
+查看 [事件](https://jin-yufeng.gitee.io/mp-html/#/basic/event) 了解更多
+
+## api
+组件实例上提供了一些 `api` 方法可供调用
+
+| 名称 | 作用 |
+|:---:|---|
+| in | 将锚点跳转的范围限定在一个 scroll-view 内 |
+| navigateTo | 锚点跳转 |
+| getText | 获取文本内容 |
+| getRect | 获取富文本内容的位置和大小 |
+| setContent | 设置富文本内容 |
+| imgList | 获取所有图片的数组 |
+| pauseMedia | 暂停播放音视频([2.2.2+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v222)) |
+| setPlaybackRate | 设置音视频播放速率([2.4.0+](https://jin-yufeng.gitee.io/mp-html/#/changelog/changelog#v240)) |
+
+查看 [api](https://jin-yufeng.gitee.io/mp-html/#/advanced/api) 了解更多
+
+## 插件扩展  
+除基本功能外,本组件还提供了丰富的扩展,可按照需要选用
+
+| 名称 | 作用 |
+|:---:|---|
+| audio | 音乐播放器 |
+| editable | 富文本 **编辑**([示例项目](https://mp-html.oss-cn-hangzhou.aliyuncs.com/editable.zip)) |
+| emoji | 解析 emoji |
+| highlight | 代码块高亮显示 |
+| markdown | 渲染 markdown |
+| search | 关键词搜索 |
+| style | 匹配 style 标签中的样式 |
+| txv-video | 使用腾讯视频 |
+| img-cache | 图片缓存 by [@PentaTea](https://github.com/PentaTea) |
+| latex | 渲染 latex 公式 by [@Zeng-J](https://github.com/Zeng-J) |
+
+从插件市场导入的包中 **不含有** 扩展插件,使用插件需通过微信小程序 `富文本插件` 获取或参考以下方法进行打包:  
+1. 获取完整组件包  
+   ```bash
+   npm install mp-html
+   ```
+2. 编辑 `tools/config.js` 中的 `plugins` 项,选择需要的插件  
+3. 生成新的组件包  
+   在 `node_modules/mp-html` 目录下执行  
+   ```bash
+   npm install
+   npm run build:uni-app
+   ```
+4. 拷贝 `dist/uni-app` 中的内容到项目根目录  
+
+查看 [插件](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin) 了解更多
+
+## 关于 nvue
+`nvue` 使用原生渲染,不支持部分 `css` 样式,为实现和 `html` 相同的效果,组件内部通过 `web-view` 进行渲染,性能上差于原生,根据 `weex` 官方建议,`web` 标签仅应用在非常规的降级场景。因此,如果通过原生的方式(如 `richtext`)能够满足需要,则不建议使用本组件,如果有较多的富文本内容,则可以直接使用 `vue` 页面  
+由于渲染方式与其他端不同,有以下限制:  
+1. 不支持 `lazy-load` 属性
+2. 视频不支持全屏播放
+3. 如果在 `flex-direction: row` 的容器中使用,需要给组件设置宽度或设置 `flex: 1` 占满剩余宽度
+
+纯 `nvue` 模式下,[此问题](https://ask.dcloud.net.cn/question/119678) 修复前,不支持通过 `uni_modules` 引入,需要本地引入(将 [dist/uni-app](https://github.com/jin-yufeng/mp-html/tree/master/dist/uni-app) 中的内容拷贝到项目根目录下)  
+
+## 立即体验
+![富文本插件](https://mp-html.oss-cn-hangzhou.aliyuncs.com/qrcode.jpg)
+
+## 问题反馈
+遇到问题时,请先查阅 [常见问题](https://jin-yufeng.gitee.io/mp-html/#/question/faq) 和 [issue](https://github.com/jin-yufeng/mp-html/issues) 中是否已有相同的问题  
+可通过 [issue](https://github.com/jin-yufeng/mp-html/issues/new/choose) 、插件问答或发送邮件到 [mp_html@126.com](mailto:mp_html@126.com) 提问,不建议在评论区提问(不方便回复)  
+提问请严格按照 [issue 模板](https://github.com/jin-yufeng/mp-html/issues/new/choose) ,描述清楚使用环境、`html` 内容或可复现的 `demo` 项目以及复现方式,对于 **描述不清**、**无法复现** 或重复的问题将不予回复  
+
+欢迎加入 `QQ` 交流群:  
+群1(已满):`699734691`  
+群2:`778239129`  
+
+查看 [问题反馈](https://jin-yufeng.gitee.io/mp-html/#/question/feedback) 了解更多

+ 129 - 0
uni_modules/mp-html/changelog.md

@@ -0,0 +1,129 @@
+## v2.4.2(2023-05-14)
+1. `A` `editable` 插件支持修改文字颜色 [详细](https://github.com/jin-yufeng/mp-html/issues/254)
+2. `F` 修复了 `svg` 中有 `style` 不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/505)
+3. `F` 修复了使用旧版编译器可能报错 `Bad attr nodes` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/472)
+4. `F` 修复了 `app` 端可能出现无法读取 `lazyLoad` 的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/513)
+5. `F` 修复了 `editable` 插件在点击换图时未拼接 `domain` 的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/497) by [@TwoKe945](https://github.com/TwoKe945)
+6. `F` 修复了 `latex` 插件部分情况下不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/515) 
+7. `F` 修复了 `editable` 插件点击音视频时其他标签框不消失的问题
+## v2.4.1(2022-12-25)
+1. `F` 修复了没有图片时 `ready` 事件可能不触发的问题
+2. `F` 修复了加载过程中可能出现 `Root label not found` 错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/470)
+3. `F` 修复了 `audio` 插件退出页面可能会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/457)
+4. `F` 修复了 `vue3` 运行到 `app` 在 `HBuilder X 3.6.10` 以上报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/480)
+5. `F` 修复了 `nvue` 端链接中包含 `%22` 时可能无法显示的问题
+6. `F` 修复了 `vue3` 使用 `highlight` 插件可能报错的问题
+## v2.4.0(2022-08-27)
+1. `A` 增加了 [setPlaybackRate](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#setPlaybackRate) 的 `api`,可以设置音视频的播放速率 [详细](https://github.com/jin-yufeng/mp-html/issues/452)
+2. `A` 示例小程序代码开源 [详细](https://github.com/jin-yufeng/mp-html-demo)
+3. `U` 优化 `ready` 事件触发时机,未设置懒加载的情况下基本可以准确触发 [详细](https://github.com/jin-yufeng/mp-html/issues/195)
+4. `U` `highlight` 插件在编辑状态下不进行高亮处理,便于编辑
+5. `F` 修复了 `flex` 布局下图片大小可能不正确的问题
+6. `F` 修复了 `selectable` 属性没有设置 `force` 也可能出现渲染异常的问题
+7. `F` 修复了表格中的图片大小可能不正确的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/448)
+8. `F` 修复了含有合并单元格的表格可能无法设置竖直对齐的问题
+9. `F` 修复了 `editable` 插件在 `scroll-view` 中使用时工具条位置可能不正确的问题
+10. `F` 修复了 `vue3` 使用 [search](advanced/plugin#search) 插件可能导致错误换行的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/449)
+## v2.3.2(2022-08-13)
+1. `A` 增加 [latex](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#latex) 插件,可以渲染数学公式 [详细](https://github.com/jin-yufeng/mp-html/pull/447) by [@Zeng-J](https://github.com/Zeng-J)
+2. `U` 优化根节点下有很多标签的长内容渲染速度
+3. `U` `highlight` 插件适配 `lang-xxx` 格式
+4. `F` 修复了 `table` 标签设置 `border` 属性后可能无法修改边框样式的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/439) by [@zouxingjie](https://github.com/zouxingjie)
+5. `F` 修复了 `editable` 插件输入连续空格无效的问题
+6. `F` 修复了 `vue3` 图片设置 `inline` 会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/438)
+7. `F` 修复了 `vue3` 使用 `table` 可能报错的问题
+## v2.3.1(2022-05-20)
+1. `U` `app` 端支持使用本地图片
+2. `U` 优化了微信小程序 `selectable` 属性在 `ios` 端的处理 [详细](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable)
+3. `F` 修复了 `editable` 插件不在顶部时 `tooltip` 位置可能错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/430)
+4. `F` 修复了 `vue3` 运行到微信小程序可能报错丢失内容的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/414)
+5. `F` 修复了 `vue3` 部分标签可能被错误换行的问题
+6. `F` 修复了 `editable` 插件 `app` 端插入视频无法预览的问题
+## v2.3.0(2022-04-01)
+1. `A` 增加了 `play` 事件,音视频播放时触发,可用于与页面其他音视频进行互斥播放 [详细](basic/event#play)
+2. `U` `show-img-menu` 属性支持控制预览时是否长按弹出菜单
+3. `U` 优化 `wxs` 处理,提高渲染性能 [详细](https://developers.weixin.qq.com/community/develop/article/doc/0006cc2b204740f601bd43fa25a413)  
+4. `U` `video` 标签支持 `object-fit` 属性
+5. `U` 增加支持一些常用实体编码 [详细](https://github.com/jin-yufeng/mp-html/issues/418)
+6. `F` 修复了图片仅设置高度可能不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/410)
+7. `F` 修复了 `video` 标签高度设置为 `auto` 不显示的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/411)
+8. `F` 修复了使用 `grid` 布局时可能样式错误的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/413)
+9. `F` 修复了含有合并单元格的表格部分情况下显示异常的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/417)
+10. `F` 修复了 `editable` 插件连续插入内容时顺序不正确的问题
+11. `F` 修复了 `uni-app` 包 `vue3` 使用 `audio` 插件报错的问题
+12. `F` 修复了 `uni-app` 包 `highlight` 插件使用自定义的 `prism.min.js` 报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/416)
+## v2.2.2(2022-02-26)
+1. `A` 增加了 [pauseMedia](https://jin-yufeng.gitee.io/mp-html/#/advanced/api#pauseMedia) 的 `api`,可用于暂停播放音视频 [详细](https://github.com/jin-yufeng/mp-html/issues/317)
+2. `U` 优化了长内容的加载速度  
+3. `U` 适配 `vue3` [#389](https://github.com/jin-yufeng/mp-html/issues/389)、[#398](https://github.com/jin-yufeng/mp-html/pull/398) by [@zhouhuafei](https://github.com/zhouhuafei)、[#400](https://github.com/jin-yufeng/mp-html/issues/400)
+4. `F` 修复了小程序端图片高度设置为百分比时可能不显示的问题
+5. `F` 修复了 `highlight` 插件部分情况下可能显示不完整的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/403)
+## v2.2.1(2021-12-24)
+1. `A` `editable` 插件增加上下移动标签功能
+2. `U` `editable` 插件支持在文本中间光标处插入内容
+3. `F` 修复了 `nvue` 端设置 `margin` 后可能导致高度不正确的问题
+4. `F` 修复了 `highlight` 插件使用压缩版的 `prism.css` 可能导致背景失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/367)
+5. `F` 修复了编辑状态下使用 `emoji` 插件内容为空时可能报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/371)
+6. `F` 修复了使用 `editable` 插件后将 `selectable` 属性设置为 `force` 不生效的问题
+## v2.2.0(2021-10-12)
+1. `A` 增加 `customElements` 配置项,便于添加自定义功能性标签 [详细](https://github.com/jin-yufeng/mp-html/issues/350)
+2. `A` `editable` 插件增加切换音视频自动播放状态的功能 [详细](https://github.com/jin-yufeng/mp-html/pull/341) by [@leeseett](https://github.com/leeseett)
+3. `A` `editable` 插件删除媒体标签时触发 `remove` 事件,便于删除已上传的文件
+4. `U` `editable` 插件 `insertImg` 方法支持同时插入多张图片 [详细](https://github.com/jin-yufeng/mp-html/issues/342)
+5. `U` `editable` 插入图片和音视频时支持拼接 `domian` 主域名
+6. `F` 修复了内部链接参数中包含 `://` 时被认为是外部链接的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/356)
+7. `F` 修复了部分 `svg` 标签名或属性名大小写不正确时不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/351)
+8. `F` 修复了 `nvue` 页面运行到非 `app` 平台时可能样式错误的问题
+## v2.1.5(2021-08-13)
+1. `A` 增加支持标签的 `dir` 属性
+2. `F` 修复了 `ruby` 标签文字与拼音没有居中对齐的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/325)
+3. `F` 修复了音视频标签内有 `a` 标签时可能无法播放的问题
+4. `F` 修复了 `externStyle` 中的 `class` 名包含下划线或数字时可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+5. `F` 修复了 `h5` 端引入 `externStyle` 可能不生效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/326)
+## v2.1.4(2021-07-14)
+1. `F` 修复了 `rt` 标签无法设置样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/318)
+2. `F` 修复了表格中有单元格同时合并行和列时可能显示不正确的问题
+3. `F` 修复了 `app` 端无法关闭图片长按菜单的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/322)
+4. `F` 修复了 `editable` 插件只能添加图片链接不能修改的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/312) by [@leeseett](https://github.com/leeseett)
+## v2.1.3(2021-06-12)
+1. `A` `editable` 插件增加 `insertTable` 方法
+2. `U` `editable` 插件支持编辑表格中的空白单元格 [详细](https://github.com/jin-yufeng/mp-html/issues/310)
+3. `F` 修复了 `externStyle` 中使用伪类可能失效的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/298)
+4. `F` 修复了多个组件同时使用时 `tag-style` 属性时可能互相影响的问题 [详细](https://github.com/jin-yufeng/mp-html/pull/305) by [@woodguoyu](https://github.com/woodguoyu)
+5. `F` 修复了包含 `linearGradient` 的 `svg` 可能无法显示的问题
+6. `F` 修复了编译到头条小程序时可能报错的问题
+7. `F` 修复了 `nvue` 端不触发 `click` 事件的问题
+8. `F` 修复了 `editable` 插件尾部插入时无法撤销的问题
+9. `F` 修复了 `editable` 插件的 `insertHtml` 方法只能在末尾插入的问题
+10. `F` 修复了 `editable` 插件插入音频不显示的问题
+## v2.1.2(2021-04-24)
+1. `A` 增加了 [img-cache](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#img-cache) 插件,可以在 `app` 端缓存图片 [详细](https://github.com/jin-yufeng/mp-html/issues/292) by [@PentaTea](https://github.com/PentaTea)
+2. `U` 支持通过 `container-style` 属性设置 `white-space` 来保留连续空格和换行符 [详细](https://jin-yufeng.gitee.io/mp-html/#/question/faq#space)
+3. `U` 代码风格符合 [standard](https://standardjs.com) 标准
+4. `U` `editable` 插件编辑状态下支持预览视频 [详细](https://github.com/jin-yufeng/mp-html/issues/286)
+5. `F` 修复了 `svg` 标签内嵌 `svg` 时无法显示的问题
+6. `F` 修复了编译到支付宝和头条小程序时部分区域不可复制的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/291)
+## v2.1.1(2021-04-09)
+1. 修复了对 `p` 标签设置 `tag-style` 可能不生效的问题
+2. 修复了 `svg` 标签中的文本无法显示的问题
+3. 修复了使用 `editable` 插件编辑表格时可能报错的问题
+4. 修复了使用 `highlight` 插件运行到头条小程序时可能没有样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/280)
+5. 修复了使用 `editable` 插件 `editable` 属性为 `false` 时会报错的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/284)
+6. 修复了 `style` 插件连续子选择器失效的问题
+7. 修复了 `editable` 插件无法修改图片和字体大小的问题
+## v2.1.0.2(2021-03-21)
+修复了 `nvue` 端使用可能报错的问题
+## v2.1.0(2021-03-20)
+1. `A` 增加了 [container-style](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#container-style) 属性 [详细](https://gitee.com/jin-yufeng/mp-html/pulls/1)
+2. `A` 增加支持 `strike` 标签
+3. `A` `editable` 插件增加 `placeholder` 属性 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+4. `A` `editable` 插件增加 `insertHtml` 方法 [详细](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#editable)
+5. `U` 外部样式支持标签名选择器 [详细](https://jin-yufeng.gitee.io/mp-html/#/overview/quickstart#setting)
+6. `F` 修复了 `nvue` 端部分情况下可能不显示的问题
+## v2.0.5(2021-03-12)
+1. `U` [linktap](https://jin-yufeng.gitee.io/mp-html/#/basic/event#linktap) 事件增加返回内部文本内容 `innerText` [详细](https://github.com/jin-yufeng/mp-html/issues/271)
+2. `U` [selectable](https://jin-yufeng.gitee.io/mp-html/#/basic/prop#selectable) 属性设置为 `force` 时能够在微信 `iOS` 端生效(文本块会变成 `inline-block`) [详细](https://github.com/jin-yufeng/mp-html/issues/267)
+3. `F` 修复了部分情况下竖向无法滚动的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/182)
+4. `F` 修复了多次修改富文本数据时部分内容可能不显示的问题
+5. `F` 修复了 [腾讯视频](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#txv-video) 插件可能无法播放的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/265)
+6. `F` 修复了 [highlight](https://jin-yufeng.gitee.io/mp-html/#/advanced/plugin#highlight) 插件没有设置高亮语言时没有应用默认样式的问题 [详细](https://github.com/jin-yufeng/mp-html/issues/276) by [@fuzui](https://github.com/fuzui)

+ 498 - 0
uni_modules/mp-html/components/mp-html/mp-html.vue

@@ -0,0 +1,498 @@
+<template>
+  <view id="_root" :class="(selectable?'_select ':'')+'_root'" :style="containerStyle">
+    <slot v-if="!nodes[0]" />
+    <!-- #ifndef APP-PLUS-NVUE -->
+    <node v-else :childs="nodes" :opts="[lazyLoad,loadingImg,errorImg,showImgMenu,selectable]" name="span" />
+    <!-- #endif -->
+    <!-- #ifdef APP-PLUS-NVUE -->
+    <web-view ref="web" src="/uni_modules/mp-html/static/app-plus/mp-html/local.html" :style="'margin-top:-2px;height:' + height + 'px'" @onPostMessage="_onMessage" />
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+/**
+ * mp-html v2.4.2
+ * @description 富文本组件
+ * @tutorial https://github.com/jin-yufeng/mp-html
+ * @property {String} container-style 容器的样式
+ * @property {String} content 用于渲染的 html 字符串
+ * @property {Boolean} copy-link 是否允许外部链接被点击时自动复制
+ * @property {String} domain 主域名,用于拼接链接
+ * @property {String} error-img 图片出错时的占位图链接
+ * @property {Boolean} lazy-load 是否开启图片懒加载
+ * @property {string} loading-img 图片加载过程中的占位图链接
+ * @property {Boolean} pause-video 是否在播放一个视频时自动暂停其他视频
+ * @property {Boolean} preview-img 是否允许图片被点击时自动预览
+ * @property {Boolean} scroll-table 是否给每个表格添加一个滚动层使其能单独横向滚动
+ * @property {Boolean | String} selectable 是否开启长按复制
+ * @property {Boolean} set-title 是否将 title 标签的内容设置到页面标题
+ * @property {Boolean} show-img-menu 是否允许图片被长按时显示菜单
+ * @property {Object} tag-style 标签的默认样式
+ * @property {Boolean | Number} use-anchor 是否使用锚点链接
+ * @event {Function} load dom 结构加载完毕时触发
+ * @event {Function} ready 所有图片加载完毕时触发
+ * @event {Function} imgtap 图片被点击时触发
+ * @event {Function} linktap 链接被点击时触发
+ * @event {Function} play 音视频播放时触发
+ * @event {Function} error 媒体加载出错时触发
+ */
+// #ifndef APP-PLUS-NVUE
+import node from './node/node'
+// #endif
+import Parser from './parser'
+const plugins=[]
+// #ifdef APP-PLUS-NVUE
+const dom = weex.requireModule('dom')
+// #endif
+export default {
+  name: 'mp-html',
+  data () {
+    return {
+      nodes: [],
+      // #ifdef APP-PLUS-NVUE
+      height: 3
+      // #endif
+    }
+  },
+  props: {
+    containerStyle: {
+      type: String,
+      default: ''
+    },
+    content: {
+      type: String,
+      default: ''
+    },
+    copyLink: {
+      type: [Boolean, String],
+      default: true
+    },
+    domain: String,
+    errorImg: {
+      type: String,
+      default: ''
+    },
+    lazyLoad: {
+      type: [Boolean, String],
+      default: false
+    },
+    loadingImg: {
+      type: String,
+      default: ''
+    },
+    pauseVideo: {
+      type: [Boolean, String],
+      default: true
+    },
+    previewImg: {
+      type: [Boolean, String],
+      default: true
+    },
+    scrollTable: [Boolean, String],
+    selectable: [Boolean, String],
+    setTitle: {
+      type: [Boolean, String],
+      default: true
+    },
+    showImgMenu: {
+      type: [Boolean, String],
+      default: true
+    },
+    tagStyle: Object,
+    useAnchor: [Boolean, Number]
+  },
+  // #ifdef VUE3
+  emits: ['load', 'ready', 'imgtap', 'linktap', 'play', 'error'],
+  // #endif
+  // #ifndef APP-PLUS-NVUE
+  components: {
+    node
+  },
+  // #endif
+  watch: {
+    content (content) {
+      this.setContent(content)
+    }
+  },
+  created () {
+    this.plugins = []
+    for (let i = plugins.length; i--;) {
+      this.plugins.push(new plugins[i](this))
+    }
+  },
+  mounted () {
+    if (this.content && !this.nodes.length) {
+      this.setContent(this.content)
+    }
+  },
+  beforeDestroy () {
+    this._hook('onDetached')
+  },
+  methods: {
+    /**
+     * @description 将锚点跳转的范围限定在一个 scroll-view 内
+     * @param {Object} page scroll-view 所在页面的示例
+     * @param {String} selector scroll-view 的选择器
+     * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
+     */
+    in (page, selector, scrollTop) {
+      // #ifndef APP-PLUS-NVUE
+      if (page && selector && scrollTop) {
+        this._in = {
+          page,
+          selector,
+          scrollTop
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 锚点跳转
+     * @param {String} id 要跳转的锚点 id
+     * @param {Number} offset 跳转位置的偏移量
+     * @returns {Promise}
+     */
+    navigateTo (id, offset) {
+      return new Promise((resolve, reject) => {
+        if (!this.useAnchor) {
+          reject(Error('Anchor is disabled'))
+          return
+        }
+        offset = offset || parseInt(this.useAnchor) || 0
+        // #ifdef APP-PLUS-NVUE
+        if (!id) {
+          dom.scrollToElement(this.$refs.web, {
+            offset
+          })
+          resolve()
+        } else {
+          this._navigateTo = {
+            resolve,
+            reject,
+            offset
+          }
+          this.$refs.web.evalJs('uni.postMessage({data:{action:"getOffset",offset:(document.getElementById(' + id + ')||{}).offsetTop}})')
+        }
+        // #endif
+        // #ifndef APP-PLUS-NVUE
+        let deep = ' '
+        // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+        deep = '>>>'
+        // #endif
+        const selector = uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this._in ? this._in.page : this)
+          // #endif
+          .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
+        if (this._in) {
+          selector.select(this._in.selector).scrollOffset()
+            .select(this._in.selector).boundingClientRect()
+        } else {
+          // 获取 scroll-view 的位置和滚动距离
+          selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
+        }
+        selector.exec(res => {
+          if (!res[0]) {
+            reject(Error('Label not found'))
+            return
+          }
+          const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + offset
+          if (this._in) {
+            // scroll-view 跳转
+            this._in.page[this._in.scrollTop] = scrollTop
+          } else {
+            // 页面跳转
+            uni.pageScrollTo({
+              scrollTop,
+              duration: 300
+            })
+          }
+          resolve()
+        })
+        // #endif
+      })
+    },
+
+    /**
+     * @description 获取文本内容
+     * @return {String}
+     */
+    getText (nodes) {
+      let text = '';
+      (function traversal (nodes) {
+        for (let i = 0; i < nodes.length; i++) {
+          const node = nodes[i]
+          if (node.type === 'text') {
+            text += node.text.replace(/&amp;/g, '&')
+          } else if (node.name === 'br') {
+            text += '\n'
+          } else {
+            // 块级标签前后加换行
+            const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
+            if (isBlock && text && text[text.length - 1] !== '\n') {
+              text += '\n'
+            }
+            // 递归获取子节点的文本
+            if (node.children) {
+              traversal(node.children)
+            }
+            if (isBlock && text[text.length - 1] !== '\n') {
+              text += '\n'
+            } else if (node.name === 'td' || node.name === 'th') {
+              text += '\t'
+            }
+          }
+        }
+      })(nodes || this.nodes)
+      return text
+    },
+
+    /**
+     * @description 获取内容大小和位置
+     * @return {Promise}
+     */
+    getRect () {
+      return new Promise((resolve, reject) => {
+        uni.createSelectorQuery()
+          // #ifndef MP-ALIPAY
+          .in(this)
+          // #endif
+          .select('#_root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
+      })
+    },
+
+    /**
+     * @description 暂停播放媒体
+     */
+    pauseMedia () {
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].pause()
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].pause()'
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置媒体播放速率
+     * @param {Number} rate 播放速率
+     */
+    setPlaybackRate (rate) {
+      this.playbackRate = rate
+      for (let i = (this._videos || []).length; i--;) {
+        this._videos[i].playbackRate(rate)
+      }
+      // #ifdef APP-PLUS
+      const command = 'for(var e=document.getElementsByTagName("video"),i=e.length;i--;)e[i].playbackRate=' + rate
+      // #ifndef APP-PLUS-NVUE
+      let page = this.$parent
+      while (!page.$scope) page = page.$parent
+      page.$scope.$getAppWebview().evalJS(command)
+      // #endif
+      // #ifdef APP-PLUS-NVUE
+      this.$refs.web.evalJs(command)
+      // #endif
+      // #endif
+    },
+
+    /**
+     * @description 设置内容
+     * @param {String} content html 内容
+     * @param {Boolean} append 是否在尾部追加
+     */
+    setContent (content, append) {
+      if (!append || !this.imgList) {
+        this.imgList = []
+      }
+      const nodes = new Parser(this).parse(content)
+      // #ifdef APP-PLUS-NVUE
+      if (this._ready) {
+        this._set(nodes, append)
+      }
+      // #endif
+      this.$set(this, 'nodes', append ? (this.nodes || []).concat(nodes) : nodes)
+
+      // #ifndef APP-PLUS-NVUE
+      this._videos = []
+      this.$nextTick(() => {
+        this._hook('onLoad')
+        this.$emit('load')
+      })
+
+      if (this.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
+        // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
+        let height = 0
+        const callback = rect => {
+          if (!rect || !rect.height) rect = {}
+          // 350ms 总高度无变化就触发 ready 事件
+          if (rect.height === height) {
+            this.$emit('ready', rect)
+          } else {
+            height = rect.height
+            setTimeout(() => {
+              this.getRect().then(callback).catch(callback)
+            }, 350)
+          }
+        }
+        this.getRect().then(callback).catch(callback)
+      } else {
+        // 未设置懒加载,等待所有图片加载完毕
+        if (!this.imgList._unloadimgs) {
+          this.getRect().then(rect => {
+            this.$emit('ready', rect)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 调用插件钩子函数
+     */
+    _hook (name) {
+      for (let i = plugins.length; i--;) {
+        if (this.plugins[i][name]) {
+          this.plugins[i][name]()
+        }
+      }
+    },
+
+    // #ifdef APP-PLUS-NVUE
+    /**
+     * @description 设置内容
+     */
+    _set (nodes, append) {
+      this.$refs.web.evalJs('setContent(' + JSON.stringify(nodes).replace(/%22/g, '') + ',' + JSON.stringify([this.containerStyle.replace(/(?:margin|padding)[^;]+/g, ''), this.errorImg, this.loadingImg, this.pauseVideo, this.scrollTable, this.selectable]) + ',' + append + ')')
+    },
+
+    /**
+     * @description 接收到 web-view 消息
+     */
+    _onMessage (e) {
+      const message = e.detail.data[0]
+      switch (message.action) {
+        // web-view 初始化完毕
+        case 'onJSBridgeReady':
+          this._ready = true
+          if (this.nodes) {
+            this._set(this.nodes)
+          }
+          break
+        // 内容 dom 加载完毕
+        case 'onLoad':
+          this.height = message.height
+          this._hook('onLoad')
+          this.$emit('load')
+          break
+        // 所有图片加载完毕
+        case 'onReady':
+          this.getRect().then(res => {
+            this.$emit('ready', res)
+          }).catch(() => {
+            this.$emit('ready', {})
+          })
+          break
+        // 总高度发生变化
+        case 'onHeightChange':
+          this.height = message.height
+          break
+        // 图片点击
+        case 'onImgTap':
+          this.$emit('imgtap', message.attrs)
+          if (this.previewImg) {
+            uni.previewImage({
+              current: parseInt(message.attrs.i),
+              urls: this.imgList
+            })
+          }
+          break
+        // 链接点击
+        case 'onLinkTap': {
+          const href = message.attrs.href
+          this.$emit('linktap', message.attrs)
+          if (href) {
+            // 锚点跳转
+            if (href[0] === '#') {
+              if (this.useAnchor) {
+                dom.scrollToElement(this.$refs.web, {
+                  offset: message.offset
+                })
+              }
+            } else if (href.includes('://')) {
+              // 打开外链
+              if (this.copyLink) {
+                plus.runtime.openWeb(href)
+              }
+            } else {
+              uni.navigateTo({
+                url: href,
+                fail () {
+                  uni.switchTab({
+                    url: href
+                  })
+                }
+              })
+            }
+          }
+          break
+        }
+        case 'onPlay':
+          this.$emit('play')
+          break
+        // 获取到锚点的偏移量
+        case 'getOffset':
+          if (typeof message.offset === 'number') {
+            dom.scrollToElement(this.$refs.web, {
+              offset: message.offset + this._navigateTo.offset
+            })
+            this._navigateTo.resolve()
+          } else {
+            this._navigateTo.reject(Error('Label not found'))
+          }
+          break
+        // 点击
+        case 'onClick':
+          this.$emit('tap')
+          this.$emit('click')
+          break
+        // 出错
+        case 'onError':
+          this.$emit('error', {
+            source: message.source,
+            attrs: message.attrs
+          })
+      }
+    }
+    // #endif
+  }
+}
+</script>
+
+<style>
+/* #ifndef APP-PLUS-NVUE */
+/* 根节点样式 */
+._root {
+  padding: 1px 0;
+  overflow-x: auto;
+  overflow-y: hidden;
+  -webkit-overflow-scrolling: touch;
+}
+
+/* 长按复制 */
+._select {
+  user-select: text;
+}
+/* #endif */
+</style>

+ 576 - 0
uni_modules/mp-html/components/mp-html/node/node.vue

@@ -0,0 +1,576 @@
+<template>
+  <view :id="attrs.id" :class="'_block _'+name+' '+attrs.class" :style="attrs.style">
+    <block v-for="(n, i) in childs" v-bind:key="i">
+      <!-- 图片 -->
+      <!-- 占位图 -->
+      <image v-if="n.name==='img'&&!n.t&&((opts[1]&&!ctrl[i])||ctrl[i]<0)" class="_img" :style="n.attrs.style" :src="ctrl[i]<0?opts[2]:opts[1]" mode="widthFix" />
+      <!-- 显示图片 -->
+      <!-- #ifdef H5 || (APP-PLUS && VUE2) -->
+      <img v-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || (APP-PLUS && VUE2) -->
+      <!-- 表格中的图片,使用 rich-text 防止大小不正确 -->
+      <rich-text v-if="n.name==='img'&&n.t" :style="'display:'+n.t" :nodes="[{attrs:{style:n.attrs.style,src:n.attrs.src},name:'img'}]" :data-i="i" @tap.stop="imgTap" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || APP-PLUS -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;height:1px;'+n.attrs.style" :src="n.attrs.src" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :lazy-load="opts[0]" :webp="n.webp" :show-menu-by-longpress="opts[3]&&!n.attrs.ignore" :image-menu-prevent="!opts[3]||n.attrs.ignore" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- #ifdef APP-PLUS && VUE3 -->
+      <image v-else-if="n.name==='img'" :id="n.attrs.id" :class="'_img '+n.attrs.class" :style="(ctrl[i]===-1?'display:none;':'')+'width:'+(ctrl[i]||1)+'px;'+n.attrs.style" :src="n.attrs.src||(ctrl.load?n.attrs['data-src']:'')" :mode="!n.h?'widthFix':(!n.w?'heightFix':'')" :data-i="i" @load="imgLoad" @error="mediaError" @tap.stop="imgTap" @longpress="imgLongTap" />
+      <!-- #endif -->
+      <!-- 文本 -->
+      <!-- #ifdef MP-WEIXIN -->
+      <text v-else-if="n.text" :user-select="opts[4]=='force'&&isiOS" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <!-- #ifndef MP-WEIXIN || MP-BAIDU || MP-ALIPAY || MP-TOUTIAO -->
+      <text v-else-if="n.text" decode>{{n.text}}</text>
+      <!-- #endif -->
+      <text v-else-if="n.name==='br'">\n</text>
+      <!-- 链接 -->
+      <view v-else-if="n.name==='a'" :id="n.attrs.id" :class="(n.attrs.href?'_a ':'')+n.attrs.class" hover-class="_hover" :style="'display:inline;'+n.attrs.style" :data-i="i" @tap.stop="linkTap">
+        <node name="span" :childs="n.children" :opts="opts" style="display:inherit" />
+      </view>
+      <!-- 视频 -->
+      <!-- #ifdef APP-PLUS -->
+      <view v-else-if="n.html" :id="n.attrs.id" :class="'_video '+n.attrs.class" :style="n.attrs.style" v-html="n.html" @vplay.stop="play" />
+      <!-- #endif -->
+      <!-- #ifndef APP-PLUS -->
+      <video v-else-if="n.name==='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :object-fit="n.attrs['object-fit']" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <!-- #ifdef H5 || APP-PLUS -->
+      <iframe v-else-if="n.name==='iframe'" :style="n.attrs.style" :allowfullscreen="n.attrs.allowfullscreen" :frameborder="n.attrs.frameborder" :src="n.attrs.src" />
+      <embed v-else-if="n.name==='embed'" :style="n.attrs.style" :src="n.attrs.src" />
+      <!-- #endif -->
+      <!-- #ifndef MP-TOUTIAO || ((H5 || APP-PLUS) && VUE3) -->
+      <!-- 音频 -->
+      <audio v-else-if="n.name==='audio'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :src="n.src[ctrl[i]||0]" :data-i="i" @play="play" @error="mediaError" />
+      <!-- #endif -->
+      <view v-else-if="(n.name==='table'&&n.c)||n.name==='li'" :id="n.attrs.id" :class="'_'+n.name+' '+n.attrs.class" :style="n.attrs.style">
+        <node v-if="n.name==='li'" :childs="n.children" :opts="opts" />
+        <view v-else v-for="(tbody, x) in n.children" v-bind:key="x" :class="'_'+tbody.name+' '+tbody.attrs.class" :style="tbody.attrs.style">
+          <node v-if="tbody.name==='td'||tbody.name==='th'" :childs="tbody.children" :opts="opts" />
+          <block v-else v-for="(tr, y) in tbody.children" v-bind:key="y">
+            <view v-if="tr.name==='td'||tr.name==='th'" :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <node :childs="tr.children" :opts="opts" />
+            </view>
+            <view v-else :class="'_'+tr.name+' '+tr.attrs.class" :style="tr.attrs.style">
+              <view v-for="(td, z) in tr.children" v-bind:key="z" :class="'_'+td.name+' '+td.attrs.class" :style="td.attrs.style">
+                <node :childs="td.children" :opts="opts" />
+              </view>
+            </view>
+          </block>
+        </view>
+      </view>
+      
+      <!-- 富文本 -->
+      <!-- #ifdef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c&&!handler.isInline(n.name, n.attrs.style)" :id="n.attrs.id" :style="n.f" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- #ifndef H5 || ((MP-WEIXIN || MP-QQ || APP-PLUS || MP-360) && VUE2) -->
+      <rich-text v-else-if="!n.c" :id="n.attrs.id" :style="'display:inline;'+n.f" :preview="false" :selectable="opts[4]" :user-select="opts[4]" :nodes="[n]" />
+      <!-- #endif -->
+      <!-- 继续递归 -->
+      <view v-else-if="n.c===2" :id="n.attrs.id" :class="'_block _'+n.name+' '+n.attrs.class" :style="n.f+';'+n.attrs.style">
+        <node v-for="(n2, j) in n.children" v-bind:key="j" :style="n2.f" :name="n2.name" :attrs="n2.attrs" :childs="n2.children" :opts="opts" />
+      </view>
+      <node v-else :style="n.f" :name="n.name" :attrs="n.attrs" :childs="n.children" :opts="opts" />
+    </block>
+  </view>
+</template>
+<script module="handler" lang="wxs">
+// 行内标签列表
+var inlineTags = {
+  abbr: true,
+  b: true,
+  big: true,
+  code: true,
+  del: true,
+  em: true,
+  i: true,
+  ins: true,
+  label: true,
+  q: true,
+  small: true,
+  span: true,
+  strong: true,
+  sub: true,
+  sup: true
+}
+/**
+ * @description 判断是否为行内标签
+ */
+module.exports = {
+  isInline: function (tagName, style) {
+    return inlineTags[tagName] || (style || '').indexOf('display:inline') !== -1
+  }
+}
+</script>
+<script>
+
+import node from './node'
+export default {
+  name: 'node',
+  options: {
+    // #ifdef MP-WEIXIN
+    virtualHost: true,
+    // #endif
+    // #ifdef MP-TOUTIAO
+    addGlobalClass: false
+    // #endif
+  },
+  data () {
+    return {
+      ctrl: {},
+      // #ifdef MP-WEIXIN
+      isiOS: uni.getSystemInfoSync().system.includes('iOS')
+      // #endif
+    }
+  },
+  props: {
+    name: String,
+    attrs: {
+      type: Object,
+      default () {
+        return {}
+      }
+    },
+    childs: Array,
+    opts: Array
+  },
+  components: {
+
+    // #ifndef (H5 || APP-PLUS) && VUE3
+    node
+    // #endif
+  },
+  mounted () {
+    this.$nextTick(() => {
+      for (this.root = this.$parent; this.root.$options.name !== 'mp-html'; this.root = this.root.$parent);
+    })
+    // #ifdef H5 || APP-PLUS
+    if (this.opts[0]) {
+      let i
+      for (i = this.childs.length; i--;) {
+        if (this.childs[i].name === 'img') break
+      }
+      if (i !== -1) {
+        this.observer = uni.createIntersectionObserver(this).relativeToViewport({
+          top: 500,
+          bottom: 500
+        })
+        this.observer.observe('._img', res => {
+          if (res.intersectionRatio) {
+            this.$set(this.ctrl, 'load', 1)
+            this.observer.disconnect()
+          }
+        })
+      }
+    }
+    // #endif
+  },
+  beforeDestroy () {
+    // #ifdef H5 || APP-PLUS
+    if (this.observer) {
+      this.observer.disconnect()
+    }
+    // #endif
+  },
+  methods:{
+    // #ifdef MP-WEIXIN
+    toJSON () { return this },
+    // #endif
+    /**
+     * @description 播放视频事件
+     * @param {Event} e
+     */
+    play (e) {
+      this.root.$emit('play')
+      // #ifndef APP-PLUS
+      if (this.root.pauseVideo) {
+        let flag = false
+        const id = e.target.id
+        for (let i = this.root._videos.length; i--;) {
+          if (this.root._videos[i].id === id) {
+            flag = true
+          } else {
+            this.root._videos[i].pause() // 自动暂停其他视频
+          }
+        }
+        // 将自己加入列表
+        if (!flag) {
+          const ctx = uni.createVideoContext(id
+            // #ifndef MP-BAIDU
+            , this
+            // #endif
+          )
+          ctx.id = id
+          if (this.root.playbackRate) {
+            ctx.playbackRate(this.root.playbackRate)
+          }
+          this.root._videos.push(ctx)
+        }
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片点击事件
+     * @param {Event} e
+     */
+    imgTap (e) {
+      const node = this.childs[e.currentTarget.dataset.i]
+      if (node.a) {
+        this.linkTap(node.a)
+        return
+      }
+      if (node.attrs.ignore) return
+      // #ifdef H5 || APP-PLUS
+      node.attrs.src = node.attrs.src || node.attrs['data-src']
+      // #endif
+      this.root.$emit('imgtap', node.attrs)
+      // 自动预览图片
+      if (this.root.previewImg) {
+        uni.previewImage({
+          // #ifdef MP-WEIXIN
+          showmenu: this.root.showImgMenu,
+          // #endif
+          // #ifdef MP-ALIPAY
+          enablesavephoto: this.root.showImgMenu,
+          enableShowPhotoDownload: this.root.showImgMenu,
+          // #endif
+          current: parseInt(node.attrs.i),
+          urls: this.root.imgList
+        })
+      }
+    },
+
+    /**
+     * @description 图片长按
+     */
+    imgLongTap (e) {
+      // #ifdef APP-PLUS
+      const attrs = this.childs[e.currentTarget.dataset.i].attrs
+      if (this.opts[3] && !attrs.ignore) {
+        uni.showActionSheet({
+          itemList: ['保存图片'],
+          success: () => {
+            const save = path => {
+              uni.saveImageToPhotosAlbum({
+                filePath: path,
+                success () {
+                  uni.showToast({
+                    title: '保存成功'
+                  })
+                }
+              })
+            }
+            if (this.root.imgList[attrs.i].startsWith('http')) {
+              uni.downloadFile({
+                url: this.root.imgList[attrs.i],
+                success: res => save(res.tempFilePath)
+              })
+            } else {
+              save(this.root.imgList[attrs.i])
+            }
+          }
+        })
+      }
+      // #endif
+    },
+
+    /**
+     * @description 图片加载完成事件
+     * @param {Event} e
+     */
+    imgLoad (e) {
+      const i = e.currentTarget.dataset.i
+      /* #ifndef H5 || (APP-PLUS && VUE2) */
+      if (!this.childs[i].w) {
+        // 设置原宽度
+        this.$set(this.ctrl, i, e.detail.width)
+      } else /* #endif */ if ((this.opts[1] && !this.ctrl[i]) || this.ctrl[i] === -1) {
+        // 加载完毕,取消加载中占位图
+        this.$set(this.ctrl, i, 1)
+      }
+      this.checkReady()
+    },
+
+    /**
+     * @description 检查是否所有图片加载完毕
+     */
+    checkReady () {
+      if (this.root && !this.root.lazyLoad) {
+        this.root._unloadimgs -= 1
+        if (!this.root._unloadimgs) {
+          setTimeout(() => {
+            this.root.getRect().then(rect => {
+              this.root.$emit('ready', rect)
+            }).catch(() => {
+              this.root.$emit('ready', {})
+            })
+          }, 350)
+        }
+      }
+    },
+
+    /**
+     * @description 链接点击事件
+     * @param {Event} e
+     */
+    linkTap (e) {
+      const node = e.currentTarget ? this.childs[e.currentTarget.dataset.i] : {}
+      const attrs = node.attrs || e
+      const href = attrs.href
+      this.root.$emit('linktap', Object.assign({
+        innerText: this.root.getText(node.children || []) // 链接内的文本内容
+      }, attrs))
+      if (href) {
+        if (href[0] === '#') {
+          // 跳转锚点
+          this.root.navigateTo(href.substring(1)).catch(() => { })
+        } else if (href.split('?')[0].includes('://')) {
+          // 复制外部链接
+          if (this.root.copyLink) {
+            // #ifdef H5
+            window.open(href)
+            // #endif
+            // #ifdef MP
+            uni.setClipboardData({
+              data: href,
+              success: () =>
+                uni.showToast({
+                  title: '链接已复制'
+                })
+            })
+            // #endif
+            // #ifdef APP-PLUS
+            plus.runtime.openWeb(href)
+            // #endif
+          }
+        } else {
+          // 跳转页面
+          uni.navigateTo({
+            url: href,
+            fail () {
+              uni.switchTab({
+                url: href,
+                fail () { }
+              })
+            }
+          })
+        }
+      }
+    },
+
+    /**
+     * @description 错误事件
+     * @param {Event} e
+     */
+    mediaError (e) {
+      const i = e.currentTarget.dataset.i
+      const node = this.childs[i]
+      // 加载其他源
+      if (node.name === 'video' || node.name === 'audio') {
+        let index = (this.ctrl[i] || 0) + 1
+        if (index > node.src.length) {
+          index = 0
+        }
+        if (index < node.src.length) {
+          this.$set(this.ctrl, i, index)
+          return
+        }
+      } else if (node.name === 'img') {
+        // #ifdef H5 && VUE3
+        if (this.opts[0] && !this.ctrl.load) return
+        // #endif
+        // 显示错误占位图
+        if (this.opts[2]) {
+          this.$set(this.ctrl, i, -1)
+        }
+        this.checkReady()
+      }
+      if (this.root) {
+        this.root.$emit('error', {
+          source: node.name,
+          attrs: node.attrs,
+          // #ifndef H5 && VUE3
+          errMsg: e.detail.errMsg
+          // #endif
+        })
+      }
+    }
+  }
+}
+</script>
+<style>
+/* a 标签默认效果 */
+._a {
+  padding: 1.5px 0 1.5px 0;
+  color: #366092;
+  word-break: break-all;
+}
+
+/* a 标签点击态效果 */
+._hover {
+  text-decoration: underline;
+  opacity: 0.7;
+}
+
+/* 图片默认效果 */
+._img {
+  max-width: 100%;
+  -webkit-touch-callout: none;
+}
+
+/* 内部样式 */
+
+._block {
+  display: block;
+}
+
+._b,
+._strong {
+  font-weight: bold;
+}
+
+._code {
+  font-family: monospace;
+}
+
+._del {
+  text-decoration: line-through;
+}
+
+._em,
+._i {
+  font-style: italic;
+}
+
+._h1 {
+  font-size: 2em;
+}
+
+._h2 {
+  font-size: 1.5em;
+}
+
+._h3 {
+  font-size: 1.17em;
+}
+
+._h5 {
+  font-size: 0.83em;
+}
+
+._h6 {
+  font-size: 0.67em;
+}
+
+._h1,
+._h2,
+._h3,
+._h4,
+._h5,
+._h6 {
+  display: block;
+  font-weight: bold;
+}
+
+._image {
+  height: 1px;
+}
+
+._ins {
+  text-decoration: underline;
+}
+
+._li {
+  display: list-item;
+}
+
+._ol {
+  list-style-type: decimal;
+}
+
+._ol,
+._ul {
+  display: block;
+  padding-left: 40px;
+  margin: 1em 0;
+}
+
+._q::before {
+  content: '"';
+}
+
+._q::after {
+  content: '"';
+}
+
+._sub {
+  font-size: smaller;
+  vertical-align: sub;
+}
+
+._sup {
+  font-size: smaller;
+  vertical-align: super;
+}
+
+._thead,
+._tbody,
+._tfoot {
+  display: table-row-group;
+}
+
+._tr {
+  display: table-row;
+}
+
+._td,
+._th {
+  display: table-cell;
+  vertical-align: middle;
+}
+
+._th {
+  font-weight: bold;
+  text-align: center;
+}
+
+._ul {
+  list-style-type: disc;
+}
+
+._ul ._ul {
+  margin: 0;
+  list-style-type: circle;
+}
+
+._ul ._ul ._ul {
+  list-style-type: square;
+}
+
+._abbr,
+._b,
+._code,
+._del,
+._em,
+._i,
+._ins,
+._label,
+._q,
+._span,
+._strong,
+._sub,
+._sup {
+  display: inline;
+}
+
+/* #ifdef APP-PLUS */
+._video {
+  width: 300px;
+  height: 225px;
+}
+/* #endif */
+</style>

File diff suppressed because it is too large
+ 1335 - 0
uni_modules/mp-html/components/mp-html/parser.js


+ 76 - 0
uni_modules/mp-html/package.json

@@ -0,0 +1,76 @@
+{
+    "id": "mp-html",
+    "displayName": "mp-html 富文本组件【全端支持,支持编辑、latex等扩展】",
+    "version": "v2.4.2",
+    "description": "一个强大的富文本组件,高效轻量,功能丰富",
+    "keywords": [
+        "富文本",
+        "编辑器",
+        "html",
+        "rich-text",
+        "editor"
+    ],
+    "repository": "https://github.com/jin-yufeng/mp-html",
+    "dcloudext": {
+        "sale": {
+            "regular": {
+                "price": "0.00"
+            },
+            "sourcecode": {
+                "price": "0.00"
+            }
+        },
+        "contact": {
+            "qq": ""
+        },
+        "declaration": {
+            "ads": "无",
+            "data": "无",
+            "permissions": "无"
+        },
+        "npmurl": "https://www.npmjs.com/package/mp-html",
+        "type": "component-vue"
+    },
+    "uni_modules": {
+        "platforms": {
+            "cloud": {
+                "tcb": "y",
+                "aliyun": "y"
+            },
+            "client": {
+                "App": {
+                    "app-vue": "y",
+                    "app-nvue": "y"
+                },
+                "H5-mobile": {
+                    "Safari": "y",
+                    "Android Browser": "y",
+                    "微信浏览器(Android)": "y",
+                    "QQ浏览器(Android)": "y"
+                },
+                "H5-pc": {
+                    "Chrome": "y",
+                    "IE": "u",
+                    "Edge": "y",
+                    "Firefox": "y",
+                    "Safari": "y"
+                },
+                "小程序": {
+                    "微信": "y",
+                    "阿里": "y",
+                    "百度": "y",
+                    "字节跳动": "y",
+                    "QQ": "y"
+                },
+                "快应用": {
+                    "华为": "y",
+                    "联盟": "y"
+                },
+                "Vue": {
+                    "vue2": "y",
+                    "vue3": "y"
+                }
+            }
+        }
+    }
+}

File diff suppressed because it is too large
+ 1 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/handler.js


File diff suppressed because it is too large
+ 1 - 0
uni_modules/mp-html/static/app-plus/mp-html/js/uni.webview.min.js


File diff suppressed because it is too large
+ 1 - 0
uni_modules/mp-html/static/app-plus/mp-html/local.html


+ 2 - 0
uni_modules/uv-image/changelog.md

@@ -1,3 +1,5 @@
+## 1.0.12(2023-10-11)
+1. 修复懒加载报错:https://gitee.com/climblee/uv-ui/issues/I869JS
 ## 1.0.11(2023-08-31)
 ## 1.0.11(2023-08-31)
 1. 修复设置widthFix时出现显示不全的BUG
 1. 修复设置widthFix时出现显示不全的BUG
 2. 修复抖音等平台在width和height属性改变时出现不显示的BUG
 2. 修复抖音等平台在width和height属性改变时出现不显示的BUG

+ 3 - 1
uni_modules/uv-image/components/uv-image/uv-image.vue

@@ -180,7 +180,9 @@
 		},
 		},
 		mounted() {
 		mounted() {
 			this.show = true;
 			this.show = true;
-			if(this.observeLazyLoad) this.observerFn();
+			this.$nextTick(()=>{
+				if(this.observeLazyLoad) this.observerFn();
+			})
 		},
 		},
 		methods: {
 		methods: {
 			// 点击图片
 			// 点击图片

+ 1 - 1
uni_modules/uv-image/package.json

@@ -1,7 +1,7 @@
 {
 {
   "id": "uv-image",
   "id": "uv-image",
   "displayName": "uv-image 图片 全面兼容vue3+2、app、h5、小程序等多端",
   "displayName": "uv-image 图片 全面兼容vue3+2、app、h5、小程序等多端",
-  "version": "1.0.11",
+  "version": "1.0.12",
   "description": "uv-image 此组件为uni-app的image组件的加强版,在继承了原有功能外,增加observer懒加载功能,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。",
   "description": "uv-image 此组件为uni-app的image组件的加强版,在继承了原有功能外,增加observer懒加载功能,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。",
   "keywords": [
   "keywords": [
     "uv-image",
     "uv-image",

+ 4 - 0
uni_modules/uv-transition/changelog.md

@@ -1,3 +1,7 @@
+## 1.0.8(2023-10-18)
+1. 修复在APP上不能正常显示的BUG
+## 1.0.7(2023-10-12)
+1. 修复部分情况,修改某属性自动关闭的BUG
 ## 1.0.6(2023-07-24)
 ## 1.0.6(2023-07-24)
 1. 优化  nvue模式下增加cellChild参数,是否在list中cell节点下,nvue中cell下建议设置成true
 1. 优化  nvue模式下增加cellChild参数,是否在list中cell节点下,nvue中cell下建议设置成true
 ## 1.0.5(2023-07-02)
 ## 1.0.5(2023-07-02)

+ 5 - 0
uni_modules/uv-transition/components/uv-transition/uv-transition.vue

@@ -210,6 +210,11 @@
 						this.$emit('change', {
 						this.$emit('change', {
 							detail: this.isShow
 							detail: this.isShow
 						})
 						})
+						// #ifdef H5
+						// #ifdef VUE3
+						this.transform = '';
+						// #endif
+						// #endif
 					}, 20);
 					}, 20);
 				})
 				})
 			},
 			},

+ 1 - 1
uni_modules/uv-transition/package.json

@@ -1,7 +1,7 @@
 {
 {
   "id": "uv-transition",
   "id": "uv-transition",
   "displayName": "uv-transition 动画 全面兼容vue3+2、app、h5、小程序等多端",
   "displayName": "uv-transition 动画 全面兼容vue3+2、app、h5、小程序等多端",
-  "version": "1.0.6",
+  "version": "1.0.8",
   "description": "transition 该组件用于组件的动画过渡效果。",
   "description": "transition 该组件用于组件的动画过渡效果。",
   "keywords": [
   "keywords": [
     "uv-transition",
     "uv-transition",

+ 6 - 0
uni_modules/uv-ui-tools/changelog.md

@@ -1,3 +1,9 @@
+## 1.1.19(2023-10-13)
+1. 兼容vue3
+## 1.1.18(2023-10-12)
+1. 1.1.15版本
+## 1.1.17(2023-09-27)
+1. 1.1.14版本发布
 ## 1.1.16(2023-09-15)
 ## 1.1.16(2023-09-15)
 1. 1.1.13版本发布
 1. 1.1.13版本发布
 ## 1.1.15(2023-09-15)
 ## 1.1.15(2023-09-15)

+ 2 - 2
uni_modules/uv-ui-tools/libs/config/config.js

@@ -1,5 +1,5 @@
-// 此版本发布于2023-09-15
-const version = '1.1.13'
+// 此版本发布于2023-10-12
+const version = '1.1.15'
 
 
 // 开发环境才提示,生产环境不会提示
 // 开发环境才提示,生产环境不会提示
 if (process.env.NODE_ENV === 'development') {
 if (process.env.NODE_ENV === 'development') {

+ 13 - 0
uni_modules/uv-ui-tools/libs/mixin/mixin.js

@@ -149,5 +149,18 @@ export default {
 				}
 				}
 			})
 			})
 		}
 		}
+	},
+	// 兼容vue3
+	unmounted() {
+		if (this.parent && test.array(this.parent.children)) {
+			// 组件销毁时,移除父组件中的children数组中对应的实例
+			const childrenList = this.parent.children
+			childrenList.map((child, index) => {
+				// 如果相等,则移除
+				if (child === this) {
+					childrenList.splice(index, 1)
+				}
+			})
+		}
 	}
 	}
 }
 }

+ 1 - 1
uni_modules/uv-ui-tools/package.json

@@ -1,7 +1,7 @@
 {
 {
   "id": "uv-ui-tools",
   "id": "uv-ui-tools",
   "displayName": "uv-ui-tools 工具集 全面兼容vue3+2、app、h5、小程序等多端",
   "displayName": "uv-ui-tools 工具集 全面兼容vue3+2、app、h5、小程序等多端",
-  "version": "1.1.16",
+  "version": "1.1.19",
   "description": "uv-ui-tools,集成工具库,强大的Http请求封装,清晰的文档说明,开箱即用。方便使用,可以全局使用",
   "description": "uv-ui-tools,集成工具库,强大的Http请求封装,清晰的文档说明,开箱即用。方便使用,可以全局使用",
   "keywords": [
   "keywords": [
     "uv-ui-tools,uv-ui组件库,工具集,uvui,uView2.x"
     "uv-ui-tools,uv-ui组件库,工具集,uvui,uView2.x"

+ 1 - 0
util/api.js

@@ -15,6 +15,7 @@ export const myRequest = (options) => {
 				'userId': uni.getStorageSync('userInfo').id
 				'userId': uni.getStorageSync('userInfo').id
 			},
 			},
 			data: options.data || {},
 			data: options.data || {},
+			timeout: 10000,
 			success: (res) => {
 			success: (res) => {
 				if (res.data.code === 200 || res.data.code === 205) {
 				if (res.data.code === 200 || res.data.code === 205) {
 					resolve(res.data)
 					resolve(res.data)