safe.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. <template>
  2. <view>
  3. <scroll-view
  4. class="wrapper"
  5. :style="{ top: top + 'px' }"
  6. scroll-y
  7. refresher-enabled
  8. refresher-default-style="white"
  9. @refresherrefresh="pullRefresh"
  10. :refresher-triggered="refreshing"
  11. >
  12. <view v-if="tableData && tableData.length > 0" class="paddingX14">
  13. <view
  14. v-for="(item, index) in tableData"
  15. :key="item.id"
  16. class="cell"
  17. @click="choose(item)"
  18. >
  19. <view class="header">
  20. <view class="titleBox">
  21. <template>
  22. <view class="checkBox" :class="{ check: !!checkMap[item.id] }">
  23. <view class="cuIcon-check"></view>
  24. </view>
  25. </template>
  26. <image class="icon-title" :src="LEVEL_MAP[item.level].titleText" />
  27. </view>
  28. <view
  29. class="lockBox"
  30. @click.stop="
  31. item.safeFlag !== 1 ? moveToBx(item, index) : moveOutBx(item, index)
  32. "
  33. >
  34. {{ item.safeFlag !== 1 ? '锁定' : '解锁' }}
  35. <image
  36. :src="item.safeFlag !== 1 ? ossurl.mine.lock : ossurl.mine.unlock"
  37. webp
  38. class="lockImage"
  39. />
  40. </view>
  41. </view>
  42. <view class="flex-align paddingT14">
  43. <image
  44. class="icon flex-shrink0"
  45. :src="item.spu.cover"
  46. @click.stop="showGoodsDetail(item)"
  47. mode="aspectFit"
  48. />
  49. <view class="flex1 marginL12">
  50. <view
  51. class="font4 bold paddingB13"
  52. style="-webkit-line-clamp: 2;word-break: break-all;text-overflow:ellipsis"
  53. >
  54. {{ item.spu.name }}
  55. </view>
  56. <view class="flex-align-between">
  57. <view class="font3" style="opacity: 0.8">
  58. <text v-if="item.fromRelationType === 'LUCK'">宝箱</text>
  59. <text v-else-if="item.fromRelationType === 'TRADE'">魔换</text>
  60. <text v-else-if="item.fromRelationType === 'LUCK_ROOM'">
  61. 福利房
  62. </text>
  63. <text v-else-if="item.fromRelationType === 'LUCK_KING'">
  64. 魔王战
  65. </text>
  66. <text v-else-if="item.fromRelationType === 'LUCK_WHEEL'">
  67. 魔天轮
  68. </text>
  69. <text v-else-if="item.fromRelationType === 'SUBSTITUTE'">
  70. 置换
  71. </text>
  72. <text v-else-if="item.fromRelationType === 'ACTIVITY'">
  73. 活动
  74. </text>
  75. <text v-else-if="item.fromRelationType === 'DOLL_MACHINE'">
  76. 娃娃机
  77. </text>
  78. <text v-else>其他</text>
  79. 获得
  80. </view>
  81. <view v-if="hide" class="flex-align-between">
  82. <view class="font4 radius2" v-if="item.magicAmount > 0">
  83. 可兑换
  84. <text :style="{ color: '#FEC433' }">
  85. {{ item.magicAmount }}
  86. </text>
  87. 源石
  88. </view>
  89. <view v-else class="font4 radius2">不可兑换</view>
  90. </view>
  91. </view>
  92. </view>
  93. </view>
  94. </view>
  95. </view>
  96. <empty v-if="isEmpty" :top="200" />
  97. </scroll-view>
  98. <image
  99. v-if="!isEmpty"
  100. :src="ossurl.mine.checkAll"
  101. webp
  102. class="check-all"
  103. @click="checkAll"
  104. />
  105. <view class="bottom paddingX10" v-if="!isEmpty">
  106. <view class="bottom-btns flex-align-center">
  107. <view class="applyBtn" @click="moveOutAll">移出保险柜</view>
  108. </view>
  109. </view>
  110. <goods-detail ref="goodsDetailRef" />
  111. </view>
  112. </template>
  113. <script>
  114. import empty from '@/components/empty'
  115. import { LEVEL_MAP } from '@/utils/config'
  116. import resource from '@/utils/resource'
  117. import ossurl from '@/utils/ossurl'
  118. import { throttle } from '@/utils'
  119. import goodsDetail from './goods_detail'
  120. export default {
  121. components: { empty, goodsDetail },
  122. data() {
  123. return {
  124. tableData: [],
  125. resource,
  126. ossurl,
  127. LEVEL_MAP,
  128. refreshing: false,
  129. checkMap: {},
  130. isEmpty: false
  131. }
  132. },
  133. computed: {
  134. top() {
  135. let height = this.$store.state.systemInfo.statusBarHeight + 36 + 50 + 10
  136. return height
  137. },
  138. itemWidth() {
  139. let width = this.$store.state.systemInfo.screenWidth
  140. width = (width - 8 - 40) / 3
  141. let height = (165 / 109) * width
  142. return { width, height }
  143. }
  144. },
  145. mounted() {
  146. this.loadData(true)
  147. },
  148. methods: {
  149. pullRefresh() {
  150. this.refreshing = true
  151. this.loadData()
  152. },
  153. async loadData(loading = false) {
  154. const res = await this.$service.award.store(1, 10000, 1, '', true)
  155. this.tableData = res
  156. this.checkMap = {}
  157. this.isEmpty = !this.tableData || this.tableData.length === 0
  158. setTimeout(() => {
  159. this.refreshing = false
  160. }, 1000)
  161. },
  162. choose(item) {
  163. if (!!this.checkMap[item.id]) {
  164. delete this.checkMap[item.id]
  165. } else {
  166. this.checkMap[item.id] = item
  167. }
  168. this.checkMap = { ...this.checkMap }
  169. },
  170. forceChoose(item, flag, refresh = true) {
  171. if (flag) {
  172. this.checkMap[item.id] = item
  173. } else {
  174. delete this.checkMap[item.id]
  175. }
  176. if (refresh) {
  177. this.checkMap = { ...this.checkMap }
  178. }
  179. },
  180. checkAll() {
  181. if (!this.tableData) return
  182. let flag = this.tableData.every((item) => !!this.checkMap[item.id])
  183. if (flag) {
  184. this.checkMap = {}
  185. } else {
  186. this.tableData.forEach((item) => {
  187. this.forceChoose(item, true, false)
  188. })
  189. this.checkMap = { ...this.checkMap }
  190. }
  191. },
  192. showGoodsDetail(item) {
  193. this.$refs.goodsDetailRef.show(item.spu)
  194. },
  195. moveOutBx(item, index) {
  196. throttle.call(() => {
  197. this.realMoveOutBx(item, index)
  198. })
  199. },
  200. async realMoveOutBx(item, index) {
  201. const res = await this.$service.award.moveOutSaveStore([item.id])
  202. if (res) {
  203. this.tableData.splice(index, 1)
  204. if (this.checkMap) {
  205. delete this.checkMap[item.id]
  206. this.checkMap = { ...this.checkMap }
  207. }
  208. this.isEmpty = !this.tableData || this.tableData.length === 0
  209. }
  210. },
  211. moveOutAll() {
  212. let values = Object.values(this.checkMap)
  213. if (!values || values.length === 0) {
  214. this.$message.warn('请至少选择一个商品!')
  215. return
  216. }
  217. throttle.call(this.realMoveOutAll)
  218. },
  219. async realMoveOutAll() {
  220. let values = Object.values(this.checkMap)
  221. let ids = values.map((item) => item.id)
  222. const res = await this.$service.award.moveOutSaveStore(ids)
  223. if (res) {
  224. this.loadData(true)
  225. this.isEmpty = !this.tableData || this.tableData.length === 0
  226. }
  227. }
  228. }
  229. }
  230. </script>
  231. <style lang="scss" scoped>
  232. .bg {
  233. position: fixed;
  234. z-index: -1;
  235. left: 0;
  236. right: 0;
  237. top: 0;
  238. width: 100%;
  239. height: 100%;
  240. opacity: 0.3;
  241. }
  242. .wrapper {
  243. position: fixed;
  244. left: 0;
  245. right: 0;
  246. bottom: 168rpx;
  247. }
  248. .bottom {
  249. position: fixed;
  250. left: 0;
  251. right: 0;
  252. bottom: 0;
  253. height: 168rpx;
  254. padding-bottom: 40rpx;
  255. .bottom-btns {
  256. height: 128rpx;
  257. }
  258. .image {
  259. height: 128rpx;
  260. width: 0;
  261. }
  262. }
  263. .cell {
  264. background: #ffffff;
  265. border-radius: 12rpx;
  266. border: 2rpx solid rgba(255, 255, 255, 0.4);
  267. padding: 30rpx;
  268. margin-bottom: 20rpx;
  269. position: relative;
  270. overflow: hidden;
  271. .header {
  272. display: flex;
  273. align-items: center;
  274. justify-content: space-between;
  275. position: relative;
  276. border-bottom: 2rpx solid rgba(0, 0, 0, 0.05);
  277. padding-bottom: 28rpx;
  278. .titleBox {
  279. display: flex;
  280. align-items: center;
  281. }
  282. .lockBox {
  283. display: flex;
  284. align-items: center;
  285. font-size: 24rpx;
  286. font-family: Source Han Sans, Source Han Sans;
  287. font-weight: 350;
  288. color: #999999;
  289. }
  290. .lockImage {
  291. width: 48rpx;
  292. height: 48rpx;
  293. }
  294. }
  295. .icon {
  296. width: 180rpx;
  297. height: 180rpx;
  298. border-radius: 10rpx;
  299. }
  300. .icon-title {
  301. width: 90rpx;
  302. height: 32rpx;
  303. // margin-left: -18rpx;
  304. }
  305. .btn-bx {
  306. width: 180rpx;
  307. height: 40rpx;
  308. background: linear-gradient(90deg, #2affff 0%, #4d70f2 100%);
  309. border-radius: 20rpx;
  310. }
  311. .safe-flag {
  312. width: 192rpx;
  313. height: 120rpx;
  314. position: absolute;
  315. right: 32rpx;
  316. }
  317. }
  318. .check-all {
  319. width: 68rpx;
  320. height: 98rpx;
  321. position: fixed;
  322. bottom: 600rpx;
  323. right: 20rpx;
  324. }
  325. .checkBox {
  326. border: 4rpx solid #000000;
  327. background-color: #fff;
  328. color: #fff;
  329. width: 32rpx;
  330. border-radius: 4rpx;
  331. margin-right: 12rpx;
  332. height: 32rpx;
  333. text-align: center;
  334. line-height: 28rpx;
  335. font-size: 24rpx;
  336. &.check {
  337. background: #fec433;
  338. border-color: #fec433;
  339. color: #000;
  340. }
  341. }
  342. .applyBtn {
  343. width: 426rpx;
  344. height: 64rpx;
  345. background: #fec433;
  346. border-radius: 178rpx 178rpx 178rpx 178rpx;
  347. font-size: 28rpx;
  348. font-family: Source Han Sans, Source Han Sans;
  349. font-weight: 400;
  350. color: #000000;
  351. text-align: center;
  352. line-height: 64rpx;
  353. }
  354. </style>