国外MOSE官网
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
10 KiB

2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
1 hour ago
2 days ago
  1. <template>
  2. <view class="activity-detail">
  3. <!-- 轮播图 -->
  4. <view class="banner-container">
  5. <swiper class="banner-swiper" height="450rpx" :indicator-dots="true" :autoplay="true" :interval="3000" :duration="500">
  6. <swiper-item v-for="(image, index) in activityData.image.split(',')" :key="index">
  7. <image class="banner-image" :src="image" mode="aspectFill"></image>
  8. </swiper-item>
  9. </swiper>
  10. </view>
  11. <!-- 活动信息 -->
  12. <view class="activity-info">
  13. <!-- 活动标题和标签 -->
  14. <view class="title-section">
  15. <view class="activity-badge">
  16. <text class="badge-text">{{ activityData.score }}</text>
  17. </view>
  18. <text class="activity-title">{{ activityData.title }}</text>
  19. </view>
  20. <!-- 活动详细信息 -->
  21. <view class="info-section">
  22. <view class="info-item">
  23. <uv-icon name="calendar" size="16" color="#666"></uv-icon>
  24. <text class="info-label">活动时间</text>
  25. <text class="info-value">{{ activityData.activityTime }}</text>
  26. </view>
  27. <view class="info-item">
  28. <uv-icon name="clock" size="16" color="#666"></uv-icon>
  29. <text class="info-label">报名时间</text>
  30. <text class="info-value">{{ activityData.startTime }}</text>
  31. </view>
  32. <view class="info-item">
  33. <uv-icon name="account-fill" size="16" color="#666"></uv-icon>
  34. <text class="info-label">联系人</text>
  35. <text class="info-value">{{ activityData.contact }}</text>
  36. </view>
  37. <view class="info-item">
  38. <uv-icon name="phone" size="16" color="#666"></uv-icon>
  39. <text class="info-label">取消规则</text>
  40. <text class="info-value">{{ activityData.rule }}</text>
  41. </view>
  42. <view class="info-item">
  43. <uv-icon name="map-fill" size="16" color="#666"></uv-icon>
  44. <text class="info-label">活动地点</text>
  45. <text class="info-value">{{ activityData.address }}</text>
  46. </view>
  47. </view>
  48. <!-- 活动详情 -->
  49. <view class="detail-section">
  50. <view class="section-title">
  51. <text class="title-text">活动详情</text>
  52. </view>
  53. <view class="detail-content">
  54. <rich-text :nodes="activityData.details"></rich-text>
  55. </view>
  56. </view>
  57. <!-- 活动图集 -->
  58. <view class="gallery-section">
  59. <view class="section-title">
  60. <text class="title-text">活动图集</text>
  61. </view>
  62. <view class="gallery-grid">
  63. <image
  64. v-for="(image, index) in activityData.atlas.split(',')"
  65. :key="index"
  66. class="gallery-image"
  67. :src="image"
  68. mode="aspectFill"
  69. @click="previewImage(image, activityData.atlas.split(','))"
  70. ></image>
  71. </view>
  72. </view>
  73. </view>
  74. <!-- 固定底部操作栏 -->
  75. <view class="bottom-action">
  76. <view class="action-left">
  77. <view class="action-item" @click="shareActivity">
  78. <uv-icon name="share" size="24" color="#000"></uv-icon>
  79. <text class="action-text">分享</text>
  80. </view>
  81. <view class="action-item" @click="collectActivity">
  82. <uv-icon name="heart-fill" size="24" :color="activityData.isCollection === 1 ? '#ff4757' : '#999'"></uv-icon>
  83. <text class="action-text">收藏</text>
  84. </view>
  85. <view class="action-item">
  86. <text class="participants-count">
  87. <text :style="{'color': activityData.numActivity >= activityData.numLimit ? '#999' : '#1488DB'}">{{ activityData.numActivity }}</text>
  88. /{{ activityData.numLimit }}</text>
  89. <text class="action-text">已报名</text>
  90. </view>
  91. </view>
  92. <view class="action-right">
  93. <!-- 未签到状态 -->
  94. <uv-button
  95. v-if="status === 'unsigned'"
  96. type="primary"
  97. size="normal"
  98. text="扫码签到"
  99. shape="circle"
  100. @click="scanQRCode"
  101. ></uv-button>
  102. <!-- 已签到状态 -->
  103. <uv-button
  104. v-else-if="status === 'signed'"
  105. type="success"
  106. size="normal"
  107. text="已签到"
  108. shape="circle"
  109. :disabled="true"
  110. ></uv-button>
  111. <!-- 系统取消状态 -->
  112. <uv-button
  113. v-else-if="status === 'cancelled'"
  114. type="error"
  115. size="normal"
  116. text="系统取消"
  117. shape="circle"
  118. :disabled="true"
  119. ></uv-button>
  120. </view>
  121. </view>
  122. </view>
  123. </template>
  124. <script>
  125. export default {
  126. data() {
  127. return {
  128. status: 'unsigned', // unsigned: 未签到, signed: 已签到, cancelled: 系统取消
  129. activityData: {
  130. title: '关爱自闭症儿童活动',
  131. score: '30积分',
  132. activityTime: '2025-06-12 14:30',
  133. startTime: '2025-06-01 14:30——2025-09-01 14:30',
  134. contact: '柳老师 (13256484512)',
  135. rule: '报名随时可取消',
  136. address: '长沙市雨花区时代阳光大夏国际大厅2145',
  137. numActivity: 9,
  138. numLimit: 30,
  139. details: '身体健康,热爱志愿服务工作,富有责任感和奉献精神',
  140. image: '/static/bannerImage.png,/static/bannerImage.png,/static/bannerImage.png',
  141. atlas: '/static/bannerImage.png,/static/bannerImage.png,/static/bannerImage.png,/static/bannerImage.png',
  142. isCollection: 0
  143. },
  144. activityId: null
  145. }
  146. },
  147. onLoad(options) {
  148. if (options.id) {
  149. this.activityId = options.id
  150. this.loadActivityDetail(options.id)
  151. } else {
  152. uni.showToast({
  153. title: '没有给活动id',
  154. icon: 'none'
  155. })
  156. }
  157. if (options.status) {
  158. this.status = options.status
  159. }
  160. },
  161. methods: {
  162. async loadActivityDetail(id) {
  163. // 根据ID加载活动详情
  164. const res = await this.$api.activity.queryActivityById({
  165. activityId: id
  166. })
  167. this.activityData = res.result
  168. },
  169. previewImage(current, urls) {
  170. uni.previewImage({
  171. current: current,
  172. urls: urls
  173. })
  174. },
  175. shareActivity() {
  176. uni.showToast({
  177. title: '分享功能',
  178. icon: 'none'
  179. })
  180. },
  181. async collectActivity() {
  182. const res = await this.$api.activity.collectionActivity({
  183. activityId: this.activityId
  184. })
  185. await this.loadActivityDetail(this.activityId)
  186. uni.showToast({
  187. title: `${res.message}`,
  188. icon: 'none'
  189. })
  190. },
  191. scanQRCode() {
  192. // 扫码签到功能
  193. uni.scanCode({
  194. success: (res) => {
  195. console.log('扫码结果:', res)
  196. // 这里可以调用签到API
  197. this.status = 'signed'
  198. uni.showToast({
  199. title: '签到成功',
  200. icon: 'success'
  201. })
  202. },
  203. fail: (err) => {
  204. console.log('扫码失败:', err)
  205. uni.showToast({
  206. title: '扫码失败',
  207. icon: 'none'
  208. })
  209. }
  210. })
  211. }
  212. }
  213. }
  214. </script>
  215. <style lang="scss" scoped>
  216. .activity-detail {
  217. min-height: 100vh;
  218. background: #f8f8f8;
  219. padding-bottom: 120rpx;
  220. .banner-container {
  221. width: 100%;
  222. height: 450rpx;
  223. .banner-swiper {
  224. width: 100%;
  225. height: 100%;
  226. .banner-image {
  227. width: 100%;
  228. height: 100%;
  229. }
  230. }
  231. }
  232. .activity-info {
  233. background: #ffffff;
  234. margin: 20rpx;
  235. border-radius: 16rpx;
  236. padding: 30rpx;
  237. .title-section {
  238. display: flex;
  239. align-items: center;
  240. margin-bottom: 30rpx;
  241. .activity-badge {
  242. background: #218CDD;
  243. border-radius: 8rpx;
  244. padding: 4rpx 10rpx;
  245. margin-right: 16rpx;
  246. .badge-text {
  247. color: #ffffff;
  248. font-size: 24rpx;
  249. font-weight: 500;
  250. }
  251. }
  252. .activity-title {
  253. font-size: 36rpx;
  254. font-weight: bold;
  255. color: #333333;
  256. flex: 1;
  257. }
  258. }
  259. .info-section {
  260. background: #F3F7F8;
  261. margin-bottom: 40rpx;
  262. border: 2rpx dashed #F3F7F8;
  263. .info-item {
  264. display: flex;
  265. align-items: center;
  266. margin-bottom: 20rpx;
  267. &:last-child {
  268. margin-bottom: 0;
  269. }
  270. .info-label {
  271. font-size: 28rpx;
  272. color: #999999;
  273. margin-left: 12rpx;
  274. margin-right: 8rpx;
  275. }
  276. .info-value {
  277. font-size: 28rpx;
  278. color: #999999;
  279. flex: 1;
  280. }
  281. }
  282. }
  283. .detail-section {
  284. margin-bottom: 40rpx;
  285. .section-title {
  286. margin-bottom: 20rpx;
  287. .title-text {
  288. font-size: 32rpx;
  289. font-weight: bold;
  290. color: #333333;
  291. }
  292. }
  293. .detail-content {
  294. .detail-text {
  295. display: block;
  296. font-size: 28rpx;
  297. color: #666666;
  298. line-height: 1.6;
  299. margin-bottom: 16rpx;
  300. &:last-child {
  301. margin-bottom: 0;
  302. }
  303. }
  304. }
  305. }
  306. .gallery-section {
  307. .section-title {
  308. margin-bottom: 20rpx;
  309. .title-text {
  310. font-size: 32rpx;
  311. font-weight: bold;
  312. color: #333333;
  313. }
  314. }
  315. .gallery-grid {
  316. display: grid;
  317. grid-template-columns: repeat(2, 1fr);
  318. gap: 16rpx;
  319. .gallery-image {
  320. width: 100%;
  321. height: 200rpx;
  322. border-radius: 12rpx;
  323. }
  324. }
  325. }
  326. }
  327. .bottom-action {
  328. position: fixed;
  329. bottom: 0;
  330. left: 0;
  331. right: 0;
  332. background: #ffffff;
  333. padding: 20rpx 30rpx;
  334. border-top: 1rpx solid #eeeeee;
  335. display: flex;
  336. align-items: center;
  337. justify-content: space-between;
  338. z-index: 100;
  339. .action-left {
  340. display: flex;
  341. align-items: center;
  342. gap: 100rpx;
  343. .action-item {
  344. display: flex;
  345. flex-direction: column;
  346. align-items: center;
  347. gap: 8rpx;
  348. .action-text {
  349. font-size: 22rpx;
  350. color: #000;
  351. }
  352. .participants-count {
  353. font-size: 24rpx;
  354. color: #333333;
  355. }
  356. }
  357. }
  358. .action-right {
  359. flex-shrink: 0;
  360. }
  361. }
  362. }
  363. </style>