index.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  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: 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. changeModalState = (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. changeModalState={this.changeModalState}
  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. console.log('add cart')
  224. let id = idGen('cart')
  225. let user_id = "obR_j5GbxDfGlOolvSeTdZUwfpKA"
  226. let {productData} = this.props
  227. let product_id = productData.productbyid.id
  228. let {count, selectColor, specList} = this.state
  229. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  230. let specificationStock_id = specFilter.id
  231. let createdAt = moment().format('YYYY-MM-DD HH:mm:ss')
  232. const cartContent = {
  233. id,
  234. user_id,
  235. product_id,
  236. specificationStock_id,
  237. count,
  238. createdAt,
  239. updatedAt: ""
  240. }
  241. console.log('cartContent',cartContent)
  242. this.props.changeModalState('openSelect')
  243. create_userCart({variables:cartContent}).then((data)=>{
  244. console.log('create_userCart data',data)
  245. let cartCount = localStorage.getItem("cartCount")*1 + count
  246. console.log('cartCount',cartCount)
  247. localStorage.setItem("cartCount",cartCount)
  248. })
  249. }
  250. // 立即购买
  251. buyNow = () => {
  252. console.log('buyNow')
  253. let {count, selectColor, specList} = this.state
  254. let createdAt = moment().format('YYYY-MM-DD HH:mm:ss')
  255. let id = idGen('cart')
  256. let {productData} = this.props
  257. let {id:product_id, img, intro, name, price, status, stock, unit} = productData.productbyid
  258. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  259. let {id:specificationStock_id, size, stock:specStock, status:specStatus} = specFilter
  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. this.props.changeModalState('openSelect')
  285. this.props.history.push({
  286. pathname: '/cart/orders',
  287. state:{
  288. dataType: 'buyNowContent'
  289. }
  290. })
  291. }
  292. render() {
  293. let {price, img, buttonType} = this.props
  294. let {count, selectColor, specList, colorList} = this.state
  295. let specFilter = specList.filter(item=>item.color === selectColor)[0].spec.filter(item=> item.select && item.status > 0)[0]
  296. let specStock = specFilter.stock || 0
  297. let selectSize = specFilter.size
  298. return(
  299. <Modal
  300. popup
  301. visible={this.props.openSelect}
  302. onClose={()=>this.props.changeModalState('openSelect',false)}
  303. animationType="slide-up"
  304. afterClose={() => { console.log('close model')}}
  305. >
  306. <div className="popup-box" >
  307. <div className="main-goods-box">
  308. <div className="close-popup" onClick={()=>this.props.changeModalState('openSelect',false)}>
  309. ×
  310. </div>
  311. <div className="goods-box">
  312. <div className="goods-info">
  313. <div className="left">
  314. <img src={img || "https://gw.alipayobjects.com/zos/rmsportal/nywPmnTAvTmLusPxHPSu.png"} alt="商品图片"/>
  315. </div>
  316. <div className="mid">
  317. <div className="goods_price"> ¥ {price}</div>
  318. <div className="selected-type">已选择: {selectColor} / {selectSize}</div>
  319. </div>
  320. <div className="right">库存
  321. {specStock}
  322. </div>
  323. </div>
  324. <div className="scroll-body">
  325. <div className="goods_type">
  326. <ul>
  327. <li>
  328. <div className="type-title">颜色</div>
  329. <dl>
  330. {
  331. colorList.map((spec)=>(
  332. <dd
  333. className={classNames({
  334. 'spec-red': spec.color === selectColor
  335. })}
  336. key={'color'+spec.id}
  337. onClick={()=>{
  338. this.changeState('selectColor',spec.color)
  339. }}
  340. >
  341. {spec.color}
  342. </dd>
  343. ))
  344. }
  345. </dl>
  346. </li>
  347. <Specification specList={specList.filter(item=>item.color === selectColor)[0]} changeState={this.changeState}/>
  348. </ul>
  349. </div>
  350. <div className="edit-product">
  351. <div className="edit-product-text">购买数量</div>
  352. <div className="edit-product-count">
  353. <button
  354. className={classNames({
  355. 'selected_button-red': true,
  356. 'selected_button-disabled': count <= 1
  357. })}
  358. // disabled={count <= 1}
  359. onClick={()=>{
  360. if(count > 1){
  361. this.reduce()
  362. }else {
  363. message.warning('数量不能小于1个')
  364. }
  365. }}
  366. >-</button>
  367. <input className="selected_input" type="text" value={count} onChange={(e)=>{this.getInputValue(e)}}/>
  368. <button className="selected_button-red" onClick={this.augment}>+</button>
  369. </div>
  370. </div>
  371. </div>
  372. </div>
  373. </div>
  374. <Mutation mutation={gql(create_userCart)}
  375. onError={error=>console.log('error',error)}
  376. >
  377. {(create_userCart,{ loading, error }) => (
  378. <div className='confirm-footer'>
  379. <button
  380. className='confirm-button'
  381. onClick={()=>{
  382. if(buttonType === 'add'){
  383. this.onCreateUserCart(create_userCart)
  384. }else if(buttonType === 'buy'){
  385. this.buyNow()
  386. }
  387. }}
  388. >
  389. <span>确认</span>
  390. </button>
  391. </div>
  392. )}
  393. </Mutation>
  394. </div>
  395. </Modal>
  396. )
  397. }
  398. }
  399. class Specification extends Component {
  400. constructor(props) {
  401. super(props)
  402. this.state = {
  403. spec:this.props.specList.spec
  404. }
  405. }
  406. componentWillReceiveProps(nextProps, nextContext) {
  407. this.setState({
  408. spec:nextProps.specList.spec,
  409. })
  410. }
  411. // 改变选择
  412. changeSelectedStatus=(i)=>{
  413. this.setState((prevState, props) => ({
  414. spec: prevState.spec.map((item,index)=>{
  415. if(index===i){
  416. item.select=true
  417. console.log('select item',item)
  418. this.props.changeState('selectSpec',item)
  419. }else {
  420. item.select=false
  421. }
  422. return item
  423. })
  424. }))
  425. }
  426. render() {
  427. let {spec} = this.state
  428. // console.log('spec',spec)
  429. return (
  430. <li>
  431. <div className="type-title">规格</div>
  432. <dl>
  433. {
  434. spec.map((item,index)=>(
  435. <dd
  436. className={classNames({
  437. 'spec-gray': item.status < 1,
  438. 'spec-red': item.status > 0 && item.select
  439. })}
  440. key={'spec'+item.id}
  441. onClick={()=>{
  442. if(item.status > 0) this.changeSelectedStatus(index)
  443. }}
  444. >
  445. {item.size}
  446. </dd>
  447. ))
  448. }
  449. </dl>
  450. </li>
  451. )
  452. }
  453. }