Ver código fonte

商品管理

kulley 6 anos atrás
pai
commit
7d608e76ea

+ 2 - 1
package.json

@@ -63,7 +63,8 @@
     "webpack": "4.28.3",
     "webpack-dev-server": "3.1.14",
     "webpack-manifest-plugin": "2.0.4",
-    "workbox-webpack-plugin": "3.6.3"
+    "workbox-webpack-plugin": "3.6.3",
+    "moment": "latest"
   },
   "scripts": {
     "start": "node scripts/start.js",

+ 56 - 0
src/pages/my/manage/goods/index.css

@@ -0,0 +1,56 @@
+.my-accordion {
+    background-color: #f5f5f9!important;
+}
+
+.list-others {
+    margin-left: 15px;
+    padding-top: 10px;
+}
+
+.list-others-subtitle {
+    font-size: 17px;
+}
+
+.am-list-content {
+    font-size: 17px!important;
+}
+
+.list-extra {
+    display: flex;
+    align-items: center;
+    justify-content: space-around;
+}
+
+.am-list-item .am-input-extra {
+    max-height: 40px;
+}
+
+.hidden {
+    display: none;
+    transition: 0.3s all ease;
+}
+
+.good-block {
+    height: 100px;
+    display: flex;
+    align-items: center;
+    margin-top: 5px;
+}
+
+.good-image {
+    height: 100px;
+    background-repeat: no-repeat;
+    background-size: cover;
+}
+
+.all-goods {
+    background-color: #f5f5f9;
+}
+
+.good-block {
+    background-color: white;
+}
+
+.modify-goods-modal{
+    height: 470px
+}

+ 378 - 85
src/pages/my/manage/goods/index.js

@@ -1,28 +1,112 @@
 import React, {Component} from 'react'
 import './index.css'
-import {NavBar, Icon, Accordion, List, InputItem, ImagePicker, Button, ActivityIndicator} from 'antd-mobile'
+import {
+    Picker,
+    NavBar,
+    Accordion,
+    List,
+    InputItem,
+    ImagePicker,
+    Button,
+    ActivityIndicator,
+    Stepper,
+    Modal
+} from 'antd-mobile'
+import {Switch, Row, Col, Icon} from 'antd'
 import {withRouter} from 'react-router-dom'
-import {create_shop, shop_by_props} from "../../../../utils/gql"
+import {create_product, update_product, category_by_props, productbyprops} from "../../../../utils/gql"
 import {Query, Mutation} from "react-apollo"
 import gql from "graphql-tag"
-import axios from 'axios'
 import {idGen} from "../../../../utils/func"
+import moment from 'moment'
+import {storeFile} from "../../../../configs/url"
+import axios from 'axios'
+import classNames from 'classnames'
+
+const Item = List.Item
 
 class Goods extends Component {
     constructor(props) {
         super(props)
         this.state = {
-            files: [],
-            imgDatas: [],
-            name: '',
-            price: 0,
-            intro: '',
-            stock: 0
+            accordionKey: ''
         }
     }
 
-    onAccordionChange = (key) => {
-        console.log(key)
+    render() {
+        let {accordionKey} = this.state
+
+        return (
+            <div className='goods-wrap'>
+                <NavBar
+                    className='navbar'
+                    mode="light"
+                    icon={<Icon type="left"/>}
+                    onLeftClick={() => {
+                        this.props.history.go(-2)
+                    }}
+                >商品管理</NavBar>
+                <div className='content-wrap'>
+                    <Accordion className="my-accordion" onChange={(key) => {
+                        this.setState({
+                            accordionKey: key[0]
+                        })
+                    }}>
+                        <Accordion.Panel header="全部分类"
+                                         className={classNames({'hidden': accordionKey === '1' || accordionKey === '2'})}>
+                            <AllCategory/>
+                        </Accordion.Panel>
+                        <Accordion.Panel header="全部商品"
+                                         className={classNames({'hidden': accordionKey === '0' || accordionKey === '2'})}>
+                            <AllGoods/>
+                        </Accordion.Panel>
+                        <Accordion.Panel header="添加商品"
+                                         className={classNames({'hidden': accordionKey === '0' || accordionKey === '1'})}>
+                            <AddGoods/>
+                        </Accordion.Panel>
+                    </Accordion>
+                </div>
+            </div>
+
+        )
+    }
+}
+
+export default withRouter(Goods)
+
+class AddGoods extends Component {
+    constructor(props) {
+        super(props)
+        let state = {
+            files: [],
+            imgDatas: [],
+        }
+        if(props.good === undefined) {
+            this.state = {
+                ...state,
+                name: '',
+                price: 0,
+                intro: '',
+                stock: 20,
+                category: '',
+                category_id: '',
+                newGood: true
+            }
+        } else {
+            console.log(props.good)
+            let {name, price, intro, stock, id} = props.good
+            this.state = {
+                ...state,
+                id,
+                name,
+                price,
+                intro,
+                stock,
+                category: props.good.category_id.name,
+                category_id: [props.good.category_id.id],
+                newGood: false
+            }
+        }
     }
 
     onChange = (id) => (files, operationType) => {
@@ -49,88 +133,297 @@ class Goods extends Component {
         })
     }
 
+    uploadImg = () => {
+        let {imgDatas} = this.state
+
+        return imgDatas.map((imgData) => (
+            axios({
+                url: storeFile,
+                method: 'post',
+                data: imgData
+            })
+        ))
+    }
+
     render() {
-        let {files, imgDatas, name, intro, stock, price} = this.state
-        let id = idGen('goods')
+        let {files, imgDatas, name, intro, stock, price, category_id, newGood} = this.state
+        let id = newGood? idGen('goods'): this.state.id
+        const categoryFilter = {
+            "status": "1",
+            "sort_by": {"order": "asc"}
+        }
         return (
-            <div className='goods-wrap'>
-                <NavBar
-                    className='navbar'
-                    mode="light"
-                    icon={<Icon type="left"/>}
-                    onLeftClick={() => {
-                        this.props.history.go(-2)
-                    }}
-                >商品管理</NavBar>
-                <div className='content-wrap'>
-                    <Accordion defaultActiveKey="0" className="my-accordion" onChange={this.onAccordionChange}>
-                        <Accordion.Panel header="添加商品">
-                            <List renderHeader={() => '店铺个性化管理'} className="my-list">
-                                <InputItem onChange={(e) => {
-                                    this.setState({name: e})
-                                }} placeholder="请输入名称">名称</InputItem>
-                                <InputItem onChange={(e) => {
-                                    this.setState({intro: e})
-                                }} placeholder="请输入简介">简介</InputItem>
-                                <InputItem onChange={(e) => {
-                                    this.setState({price: e})
-                                }} placeholder="请输入价格">价格</InputItem>
-                                <InputItem onChange={(e) => {
-                                    this.setState({stock: e})
-                                }} placeholder="请输入库存">库存</InputItem>
-                                <div className='my-list-subtitle'>商品图片</div>
-                                <ImagePicker
-                                    files={files}
-                                    onChange={this.onChange(id)}
-                                    onImageClick={(index, fs) => console.log(index, fs)}
-                                    selectable={true}
-                                    multiple={false}
-                                />
-                                <Mutation mutation={gql(create_shop)}>
-                                    {(createstore, {loading, error}) => {
-                                        if (loading)
-                                            return (
-                                                <div className="loading">
-                                                    <div className="align">
-                                                        <ActivityIndicator text="Loading..." size="large"/>
-                                                    </div>
+            <List className="my-add-goods-list">
+                <InputItem onChange={(e) => {
+                    this.setState({name: e})
+                }} value={name} placeholder="请输入名称">名称</InputItem>
+                <Query query={gql(category_by_props)} variables={categoryFilter}>
+                    {
+                        ({loading, error, data}) => {
+                            if (loading) {
+                                return (
+                                    <div className="loading-center">
+                                        <ActivityIndicator text="Loading..." size="large"/>
+                                    </div>
+                                )
+                            }
+                            if (error) {
+                                return 'error!'
+                            }
+
+                            let categoryList = data.categorybyprops.map(category => {
+                                category.value = category.id
+                                category.label = category.text
+                                return category
+                            })
+
+                            return (
+                                <Picker data={categoryList}
+                                        cols={1}
+                                        value={this.state.category_id}
+                                        onChange={v => {
+                                            this.setState({category_id: v});
+                                        }}
+                                >
+                                    <List.Item arrow="horizontal">选择种类</List.Item>
+                                </Picker>
+                            )
+                        }
+                    }
+                </Query>
+                <InputItem onChange={(e) => {
+                    this.setState({intro: e})
+                }} value={intro} placeholder="请输入简介">简介</InputItem>
+                <InputItem onChange={(e) => {
+                    this.setState({price: e})
+                }} value={price} placeholder="请输入价格">价格</InputItem>
+                <Item extra={<Stepper onChange={(e) => {
+                    this.setState({stock: e})
+                }} value={stock} style={{width: '100%', minWidth: '100px'}} showNumber size="small"/>}>库存</Item>
+                <div className='list-others'>
+                    <div className='list-others-subtitle'>商品图片</div>
+                    <ImagePicker
+                        files={files}
+                        onChange={this.onChange(id)}
+                        onImageClick={(index, fs) => console.log(index, fs)}
+                        selectable={true}
+                        multiple={false}
+                    />
+                    {
+                        newGood?
+                            <Mutation mutation={gql(create_product)}>
+                                {(createproduct, {loading, error}) => {
+                                    if (loading)
+                                        return (
+                                            <div className="loading">
+                                                <div className="align">
+                                                    <ActivityIndicator text="Loading..." size="large"/>
                                                 </div>
-                                            )
-                                        if (error)
-                                            return 'error'
-                                        let varObj = {
-                                            id,
-                                            name,
-                                            stock,
-                                            intro,
-                                            price,
-                                            createdAt: new Date().getTime(),
-                                            updatedAt: ''
-                                        }
+                                            </div>
+                                        )
+                                    if (error)
+                                        return 'error'
+                                    let varObj = {
+                                        id,
+                                        unit: '1件',
+                                        status: '',
+                                        recommend: 0,
+                                        category_id: category_id[0],
+                                        name,
+                                        stock,
+                                        intro,
+                                        price,
+                                        createdAt: moment().format('YYYY-MM-DD HH:mm:ss'),
+                                        updatedAt: ''
+                                    }
+                                    return (
+                                        <Button type="primary" size="small" inline onClick={() => {
+                                            Promise.all(this.uploadImg()).then(res => {
+                                                let prefix = 'https://case-1254337200.cos.ap-beijing.myqcloud.com/'
+                                                let img = imgDatas.length === 1 ? prefix + imgDatas[0]['file-name'] : imgDatas.map((imgData, index) => (
+                                                    prefix + imgDatas[index]['file-name']
+                                                ))
+                                                createproduct({variables: {...varObj, img}})
+                                            })
+                                        }}>创建</Button>
+                                    )
+                                }}
+                            </Mutation>
+                            :
+                            <Mutation mutation={gql(update_product)}>
+                                {(updateproduct, {loading, error}) => {
+                                    if (loading)
                                         return (
-                                            <Button type="primary" size="small" inline onClick={() => {
-                                                Promise.all(this.uploadImg()).then(res => {
-                                                    let prefix = 'https://case-1254337200.cos.ap-beijing.myqcloud.com/'
-                                                    let slideshow = imgDatas.length === 1 ? prefix + imgDatas[0]['file-name'] : imgDatas.map((imgData, index) => (
-                                                        prefix + imgDatas[index]['file-name']
-                                                    ))
-                                                    createstore({variables: {...varObj, slideshow}})
-                                                })
-                                            }}>创建</Button>
+                                            <div className="loading">
+                                                <div className="align">
+                                                    <ActivityIndicator text="Loading..." size="large"/>
+                                                </div>
+                                            </div>
                                         )
-                                    }}
-                                </Mutation>
-                            </List>
-                        </Accordion.Panel>
-                        <Accordion.Panel header="全部商品" className="pad">
-
-                        </Accordion.Panel>
-                    </Accordion>
+                                    if (error)
+                                        return 'error'
+                                    let varObj = {
+                                        id,
+                                        unit: '1件',
+                                        status: '',
+                                        recommend: 0,
+                                        category_id: category_id[0],
+                                        name,
+                                        stock,
+                                        intro,
+                                        price,
+                                        updatedAt: moment().format('YYYY-MM-DD HH:mm:ss')
+                                    }
+                                    return (
+                                        <Button type="primary" size="small" inline onClick={() => {
+                                            Promise.all(this.uploadImg()).then(res => {
+                                                let prefix = 'https://case-1254337200.cos.ap-beijing.myqcloud.com/'
+                                                let img = imgDatas.length === 1 ? prefix + imgDatas[0]['file-name'] : imgDatas.map((imgData, index) => (
+                                                    prefix + imgDatas[index]['file-name']
+                                                ))
+                                                updateproduct({variables: {...varObj, img}})
+                                            })
+                                        }}>更新</Button>
+                                    )
+                                }}
+                            </Mutation>
+                    }
                 </div>
-            </div>
+            </List>
+        )
+    }
+}
+
+class AllCategory extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            newCategory: ''
+        }
+    }
 
