图书馆小程序
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.

350 lines
7.3 KiB

5 months ago
1 month ago
1 month ago
5 months ago
1 month ago
4 months ago
1 month ago
4 months ago
5 months ago
1 month ago
4 months ago
4 months ago
1 month ago
5 months ago
1 month ago
5 months ago
4 months ago
1 month ago
5 months ago
1 month ago
5 months ago
1 month ago
5 months ago
1 month ago
5 months ago
1 month ago
1 month ago
4 months ago
1 month ago
3 weeks ago
1 month ago
4 months ago
1 month ago
5 months ago
1 month ago
5 months ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
5 months ago
1 month ago
5 months ago
1 month ago
5 months ago
1 month ago
5 months ago
1 month ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
1 month ago
4 months ago
1 month ago
  1. <template>
  2. <view class="activity-list">
  3. <view class="tab-box">
  4. <view
  5. class="tab-item"
  6. :class="{ active: currentTab === 0 }"
  7. @click="switchTab(0)"
  8. >
  9. 进行中
  10. </view>
  11. <view
  12. class="tab-item"
  13. :class="{ active: currentTab === 1 }"
  14. @click="switchTab(1)"
  15. >
  16. 往期活动
  17. </view>
  18. </view>
  19. <scroll-view
  20. scroll-y
  21. @scrolltolower="onLoadMore"
  22. lower-threshold="150"
  23. class="scroll-view"
  24. >
  25. <view class="activity-item" v-for="(item, index) in displayList" @click="toActivityDetail(item)" :key="index">
  26. <image class="activity-img" :src="item.coverImage" mode="aspectFill"></image>
  27. <!-- 状态小标 -->
  28. <view class="status-tag"
  29. v-if="item.status === '未开始' || item.status === '进行中' || item.status === '已结束'"
  30. :class="[
  31. item.status === '未开始' ? 'tag-wait' : '',
  32. item.status === '进行中' ? 'tag-doing' : '',
  33. item.status === '已结束' ? 'tag-end' : ''
  34. ]"
  35. >
  36. {{item.status}}
  37. </view>
  38. <view class="activity-info">
  39. <view class="activity-info-left">
  40. <view class="title-wrap">
  41. <text class="activity-title">{{ item.title }}</text>
  42. </view>
  43. <view class="time">
  44. <uni-icons class="time-icon" custom-prefix="iconfont" type="icon-shijian" size="15"></uni-icons>
  45. <text>{{ item.startTime }} - {{ item.endTime }}</text>
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. <view class="empty" v-if="displayList.length === 0 && !loading">
  51. <uni-icons custom-prefix="iconfont" type="icon-kongshuju" size="80"></uni-icons>
  52. <text style="margin-top: 20px;">暂无{{ currentTab === 0 ? '进行中的活动' : '往期活动' }}~</text>
  53. </view>
  54. <!-- 底部加载提示 -->
  55. <view class="footer-tip" v-if="displayList.length>0">
  56. <text v-if="loading">加载中...</text>
  57. <text v-else-if="noMore">没有更多数据了</text>
  58. </view>
  59. </scroll-view>
  60. </view>
  61. </template>
  62. <script>
  63. import { FetchActivityInfo } from '@/api/activity';
  64. import config from '@/utils/config';
  65. export default {
  66. data() {
  67. return {
  68. currentTab: 0,
  69. activityList: [],
  70. baseUrl: config.baseUrl,
  71. page: 0,
  72. size: 10,
  73. loading: false,
  74. noMore: false
  75. };
  76. },
  77. computed: {
  78. displayList() {
  79. return this.activityList
  80. }
  81. },
  82. onLoad() {
  83. this.getNewActivityList(false);
  84. },
  85. /** 页面原生下拉刷新,pages.json对应页面开启enablePullDownRefresh */
  86. async onPullDownRefresh() {
  87. if(this.loading){
  88. uni.stopPullDownRefresh()
  89. return
  90. }
  91. this.page = 0;
  92. this.noMore = false;
  93. try{
  94. await this.getNewActivityList(false);
  95. }finally{
  96. uni.stopPullDownRefresh()
  97. }
  98. },
  99. methods: {
  100. switchTab(index) {
  101. this.currentTab = index;
  102. //切换tab重置分页
  103. this.page = 0;
  104. this.activityList = [];
  105. this.noMore = false;
  106. this.getNewActivityList(false);
  107. },
  108. /**
  109. * @param {Boolean} isLoadMore true=上拉加载更多追加 false=刷新重置列表
  110. */
  111. async getNewActivityList(isLoadMore = false){
  112. if(this.loading) return;
  113. this.loading = true;
  114. let statusArr = []
  115. if(this.currentTab === 0){
  116. // 进行中:未开始0、进行中1
  117. statusArr = [0, 1]
  118. }else{
  119. // 往期:已结束2
  120. statusArr = [2]
  121. }
  122. const params = {
  123. page: this.page,
  124. size: this.size,
  125. status: statusArr
  126. }
  127. console.log('params',params)
  128. try {
  129. const res = await FetchActivityInfo(params)
  130. console.log(res)
  131. if (res.code === 200 ) {
  132. const records = res.data.content || []
  133. records.forEach(item => {
  134. if(item.coverImage){
  135. const imgId = encodeURIComponent(item.coverImage);
  136. item.coverImage = `${this.baseUrl}/files/${imgId}`;
  137. }else{
  138. item.coverImage = ''
  139. }
  140. })
  141. if(isLoadMore){
  142. this.activityList.push(...records)
  143. }else{
  144. this.activityList = records
  145. }
  146. // 判断是否没有更多
  147. this.noMore = records.length < this.size
  148. }else{
  149. if(!isLoadMore){
  150. this.activityList = [];
  151. }
  152. }
  153. } catch (e) {
  154. console.error(e)
  155. } finally {
  156. this.loading = false
  157. }
  158. },
  159. //上拉加载更多
  160. onLoadMore(){
  161. if(this.loading || this.noMore) return
  162. this.page = this.page + 1
  163. this.getNewActivityList(true)
  164. },
  165. getBtnText(status) {
  166. switch(status){
  167. case '已结束':
  168. return '活动结束'
  169. case '已取消':
  170. return '活动取消'
  171. case '未开始':
  172. case '进行中':
  173. return '立即参加'
  174. default:
  175. return '立即参加'
  176. }
  177. },
  178. isItemDisabled(item) {
  179. return ['已结束', '已取消'].includes(item.status)
  180. },
  181. toActivityDetail(item) {
  182. uni.navigateTo({
  183. url: "/subpkg/pages/activity-detail/activity-detail?item=" + encodeURIComponent(JSON.stringify(item))
  184. });
  185. }
  186. },
  187. };
  188. </script>
  189. <style lang="scss" scoped>
  190. .activity-list {
  191. padding: 0;
  192. height: 100vh;
  193. box-sizing: border-box;
  194. background-color: #f5f5f5;
  195. display:flex;
  196. flex-direction:column;
  197. }
  198. .tab-box {
  199. display: flex;
  200. background-color: #fff;
  201. margin-bottom: 10px;
  202. position: sticky;
  203. top: 0;
  204. z-index: 99;
  205. }
  206. .tab-item {
  207. flex: 1;
  208. text-align: center;
  209. padding: 10px 0;
  210. font-size: 15px;
  211. color: #333;
  212. position: relative;
  213. }
  214. .tab-item.active {
  215. color: #01a4fe;
  216. font-weight: bold;
  217. }
  218. .tab-item.active::after {
  219. content: '';
  220. position: absolute;
  221. width: 25px;
  222. height: 2px;
  223. background-color: #01a4fe;
  224. bottom: 0;
  225. left: 50%;
  226. transform: translateX(-50%);
  227. border-radius: 2px;
  228. }
  229. .scroll-view {
  230. flex: 1;
  231. height: 0;
  232. padding: 0 12px;
  233. box-sizing: border-box;
  234. }
  235. .empty {
  236. padding: 80rpx 0;
  237. display: flex;
  238. flex-direction: column;
  239. align-items: center;
  240. justify-content: center;
  241. color: #999;
  242. }
  243. .footer-tip{
  244. text-align: center;
  245. padding: 10px 0 20px;
  246. color:#999;
  247. font-size:13px;
  248. }
  249. .activity-item {
  250. position: relative;
  251. background: #fff;
  252. border-radius: 12px;
  253. margin-bottom: 15px;
  254. overflow: hidden;
  255. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  256. .activity-img {
  257. width: 100%;
  258. height: 100px;
  259. object-fit: cover;
  260. }
  261. .status-tag{
  262. position: absolute;
  263. top: 0;
  264. left: 0;
  265. padding: 4px 8px;
  266. border-radius: 12px 0 12px 0;
  267. font-size: 12px;
  268. &.tag-wait{
  269. color: #01a4fe;
  270. background: #e6f7ff;
  271. }
  272. &.tag-doing{
  273. color: #00b42a;
  274. background: #e6ffed;
  275. }
  276. &.tag-end{
  277. color:#868686;
  278. background:#f2f2f2;
  279. }
  280. }
  281. .activity-info {
  282. padding: 15px;
  283. display: flex;
  284. justify-content: space-between;
  285. align-items: center;
  286. .activity-info-left {
  287. flex: 1;
  288. .title-wrap{
  289. display:flex;
  290. justify-content: flex-start;
  291. align-items: flex-start;
  292. gap:5px;
  293. margin-bottom:8px;
  294. }
  295. .activity-title {
  296. flex: 1;
  297. font-size: 16px;
  298. font-weight: bold;
  299. color: #333;
  300. }
  301. .time {
  302. display: flex;
  303. align-items: center;
  304. font-size: 12px;
  305. color: #999;
  306. .time-icon {
  307. margin-right: 4px;
  308. }
  309. }
  310. }
  311. .activity-btn {
  312. background-color: #01a4fe;
  313. font-size: 14px;
  314. border-radius: 30px;
  315. padding: 0 15px;
  316. height: 36px;
  317. line-height: 36px;
  318. &::after{
  319. border:none;
  320. }
  321. }
  322. .disabled-btn {
  323. background-color: #ccc !important;
  324. }
  325. }
  326. }
  327. </style>