act_detail.vue 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. <template>
  2. <view class="container">
  3. <!-- 标题区域 -->
  4. <view class="title">{{ info.theme }}</view>
  5. <!-- 时间区域 -->
  6. <view class="time">时间:{{ dayjs(info.startTime).format('YYYY-MM-DD HH:mm:ss') }} 至 {{ dayjs(info.endTime).format('YYYY-MM-DD HH:mm:ss') }}</view>
  7. <!-- 地址区域 -->
  8. <view class="address">
  9. 地点:{{ info.address }}
  10. <uni-icons type="location" size="20" color="#007AFF"></uni-icons>
  11. </view>
  12. <!-- 咨询方式 -->
  13. <view class="phone">
  14. 咨询方式:
  15. <view class="phone_value" @click="clickPhone(info.phone)">
  16. {{ info.phone }}
  17. </view>
  18. </view>
  19. <!-- 富文本区域 -->
  20. <view class="richtext">
  21. <uv-parse :content="info.themeDetail" :tagStyle="tagStyle"></uv-parse>
  22. </view>
  23. <!-- 参与说明区域 -->
  24. <view class="box">
  25. <view class="box_icon"></view>
  26. <view class="box_title">参与说明</view>
  27. </view>
  28. <view class="desc">
  29. {{ info.describes }}
  30. </view>
  31. <!-- 已报名区域 -->
  32. <view class="box" v-if="info.reportDatas?.length">
  33. <view class="box_icon"></view>
  34. <view class="box_title">已报名({{ info.reportDatas.length }}人)</view>
  35. <view class="box_more" @click="goDetail(1)">
  36. 查看更多&nbsp;
  37. <uni-icons type="right" size="18" color="#007AFF"></uni-icons>
  38. </view>
  39. </view>
  40. <view class="sign" v-if="info.reportDatas?.length">
  41. <!-- 每一个报名人员 -->
  42. <view class="sign_box" v-for="(item, index) in info.reportDatas" :key="index">
  43. <image class="img" src="@/static/images/9.png" mode="aspectFill"></image>
  44. <view class="box_text">{{ item.name }}</view>
  45. </view>
  46. </view>
  47. <!-- 签到人员区域 -->
  48. <view class="box" v-if="info.signinDatas?.length">
  49. <view class="box_icon"></view>
  50. <view class="box_title">签到人员({{ info.signinDatas.length }}人)</view>
  51. <view class="box_more" @click="goDetail(2)">
  52. 查看更多&nbsp;
  53. <uni-icons type="right" size="18" color="#007AFF"></uni-icons>
  54. </view>
  55. </view>
  56. <view class="sign" v-if="info.signinDatas?.length">
  57. <!-- 每一个签到人员 -->
  58. <view class="sign_box" v-for="(item, index) in info.signinDatas" :key="index">
  59. <image class="img" src="@/static/images/9.png" mode="aspectFill"></image>
  60. <view class="box_text">{{ item.name }}</view>
  61. </view>
  62. </view>
  63. <!-- 活动相册区域 -->
  64. <view class="box" v-if="info.isImage == 1 && info.isReport == 1">
  65. <view class="box_icon"></view>
  66. <view class="box_title">活动相册</view>
  67. <view class="box_more" @click="goDetail(3)">
  68. {{ info.images?.length ? '查看更多&nbsp;' : '去上传&nbsp;' }}
  69. <uni-icons type="right" size="18" color="#007AFF"></uni-icons>
  70. </view>
  71. </view>
  72. <view class="album" v-if="info.isImage == 1 && info.images?.length">
  73. <!-- 每一张照片区域 -->
  74. <image class="img" :src="item" mode="aspectFill" v-for="(item, index) in actImgList" :key="item"></image>
  75. </view>
  76. <!-- 按钮区域 -->
  77. <view v-if="info.isReport == 2">
  78. <!-- 未报名时 -->
  79. <view v-if="dayjs(info.signsTime).valueOf() > Date.now()" class="btn nostart">
  80. 报名未开始
  81. <view class="btn_text">{{ dayjs(info.signsTime).format('YYYY-MM-DD HH:mm:ss') }} 开始报名</view>
  82. </view>
  83. <view v-if="dayjs(info.signeTime).valueOf() > Date.now()" class="btn" @click="handleApply_throttle">
  84. 我要报名
  85. <view class="btn_text">{{ dayjs(info.signeTime).format('YYYY-MM-DD HH:mm:ss') }} 报名截止</view>
  86. </view>
  87. <view v-else class="btn off">报名已截止</view>
  88. </view>
  89. <view v-if="info.isReport == 1 && info.isSign == 2">
  90. <!-- 未签到时 -->
  91. <view v-if="dayjs(info.startTime).valueOf() > Date.now()" class="btn nostart">
  92. 活动未开始
  93. <view class="btn_text">{{ dayjs(info.startTime).format('YYYY-MM-DD HH:mm:ss') }} 开始签到</view>
  94. </view>
  95. <view v-if="dayjs(info.endTime).valueOf() > Date.now()" class="btn" @click="handleSign_throttle">
  96. 我要签到
  97. <view class="btn_text">{{ dayjs(info.endTime).format('YYYY-MM-DD HH:mm:ss') }} 签到截止</view>
  98. </view>
  99. <view v-else class="btn off">活动已结束</view>
  100. </view>
  101. <view class="btn off" v-if="info.isReport == 1 && info.isSign == 1">已签到</view>
  102. </view>
  103. </template>
  104. <script setup>
  105. import { onLoad } from '@dcloudio/uni-app'
  106. import { ref } from 'vue'
  107. import { getDetailInfoById, getReportById, getSigninById } from '@/api/index.js'
  108. import dayjs from 'dayjs'
  109. import { calculateDistance } from '@/utils/calculateDistance.js'
  110. import lodash from 'lodash'
  111. // 富文本样式
  112. let tagStyle = {
  113. img: 'height:350rpx'
  114. }
  115. // 详情数据
  116. const info = ref({})
  117. // 活动ID
  118. const currentId = ref()
  119. const lat = ref('')
  120. const lng = ref('')
  121. // 活动相册列表
  122. const actImgList = ref([])
  123. onLoad((options) => {
  124. if (options.id) {
  125. currentId.value = options.id
  126. // 根据ID获取活动数据详情
  127. getData(options.id)
  128. // 获取当前用户经纬度
  129. getAddress()
  130. }
  131. })
  132. // 根据ID获取活动数据详情
  133. const getData = async (id) => {
  134. let data = {
  135. id
  136. }
  137. const res = await getDetailInfoById(data)
  138. // console.log(res)
  139. info.value = res.data
  140. let arr = JSON.parse(JSON.stringify(info.value.images))
  141. actImgList.value = arr.splice(0, 3)
  142. }
  143. // 获取当前用户经纬度
  144. const getAddress = () => {
  145. uni.getLocation({
  146. // type: 'wgs84',
  147. success: (res) => {
  148. lng.value = res.longitude
  149. lat.value = res.latitude
  150. }
  151. })
  152. }
  153. // 点击查看更多回调
  154. const goDetail = (e) => {
  155. // 1为已报名,2为签到人员,3为活动相册
  156. if (e == 1 || e == 2) {
  157. let temList = e == 1 ? info.value.reportDatas : info.value.signinDatas
  158. let list = encodeURIComponent(JSON.stringify(temList))
  159. uni.navigateTo({
  160. url: `/pages/people_detail/people_detail?type=${e}&list=${list}`
  161. })
  162. } else if (e == 3) {
  163. let imgList = encodeURIComponent(JSON.stringify(info.value.images))
  164. uni.navigateTo({
  165. url: `/pages/act_album/act_album?imgList=${imgList}&currentId=${currentId.value}`
  166. })
  167. }
  168. }
  169. // 我要报名按钮回调
  170. const handleApply = () => {
  171. uni.showModal({
  172. title: '提示',
  173. content: '确定报名吗?',
  174. success: async (res) => {
  175. if (res.confirm) {
  176. let data = {
  177. id: currentId.value
  178. }
  179. const res = await getReportById(data)
  180. // console.log(res)
  181. if (res.code == 200) {
  182. uni.showToast({
  183. title: res.message,
  184. icon: 'success',
  185. mask: true
  186. })
  187. setTimeout(() => {
  188. getData(currentId.value)
  189. }, 1500)
  190. }
  191. }
  192. }
  193. })
  194. }
  195. // 节流
  196. const handleApply_throttle = lodash.throttle(handleApply, 1000, {
  197. trailing: false
  198. })
  199. // 我要签到按钮回调
  200. const handleSign = () => {
  201. let rangValue = 500
  202. // 计算出距离
  203. let distance = calculateDistance(info.value.lat, info.value.lng, lat.value, lng.value)
  204. // console.log(distance)
  205. if (rangValue > distance) {
  206. uni.showModal({
  207. title: '提示',
  208. content: '确定签到吗?',
  209. success: async (res) => {
  210. if (res.confirm) {
  211. let data = {
  212. id: currentId.value
  213. }
  214. const res = await getSigninById(data)
  215. // console.log(res)
  216. if (res.code == 200) {
  217. uni.showToast({
  218. title: res.message,
  219. icon: 'success',
  220. mask: true
  221. })
  222. setTimeout(() => {
  223. getData(currentId.value)
  224. }, 1500)
  225. }
  226. }
  227. }
  228. })
  229. } else {
  230. uni.showToast({
  231. title: '超出签到范围,无法签到',
  232. icon: 'none',
  233. mask: true
  234. })
  235. }
  236. }
  237. // 节流
  238. const handleSign_throttle = lodash.throttle(handleSign, 1000, {
  239. trailing: false
  240. })
  241. // 拨打电话回调
  242. const clickPhone = (phone) => {
  243. uni.makePhoneCall({
  244. phoneNumber: phone
  245. })
  246. }
  247. </script>
  248. <style lang="scss" scoped>
  249. .container {
  250. padding: 20rpx 18rpx 150rpx;
  251. margin-bottom: 60rpx;
  252. // min-height: 100vh;
  253. font-size: 28rpx;
  254. .title {
  255. font-size: 32rpx;
  256. font-weight: bold;
  257. }
  258. .time {
  259. margin-top: 15rpx;
  260. font-size: 24rpx;
  261. color: #808080;
  262. }
  263. .address {
  264. margin-top: 15rpx;
  265. line-height: 45rpx;
  266. font-size: 24rpx;
  267. color: #808080;
  268. }
  269. .phone {
  270. display: flex;
  271. margin-top: 15rpx;
  272. line-height: 45rpx;
  273. font-size: 24rpx;
  274. color: #808080;
  275. .phone_value {
  276. color: #007aff;
  277. }
  278. }
  279. .richtext {
  280. margin: 15rpx 0;
  281. }
  282. .box {
  283. display: flex;
  284. align-items: center;
  285. .box_icon {
  286. width: 10rpx;
  287. height: 27rpx;
  288. border-radius: 30rpx;
  289. background-color: #007aff;
  290. }
  291. .box_title {
  292. margin-left: 16rpx;
  293. font-weight: bold;
  294. }
  295. .box_more {
  296. display: flex;
  297. align-items: center;
  298. margin-left: auto;
  299. color: #007aff;
  300. font-size: 24rpx;
  301. }
  302. }
  303. .desc {
  304. margin: 20rpx 0;
  305. line-height: 40rpx;
  306. }
  307. .sign {
  308. display: grid;
  309. grid-template-columns: repeat(6, 1fr);
  310. margin: 20rpx 0;
  311. .sign_box {
  312. display: flex;
  313. flex-direction: column;
  314. justify-content: center;
  315. align-items: center;
  316. height: 120rpx;
  317. .img {
  318. margin-bottom: 5rpx;
  319. width: 80rpx;
  320. height: 80rpx;
  321. border-radius: 50%;
  322. }
  323. .box_text {
  324. flex: 1;
  325. text-align: center;
  326. overflow: hidden;
  327. }
  328. }
  329. }
  330. .album {
  331. display: grid;
  332. grid-template-columns: repeat(3, 1fr);
  333. margin: 20rpx 0 120rpx;
  334. .img {
  335. width: 200rpx;
  336. height: 200rpx;
  337. border-radius: 10rpx;
  338. }
  339. }
  340. .btn {
  341. position: fixed;
  342. left: 50%;
  343. bottom: 40rpx;
  344. transform: translateX(-50%);
  345. display: flex;
  346. flex-direction: column;
  347. justify-content: space-evenly;
  348. align-items: center;
  349. width: 661rpx;
  350. height: 100rpx;
  351. color: #fff;
  352. font-size: 28rpx;
  353. border-radius: 8rpx;
  354. background-color: #007aff;
  355. .btn_text {
  356. font-size: 20rpx;
  357. }
  358. }
  359. .off {
  360. color: #a6a6a6;
  361. background-color: #e5e5e5;
  362. }
  363. .nostart {
  364. color: #fff;
  365. background-color: #007aff;
  366. opacity: 0.3;
  367. }
  368. }
  369. </style>