index.tsx 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import request from '@/helpers/request'
  2. import { browser, moneyFormat } from '@/helpers/utils'
  3. import {
  4. Swipe,
  5. SwipeItem,
  6. Image,
  7. CellGroup,
  8. Cell,
  9. ImagePreview,
  10. RadioGroup,
  11. Radio,
  12. Tag,
  13. Row,
  14. Col,
  15. Badge,
  16. Button,
  17. Dialog
  18. } from 'vant'
  19. import { defineComponent } from 'vue'
  20. import styles from './index.module.less'
  21. import ColSticky from '@/components/col-sticky'
  22. import { shareCall } from '../share'
  23. import { state } from '@/state'
  24. import qs from 'query-string'
  25. export default defineComponent({
  26. name: 'goods-detail',
  27. data() {
  28. const query = this.$route.query
  29. return {
  30. id: query.id,
  31. albumPics: [] as any[],
  32. product: {} as Record<string | number | symbol, any>,
  33. radio: 0,
  34. skuStockList: [] as any[],
  35. detailMobileHtml: '',
  36. loading: false
  37. }
  38. },
  39. computed: {
  40. getPrice() {
  41. let item = this.skuStockList.filter(n => n.id == this.radio) as any
  42. if (item && Array.isArray(item) && item.length) {
  43. return item[0].price
  44. }
  45. const price = this.product.price as any
  46. return price
  47. }
  48. },
  49. mounted() {
  50. this.getProduct()
  51. if (browser().isApp) {
  52. if (state.platformType === 'STUDENT') {
  53. const { query } = this.$route as any
  54. const params = Object.assign(
  55. {
  56. id: query.bizId,
  57. promoterId: query.userId
  58. },
  59. query
  60. )
  61. // 自动跳转到学生端商品详情
  62. // window.location.replace(
  63. // `${location.origin}/student/#/goodsDetail?${qs.stringify(params)}`
  64. // )
  65. this.locationReplace(
  66. `${location.origin}/student/#/goodsDetail?${qs.stringify(params)}`
  67. )
  68. } else if (state.platformType === 'TEACHER') {
  69. Dialog.alert({
  70. title: '提示',
  71. message: '请使用酷乐秀学生端扫码打开'
  72. }).then(() => {
  73. postMessage({ api: 'back' })
  74. })
  75. }
  76. } else {
  77. const { origin } = location
  78. const query = this.$route.query
  79. let str =
  80. origin +
  81. `/student/#/goodsDetail?id=${query.bizId}&promoterId=${query.userId}`
  82. shareCall(str, {})
  83. }
  84. },
  85. methods: {
  86. locationReplace(url: string) {
  87. // alert(url)
  88. if (history.replaceState) {
  89. history.replaceState(null, document.title, url)
  90. window.location.reload()
  91. } else {
  92. location.replace(url)
  93. }
  94. },
  95. async getProduct() {
  96. this.loading = true
  97. let product = {} as any
  98. let skuStockList = []
  99. // 获取产品信息
  100. try {
  101. const result = await request.post(
  102. `/api-mall-portal/open/productProfit`,
  103. {
  104. data: {
  105. bizId: this.$route.query.bizId,
  106. userId: this.$route.query.userId
  107. }
  108. }
  109. )
  110. if (result.data && result.data.productDetail) {
  111. product = result.data.productDetail.product
  112. skuStockList = result.data.productDetail.skuStockList || []
  113. }
  114. } catch {}
  115. this.product = product
  116. this.skuStockList = skuStockList.map((item: any) => {
  117. if (item.spData) {
  118. const spData = JSON.parse(item.spData)
  119. item.spDataJson = spData.reduce((spDataJson, value) => {
  120. spDataJson += value.value
  121. return spDataJson
  122. }, '')
  123. item.sku = spData
  124. .reduce((sku, value) => {
  125. sku.push(`${value.key}: ${value.value}`)
  126. return sku
  127. }, [])
  128. .join(',')
  129. } else {
  130. item.spDataJson = '默认'
  131. }
  132. return item
  133. })
  134. this.albumPics = [product.pic]
  135. .concat(product.albumPics.split(','))
  136. .filter(n => n)
  137. this.detailMobileHtml = product.detailMobileHtml
  138. this.loading = false
  139. },
  140. onPreview(index: number) {
  141. // 图片预览
  142. ImagePreview({
  143. images: this.albumPics,
  144. startPosition: index,
  145. closeable: true
  146. })
  147. },
  148. onShowImg(target: any) {
  149. const { localName } = target.srcElement
  150. if (localName !== 'img') {
  151. return
  152. }
  153. let startPosition = 0
  154. const domList = document.querySelectorAll('.msgWrap img')
  155. let imgList = Array.from(domList).map((item: any, index: number) => {
  156. if (target.srcElement == item) {
  157. startPosition = index
  158. }
  159. return item.src
  160. })
  161. ImagePreview({
  162. images: imgList,
  163. startPosition: startPosition,
  164. closeable: true
  165. })
  166. },
  167. //打开APP
  168. onDetail() {
  169. const { origin } = location
  170. const query = this.$route.query
  171. let str =
  172. origin +
  173. `/student/#/goodsDetail?id=${query.bizId}&promoterId=${query.userId}`
  174. shareCall(str, {})
  175. setTimeout(() => {
  176. location.href = origin + '/student/#/download'
  177. }, 3000)
  178. }
  179. },
  180. render() {
  181. const product = this.product
  182. const selectSku = this.skuStockList.find((n: any) => n.id === this.radio)
  183. return (
  184. <div class={styles.goodsDetail}>
  185. <Swipe
  186. class={styles.swipe}
  187. lazyRender
  188. v-slots={{
  189. indicator: (item: any) =>
  190. item.total > 1 && (
  191. <div class={styles['custom-indicator']}>
  192. {(item.active || 0) + 1} / {item.total}
  193. </div>
  194. )
  195. }}
  196. >
  197. {this.albumPics.map((item: string, index: number) => (
  198. <SwipeItem>
  199. <Image
  200. class={styles.swipeItemImg}
  201. src={item}
  202. onClick={() => this.onPreview(index)}
  203. fit="cover"
  204. />
  205. </SwipeItem>
  206. ))}
  207. </Swipe>
  208. <CellGroup border={false} class={[styles.goodsHead, 'mb12']}>
  209. <Cell
  210. center
  211. border={false}
  212. v-slots={{
  213. title: () => (
  214. <div class={styles.priceGroup}>
  215. <span class={styles.price}>
  216. <i>¥</i>
  217. {moneyFormat(this.getPrice)}
  218. </span>
  219. {/* <del class={styles.delPrice}>
  220. ¥{moneyFormat(product.originalPrice)}
  221. </del> */}
  222. </div>
  223. )
  224. }}
  225. />
  226. <Cell
  227. center
  228. border={false}
  229. title={product.name}
  230. titleClass={[styles.goodsName, 'van-ellipsis']}
  231. />
  232. </CellGroup>
  233. <Row class={[styles.row, 'mb12']}>
  234. <Col span={4} class={styles.col}>
  235. 规格
  236. </Col>
  237. <Col span={20}>
  238. {selectSku ? (
  239. <div class={styles.selectWrap}>
  240. {selectSku.stock <= 0
  241. ? `当前款式暂时缺货`
  242. : `已选择 ${selectSku.spDataJson}`}
  243. </div>
  244. ) : (
  245. <div class={styles.selectWrap}>请选择 规格</div>
  246. )}
  247. <RadioGroup
  248. class={styles['radio-group']}
  249. modelValue={this.radio}
  250. onUpdate:modelValue={val => (this.radio = val)}
  251. >
  252. {this.skuStockList.map((item: any) => {
  253. const isActive = item.id === this.radio
  254. const type = isActive ? 'primary' : 'default'
  255. return (
  256. <Badge
  257. position="top-right"
  258. content={item.stock <= 0 ? '缺货' : ''}
  259. color={'#999999'}
  260. class={styles.badge}
  261. offset={[-20, 0]}
  262. >
  263. <Radio
  264. class={styles.radio}
  265. name={item.id}
  266. disabled={item.stock <= 0}
  267. onClick={() => {
  268. // 判断是否有库存
  269. if (item.stock <= 0) {
  270. return
  271. }
  272. this.radio = item.id
  273. }}
  274. >
  275. <Tag size="large" plain={isActive} type={type}>
  276. {item.spDataJson}
  277. </Tag>
  278. </Radio>
  279. </Badge>
  280. )
  281. })}
  282. </RadioGroup>
  283. </Col>
  284. </Row>
  285. {this.detailMobileHtml && (
  286. <div class={[styles.section]}>
  287. <div class={styles.detail}>
  288. <span>图文详情</span>
  289. </div>
  290. <div
  291. class={[styles.photoDetail, 'msgWrap']}
  292. onClick={this.onShowImg}
  293. v-html={this.detailMobileHtml}
  294. ></div>
  295. </div>
  296. )}
  297. <ColSticky position="bottom">
  298. <div class={['btnGroup']} style={{ paddingTop: '12px' }}>
  299. <Button block round type="primary" onClick={this.onDetail}>
  300. 下载酷乐秀购买商品
  301. </Button>
  302. </div>
  303. </ColSticky>
  304. </div>
  305. )
  306. }
  307. })