+    render() {
+        let {newCategory} = this.state
+        const categoryFilter = {
+            "status": "1",
+            "sort_by": {"order": "asc"}
+        }
+        return (
+            <div>
+                <Query query={gql(category_by_props)} variables={categoryFilter}>
+                    {
+                        ({loading, error, data}) => {
+                            if (loading) {
+                                return (
+                                    <div className="loading-center">
+                                        <ActivityIndicator text="Loading..." size="large"/>
+                                    </div>
+                                )
+                            }
+                            if (error) {
+                                return 'error!'
+                            }
+
+                            let categoryList = data.categorybyprops
+                            // id: "coat", text: "外套", icon: "https://ece-img-1254337200.cos.ap-chengdu.myqcloud.com/icon/coat.png"
+                            return (
+                                <List>
+                                    {
+                                        categoryList.map(category => {
+                                            console.log(category.status)
+                                            return (
+                                                <Item key={category.id} extra={<div className='list-extra'><Switch
+                                                    checked={category.status === '1'}/><Button type='warning' inline
+                                                                                               size="small">删除</Button>
+                                                </div>}>{category.text}</Item>
+                                            )
+                                        })
+                                    }
+                                </List>
+                            )
+                        }
+                    }
+                </Query>
+                <InputItem onChange={(e) => {
+                    this.setState({newCategory: e})
+                }} value={newCategory} placeholder="请输入分类名称"
+                           extra={<Button type='primary' inline size="small">添加</Button>}>新的分类</InputItem>
+            </div>
         )
     }
 }
 
