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

288 lines
5.8 KiB

  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. class="tab-item"
  20. :class="{ active: currentTab === 2 }"
  21. @click="switchTab(2)"
  22. >
  23. 已结束
  24. </view>
  25. </view>
  26. <scroll-view
  27. scroll-y
  28. refresher-enabled
  29. :refresher-triggered="refreshing"
  30. @refresherrefresh="onRefresh"
  31. lower-threshold="100"
  32. class="scroll-view"
  33. >
  34. <view
  35. class="activity-item"
  36. v-for="item in displayList"
  37. :key="item.id"
  38. @click="toActivityDetail(item)"
  39. >
  40. <view class="activity-info">
  41. <text class="title">{{ item.area }}</text>
  42. <view class="item-info">
  43. <text class="label">开始时间</text>
  44. <text class="value">{{ item.startTime }}</text>
  45. </view>
  46. <view class="item-info">
  47. <text class="label">结束时间</text>
  48. <text class="value">{{ item.endTime }}</text>
  49. </view>
  50. <view class="item-info">
  51. <text class="label">座位号</text>
  52. <text class="value">{{ item.seatNumber }}</text>
  53. </view>
  54. <view class="item-info">
  55. <text class="label">状态</text>
  56. <text class="value status-tag" :class="item.statusClass">{{ item.statusText }}</text>
  57. </view>
  58. <view class="btn-box" v-if="item.status === 0">
  59. <button class="activity-btn" type="primary" @click.stop="cancelAppoint(item)">
  60. 取消预约
  61. </button>
  62. </view>
  63. </view>
  64. </view>
  65. <view class="empty-box" v-if="displayList.length === 0">
  66. <uni-icons type="empty" size="80" color="#ccc"></uni-icons>
  67. <text class="empty-text">{{ getEmptyText() }}</text>
  68. </view>
  69. </scroll-view>
  70. </view>
  71. </template>
  72. <script>
  73. export default {
  74. data() {
  75. return {
  76. currentTab: 0,
  77. activityList: [],
  78. refreshing: false
  79. };
  80. },
  81. computed: {
  82. displayList() {
  83. const statusMap = {
  84. 0: [0, '0', '未开始', 'pending'],
  85. 1: [1, '1', '进行中', 'ongoing'],
  86. 2: [2, '2', '已结束', 'ended']
  87. };
  88. const targetStatuses = statusMap[this.currentTab] || [];
  89. return this.activityList.filter(item => {
  90. const itemStatus = String(item.status);
  91. return targetStatuses.some(status => String(status) === itemStatus);
  92. });
  93. }
  94. },
  95. onLoad() {
  96. this.getActivityList();
  97. },
  98. methods: {
  99. switchTab(index) {
  100. this.currentTab = index;
  101. },
  102. getActivityList() {
  103. this.refreshing = true;
  104. setTimeout(() => {
  105. const rawData = [
  106. {id:1,area:'一楼自习区',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:0,statusText:'已预约'},
  107. {id:2,area:'综合阅览一',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:1,statusText:'进行中'},
  108. {id:4,area:'专题阅览室',startTime:'2026-05-21 08:00:00',endTime:'2026-05-21 11:30:00',seatNumber:'8号',status:0,statusText:'已预约'},
  109. ];
  110. this.activityList = rawData.map(item => ({
  111. ...item,
  112. statusClass: `status-${item.status}`
  113. }));
  114. this.refreshing = false;
  115. }, 500);
  116. },
  117. onRefresh() {
  118. this.getActivityList();
  119. },
  120. cancelAppoint(item) {
  121. uni.showModal({
  122. title: '提示',
  123. content: `确定要取消${item.area}的预约吗?`,
  124. success: (res) => {
  125. if (res.confirm) {
  126. uni.showToast({ title: '取消成功', icon: 'success' });
  127. this.getActivityList();
  128. }
  129. }
  130. })
  131. },
  132. toActivityDetail(item) {
  133. uni.navigateTo({
  134. url: "/subpkg/pages/activity-detail/activity-detail?item=" + encodeURIComponent(JSON.stringify(item))
  135. });
  136. },
  137. getEmptyText() {
  138. const textMap = {
  139. 0: '未开始',
  140. 1: '进行中',
  141. 2: '已结束'
  142. }
  143. return `暂无${textMap[this.currentTab]}的预约~`
  144. }
  145. },
  146. };
  147. </script>
  148. <style lang="scss" scoped>
  149. .activity-list {
  150. padding: 0;
  151. height: 100vh;
  152. box-sizing: border-box;
  153. background-color: #f5f5f5;
  154. }
  155. .tab-box {
  156. display: flex;
  157. background-color: #fff;
  158. margin-bottom: 10px;
  159. position: sticky;
  160. top: 0;
  161. z-index: 99;
  162. }
  163. .tab-item {
  164. flex: 1;
  165. text-align: center;
  166. padding: 12px 0;
  167. font-size: 15px;
  168. color: #666;
  169. position: relative;
  170. }
  171. .tab-item.active {
  172. color: #01a4fe;
  173. font-weight: bold;
  174. }
  175. .tab-item.active::after {
  176. content: '';
  177. position: absolute;
  178. width: 30px;
  179. height: 3px;
  180. background-color: #01a4fe;
  181. bottom: 0;
  182. left: 50%;
  183. transform: translateX(-50%);
  184. border-radius: 2px;
  185. }
  186. .scroll-view {
  187. height: calc(100vh - 60px);
  188. padding: 0 12px;
  189. box-sizing: border-box;
  190. }
  191. .empty-box {
  192. height: calc(100vh - 200px);
  193. display: flex;
  194. flex-direction: column;
  195. align-items: center;
  196. justify-content: center;
  197. }
  198. .empty-text {
  199. margin-top: 16px;
  200. font-size: 14px;
  201. color: #999;
  202. }
  203. .activity-item {
  204. background: #fff;
  205. border-radius: 12px;
  206. margin-bottom: 12px;
  207. overflow: hidden;
  208. box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
  209. cursor: pointer;
  210. transition: transform 0.2s;
  211. &:active {
  212. transform: scale(0.98);
  213. }
  214. }
  215. .activity-info {
  216. display: flex;
  217. flex-direction: column;
  218. align-items: flex-start;
  219. padding: 16px;
  220. .title {
  221. font-size: 16px;
  222. font-weight: bold;
  223. color: #222;
  224. margin-bottom: 12px;
  225. display: block;
  226. }
  227. .item-info {
  228. display: flex;
  229. padding: 4px 0;
  230. font-size: 14px;
  231. .label {
  232. color: #666;
  233. width: 72px;
  234. }
  235. .value {
  236. color: #333;
  237. flex: 1;
  238. }
  239. }
  240. }
  241. /* 正确的状态样式 */
  242. .status-tag {
  243. padding: 2px 8px;
  244. border-radius: 4px;
  245. font-size: 12px;
  246. }
  247. .status-tag.status-0 {
  248. color: #01a4fe;
  249. background: #e6f7ff;
  250. }
  251. .status-tag.status-1 {
  252. color: #00b42a;
  253. background: #e6ffed;
  254. }
  255. .status-tag.status-2 {
  256. color: #999;
  257. background: #f5f5f5;
  258. }
  259. .btn-box {
  260. width: 100%;
  261. display: flex;
  262. justify-content: flex-end;
  263. margin-top: 10px;
  264. }
  265. .activity-btn {
  266. background-color: #01a4fe;
  267. font-size: 13px;
  268. border-radius: 6px;
  269. padding: 0 14px;
  270. height: 28px;
  271. line-height: 28px;
  272. }
  273. </style>