index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. import React, {Component} from 'react'
  2. import {withRouter} from 'react-router-dom'
  3. import {Query, Mutation} from "react-apollo"
  4. import gql from "graphql-tag"
  5. import {message} from 'antd'
  6. import {NavBar, Icon, ActivityIndicator, Badge, Modal} from 'antd-mobile'
  7. import classNames from 'classnames'
  8. import moment from 'moment'
  9. import {productAndSpec_by_id, create_userCart} from "../../../utils/gql"
  10. import {idGen} from '../../../utils/func'
  11. import './index.css'
  12. class Detail extends Component {
  13. constructor(props) {
  14. super(props)
  15. this.state = {
  16. id: ''
  17. }
  18. }
  19. componentWillMount() {
  20. let {location} = this.props
  21. if(location && location.state) {
  22. this.setState({
  23. id: location.state.id
  24. })
  25. }
  26. }
  27. render() {
  28. let {id} = this.state
  29. let contentHeight = window.innerHeight
  30. return (
  31. <div className='detail-wrap' style={{height: contentHeight}}>
  32. <div className='detail-navbar-wrap navbar'>
  33. <NavBar
  34. mode="light"
  35. icon={<Icon type="left"/>}
  36. onLeftClick={() => {this.props.history.go(-1)}}
  37. >商品详情
  38. </NavBar>
  39. </div>
  40. <Query query={gql(productAndSpec_by_id)} variables={{id}}>
  41. {
  42. ({loading, error, data}) => {
  43. if (loading) {
  44. return (
  45. <div className="loading-center">
  46. <ActivityIndicator text="Loading..." size="large"/>
  47. </div>
  48. )
  49. }
  50. if (error) {
  51. return 'error!'
  52. }
  53. // console.log('productAndSpec_by_id data',data)
  54. return (
  55. <DetailRender data={data} history={this.props.history}/>
  56. )
  57. }
  58. }
  59. </Query>
  60. </div>
  61. )
  62. }
  63. }
  64. export default withRouter(Detail)
  65. class DetailRender extends Component {
  66. constructor(props) {
  67. super(props)
  68. this.state = {
  69. cartCount: JSON.parse(localStorage.getItem('cartCount')),
  70. openSelect: false,
  71. buttonType: 'add'
  72. }
  73. }
  74. showModal = (e,key) => {
  75. e.preventDefault(); // 修复 Android 上点击穿透
  76. this.setState({
  77. [key]: true,
  78. })
  79. }
  80. changeDetailState = (state,val) => {
  81. this.setState({
  82. [state]:val
  83. })
  84. }
  85. changeBottomButtonType = (e,val) => {
  86. this.setState({
  87. buttonType:val
  88. })
  89. this.showModal(e,'openSelect')
  90. }
  91. render() {
  92. let {data} = this.props
  93. let {name, img, price, stock} = data.productbyid
  94. let {cartCount, openSelect, buttonType} = this.state
  95. // console.log('DetailRender openSelect',openSelect)
  96. return (
  97. <div className='detail-wrapper content-wrap'>
  98. <div className='detail-simple-show'>
  99. <div className='detail-img' style={{backgroundImage: "url('"+ img + "')"}}/>
  100. <div className='detail-intro'>
  101. <div className='detail-name detail-padding'>{name}</div>
  102. <div className='detail-price detail-padding'>
  103. <span>¥{price}</span>&nbsp;&nbsp;
  104. <span>¥{price}</span>
  105. <span className='detail-stock'>库存 {stock}</span>
  106. </div>
  107. </div>
  108. </div>
  109. <div className='detail-complicate-show'>
  110. <div className='detail-padding detail-complicate-title'>商品信息</div>
  111. <div>通过商品详情图片展示</div>
  112. </div>
  113. <div className='detail-footer'>
  114. <div className='detail-bottom'>
  115. <span className='detail-bottom-icon border-right' onClick={()=>{this.props.history.push({pathname: '/home'})}}>
  116. <div className='detail-icon detail-icon-shop'/>
  117. </span>
  118. <span className='detail-bottom-icon' onClick={()=>{this.props.history.push({pathname: '/cart'})}}>
  119. <div className='detail-icon detail-icon-cart'/>
  120. <Badge text={cartCount} overflowCount={90} hot>
  121. <span style={{display: 'inline-block' }} />
  122. </Badge>
  123. </span>
  124. <span className='detail-bottom-button add' onClick={(e)=>{this.changeBottomButtonType(e,'add')}}>加入购物袋</span>
  125. <span className='detail-bottom-button buy' onClick={(e)=>{this.changeBottomButtonType(e,'buy')}}>立即购买</span>
  126. <SelectModal
  127. changeDetailState={this.changeDetailState}
  128. openSelect={openSelect}
  129. buttonType={buttonType}
  130. productData={data}
  131. price={price}
  132. img={img}
  133. history={this.props.history}
  134. />
  135. </div>
  136. </div>
  137. </div>
  138. )
  139. }
  140. }
  141. class SelectModal extends Component {
  142. constructor(props) {
  143. super(props)
  144. this.state = {
  145. count: 1,
  146. selectColor: '',
  147. selectSpec:{},
  148. specList: [],
  149. colorList: []
  150. }
  151. }
  152. componentWillMount() {
  153. let {productData} = this.props
  154. this.handleData(productData.spec)
  155. }
  156. // 规格表处理
  157. handleData = (specs) => {
  158. let flag = true, selectFlag = true
  159. let specObject = {}, i = 0, specList = []
  160. let colorObject = {}, j = 0, colorList = [], selectColor = ''
  161. specs.forEach((item) => {
  162. let {id,color,size,stock,status} = item
  163. if(flag && status > 0) {
  164. selectColor = color
  165. flag = false
  166. }
  167. specObject[color] ? specList[specObject[color] - 1].spec.push({id, size, stock, status}) : specObject[color] = ++i && specList.push({
  168. color,
  169. spec: [{id, size, stock, status}],
  170. })
  171. if(!colorObject[color]) {
  172. colorObject[color] = ++j
  173. colorList.push({
  174. id,
  175. color
  176. })
  177. }
  178. })
  179. specList.forEach((items)=>{
  180. let {spec} = items
  181. spec.forEach((item)=>{
  182. item.select = false
  183. if(selectFlag && item.status > 0) {
  184. item.select = true
  185. selectFlag = false
  186. }
  187. })
  188. selectFlag = true
  189. })
  190. this.setState({
  191. selectColor,
  192. specList,
  193. colorList
  194. })
  195. // console.log('specList',specList)
  196. // console.log('colorList',colorList)
  197. }
  198. changeState = (state,val) => {
  199. this.setState({
  200. [state]:val
  201. })
  202. }
  203. //获取输入框的值
  204. getInputValue=(e)=>{
  205. this.setState({
  206. count:e.target.value
  207. })
  208. }
  209. // 增加
  210. augment=()=>{
  211. this.setState({
  212. count:this.state.count*1+1
  213. })
  214. }
  215. // 减少
  216. reduce=()=> {
  217. this.setState({
  218. count:this.state.count*1-1
  219. })
  220. }
  221. // 添加至购物袋
  222. onCreateUserCart = (create_userCart) => {
  223. let id = idGen('cart')
  224. let user_id = "obR_j5GbxDfGlOolvSeTdZUwfpKA"
  225. let {productData} = this.props
  226. let product_id = productData.productbyid.id
  227. let {count, selectColor, specList} = this.state
  228. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  229. let specificationStock_id = specFilter.id
  230. let createdAt = moment().format('YYYY-MM-DD HH:mm:ss')
  231. const cartContent = {
  232. id,
  233. user_id,
  234. product_id,
  235. specificationStock_id,
  236. count,
  237. createdAt,
  238. updatedAt: ""
  239. }
  240. console.log('cartContent',cartContent)
  241. this.props.changeDetailState('openSelect',false)
  242. create_userCart({variables:cartContent}).then((data)=>{
  243. console.log('create_userCart data',data)
  244. let cartCount = JSON.parse(localStorage.getItem("cartCount")) + count
  245. this.props.changeDetailState('cartCount',cartCount)
  246. message.success('成功添加至购物车')
  247. localStorage.setItem("cartCount",JSON.stringify(cartCount))
  248. })
  249. }
  250. // 立即购买
  251. buyNow = () => {
  252. let {count, selectColor, specList} = this.state
  253. let createdAt = moment().format('YYYY-MM-DD HH:mm:ss')
  254. let id = idGen('cart')
  255. let {productData} = this.props
  256. let {id:product_id, img, intro, name, price, status, stock, unit} = productData.productbyid
  257. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  258. let {id:specificationStock_id, size, stock:specStock, status:specStatus} = specFilter
  259. let totalPrice = price * count
  260. let buyNowContent = [{
  261. count,
  262. createdAt,
  263. id,
  264. product_id:{
  265. id:product_id,
  266. img,
  267. intro,
  268. name,
  269. price,
  270. status,
  271. stock,
  272. unit
  273. },
  274. specificationStock_id:{
  275. id:specificationStock_id,
  276. color:selectColor,
  277. size,
  278. stock:specStock,
  279. status:specStatus
  280. }
  281. }]
  282. console.log('buyNowContent',buyNowContent)
  283. sessionStorage.setItem("buyNowContent",JSON.stringify(buyNowContent))
  284. sessionStorage.setItem("totalPrice",JSON.stringify(totalPrice))
  285. this.props.changeDetailState('openSelect')
  286. this.props.history.push({
  287. pathname: '/cart/orders',
  288. state:{
  289. dataType: 'buyNowContent'
  290. }
  291. })
  292. }
  293. render() {
  294. let {price, img, buttonType} = this.props
  295. let {count, selectColor, specList, colorList} = this.state
  296. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  297. let specStock = specFilter.stock || 0
  298. let selectSize = specFilter.size
  299. return(
  300. <Modal
  301. popup
  302. visible={this.props.openSelect}
  303. onClose={()=>this.props.changeDetailState('openSelect',false)}
  304. animationType="slide-up"
  305. afterClose={() => { console.log('close model')}}
  306. >
  307. <div className="popup-box" >
  308. <div className="main-goods-box">
  309. <div className="close-popup" onClick={()=>this.props.changeDetailState('openSelect',false)}>
  310. ×
  311. </div>
  312. <div className="goods-box">
  313. <div className="goods-info">
  314. <div className="left">
  315. <img src={img || "https://gw.alipayobjects.com/zos/rmsportal/nywPmnTAvTmLusPxHPSu.png"} alt="商品图片"/>
  316. </div>
  317. <div className="mid">
  318. <div className="goods_price"> ¥ {price}</div>
  319. <div className="selected-type">已选择: {selectColor} / {selectSize}</div>
  320. </div>
  321. <div className="right">库存
  322. {specStock}
  323. </div>
  324. </div>
  325. <div className="scroll-body">
  326. <div className="goods_type">
  327. <ul>
  328. <li>
  329. <div className="type-title">颜色</div>
  330. <dl>
  331. {
  332. colorList.map((spec)=>(
  333. <dd
  334. className={classNames({
  335. 'spec-red': spec.color === selectColor
  336. })}
  337. key={'color'+spec.id}
  338. onClick={()=>{
  339. this.changeState('selectColor',spec.color)
  340. }}
  341. >
  342. {spec.color}
  343. </dd>
  344. ))
  345. }
  346. </dl>
  347. </li>
  348. <Specification specList={specList.filter(item=>item.color === selectColor)[0]} changeState={this.changeState}/>
  349. </ul>
  350. </div>
  351. <div className="edit-product">
  352. <div className="edit-product-text">购买数量</div>
  353. <div className="edit-product-count">
  354. <button
  355. className={classNames({
  356. 'selected_button-red': true,
  357. 'selected_button-disabled': count <= 1
  358. })}
  359. // disabled={count <= 1}
  360. onClick={()=>{
  361. if(count > 1){
  362. this.reduce()
  363. }else {
  364. message.warning('数量不能小于1个')
  365. }
  366. }}
  367. >-</button>
  368. <input className="selected_input" type="text" value={count} onChange={(e)=>{this.getInputValue(e)}}/>
  369. <button className="selected_button-red" onClick={this.augment}>+</button>
  370. </div>
  371. </div>
  372. </div>
  373. </div>
  374. </div>
  375. <Mutation mutation={gql(create_userCart)}
  376. onError={error=>console.log('error',error)}
  377. >
  378. {(create_userCart,{ loading, error }) => (
  379. <div className='confirm-footer'>
  380. <button
  381. className='confirm-button'
  382. onClick={()=>{
  383. if(buttonType === 'add'){
  384. this.onCreateUserCart(create_userCart)
  385. }else if(buttonType === 'buy'){
  386. this.buyNow()
  387. }
  388. }}
  389. >
  390. <span>确认</span>
  391. </button>
  392. </div>
  393. )}
  394. </Mutation>
  395. </div>
  396. </Modal>
  397. )
  398. }
  399. }
  400. class Specification extends Component {
  401. constructor(props) {
  402. super(props)
  403. this.state = {
  404. spec:this.props.specList.spec
  405. }
  406. }
  407. componentWillReceiveProps(nextProps, nextContext) {
  408. this.setState({
  409. spec:nextProps.specList.spec,
  410. })
  411. }
  412. // 改变选择
  413. changeSelectedStatus=(i)=>{
  414. this.setState((prevState, props) => ({
  415. spec: prevState.spec.map((item,index)=>{
  416. if(index===i){
  417. item.select=true
  418. console.log('select item',item)
  419. this.props.changeState('selectSpec',item)
  420. }else {
  421. item.select=false
  422. }
  423. return item
  424. })
  425. }))
  426. }
  427. render() {
  428. let {spec} = this.state
  429. // console.log('spec',spec)
  430. return (
  431. <li>
  432. <div className="type-title">规格</div>
  433. <dl>
  434. {
  435. spec.map((item,index)=>(
  436. <dd
  437. className={classNames({
  438. 'spec-gray': item.status < 1,
  439. 'spec-red': item.status > 0 && item.select
  440. })}
  441. key={'spec'+item.id}
  442. onClick={()=>{
  443. if(item.status > 0) this.changeSelectedStatus(index)
  444. }}
  445. >
  446. {item.size}
  447. </dd>
  448. ))
  449. }
  450. </dl>
  451. </li>
  452. )
  453. }
  454. }