-export default withRouter(Goods)
+class AllGoods extends Component {
+    constructor(props) {
+        super(props)
+        this.state = {
+            modal: false,
+            product: {}
+        }
+    }
+
+    controlModal = (bool) => () => {
+        this.setState({
+            modal: bool
+        })
+        if(!bool) {
+            this.setState({
+                product: {}
+            })
+        }
+    }
+
+    render() {
+        let {modal,product} = this.state
+        return (
+            <Query query={gql(productbyprops)} variables={{}}>
+                {
+                    ({loading, error, data}) => {
+                        if (loading) {
+                            return (
+                                <div className="loading-center">
+                                    <ActivityIndicator text="Loading..." size="large"/>
+                                </div>
+                            )
+                        }
+                        if (error) {
+                            return 'error!'
+                        }
+                        let products = data.productbyprops
+                        return (
+                            <div>
+                                <div className='all-goods'>
+                                    {
+                                        products.map(product => {
+                                            return (
+                                                <Row className='good-block' key={product.id}>
+                                                    <Col span={6}>
+                                                        <div className='good-image' style={{backgroundImage: `url(${product.img})`}}/>
+                                                    </Col>
+                                                    <Col span={11} offset={2}>{product.name}</Col>
+                                                    <Col span={1} offset={3}><Icon type="form" onClick={()=>{this.setState({modal: true, product})}}/></Col>
+                                                </Row>
+                                            )
+                                        })
+                                    }
+                                </div>
+                                <Modal
+                                    popup
+                                    visible={modal}
+                                    onClose={this.controlModal(false)}
+                                    animationType="slide-up"
+                                    className='modify-goods-modal'
+                                >
+                                    <div className='close-popup' onClick={this.controlModal(false)}>X</div>
+                                    <div style={{paddingTop:52}}>
+                                        <AddGoods good={product}/>
+                                    </div>
+                                </Modal>
+                            </div>
+                        )
+                    }
+                }
+            </Query>
+        )
+    }
+}

