木邻有你前端代码仓库
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.

308 lines
8.4 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
  1. <template>
  2. <view class="activity-calendar">
  3. <!-- 活动列表 -->
  4. <view class="calendar-content">
  5. <view
  6. v-for="(dayData, index) in activityData"
  7. :key="index"
  8. class="day-section"
  9. >
  10. <!-- 日期和日历图标 (在容器外部) -->
  11. <view class="date-header">
  12. <image
  13. src="/subPages/static/活动日历_图标@2x.png"
  14. class="calendar-icon"
  15. ></image>
  16. <text class="date-text">{{ dayData.activityTime }} {{ dayData.dayOfWeek }}</text>
  17. </view>
  18. <!-- 活动列表容器 -->
  19. <view class="activities-container">
  20. <view
  21. v-for="(activity, actIndex) in dayData.activities"
  22. :key="actIndex"
  23. class="activity-item"
  24. @click="viewActivityDetail(activity)"
  25. >
  26. <!-- 活动图片 -->
  27. <image class="activity-image" :src="activity.image" mode="aspectFill"></image>
  28. <!-- 活动信息 -->
  29. <view class="activity-info">
  30. <view class="title-row">
  31. <view class="activity-badge">
  32. <text class="badge-text">{{ activity.score }}</text>
  33. </view>
  34. <text class="activity-title">{{ activity.title }}</text>
  35. </view>
  36. <view class="activity-location">
  37. <uv-icon name="map-fill" size="14" color="#999"></uv-icon>
  38. <text class="location-text">{{ activity.address }}</text>
  39. </view>
  40. <view class="activity-time">
  41. <uv-icon name="calendar" size="14" color="#999"></uv-icon>
  42. <text class="time-text">{{ activity.activityTime }}</text>
  43. </view>
  44. <view class="activity-participants">
  45. <uv-icon name="account-fill" size="14" color="#999"></uv-icon>
  46. <text class="participants-text">{{ activity.numActivity }}/{{ activity.numLimit }}人已报名</text>
  47. </view>
  48. </view>
  49. <!-- 查看详情按钮 -->
  50. <view class="activity-action">
  51. <view class="detail-btn" @click.stop="viewActivityDetail(activity)">
  52. <text class="detail-btn-text">查看详情</text>
  53. </view>
  54. </view>
  55. </view>
  56. </view>
  57. </view>
  58. </view>
  59. </view>
  60. </template>
  61. <script>
  62. export default {
  63. name: 'ActivityCalendar',
  64. data() {
  65. return {
  66. activityData: [],
  67. pageNo: 1,
  68. pageSize: 10,
  69. hasMore: true
  70. }
  71. },
  72. methods: {
  73. viewActivityDetail(activity) {
  74. // 跳转到活动详情页面
  75. uni.navigateTo({
  76. url: `/subPages/index/activityDetail?id=${activity.id}`
  77. });
  78. },
  79. // 处理后端返回的时间格式
  80. formatTime(timeString) {
  81. // 只截取年月日 中间有空格区分年月日和具体时间
  82. const [datePart, timePart] = timeString.split(' ');
  83. return datePart;
  84. },
  85. // 转化为时间格式
  86. changeData(arr, isRefresh) {
  87. if (isRefresh) {
  88. this.activityData = []
  89. }
  90. arr.forEach(item => {
  91. // 先查找是否存在相同日期的数据
  92. const existingDay = this.activityData.find(day =>
  93. day.dayOfWeek === item.dayOfWeek && this.formatTime(day.activityTime) === this.formatTime(item.activityTime)
  94. );
  95. if (existingDay) {
  96. // 如果找到了,添加到现有的activities数组中
  97. existingDay.activities.push(item);
  98. } else {
  99. // 如果没找到,创建新的日期条目
  100. this.activityData.push({
  101. activityTime: this.formatTime(item.activityTime),
  102. dayOfWeek: item.dayOfWeek,
  103. activities: [item]
  104. });
  105. }
  106. });
  107. },
  108. async getActivityData(isRefresh = false) {
  109. if (!this.hasMore) return
  110. const res = await this.$api.activity.queryActivityList({
  111. pageNo: this.pageNo,
  112. pageSize: this.pageSize
  113. })
  114. if (res.result.records.length){
  115. this.changeData(res.result.records, isRefresh)
  116. this.pageNo++
  117. }else {
  118. uni.showToast({
  119. title: '暂无数据',
  120. icon: 'none'
  121. })
  122. this.hasMore = false
  123. }
  124. },
  125. initData() {
  126. this.hasMore = true
  127. // this.activityData = []
  128. this.pageNo = 1
  129. }
  130. },
  131. async onShow() {
  132. this.initData()
  133. await this.getActivityData(true);
  134. },
  135. onReachBottom() {
  136. this.getActivityData();
  137. },
  138. async onPullDownRefresh() {
  139. this.initData()
  140. await this.getActivityData(true);
  141. uni.stopPullDownRefresh()
  142. }
  143. }
  144. </script>
  145. <style lang="scss" scoped>
  146. // @import '@/uni.scss';
  147. .activity-calendar {
  148. background-color: #f5f5f5;
  149. min-height: 100vh;
  150. .calendar-content {
  151. padding: 40rpx 30rpx;
  152. .day-section {
  153. margin-bottom: 60rpx;
  154. &:last-child {
  155. margin-bottom: 0;
  156. }
  157. .date-header {
  158. display: flex;
  159. align-items: center;
  160. margin-bottom: 30rpx;
  161. .calendar-icon {
  162. width: 48rpx;
  163. height: 48rpx;
  164. margin-right: 20rpx;
  165. }
  166. .date-text {
  167. font-size: 32rpx;
  168. font-weight: bold;
  169. color: #000000;
  170. }
  171. }
  172. .activities-container {
  173. .activity-item {
  174. background: #ffffff;
  175. // border-radius: 16rpx;
  176. padding: 24rpx;
  177. margin-bottom: 20rpx;
  178. // box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
  179. display: flex;
  180. align-items: flex-start;
  181. transition: all 0.3s ease;
  182. position: relative;
  183. &:last-child {
  184. margin-bottom: 0;
  185. }
  186. &:active {
  187. transform: scale(0.98);
  188. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.12);
  189. }
  190. .activity-image {
  191. width: 190rpx;
  192. height: 190rpx;
  193. border-radius: 8rpx;
  194. margin-right: 20rpx;
  195. }
  196. .activity-info {
  197. flex: 1;
  198. display: flex;
  199. flex-direction: column;
  200. justify-content: space-between;
  201. .title-row {
  202. display: flex;
  203. align-items: center;
  204. margin-bottom: 10rpx;
  205. .activity-badge {
  206. width: 31px;
  207. height: 20px;
  208. background: #218cdd;
  209. border-radius: 3.5px;
  210. margin-right: 7rpx;
  211. display: flex;
  212. align-items: center;
  213. justify-content: center;
  214. .badge-text {
  215. font-size: 18rpx;
  216. color: #fff;
  217. }
  218. }
  219. }
  220. .activity-title {
  221. font-size: 28rpx;
  222. font-weight: bold;
  223. color: $uni-text-color;
  224. overflow: hidden;
  225. text-overflow: ellipsis;
  226. white-space: nowrap;
  227. }
  228. .activity-location,
  229. .activity-time,
  230. .activity-participants {
  231. display: flex;
  232. align-items: center;
  233. margin-bottom: 6rpx;
  234. .location-text,
  235. .time-text,
  236. .participants-text {
  237. font-size: 24rpx;
  238. color: $uni-text-color-grey;
  239. margin-left: 6rpx;
  240. overflow: hidden;
  241. text-overflow: ellipsis;
  242. white-space: nowrap;
  243. flex: 1;
  244. }
  245. }
  246. }
  247. .activity-action {
  248. position: absolute;
  249. bottom: 20rpx;
  250. right: 20rpx;
  251. .detail-btn {
  252. background: #218CDD;
  253. border-radius: 26rpx;
  254. width: 140rpx;
  255. height: 52rpx;
  256. text-align: center;
  257. line-height: 44rpx;
  258. .detail-btn-text {
  259. font-size: 26rpx;
  260. color: #ffffff;
  261. font-weight: 500;
  262. }
  263. }
  264. .detail-btn:active {
  265. background: #1976C7;
  266. transform: scale(0.95);
  267. }
  268. }
  269. }
  270. }
  271. }
  272. }
  273. }
  274. </style>