普兆健康管家前端代码仓库
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.

268 lines
5.1 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view>
  3. <uv-popup ref="popup" mode="bottom" bgColor="none" >
  4. <view class="popup__view">
  5. <view class="flex header">
  6. <view class="title">选择规格</view>
  7. <button class="btn" @click="close">关闭</button>
  8. </view>
  9. <view class="section info">
  10. <view class="flex card">
  11. <view class="left">
  12. <image class="img" :src="coverImg" mode="aspectFill"></image>
  13. </view>
  14. <view class="right">
  15. <view class="name">{{ data.name }}</view>
  16. <view class="desc">可在以下安全剂量内根据你的额外需求选择颗数</view>
  17. </view>
  18. </view>
  19. </view>
  20. <view class="section option">
  21. <view
  22. v-for="item in options"
  23. :key="item.id"
  24. :class="['option-item', selectId == item.id ? 'is-active' : '']"
  25. @click="selectId = item.id"
  26. >
  27. {{ item.specName }}
  28. </view>
  29. </view>
  30. <view class="footer">
  31. <button class="flex btn" @click="onConfirm">{{ confirmText }}</button>
  32. </view>
  33. </view>
  34. </uv-popup>
  35. </view>
  36. </template>
  37. <script>
  38. import { mapState } from 'vuex'
  39. export default {
  40. props: {
  41. value: {
  42. type: String | Number,
  43. default: null
  44. },
  45. data: {
  46. type: Object,
  47. default() {
  48. return {}
  49. }
  50. },
  51. confirmText: {
  52. type: String,
  53. default: '确定'
  54. }
  55. },
  56. data() {
  57. return {
  58. selectId: null,
  59. options: [],
  60. }
  61. },
  62. computed : {
  63. ...mapState(['configList']),
  64. coverImg() {
  65. const { image } = this.data
  66. if (!image) {
  67. return ''
  68. }
  69. let arr = Array.isArray(image) ? image : image.split(',')
  70. return arr[0]
  71. },
  72. },
  73. methods: {
  74. async initSpecs() {
  75. try {
  76. if (this.options.length) {
  77. return
  78. }
  79. let arr = []
  80. if (this.data?.specs?.length) {
  81. arr = this.data.specs
  82. } else {
  83. arr = await this.$fetch('getProductSpec', { productId: this.data.id })
  84. }
  85. arr.sort((a, b) => a.sortOrder - b.sortOrder)
  86. this.options = arr
  87. } catch (err) {
  88. }
  89. },
  90. async open() {
  91. this.selectId = this.value
  92. await this.initSpecs()
  93. this.$refs.popup.open()
  94. },
  95. close() {
  96. this.$refs.popup.close()
  97. this.selectId = null
  98. },
  99. onConfirm() {
  100. if (!this.selectId) {
  101. uni.showToast({
  102. title: '请选择规格',
  103. icon: 'none',
  104. })
  105. return
  106. }
  107. const target = this.options.find(item => item.id === this.selectId)
  108. console.log('target', target)
  109. this.$emit('confirm', target)
  110. this.close()
  111. },
  112. },
  113. }
  114. </script>
  115. <style lang="scss" scoped>
  116. .popup__view {
  117. width: 100vw;
  118. display: flex;
  119. flex-direction: column;
  120. box-sizing: border-box;
  121. background: #FFFFFF;
  122. border-top-left-radius: 32rpx;
  123. border-top-right-radius: 32rpx;
  124. }
  125. .header {
  126. position: relative;
  127. width: 100%;
  128. padding: 24rpx 0;
  129. box-sizing: border-box;
  130. .title {
  131. font-family: PingFang SC;
  132. font-weight: 500;
  133. font-size: 34rpx;
  134. line-height: 1.4;
  135. color: #181818;
  136. }
  137. .btn {
  138. font-family: PingFang SC;
  139. font-weight: 500;
  140. font-size: 32rpx;
  141. line-height: 1.4;
  142. color: #8B8B8B;
  143. position: absolute;
  144. top: 26rpx;
  145. left: 40rpx;
  146. }
  147. }
  148. .section {
  149. border-top: 2rpx solid #EEEEEE;
  150. }
  151. .info {
  152. width: 100%;
  153. padding: 32rpx;
  154. box-sizing: border-box;
  155. .card {
  156. width: 100%;
  157. padding: 32rpx;
  158. box-sizing: border-box;
  159. background-image: linear-gradient(#FAFAFF, #F3F3F3);
  160. border-radius: 32rpx;
  161. column-gap: 24rpx;
  162. .left {
  163. width: 144rpx;
  164. height: 144rpx;
  165. border-radius: 16rpx;
  166. overflow: hidden;
  167. .img {
  168. width: 100%;
  169. height: 100%;
  170. }
  171. }
  172. .right {
  173. flex: 1;
  174. .name {
  175. font-family: PingFang SC;
  176. font-weight: 500;
  177. font-size: 28rpx;
  178. line-height: 1.4;
  179. color: #000000;
  180. }
  181. .desc {
  182. margin-top: 8rpx;
  183. font-family: PingFang SC;
  184. font-weight: 400;
  185. font-size: 26rpx;
  186. line-height: 1.5;
  187. color: #8B8B8B;
  188. }
  189. }
  190. }
  191. }
  192. .option {
  193. width: 100%;
  194. padding: 44rpx;
  195. box-sizing: border-box;
  196. display: grid;
  197. grid-template-columns: repeat(2, 1fr);
  198. gap: 24rpx;
  199. &-item {
  200. padding: 18rpx 14rpx;
  201. text-align: center;
  202. font-family: PingFang SC;
  203. font-weight: 400;
  204. font-size: 28rpx;
  205. line-height: 1.4;
  206. color: #181818;
  207. background: #F9F9F9;
  208. border: 2rpx solid #F9F9F9;
  209. border-radius: 16rpx;
  210. &.is-active {
  211. color: #7451DE;
  212. background: #F2EEFF;
  213. border-color: #7451DE;
  214. }
  215. }
  216. }
  217. .footer {
  218. width: 100%;
  219. padding: 32rpx 40rpx;
  220. box-sizing: border-box;
  221. .btn {
  222. width: 100%;
  223. padding: 16rpx 0;
  224. font-family: PingFang SC;
  225. font-weight: 500;
  226. font-size: 36rpx;
  227. line-height: 1.4;
  228. color: #FFFFFF;
  229. background-image: linear-gradient(to right, #4B348F, #845CFA);
  230. border-radius: 41rpx;
  231. }
  232. }
  233. </style>