+ 13 - 8
src/pages/my/manage/shop/index.js

@@ -8,6 +8,7 @@ import {Query, Mutation} from "react-apollo"
 import gql from "graphql-tag"
 import {shop_by_props, create_shop, update_shop} from "../../../../utils/gql"
 import {storeFile} from "../../../../configs/url"
+import moment from 'moment'
 
 const Item = List.Item
 
@@ -147,26 +148,26 @@ class ShopRender extends Component {
                 <List renderHeader={() => '店铺个性化管理'} className="my-list">
                     <InputItem onChange={(e) => {
                         this.setState({name: e})
-                    }} value={name} placeholder="请输入店铺名称">名称</InputItem>
+                    }} value={name} placeholder="请输入名称">名称</InputItem>
                     <InputItem onChange={(e) => {
                         this.setState({intro: e})
-                    }} value={intro} placeholder="请输入店铺名称简介">简介</InputItem>
+                    }} value={intro} placeholder="请输入简介">简介</InputItem>
                     <InputItem onChange={(e) => {
                         this.setState({description: e})
-                    }} value={description} placeholder="请输入店铺名称描述">描述</InputItem>
+                    }} value={description} placeholder="请输入描述">描述</InputItem>
                     <InputItem onChange={(e) => {
                         this.setState({address: e})
-                    }} value={address} placeholder="请输入店铺名称地址">地址</InputItem>
+                    }} value={address} placeholder="请输入地址">地址</InputItem>
                     <InputItem onChange={(e) => {
                         this.setState({notice: e})
-                    }} value={notice} placeholder="请输入店铺名称公告,不输入为不显示">通告</InputItem>
+                    }} value={notice} placeholder="不输入或留空则不显示">通告</InputItem>
                     <div className='my-list-subtitle'>首页轮播图</div>
                     <ImagePicker
                         files={files}
                         onChange={this.onChange}
                         onImageClick={(index, fs) => console.log(index, fs)}
                         selectable={true}
