favorites.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <template>
  2. <view class="favorites-page">
  3. <!-- 列表 -->
  4. <view class="fav-list">
  5. <uv-swipe-action>
  6. <uv-swipe-action-item v-for="(item, idx) in list" :key="idx" :options="[{
  7. text: '取消收藏',
  8. style: {
  9. backgroundColor: '#f56c6c'
  10. }
  11. }]" @click="handleOption('cancelCollection', idx)">
  12. <view class="fav-card">
  13. <image @click="goPage('/pages/crowdFunding/crowdfundingDetails?id=' + item.id)" :src="item.main_image"
  14. class="fav-img"></image>
  15. <view class="fav-content">
  16. <view class="fav-header">
  17. <image :src="item.creator_avatar" class="avatar"></image>
  18. <text class="nickname" @click="goPage('/pages/crowdFunding/crowdfundingDetails?id=' + item.id)">{{
  19. item.creator_username }}</text>
  20. <view class="tag" @click="goPage('/pages/crowdFunding/crowdfundingDetails?id=' + item.id)">
  21. <image src="@/static/crowdFunding/authentication.png" mode="widthFix"></image> 发起人
  22. </view>
  23. <view style="position: relative;left: 0;top: 0;">
  24. <!-- <image src="/static/crowdFunding/more.png" class="more-img" @click="toggleDropdown(idx)"></image>
  25. <view class="dropdown-menu" v-if="currentDropdownIndex === idx">
  26. <view class="dropdown-item" @tap="handleOption('cancelCollection', idx)">取消收藏</view>
  27. </view> -->
  28. </view>
  29. </view>
  30. <view class="fav-title two-omit" @click="goPage('/pages/crowdFunding/crowdfundingDetails?id=' + item.id)">
  31. {{ item.title }}</view>
  32. <view class="fav-bottom">
  33. <text class="amount">已筹 ¥{{ item.current_amount }}</text>
  34. <!-- <text class="favorite-time">收藏于{{ item.favorite_time }}</text> -->
  35. </view>
  36. </view>
  37. </view>
  38. </uv-swipe-action-item>
  39. </uv-swipe-action>
  40. </view>
  41. <view v-if="!isLoading && list.length === 0" class="no-data">
  42. <text>暂无数据</text>
  43. </view>
  44. </view>
  45. </template>
  46. <script>
  47. export default {
  48. data() {
  49. return {
  50. list: [],
  51. page: 1,
  52. pageSize: 20,
  53. total: 0,
  54. isLoading: false,
  55. hasMore: true,
  56. currentDropdownIndex: null,
  57. show1: false,
  58. };
  59. },
  60. onLoad() {
  61. this.page = 1;
  62. this.list = [];
  63. this.hasMore = true;
  64. this.getList();
  65. },
  66. onPullDownRefresh() {
  67. this.page = 1;
  68. this.list = [];
  69. this.hasMore = true;
  70. this.getList(() => uni.stopPullDownRefresh());
  71. },
  72. onReachBottom() {
  73. if (this.hasMore && !this.isLoading) {
  74. this.getList();
  75. }
  76. },
  77. methods: {
  78. getList(cb) {
  79. if (this.isLoading) return;
  80. this.isLoading = true;
  81. uni.request({
  82. url: this.$apiHost + '/crowdfund/favorites',
  83. method: 'GET',
  84. data: {
  85. page: this.page,
  86. pageSize: this.pageSize,
  87. uuid: getApp().globalData.uuid,
  88. skey: getApp().globalData.skey,
  89. },
  90. success: (res) => {
  91. if (res.data && res.data.success === 'yes' && res.data.data) {
  92. var { list, total } = res.data.data;
  93. if (!Array.isArray(list)) {
  94. list = [];
  95. }
  96. if (this.page === 1) {
  97. this.list = list;
  98. } else {
  99. this.list = [...this.list, ...list];
  100. }
  101. this.total = total;
  102. this.hasMore = this.list && this.list.length < total;
  103. if (this.hasMore) this.page++;
  104. }
  105. },
  106. complete: () => {
  107. this.isLoading = false;
  108. cb && cb();
  109. }
  110. });
  111. },
  112. goBack() {
  113. uni.navigateBack();
  114. },
  115. toggleDropdown(idx) {
  116. this.currentDropdownIndex = this.currentDropdownIndex === idx ? null : idx;
  117. },
  118. goPage(url) {
  119. console.log(url, 888);
  120. uni.navigateTo({
  121. url,
  122. });
  123. },
  124. // 处理下拉菜单选项点击
  125. handleOption(type, idx) {
  126. this.currentDropdownIndex = null;
  127. if (type === "cancelCollection") {
  128. const item = this.list[idx];
  129. uni.request({
  130. url: this.$apiHost + '/crowdfund/favorite',
  131. method: 'POST',
  132. header: {
  133. 'content-type': 'application/x-www-form-urlencoded',
  134. },
  135. data: {
  136. crowdfund_id: item.id,
  137. action: 'remove',
  138. uuid: getApp().globalData.uuid,
  139. skey: getApp().globalData.skey,
  140. },
  141. success: (res) => {
  142. if (res.data && res.data.success && res.data.success === 'yes') {
  143. this.list.splice(idx, 1);
  144. uni.showToast({
  145. title: '取消收藏成功',
  146. icon: 'none',
  147. duration: 2000
  148. });
  149. this.show1 = !this.show1;
  150. } else {
  151. uni.showToast({
  152. title: res.data.msg || '取消失败',
  153. icon: 'none',
  154. duration: 2000
  155. });
  156. }
  157. },
  158. fail: () => {
  159. uni.showToast({
  160. title: '网络错误',
  161. icon: 'none',
  162. duration: 2000
  163. });
  164. }
  165. });
  166. }
  167. },
  168. },
  169. };
  170. </script>
  171. <style lang="scss" scoped>
  172. .favorites-page {
  173. min-height: 100vh;
  174. background: #f2f6f2;
  175. .fav-list {
  176. padding: 24rpx 0;
  177. .fav-card {
  178. display: flex;
  179. background: #fff;
  180. // border-radius: 18rpx;
  181. box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
  182. padding: 20rpx;
  183. .fav-img {
  184. width: 140rpx;
  185. height: 140rpx;
  186. border-radius: 12rpx;
  187. object-fit: cover;
  188. flex-shrink: 0;
  189. }
  190. .fav-content {
  191. flex: 1;
  192. margin-left: 20rpx;
  193. display: flex;
  194. flex-direction: column;
  195. justify-content: space-between;
  196. .fav-header {
  197. display: flex;
  198. align-items: center;
  199. .avatar {
  200. width: 44rpx;
  201. height: 44rpx;
  202. border-radius: 50%;
  203. margin-right: 12rpx;
  204. }
  205. .nickname {
  206. font-weight: 400;
  207. font-size: 24rpx;
  208. color: #1f1f1f;
  209. font-family: "PingFang SC-Bold";
  210. max-width: 250rpx;
  211. margin-right: 12rpx;
  212. }
  213. .tag {
  214. font-size: 20rpx;
  215. color: #acf934;
  216. background: #1f1f1f;
  217. border-radius: 8rpx;
  218. padding: 2rpx 12rpx;
  219. margin-right: auto;
  220. margin-left: 4rpx;
  221. display: inline-flex;
  222. align-items: center;
  223. image {
  224. width: 28rpx;
  225. height: 28rpx;
  226. }
  227. }
  228. .more-img {
  229. width: 36rpx;
  230. height: 36rpx;
  231. margin-left: 12rpx;
  232. }
  233. }
  234. .fav-title {
  235. font-size: 26rpx;
  236. color: #222;
  237. font-weight: 500;
  238. margin: 10rpx 0 0 0;
  239. overflow: hidden;
  240. text-overflow: ellipsis;
  241. width: 100%;
  242. }
  243. .fav-bottom {
  244. margin-top: 10rpx;
  245. display: flex;
  246. justify-content: flex-end;
  247. align-items: center;
  248. .amount {
  249. font-size: 22rpx;
  250. color: #bdbdbd;
  251. }
  252. .favorite-time {
  253. font-size: 22rpx;
  254. color: #bdbdbd;
  255. margin-left: 10rpx;
  256. }
  257. }
  258. }
  259. }
  260. }
  261. .dropdown-menu {
  262. position: absolute;
  263. top: calc(100% + 10rpx);
  264. right: 20rpx;
  265. background-color: #ffffff;
  266. border-radius: 20rpx;
  267. padding: 0;
  268. width: 150rpx;
  269. box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
  270. z-index: 100;
  271. transform-origin: top right;
  272. animation: dropdownAnimation 0.2s ease-out;
  273. overflow: hidden;
  274. .dropdown-item {
  275. padding: 15rpx 0;
  276. color: #333333;
  277. font-size: 24rpx;
  278. position: relative;
  279. text-align: center;
  280. &:not(:last-child)::after {
  281. content: "";
  282. position: absolute;
  283. left: 0;
  284. right: 0;
  285. bottom: 0;
  286. height: 1rpx;
  287. background-color: #eeeeee;
  288. }
  289. &:active {
  290. background-color: #f8f8f8;
  291. }
  292. }
  293. }
  294. @keyframes dropdownAnimation {
  295. 0% {
  296. opacity: 0;
  297. transform: scale(0.95) translateY(-5rpx);
  298. }
  299. 100% {
  300. opacity: 1;
  301. transform: scale(1) translateY(0);
  302. }
  303. }
  304. .no-data {
  305. text-align: center;
  306. color: #bbb;
  307. font-size: 28rpx;
  308. padding: 80rpx 0 40rpx 0;
  309. }
  310. }
  311. ::v-deep .uv-swipe-action {
  312. margin: 0 24rpx 24rpx 24rpx;
  313. border-radius: 18rpx;
  314. overflow: hidden;
  315. .uv-swipe-action-item__content {
  316. background-color: #f2f6f2;
  317. }
  318. .uv-swipe-action-item__right {
  319. border-top-right-radius: 32rpx;
  320. border-bottom-right-radius: 32rpx;
  321. top: 2rpx;
  322. bottom: 2rpx;
  323. right: 2rpx;
  324. }
  325. }
  326. .uv-swipe-action-item {
  327. border-radius: 18rpx;
  328. overflow: hidden;
  329. margin-bottom: 24rpx;
  330. }
  331. </style>