StepOne.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <template>
  2. <div class="step-1 ptc-wrapper">
  3. <div class="ptc-block">
  4. <div class="ptc-inner">
  5. <p class="ptc-label">Choose a version</p>
  6. <PtcRadioGroup
  7. v-model="state.form.product_id"
  8. class="version-list"
  9. :class="{ loose: state.productList.length === 2 }"
  10. >
  11. <div
  12. v-for="product of state.productList"
  13. :key="product.id"
  14. class="version-wrap"
  15. >
  16. <PtcRadio
  17. class="version"
  18. :value="product.id"
  19. :disabled="!!state.form.renewal"
  20. :style="{ fontSize: calcFZ(product.name) }"
  21. >
  22. <i
  23. class="version-icon"
  24. :style="{ backgroundImage: `url(${product.image})` }"
  25. ></i>
  26. <p class="version-name ellipsis-2">{{ product.name }}</p>
  27. </PtcRadio>
  28. </div>
  29. </PtcRadioGroup>
  30. <div
  31. class="version-desc"
  32. :class="{
  33. second:
  34. state.productList[1] &&
  35. state.form.product_id === state.productList[1].id,
  36. }"
  37. >
  38. {{ getters.selectedProduct.remark }}
  39. </div>
  40. </div>
  41. </div>
  42. <div class="ptc-block">
  43. <div class="ptc-inner">
  44. <p class="ptc-label">Choose a subscription method</p>
  45. <PtcRadioGroup v-model="state.form.subscribe_type">
  46. <PtcRadio class="method" value="year">
  47. <span class="cost">${{ getters.selectedProduct.amount_year }}</span>
  48. <span class="name">Annual</span>
  49. <span class="ptc-tag"
  50. >-{{ getters.selectedProduct.better_than_monthly }}% OFF</span
  51. >
  52. </PtcRadio>
  53. <PtcRadio class="method" value="month">
  54. <span class="cost"
  55. >${{ getters.selectedProduct.amount_month }}</span
  56. >
  57. <span class="name">
  58. Monthly<template v-if="+getters.selectedProduct.amount_month_open"
  59. >&nbsp; Activation fee ${{
  60. getters.selectedProduct.amount_month_open
  61. }}</template
  62. ></span
  63. >
  64. </PtcRadio>
  65. </PtcRadioGroup>
  66. </div>
  67. </div>
  68. <div class="ptc-block">
  69. <div class="ptc-inner">
  70. <p class="ptc-label">Do you have a discount code?</p>
  71. <div v-if="!state.discount" class="input-wrap pr">
  72. <input
  73. v-model="state.form.discount_code"
  74. class="ptc-input"
  75. placeholder="Enter promotional code"
  76. />
  77. <button class="input-btn" @click="checkDiscount">Submit</button>
  78. </div>
  79. <div v-else-if="state.discount.discount_code" class="coupon-wrap">
  80. <div class="coupon">
  81. <p class="p1">PTC CARE PLUS</p>
  82. <p class="p2">{{ state.discount.name }}</p>
  83. <p class="p3">- ${{ state.discount.discount_amount }}</p>
  84. </div>
  85. <div class="action">
  86. <span class="code">{{ state.form.discount_code }}</span>
  87. <span class="primary" @click="reviseDiscount">Revise</span>
  88. </div>
  89. </div>
  90. <div v-else class="input-wrap">
  91. <div class="ptc-input readonly">
  92. {{ state.discount.name }} -${{ state.discount.discount_amount }}
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. <div class="total">
  98. <div v-if="getters.cost" class="ptc-inner">
  99. <p>
  100. total<strong>${{ getters.cost }}</strong>
  101. </p>
  102. <p v-if="state.discount" class="highlight">
  103. (${{ state.discount.discount_amount }} discounted)
  104. </p>
  105. </div>
  106. </div>
  107. <div class="ptc-button-group">
  108. <div class="ptc-inner">
  109. <button
  110. class="ptc-button"
  111. :class="{ disabled: !state.form.subscribe_type }"
  112. @click="next"
  113. >
  114. NEXT
  115. </button>
  116. </div>
  117. </div>
  118. </div>
  119. </template>
  120. <script setup lang="ts">
  121. import { PtcRadioGroup, PtcRadio } from '@/components/radio'
  122. import { state, getters, getBrandList } from './store'
  123. import * as api from '@/service/order'
  124. import Toast from '@/components/toast'
  125. const emit = defineEmits<{
  126. (e: 'go', delta?: number): void
  127. }>()
  128. async function checkDiscount() {
  129. if (!state.form.discount_code) return Toast('Please enter promotional code')
  130. try {
  131. const { results, message } = await api.checkDiscount(
  132. state.form.discount_code
  133. )
  134. Toast(message)
  135. state.discount = results
  136. } catch {
  137. state.form.discount_code = ''
  138. }
  139. }
  140. function reviseDiscount() {
  141. state.discount = null
  142. state.form.discount_code = ''
  143. }
  144. function calcFZ(text: string) {
  145. const scale = Math.max(Math.min(5 / text.length, 1), 24 / 56)
  146. return 0.56 * scale + 'rem'
  147. }
  148. async function next() {
  149. if (!state.form.subscribe_type)
  150. return Toast('Please choose a subscription method')
  151. if (!state.brandList.length) await getBrandList()
  152. emit('go')
  153. if (!state.discount) state.form.discount_code = ''
  154. }
  155. </script>
  156. <style lang="scss" scoped>
  157. .version-list {
  158. display: flex;
  159. flex-wrap: wrap;
  160. }
  161. .version-wrap {
  162. display: flex;
  163. margin-bottom: 32px;
  164. width: 33.33%;
  165. &:nth-child(3n - 1) {
  166. justify-content: center;
  167. }
  168. &:nth-child(3n) {
  169. justify-content: flex-end;
  170. }
  171. .loose & {
  172. width: 256px;
  173. }
  174. }
  175. .version {
  176. display: flex;
  177. flex-direction: column;
  178. justify-content: center;
  179. align-items: center;
  180. width: 212px;
  181. height: 212px;
  182. font-size: 56px;
  183. font-weight: bold;
  184. &:nth-child(3n) {
  185. margin-right: 0;
  186. }
  187. &-icon {
  188. width: 36px;
  189. height: 36px;
  190. background-repeat: no-repeat;
  191. background-size: contain;
  192. }
  193. &-name {
  194. margin-top: 18px;
  195. padding: 0 8px;
  196. text-align: center;
  197. }
  198. &-desc {
  199. position: relative;
  200. // margin-top: 32px;
  201. padding: 28px 24px;
  202. line-height: 40px;
  203. font-size: 28px;
  204. color: #193059;
  205. background: #f2f5fb;
  206. // &::before {
  207. // content: '';
  208. // position: absolute;
  209. // left: 88px;
  210. // top: 0;
  211. // transform: translateY(-100%);
  212. // border-style: solid;
  213. // border-width: 0 12px 14px;
  214. // border-color: #f2f5fb transparent;
  215. // }
  216. // &.second::before {
  217. // left: 88px + 276px;
  218. // }
  219. }
  220. }
  221. .method {
  222. display: flex;
  223. align-items: center;
  224. padding: 0 38px;
  225. height: 130px;
  226. + .method {
  227. margin-top: 48px;
  228. }
  229. .cost {
  230. font-size: 56px;
  231. font-weight: bold;
  232. }
  233. .name {
  234. margin-left: 20px;
  235. font-size: 32px;
  236. }
  237. }
  238. .ptc-input {
  239. padding-right: 154px;
  240. &.readonly {
  241. display: flex;
  242. align-items: center;
  243. }
  244. }
  245. .input-btn {
  246. position: absolute;
  247. top: 0;
  248. right: 0;
  249. height: 100%;
  250. width: 154px;
  251. background: #1a3059;
  252. border-radius: 0px 8px 8px 0px;
  253. color: #fff;
  254. font-size: 32px;
  255. &:active {
  256. background: $primary-color-lighten;
  257. }
  258. }
  259. .total {
  260. padding-left: 36px;
  261. font-size: 32px;
  262. color: #333;
  263. strong {
  264. margin-left: 8px;
  265. font-size: 40px;
  266. }
  267. }
  268. .coupon {
  269. @include icon('@img/coupon-s.png', 488px, 224px);
  270. margin-bottom: 48px;
  271. padding-top: 22px;
  272. text-align: center;
  273. font-size: 28px;
  274. font-weight: bold;
  275. line-height: 1;
  276. .p1 {
  277. color: #9aa8c5;
  278. }
  279. .p2 {
  280. margin: 16px 0 34px;
  281. color: $primary-color;
  282. }
  283. .p3 {
  284. font-size: 56px;
  285. color: $primary-color;
  286. }
  287. }
  288. .action {
  289. font-size: 32px;
  290. color: #666;
  291. .code {
  292. margin-right: 64px;
  293. }
  294. }
  295. .highlight {
  296. margin-top: 4px;
  297. color: $danger-color;
  298. }
  299. </style>