-                        multiple={false}
+                        multiple={true}
                     />
                     <Item>
                         {
@@ -179,6 +180,8 @@ class ShopRender extends Component {
                                     address={address}
                                     alert={alert}
                                     slideshow={slideshow}
+                                    notice={notice}
+                                    intro={intro}
                                 />
                                 :
                                 <UpdateShopButton
@@ -189,6 +192,8 @@ class ShopRender extends Component {
                                     address={address}
                                     alert={alert}
                                     slideshow={slideshow}
+                                    notice={notice}
+                                    intro={intro}
                                 />
                         }
                         <Button size="small" inline style={{marginLeft: '2.5px'}} onClick={this.onReset}>重置</Button>
@@ -242,7 +247,7 @@ class UpdateShopButton extends Component {
                         address,
                         intro,
                         notice,
-                        updatedAt: new Date().getTime(),
+                        updatedAt: moment().format('YYYY-MM-DD HH:mm:ss'),
                     }
                     return (
                         <Button type="primary" size="small" inline onClick={() => {
@@ -308,7 +313,7 @@ class CreateShopButton extends Component {
                         address: address ? address : '',
                         intro: intro ? intro : '',
                         notice: notice ? notice : '',
-                        createdAt: new Date().getTime(),
+                        createdAt: moment().format('YYYY-MM-DD HH:mm:ss'),
                         updatedAt: ''
                     }
                     return (

+ 48 - 1
src/utils/gql.js

@@ -4,6 +4,7 @@ const category_by_props = `
             id
             text:name
             icon:img
+            status
         }
     }
 `
@@ -13,6 +14,7 @@ const productbyprops = `
         productbyprops: product_by_props(category_id: $category_id updatedAt: $updatedAt name: $name createdAt: $createdAt status: $status intro: $intro price: $price img: $img stock: $stock) {
             category_id{
                 id
+                name
             }
             updatedAt
             unit
@@ -361,6 +363,49 @@ const create_shop = `
     }
 `
 
+const create_product = `
+    mutation createproduct($recommend: Int, $updatedAt: String, $unit: String, $name: String, $createdAt: String, $status: String, $id: ID!, $intro: String, $price: Float, $category_id: ID, $img: String, $stock: Int) {
+        createproduct: create_product(recommend: $recommend updatedAt: $updatedAt unit: $unit name: $name createdAt: $createdAt status: $status id: $id intro: $intro price: $price category_id: $category_id img: $img stock: $stock) {
+            result
+            product {
+                recommend
+                updatedAt
+                unit
+                name
+                createdAt
+                status
+                id
+                intro
+                price
+                img
+                stock
+            }
+        }
+    }
+`
+
+const update_product = `
+    mutation updateproduct($recommend: Int, $updatedAt: String, $where: product_filter, $unit: String, $name: String, $createdAt: String, $status: String, $id: ID, $intro: String, $price: Float, $category_id: ID, $img: String, $stock: Int) {
+        updateproduct: update_product(id: $id recommend: $recommend updatedAt: $updatedAt where: $where unit: $unit name: $name createdAt: $createdAt status: $status intro: $intro price: $price category_id: $category_id img: $img stock: $stock) {
+            result
+            product {
+                recommend
+                updatedAt
+                unit
+                name
+                createdAt
+                status
+                id
+                intro
+                price
+    
+                img
+                stock
+            }
+        }
+    }
+`
+
 export {
     category_by_props,
     productbyprops,
@@ -375,5 +420,7 @@ export {
     create_order_product,
     shop_by_props,
     create_shop,
-    update_shop
+    update_shop,
+    create_product,
+    update_product
 }