From 1868269ad4a90543634f9a0219735a705f6f90e6 Mon Sep 17 00:00:00 2001 From: lijiantao Date: Fri, 1 Nov 2019 17:38:25 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/config/router.config.js | 13 ++++ antd-ova/src/OvaConfig.js | 2 +- antd-ova/src/locales/zh-CN/menu.js | 3 + antd-ova/src/models/login.js | 4 +- antd-ova/src/pages/Goods/Create.js | 42 +++++++++++ antd-ova/src/pages/Goods/Create/StepOne.js | 40 +++++++++++ antd-ova/src/pages/Goods/Create/StepThree.js | 0 antd-ova/src/pages/Goods/Create/StepTwo.js | 0 antd-ova/src/pages/Goods/List.js | 69 +++++++++++++++++++ .../cn/ova/entity/tenant/goods/OvaGoods.java | 8 ++- .../src/main/resources/application.yml | 4 +- ova-boot/pom.xml | 2 + 12 files changed, 181 insertions(+), 6 deletions(-) create mode 100644 antd-ova/src/pages/Goods/Create.js create mode 100644 antd-ova/src/pages/Goods/Create/StepOne.js create mode 100644 antd-ova/src/pages/Goods/Create/StepThree.js create mode 100644 antd-ova/src/pages/Goods/Create/StepTwo.js create mode 100644 antd-ova/src/pages/Goods/List.js diff --git a/antd-ova/config/router.config.js b/antd-ova/config/router.config.js index f04b39a..d65aa4b 100644 --- a/antd-ova/config/router.config.js +++ b/antd-ova/config/router.config.js @@ -41,6 +41,19 @@ export default [ component: './System/Role/edit/Index' } ] + },{ + path: '/goods', + name: "goods", + routes: [ + { + path:'/goods/list', + name: 'goodslist', + component: "./Goods/List", + },{ + path: '/goods/create', + component: './Goods/Create', + } + ] }, { component: '404', diff --git a/antd-ova/src/OvaConfig.js b/antd-ova/src/OvaConfig.js index 6c6db6c..fd338de 100644 --- a/antd-ova/src/OvaConfig.js +++ b/antd-ova/src/OvaConfig.js @@ -1,7 +1,7 @@ module.exports = { OvaBase: '/ova', - OvaServiceApi: 'http://user1.ova.com:8088/ova-api', + OvaServiceApi: 'http://localhost:8088/ova-api', OvaUploadApi: '/ova-api/fileupload', // OvaDownloadApi: 'http://www.qiniuimage.jt-lee.cn', } diff --git a/antd-ova/src/locales/zh-CN/menu.js b/antd-ova/src/locales/zh-CN/menu.js index a6b6bb1..707c833 100644 --- a/antd-ova/src/locales/zh-CN/menu.js +++ b/antd-ova/src/locales/zh-CN/menu.js @@ -5,5 +5,8 @@ export default { 'menu.system.role': '角色管理', 'menu.account.center': '个人中心', + 'menu.goods':'商品管理', + 'menu.goods.goodslist':'全部商品', + 'menu.account.logout': '退出登录' }; diff --git a/antd-ova/src/models/login.js b/antd-ova/src/models/login.js index 88f772a..b78a76c 100644 --- a/antd-ova/src/models/login.js +++ b/antd-ova/src/models/login.js @@ -34,7 +34,7 @@ export default { if (redirect.match(/^\/.*#/)) { redirect = redirect.substr(redirect.indexOf('#') + 1); } - if(redirect.indexOf('/antdsp') == 0){ + if(redirect.indexOf('/ova') == 0){ redirect = redirect.substr(7); } } else { @@ -61,7 +61,7 @@ export default { }); reloadAuthorized(); // redirect - if (window.location.pathname !== '/antdsp/login') { + if (window.location.pathname !== '/ova/login') { yield put( routerRedux.replace({ pathname: '/login', diff --git a/antd-ova/src/pages/Goods/Create.js b/antd-ova/src/pages/Goods/Create.js new file mode 100644 index 0000000..3ed090f --- /dev/null +++ b/antd-ova/src/pages/Goods/Create.js @@ -0,0 +1,42 @@ +import { PureComponent, Fragment } from "react"; +import PageHeaderWrapper from "@/components/PageHeaderWrapper"; +import { Card, Steps, Affix } from "antd"; +import StepOne from "./Create/StepOne"; +import Block from "@/custom/Block"; +import { Button } from "antd/lib/radio"; + +const Step = Steps.Step; +const CreateStep = [{ + title: '1.基本信息', + components: , +},{ + title: '2.详细信息' +},{ + title: '3.图文描述' +}]; + +export default class extends PureComponent{ + + state={ + currentStep : 0, + } + + render(){ + + return + + + + {CreateStep.map((value)=>)} + + + {CreateStep[this.state.currentStep].components} + + + + + + + + } +} diff --git a/antd-ova/src/pages/Goods/Create/StepOne.js b/antd-ova/src/pages/Goods/Create/StepOne.js new file mode 100644 index 0000000..0502b45 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepOne.js @@ -0,0 +1,40 @@ +import { PureComponent } from "react"; +import { Card, Form, Input } from "antd"; + +const FormItem = Form.Item; + +@Form.create() +export default class extends PureComponent{ + + render(){ + + const { form: {getFieldDecorator}, } = this.props; + return( + +
+ + {getFieldDecorator('type')( + + )} + + + {getFieldDecorator('name')( + + )} + + + {getFieldDecorator('img')( + + )} + + + {getFieldDecorator('sku')( + + )} + +
+ +
+ ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepThree.js b/antd-ova/src/pages/Goods/Create/StepThree.js new file mode 100644 index 0000000..e69de29 diff --git a/antd-ova/src/pages/Goods/Create/StepTwo.js b/antd-ova/src/pages/Goods/Create/StepTwo.js new file mode 100644 index 0000000..e69de29 diff --git a/antd-ova/src/pages/Goods/List.js b/antd-ova/src/pages/Goods/List.js new file mode 100644 index 0000000..22bdc3e --- /dev/null +++ b/antd-ova/src/pages/Goods/List.js @@ -0,0 +1,69 @@ +import { PureComponent, Fragment } from "react"; +import PageHeaderWrapper from "@/components/PageHeaderWrapper"; +import { Card, Table, Button, Form, Input } from "antd"; +import Block from "@/custom/Block"; +import router from 'umi/router'; + +const FormItem = Form.Item; + +export default class extends PureComponent{ + + + + render(){ + + const columns = [{ + title: '商品名称', + dataIndex: 'name', + },{ + title: '总库存', + dataIndex: 'stockQuantity' + },{ + title: '总销量', + dataIndex: 'soldQuantity', + },{ + title: '状态', + dataIndex: 'status' + },{ + title: '操作', + render:()=>{} + }]; + + return + + + + + + + + + + + } +} + + +const QueryForm = Form.create()( + class extends PureComponent{ + render(){ + + const { form: {getFieldDecorator}, loading } = this.props; + + return( + + + {getFieldDecorator("name")( + + )} + + + + + + ); + } + } +); \ No newline at end of file diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java index fb3aae2..65af8ae 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java @@ -35,7 +35,13 @@ public class OvaGoods extends AbstractEntity { * 总库存 */ @Column(name = "stock_quantity", nullable = false) - private BigDecimal stock_quantity; + private BigDecimal stockQuantity; + + /** + * 总销售库存 + */ + @Column(name = "sold_quantity", nullable = false) + private BigDecimal soldQuantity; /** * 0 正常 1删除 diff --git a/ova-boot/ova-web/src/main/resources/application.yml b/ova-boot/ova-web/src/main/resources/application.yml index 580fa37..bc76644 100644 --- a/ova-boot/ova-web/src/main/resources/application.yml +++ b/ova-boot/ova-web/src/main/resources/application.yml @@ -28,8 +28,8 @@ spring: show-sql: true database-platform: org.hibernate.dialect.MySQL5InnoDBDialect redis: - host: localhost - port: 6379 + host: @ova.redis.host@ + port: @ova.redis.port@ timeout: 3000 # 最大登录尝试次数 maxRetryCount: 10 diff --git a/ova-boot/pom.xml b/ova-boot/pom.xml index 134e38c..8d50e9f 100644 --- a/ova-boot/pom.xml +++ b/ova-boot/pom.xml @@ -173,6 +173,8 @@ com.alibaba.druid.pool.DruidDataSourcelogs + 192.168.1.231 + 6379 -- Gitee From b9bd49dd6ecdfa614b9d75d3f088879e1a7eeaba Mon Sep 17 00:00:00 2001 From: lijiantao Date: Tue, 5 Nov 2019 17:47:01 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/package.json | 1 + antd-ova/src/custom/BraftEditor.js | 65 ++++++++ antd-ova/src/custom/BraftEditor.less | 25 ++++ antd-ova/src/pages/Goods/Create.js | 74 +++++++-- antd-ova/src/pages/Goods/Create/ChooseCate.js | 141 ++++++++++++++++++ antd-ova/src/pages/Goods/Create/StepFirst.js | 131 ++++++++++++++++ antd-ova/src/pages/Goods/Create/StepOne.js | 40 ----- antd-ova/src/pages/Goods/Create/StepSecond.js | 73 +++++++++ antd-ova/src/pages/Goods/Create/StepThird.js | 19 +++ antd-ova/src/pages/Goods/Create/StepThree.js | 0 antd-ova/src/pages/Goods/Create/StepTwo.js | 0 antd-ova/src/pages/Goods/models/goods.js | 66 ++++++++ antd-ova/src/pages/Goods/style.less | 18 +++ antd-ova/src/services/goods.js | 12 ++ .../response/pagination/PaginationData.java | 4 + .../dao/tenant/goods/OvaGoodsCategoryDao.java | 19 +++ .../cn/ova/entity/tenant/goods/OvaGoods.java | 6 + .../entity/tenant/goods/OvaGoodsCategory.java | 28 ++++ .../cn/ova/web/goods/GoodsCategoryRest.java | 39 +++++ 19 files changed, 707 insertions(+), 54 deletions(-) create mode 100644 antd-ova/src/custom/BraftEditor.js create mode 100644 antd-ova/src/custom/BraftEditor.less create mode 100644 antd-ova/src/pages/Goods/Create/ChooseCate.js create mode 100644 antd-ova/src/pages/Goods/Create/StepFirst.js delete mode 100644 antd-ova/src/pages/Goods/Create/StepOne.js create mode 100644 antd-ova/src/pages/Goods/Create/StepSecond.js create mode 100644 antd-ova/src/pages/Goods/Create/StepThird.js delete mode 100644 antd-ova/src/pages/Goods/Create/StepThree.js delete mode 100644 antd-ova/src/pages/Goods/Create/StepTwo.js create mode 100644 antd-ova/src/pages/Goods/models/goods.js create mode 100644 antd-ova/src/pages/Goods/style.less create mode 100644 antd-ova/src/services/goods.js create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsCategoryDao.java create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsCategory.java create mode 100644 ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java diff --git a/antd-ova/package.json b/antd-ova/package.json index 50f3160..5261bc1 100644 --- a/antd-ova/package.json +++ b/antd-ova/package.json @@ -51,6 +51,7 @@ "axios": "^0.19.0", "bizcharts": "^3.4.3", "bizcharts-plugin-slider": "^2.1.1-beta.1", + "braft-editor": "^2.3.8", "classnames": "^2.2.6", "dva": "^2.4.1", "enquire-js": "^0.2.1", diff --git a/antd-ova/src/custom/BraftEditor.js b/antd-ova/src/custom/BraftEditor.js new file mode 100644 index 0000000..8b4796c --- /dev/null +++ b/antd-ova/src/custom/BraftEditor.js @@ -0,0 +1,65 @@ +import 'braft-editor/dist/index.css'; +// import 'prismjs/components/prism-java' + +import BraftEditor from 'braft-editor' +import styles from "./BraftEditor.less"; + +import { PureComponent } from 'react'; +import { Upload } from 'antd'; +import { ContentUtils } from 'braft-utils' +import { ImageUtils } from 'braft-finder' + +export default class CustomerBraftEditor extends PureComponent { + + state = { + editorState: BraftEditor.createEditorState(this.props.value) + } + + handleChange = (editorState) => { + this.setState({ editorState }); + this.props.onChange(editorState.toHTML()); + } + + uploadHandler = (param) => { + if (!param.file) { + return false + } + + this.setState({ + editorState: ContentUtils.insertMedias(this.state.editorState, [{ + type: 'IMAGE', + url: URL.createObjectURL + }]) + }) + + } + + render() { + + const extendControls = [ + { + key: 'antd-uploader', + type: 'component', + component: ( + + + + ) + } + ]; + + return ( +
+ +
+ ) + } +} \ No newline at end of file diff --git a/antd-ova/src/custom/BraftEditor.less b/antd-ova/src/custom/BraftEditor.less new file mode 100644 index 0000000..aea4a1f --- /dev/null +++ b/antd-ova/src/custom/BraftEditor.less @@ -0,0 +1,25 @@ +.controlitem.button { + box-sizing: border-box; + min-width: 36px; + padding: 0 8px; + background-color: transparent; + border: none; + color: #6a6f7b; + font-size: 14px; +} +.controlitem.button:hover { + background-color: rgba(0,0,0,.05); +} + +.controlitem { + display: block; + float: left; + height: 36px; + margin: 5px 0 5px 3px; + border-radius: 2px; + cursor: pointer; +} +.embededitor { + border: 1px solid #d1d1d1; + border-radius: 5px; +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create.js b/antd-ova/src/pages/Goods/Create.js index 3ed090f..ecc379c 100644 --- a/antd-ova/src/pages/Goods/Create.js +++ b/antd-ova/src/pages/Goods/Create.js @@ -1,24 +1,69 @@ import { PureComponent, Fragment } from "react"; import PageHeaderWrapper from "@/components/PageHeaderWrapper"; -import { Card, Steps, Affix } from "antd"; -import StepOne from "./Create/StepOne"; +import { Card, Steps, Affix, Form } from "antd"; +import StepFirst from "./Create/StepFirst"; import Block from "@/custom/Block"; import { Button } from "antd/lib/radio"; +import StepSecond from "./Create/StepSecond"; +import StepThird from "./Create/StepThird"; +import { connect } from 'dva'; const Step = Steps.Step; const CreateStep = [{ title: '1.基本信息', - components: , + components: , },{ - title: '2.详细信息' -},{ - title: '3.图文描述' + title: '2.详细信息', + components: }]; +@connect(({goods, loading})=>({ + goods, + loading: loading.models.goods +})) export default class extends PureComponent{ state={ currentStep : 0, + stepStatus: "process" + } + + handlerStepsOnChange= current =>{ + + const currentStep = this.state.currentStep; + if(currentStep > current){ + return this.setState({ + currentStep: current + }); + }else if (currentStep < current - 1){ + return ; + } + + if(current ==1){ //提交第一步数据 + this.firstForm.handlerSubmit(()=>{ + this.setState({stepStatus: "process", currentStep: current}); + },()=>{ + this.setState({stepStatus: "error"}); + }); + }else if (current ==2){ // 提交第二步数据 + this.secondForm.handlerSubmit(()=>{ + this.setState({stepStatus: "process", currentStep: current}); + },()=>{ + this.setState({stepStatus: "error"}); + }); + } + } + + renderCreateSteps = ()=>{ + const current = this.state.currentStep; + switch (current){ + case 0 : + return {this.firstForm = form;}}/>; + case 1 : + return this.secondForm = form}/>; + case 2 : + return this.thirdForm = form}/>; + } } render(){ @@ -26,17 +71,18 @@ export default class extends PureComponent{ return - + {CreateStep.map((value)=>)} - {CreateStep[this.state.currentStep].components} - - - - - + {this.renderCreateSteps()} + {/* {this.firstForm = form;}}/> */} } -} +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/ChooseCate.js b/antd-ova/src/pages/Goods/Create/ChooseCate.js new file mode 100644 index 0000000..577bf77 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/ChooseCate.js @@ -0,0 +1,141 @@ +import { PureComponent } from "react"; + +import styles from "../style.less"; +import { Table, Row, Col, Modal } from "antd"; + +export default class extends PureComponent { + + state = { + selectedKeys: { + pCate: {}, + cCate: {} + }, + visible: false, + } + + componentWillReceiveProps(newProps){ + this.setState({ + visible: newProps.visible + }) + } + + renderSelected = ({ pCate, cCate }) => { + let word = ""; + if (!pCate.name) { + return word; + } + word += pCate.name; + if (!cCate.name) { + return word; + } + return word += ` - ${cCate.name}`; + } + + handlerModalOnOk=()=>{ + + this.props.onOk(this.state.selectedKeys); + this.props.onCancel(); + } + + render() { + + const { Category } = this.props; + const { selectedKeys } = this.state; + + const columns = [{ + dataIndex: 'name' + }]; + + return ( + + +
+
+
已选:{this.renderSelected(selectedKeys)}
+
+
+ +
+
{ + + if (record.id == selectedKeys.pCate.id) { + return `${styles.tr_cate_selected}` + } + if (index % 2) { + return ''; + } + return `${styles.tr_cate_even}`; + }} + onRow={record => { + return { + onClick: event => { //行点击事件 + this.props.onRowSelect(record.id); + this.setState({ + selectedKeys: { + pCate: record, + cCate: {} + } + }) + } + } + }} + /> + + +
{ + + if (record.id == selectedKeys.cCate.id) { + return `${styles.tr_cate_selected}` + } + if (index % 2) { + return ''; + } + return `${styles.tr_cate_even}`; + }} + onRow={record => { + return { + onClick: event => { //行点击事件 + // this.props.onRowSelect(record.id); + this.setState({ + selectedKeys: { + ...selectedKeys, + cCate: record + } + }) + } + } + }} + /> + + + + + + ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepFirst.js b/antd-ova/src/pages/Goods/Create/StepFirst.js new file mode 100644 index 0000000..1710655 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -0,0 +1,131 @@ +import { PureComponent } from "react"; +import { Card, Form, Input, Button, Modal } from "antd"; + +import styles from "../style.less"; +import ChooseCate from "./ChooseCate"; + +import { connect } from 'dva'; + +const FormItem = Form.Item; + + +@connect(({goods})=>({ + goods, +})) +@Form.create() +export default class extends PureComponent{ + + state={ + cateVisible: false, + selectCate:{} //已选择的类目 + } + + componentDidMount(){ + const { dispatch } = this.props; + dispatch({ + type: 'goods/fetchCategory', + payload: { + pid: 0 + } + }) + } + + fetchCategory=(pid)=>{ + const { dispatch } = this.props; + dispatch({ + type: 'goods/fetchCategoryChild', + payload: { + pid: pid + } + }) + } + + handlerSubmit=(success,error)=>{ + const { form, dispatch } = this.props; + form.validateFields((err, fieldValues)=>{ + + // if(err){ + // return error(); + // } + // dispatch({ + // type: 'goods/fillGoodsCreator', + // payload: {...fieldValues} + // }) + success(); + }); + } + + handlerChooseCategory=()=>{ + this.setState({cateVisible: true}) + } + + handlerModalOnCateOk=(selectKeys)=>{ + const { form: {setFieldsValue} } = this.props; + let cateIdValue = `${selectKeys.pCate.name} - ${selectKeys.cCate.name}`; + setFieldsValue({ + cateId: cateIdValue + }) + + } + + render(){ + + const { form: {getFieldDecorator}, goods: {Category} } = this.props; + + const formItemLayout = { + labelCol:{ + xs: { span : 2}, + sm: { span : 2}, + }, + wrapperCol:{ + xs: { span : 12}, + sm: { span : 12 }, + } + } + return( + +
+ + {getFieldDecorator('cateId',{ + rules:[{ + required: true, + message: '请选择类目' + }] + })( + 选择类目} /> + )} + + + {getFieldDecorator('name')( + + )} + + + {getFieldDecorator('sku')( + + )} + + + {getFieldDecorator('img')( + + )} + + + {getFieldDecorator('stockQuantity')( + + )} + + + { + this.setState({ cateVisible: false }); + }} + onOk={this.handlerModalOnCateOk} + /> +
+ ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepOne.js b/antd-ova/src/pages/Goods/Create/StepOne.js deleted file mode 100644 index 0502b45..0000000 --- a/antd-ova/src/pages/Goods/Create/StepOne.js +++ /dev/null @@ -1,40 +0,0 @@ -import { PureComponent } from "react"; -import { Card, Form, Input } from "antd"; - -const FormItem = Form.Item; - -@Form.create() -export default class extends PureComponent{ - - render(){ - - const { form: {getFieldDecorator}, } = this.props; - return( - -
- - {getFieldDecorator('type')( - - )} - - - {getFieldDecorator('name')( - - )} - - - {getFieldDecorator('img')( - - )} - - - {getFieldDecorator('sku')( - - )} - - - -
- ) - } -} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepSecond.js b/antd-ova/src/pages/Goods/Create/StepSecond.js new file mode 100644 index 0000000..8f7d072 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepSecond.js @@ -0,0 +1,73 @@ +import { PureComponent } from "react"; +import { Card, Form, Input } from "antd"; +import { connect } from 'dva'; + +import ReactQuillWrapper from '@/custom/ReactQuillWrapper'; +import BraftEditor from '@/custom/BraftEditor' + +const FormItem = Form.Item; + +@connect(({goods})=>({ + goods, +})) +@Form.create() +export default class extends PureComponent{ + + handlerSubmit =()=>{ + const { form } = this.props; + form.validateFields((err, fieldValues)=>{ + + if(err){ + return error(); + } + dispatch({ + type: 'goods/fillGoodsCreator', + payload: { + ...fieldValues + } + }) + success(); + }); + } + + render(){ + + const formItemLayout = { + labelCol:{ + xs: { span : 2}, + sm: { span : 2}, + }, + wrapperCol:{ + xs: { span : 12}, + sm: { span : 12 }, + } + } + + const {form: {setFieldsValue}} = this.props; + + return( + +
+ + + + + + + + {/* { + setFieldsValue({detail: value}); + }}/> */} + { + setFieldsValue({detail: value}); + }} + /> + + + +
+ ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepThird.js b/antd-ova/src/pages/Goods/Create/StepThird.js new file mode 100644 index 0000000..4bd6f11 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepThird.js @@ -0,0 +1,19 @@ +import { PureComponent } from "react"; + +import { Card, Form, Input } from "antd"; +import { connect } from 'dva'; + +@connect(({goods})=>({ + goods, +})) +export default class extends PureComponent{ + + render(){ + + return( + +
StepThree
+
+ ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepThree.js b/antd-ova/src/pages/Goods/Create/StepThree.js deleted file mode 100644 index e69de29..0000000 diff --git a/antd-ova/src/pages/Goods/Create/StepTwo.js b/antd-ova/src/pages/Goods/Create/StepTwo.js deleted file mode 100644 index e69de29..0000000 diff --git a/antd-ova/src/pages/Goods/models/goods.js b/antd-ova/src/pages/Goods/models/goods.js new file mode 100644 index 0000000..f307826 --- /dev/null +++ b/antd-ova/src/pages/Goods/models/goods.js @@ -0,0 +1,66 @@ +import { + queryCategory +} from '@/services/goods'; + +export default { + namespace: "goods", + state: { + GoodsCreator: { + + }, + Category: { + childs:[] + } + }, + effects: { + *fillGoodsCreator({payload}, {put}){ + yield put({ + type: 'reducersGoodsCreator', + payload: payload + }) + }, + *fetchCategory({payload},{call, put}){ + const response = yield call(queryCategory, payload); + yield put({ + type: 'reducersCategory', + payload: response + }) + }, + *fetchCategoryChild({payload},{call, put}){ + const response = yield call(queryCategory, payload); + yield put({ + type: "reducersCategoryChild", + payload: response + }) + } + }, + reducers: { + reducersGoodsCreator(state, action){ + return { + ...state, + GoodsCreator: { + ...state.GoodsCreator, + ...action.payload + } + } + }, + reducersCategory(state, {payload}){ + return { + ...state, + Category: { + ...payload + } + } + }, + reducersCategoryChild(state, { payload }){ + console.log(state); + return { + ...state, + Category: { + ...state.Category, + childs: payload.data + } + } + } + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/style.less b/antd-ova/src/pages/Goods/style.less new file mode 100644 index 0000000..9f7349d --- /dev/null +++ b/antd-ova/src/pages/Goods/style.less @@ -0,0 +1,18 @@ + +.btn_lb { + cursor: pointer; +} +.label_choosed{ + height: 36px; + line-height: 36px; + padding-left: 10px; + font-size: 12px; + border: 1px solid #1890FF; +} +.tr_cate_even{ + background-color: #F2F2F6; +} +.tr_cate_selected{ + color: #1890FF; + background-color: rgb(190, 222, 252); +} \ No newline at end of file diff --git a/antd-ova/src/services/goods.js b/antd-ova/src/services/goods.js new file mode 100644 index 0000000..aa7f9b0 --- /dev/null +++ b/antd-ova/src/services/goods.js @@ -0,0 +1,12 @@ +import request from '@/utils/request'; +import qs from 'qs'; + +const API_BASE = "/ova-api"; + +/** + * + * @param {pid:0} params + */ +export async function queryCategory(params){ + return request(`${API_BASE}/seller/category/query_category?${qs.stringify(params, { indices: false })}`); +} \ No newline at end of file diff --git a/ova-boot/ova-core/src/main/java/cn/ova/core/response/pagination/PaginationData.java b/ova-boot/ova-core/src/main/java/cn/ova/core/response/pagination/PaginationData.java index ed06a8f..a2b263a 100644 --- a/ova-boot/ova-core/src/main/java/cn/ova/core/response/pagination/PaginationData.java +++ b/ova-boot/ova-core/src/main/java/cn/ova/core/response/pagination/PaginationData.java @@ -26,6 +26,10 @@ public class PaginationData { public PaginationData() { super(); } + + public PaginationData(List data){ + this(data, new Pagination()); + } public PaginationData(List data, Pagination pagination) { super(); this.data = data; diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsCategoryDao.java b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsCategoryDao.java new file mode 100644 index 0000000..45c41ee --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsCategoryDao.java @@ -0,0 +1,19 @@ +package cn.ova.dao.tenant.goods; + +import cn.ova.core.repository.OvaBaseRepository; +import cn.ova.entity.tenant.goods.OvaGoodsCategory; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.List; + +/** + * @author lijiantao + * @date 2019-11-05 + * @description + */ +public interface OvaGoodsCategoryDao extends OvaBaseRepository { + + @Query("FROM OvaGoodsCategory WHERE pId= :pid") + List findByPid(@Param("pid") Long pid); +} diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java index 65af8ae..19a0b06 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java @@ -28,6 +28,12 @@ public class OvaGoods extends AbstractEntity { @Column(name = "g_detail", length = 10240) private String detail; + /** + * 分类ID + */ + @Column(name = "cate_id", nullable = false) + private Long cateId; + @Column(name = "img", length = 128) private String img; diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsCategory.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsCategory.java new file mode 100644 index 0000000..7d283bf --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsCategory.java @@ -0,0 +1,28 @@ +package cn.ova.entity.tenant.goods; + +import cn.ova.core.base.AbstractEntity; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author lijiantao + * @date 2019-11-05 + * @description + */ +@Data +@Table(name = "ova_goods_cate") +@Entity +public class OvaGoodsCategory extends AbstractEntity { + + @Column(name = "c_name", length = 128) + private String name; + + @Column(name = "p_id") + private Long pId; + + @Column(name = "is_custom") + private boolean isCustom; +} diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java new file mode 100644 index 0000000..b9f7108 --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java @@ -0,0 +1,39 @@ +package cn.ova.web.goods; + +import cn.ova.core.response.pagination.PaginationData; +import cn.ova.dao.tenant.goods.OvaGoodsCategoryDao; +import cn.ova.entity.tenant.goods.OvaGoodsCategory; +import io.swagger.annotations.Api; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lijiantao + * @date 2019-11-05 + * @description + */ +@RestController +@RequestMapping("/seller/category") +@Api(value = "商品类目管理", description = "商品类目管理") +@RequiresRoles("Seller") +public class GoodsCategoryRest { + + @Autowired + private OvaGoodsCategoryDao ovaGoodsCategoryDao; + + @GetMapping("/query_category") + public PaginationData queryCategory(Long pid){ + + if(pid == null){ + pid = 0L; + } + List result = ovaGoodsCategoryDao.findByPid(pid); + + return new PaginationData(result) ; + } +} -- Gitee From 5ec1c941e4a8a0e2606c2317140c94b7506126ef Mon Sep 17 00:00:00 2001 From: lijiantao Date: Wed, 6 Nov 2019 17:53:33 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/src/pages/Goods/Create/Spec.js | 15 ++++++ antd-ova/src/pages/Goods/Create/StepFirst.js | 52 ++++++++++++++----- antd-ova/src/pages/Goods/Create/StepSecond.js | 8 +-- .../main/java/cn/ova/bo/SpecKeyValueBo.java | 34 ++++++++++++ .../dao/tenant/goods/OvaGoodsCategoryDao.java | 5 ++ .../cn/ova/dao/tenant/goods/OvaGoodsDao.java | 2 + .../cn/ova/entity/tenant/goods/OvaGoods.java | 12 ++++- .../entity/tenant/goods/OvaGoodsSpecKey.java | 32 ++++++++++++ .../tenant/goods/OvaGoodsSpecValue.java | 30 +++++++++++ .../entity/tenant/goods/OvaGoodsStock.java | 36 +++++++++++++ .../cn/ova/dto/goods/SpecKeyValueDto.java | 51 ++++++++++++++++++ .../main/java/cn/ova/dto/goods/SpecValue.java | 20 +++++++ .../cn/ova/web/goods/GoodsCategoryRest.java | 14 +++++ .../main/java/cn/ova/web/goods/GoodsRest.java | 25 +++++++++ 14 files changed, 319 insertions(+), 17 deletions(-) create mode 100644 antd-ova/src/pages/Goods/Create/Spec.js create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecKey.java create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecValue.java create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java create mode 100644 ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecKeyValueDto.java create mode 100644 ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecValue.java create mode 100644 ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsRest.java diff --git a/antd-ova/src/pages/Goods/Create/Spec.js b/antd-ova/src/pages/Goods/Create/Spec.js new file mode 100644 index 0000000..50d7758 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/Spec.js @@ -0,0 +1,15 @@ +import { PureComponent } from "react"; +import { Card } from "antd"; + + +export default class extends PureComponent{ + + render(){ + + return( + + + + ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepFirst.js b/antd-ova/src/pages/Goods/Create/StepFirst.js index 1710655..8018a26 100644 --- a/antd-ova/src/pages/Goods/Create/StepFirst.js +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -5,6 +5,8 @@ import styles from "../style.less"; import ChooseCate from "./ChooseCate"; import { connect } from 'dva'; +import { isNewExpression } from "@babel/types"; +import SpecCard from "./Spec"; const FormItem = Form.Item; @@ -17,7 +19,8 @@ export default class extends PureComponent{ state={ cateVisible: false, - selectCate:{} //已选择的类目 + selectCate:{}, //已选择的类目 + countName:0, } componentDidMount(){ @@ -60,17 +63,31 @@ export default class extends PureComponent{ } handlerModalOnCateOk=(selectKeys)=>{ - const { form: {setFieldsValue} } = this.props; + const { form: {setFieldsValue}, dispatch } = this.props; + + //根据商品类目获取规格信息 + dispatch({ + type: 'goods/fetchSpec', + payload: { + cateId: selectKeys.cCate.id + } + }); + let cateIdValue = `${selectKeys.pCate.name} - ${selectKeys.cCate.name}`; setFieldsValue({ cateId: cateIdValue - }) + }); } + handlerNameOnChange=(e)=>{ + const { value } = e.target; + this.setState({countName: value.length}); + } + render(){ - const { form: {getFieldDecorator}, goods: {Category} } = this.props; + const { form: {getFieldDecorator}, goods: {Category, Spec} } = this.props; const formItemLayout = { labelCol:{ @@ -96,21 +113,30 @@ export default class extends PureComponent{ )} - {getFieldDecorator('name')( - + {getFieldDecorator('name',{ + rules:[{ + required: true, + message: '请输入商品名称' + },{ + max: 32, + message: '商品名称不能超过32个字符' + }], + })( + )} - - {getFieldDecorator('sku')( + + {getFieldDecorator('spu')( )} - - {getFieldDecorator('img')( - - )} + + - + {getFieldDecorator('stockQuantity')( )} diff --git a/antd-ova/src/pages/Goods/Create/StepSecond.js b/antd-ova/src/pages/Goods/Create/StepSecond.js index 8f7d072..d1af0ae 100644 --- a/antd-ova/src/pages/Goods/Create/StepSecond.js +++ b/antd-ova/src/pages/Goods/Create/StepSecond.js @@ -43,7 +43,7 @@ export default class extends PureComponent{ } } - const {form: {setFieldsValue}} = this.props; + const {form: {setFieldsValue, getFieldDecorator}} = this.props; return( @@ -51,8 +51,10 @@ export default class extends PureComponent{ - - + + {getFieldDecorator('img')( + + )} {/* @Query("FROM OvaGoodsCategory WHERE pId= :pid") List findByPid(@Param("pid") Long pid); + + @Query("SELECT new cn.ova.bo.SpecKeyValueBo(u.cateId,u.id,u.specName,u.nameSort, u.remark, v.specValue, v.valueSort) " + + "FROM OvaGoodsSpecKey u , OvaGoodsSpecValue v WHERE u.id = v.specId AND u.cateId = :cateId order by u.nameSort , v.valueSort") + List queryAllSpecKeyByCateId(@Param("cateId") Long cateId); } diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsDao.java b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsDao.java index 09f37ff..9ce1774 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsDao.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsDao.java @@ -4,4 +4,6 @@ import cn.ova.core.repository.OvaBaseRepository; import cn.ova.entity.tenant.goods.OvaGoods; public interface OvaGoodsDao extends OvaBaseRepository { + + } diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java index 19a0b06..56e0019 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java @@ -20,10 +20,14 @@ import java.math.BigDecimal; @Entity public class OvaGoods extends AbstractEntity { + //新的iPhoneXS就是一个SPU,而红色iPhoneXS就是一个SKU + @Column(name = "sku", length = 64) private String sku; - @Column(name = "g_name", nullable = false) + private String spu; + + @Column(name = "g_name", length = 64, nullable = false) private String name; @Column(name = "g_detail", length = 10240) private String detail; @@ -59,4 +63,10 @@ public class OvaGoods extends AbstractEntity { */ @Column(name = "remark") private String remark; + + /** + * 商品参数 + */ + @Column(name = "param_list", length = 1024, nullable = false) + private String paramList; } diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecKey.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecKey.java new file mode 100644 index 0000000..d082903 --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecKey.java @@ -0,0 +1,32 @@ +package cn.ova.entity.tenant.goods; + +import cn.ova.core.base.AbstractEntity; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description 商品规格key表 + */ + +@Data +@Table(name = "ova_goods_spec_key") +@Entity +public class OvaGoodsSpecKey extends AbstractEntity { + + @Column(nullable = false, name = "cate_id") + private Long cateId; + + @Column(name = "spec_name", nullable = false, length = 16) + private String specName; + + @Column(name = "name_sort") + private int nameSort; + + @Column(name = "remark") + private String remark; +} diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecValue.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecValue.java new file mode 100644 index 0000000..53ef485 --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsSpecValue.java @@ -0,0 +1,30 @@ +package cn.ova.entity.tenant.goods; + +import cn.ova.core.base.AbstractEntity; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description + */ + +@Data +@Table(name = "ova_goods_spec_value") +@Entity +public class OvaGoodsSpecValue extends AbstractEntity { + + @Column(name = "spec_id", nullable = false) + private Long specId; + + @Column(name = "spec_value", nullable = false, length = 32) + private String specValue; + + @Column(name = "value_sort") + private int valueSort; + +} diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java new file mode 100644 index 0000000..22b5cfd --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java @@ -0,0 +1,36 @@ +package cn.ova.entity.tenant.goods; + +import cn.ova.core.base.AbstractEntity; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import java.math.BigDecimal; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description 商品库存表 + */ +@Data +@Table(name = "ova_goods_stock") +@Entity +public class OvaGoodsStock extends AbstractEntity { + + @Column(name = "goods_id", nullable = false) + private Long goodsId; + + @Column(name = "goods_spec", length = 1024, nullable = false) + private String goodsSpec; + + @Column(name = "spec_sort") + private int specSort; + + @Column(name = "stock_quantity", nullable = false) + private BigDecimal stockQuantity; + + @Column(name = "sale_price", nullable = false) + private BigDecimal salePrice; + +} diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecKeyValueDto.java b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecKeyValueDto.java new file mode 100644 index 0000000..90c1db1 --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecKeyValueDto.java @@ -0,0 +1,51 @@ +package cn.ova.dto.goods; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description + */ +@Data +public class SpecKeyValueDto { + private Long cateId; + private Long specId; + private String specName; + private int nameSort; + private String remark; + private List specValues = new ArrayList<>(); + + public SpecKeyValueDto(Long cateId, Long specId, String specName, int nameSort, String remark, List specValues ) { + this.cateId = cateId; + this.specId = specId; + this.specName = specName; + this.nameSort = nameSort; + this.remark = remark; + this.specValues = specValues; + + } + + public SpecKeyValueDto(Long cateId, Long specId, String specName, int nameSort, String remark, String specValue, int valueSort){ + this.cateId = cateId; + this.specId = specId; + this.specName = specName; + this.nameSort = nameSort; + this.remark = remark; + SpecValue spec = new SpecValue(specValue, valueSort); + this.specValues.add(spec); + } + + public void appendSpecValue(String specValue, int valueSort){ + this.appendSpecValue(new SpecValue(specValue, valueSort)); + } + + public void appendSpecValue(SpecValue specValue){ + this.specValues.add(specValue); + } +} + + diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecValue.java b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecValue.java new file mode 100644 index 0000000..e22b9fb --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/SpecValue.java @@ -0,0 +1,20 @@ +package cn.ova.dto.goods; + +import lombok.Data; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description + */ +@Data +public class SpecValue { + + private String specValue; + private int valueSort; + + public SpecValue(String value, int sort){ + specValue = value; + valueSort = sort; + } +} diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java index b9f7108..a38bd22 100644 --- a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java +++ b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java @@ -1,7 +1,11 @@ package cn.ova.web.goods; +import cn.ova.bo.SpecKeyValueBo; +import cn.ova.core.response.OvaResponse; import cn.ova.core.response.pagination.PaginationData; import cn.ova.dao.tenant.goods.OvaGoodsCategoryDao; +import cn.ova.dto.goods.SpecKeyValueDto; +import cn.ova.dto.goods.SpecValue; import cn.ova.entity.tenant.goods.OvaGoodsCategory; import io.swagger.annotations.Api; import org.apache.shiro.authz.annotation.RequiresRoles; @@ -10,7 +14,9 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /** * @author lijiantao @@ -36,4 +42,12 @@ public class GoodsCategoryRest { return new PaginationData(result) ; } + + @GetMapping("/query_spec") + public OvaResponse querySpec(Long cateId){ + + List allSpecKeyValue = ovaGoodsCategoryDao.queryAllSpecKeyByCateId(cateId); + + return OvaResponse.success("执行成功", allSpecKeyValue); + } } diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsRest.java b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsRest.java new file mode 100644 index 0000000..c6fbee2 --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsRest.java @@ -0,0 +1,25 @@ +package cn.ova.web.goods; + +import cn.ova.dao.tenant.goods.OvaGoodsDao; +import io.swagger.annotations.Api; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description + */ +@RestController +@RequestMapping("/seller/goods") +@Api(value = "商品管理", description = "商品管理") +@RequiresRoles("Seller") +public class GoodsRest { + + + +} -- Gitee From 3e304c5cd121c8d98943bd317ec2896c800db2f6 Mon Sep 17 00:00:00 2001 From: lijiantao Date: Thu, 7 Nov 2019 17:58:52 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=95=86=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/src/pages/Goods/Create/MultiSpec.js | 147 +++++++++++++++++++ antd-ova/src/pages/Goods/Create/Spec.js | 15 -- antd-ova/src/pages/Goods/Create/StepFirst.js | 26 ++-- antd-ova/src/pages/Goods/models/goods.js | 20 ++- antd-ova/src/services/goods.js | 9 +- 5 files changed, 188 insertions(+), 29 deletions(-) create mode 100644 antd-ova/src/pages/Goods/Create/MultiSpec.js delete mode 100644 antd-ova/src/pages/Goods/Create/Spec.js diff --git a/antd-ova/src/pages/Goods/Create/MultiSpec.js b/antd-ova/src/pages/Goods/Create/MultiSpec.js new file mode 100644 index 0000000..7868fca --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/MultiSpec.js @@ -0,0 +1,147 @@ +import { PureComponent } from "react"; +import { Card, Button, Input, AutoComplete, Popover, Tag, Icon } from "antd"; + +import styles from "../style.less"; + +const { CheckableTag } = Tag; + +export default class extends PureComponent{ + + state = { + completeSpec:[], + SpecKeys: [], + } + + componentDidMount(){ + const {Spec} = this.props; + let SpecKeys = []; + let specValues = []; + Spec.forEach(element => { + if(SpecKeys.some((value)=>value.specId == element.specId)){ + SpecKeys.find((value)=>value.specId == element.specId).specValues.push(element.specValue); + return ; + } + SpecKeys.push({ + cateId: element.cateId, + specId: element.specId, + specName: element.specName, + remark: element.remark, + specValues:[ + element.specValue + ] + }); + }); + this.setState({ + SpecKeys: [ + ...SpecKeys + ], + }) + } + + //取出规格分类 + pickSpecKey(spec, completeSpec){ + let result = []; + spec.forEach(element => { + + if(completeSpec.some((value)=> value.specName == element.specName)){ + return ; + } + if(result.length == 0){ + result.push(element); + return ; + } + if(!result.some((value)=>value.specId == element.specId)){ + result.push(element); + } + }); + return result; + } + + pickSpecValuesBySpecName(spec, specName){ + let result = spec.find((item)=> item.specName == specName); + if(result){ + return result.specValues; + } + return []; + } + + renderDataSource=()=>{ + const SpecKeys = this.state.SpecKeys; + const completeSpec = this.state.completeSpec; + return SpecKeys.filter((item)=>!completeSpec.some((value)=>value.specName == item.specName)) + .map((item)=>{return item.specName}); + } + + handlerAddSpecValueOnClick=()=>{ + + } + + handlerTagOnChange=(specId, value)=>{ + let {completeSpec} = this.state; + completeSpec.find((item)=> item.specId == specId).specValues.push(value); + this.setState({ + completeSpec: [ + ...completeSpec + ] + }) + } + + renderCompleteSpecItem=()=>{ + const {completeSpec , SpecKeys} = this.state; + + return completeSpec.map((item, index)=>{ + + return 移除}> + { + this.pickSpecValuesBySpecName(SpecKeys, item.specName).map((value, index)=>{ + let checked = item.specValues.some((v)=> v == value); + return {this.handlerTagOnChange(item.specId,value)}}>{value} + + }) + } + + 添加规格值 + + + }); + } + + handlerAutoCompleteOnSelect=(value, option)=>{ + const Spec = this.state.SpecKeys; + let SpceItem = Spec.find((item)=>{ + return item.specName == value + }); + let completeSpec = this.state.completeSpec; + this.setState({ + completeSpec: [...completeSpec,{ + cateId: SpceItem.cateId, + specId: SpceItem.specId, + specName: SpceItem.specName, + specValues:[ ] + }] + }) + } + + render(){ + + + return( + + + {this.renderCompleteSpecItem()} + + + 新增} /> + + + + ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/Spec.js b/antd-ova/src/pages/Goods/Create/Spec.js deleted file mode 100644 index 50d7758..0000000 --- a/antd-ova/src/pages/Goods/Create/Spec.js +++ /dev/null @@ -1,15 +0,0 @@ -import { PureComponent } from "react"; -import { Card } from "antd"; - - -export default class extends PureComponent{ - - render(){ - - return( - - - - ) - } -} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StepFirst.js b/antd-ova/src/pages/Goods/Create/StepFirst.js index 8018a26..12deac1 100644 --- a/antd-ova/src/pages/Goods/Create/StepFirst.js +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -1,12 +1,12 @@ import { PureComponent } from "react"; -import { Card, Form, Input, Button, Modal } from "antd"; +import { Card, Form, Input, Button, Modal, Radio } from "antd"; import styles from "../style.less"; import ChooseCate from "./ChooseCate"; import { connect } from 'dva'; import { isNewExpression } from "@babel/types"; -import SpecCard from "./Spec"; +import MultiSpec from "./MultiSpec"; const FormItem = Form.Item; @@ -21,6 +21,7 @@ export default class extends PureComponent{ cateVisible: false, selectCate:{}, //已选择的类目 countName:0, + isMultiSpec: false, } componentDidMount(){ @@ -85,18 +86,21 @@ export default class extends PureComponent{ this.setState({countName: value.length}); } + handlerMultiSpecOnChange=(value)=>{ + + } + render(){ const { form: {getFieldDecorator}, goods: {Category, Spec} } = this.props; - const formItemLayout = { labelCol:{ - xs: { span : 2}, - sm: { span : 2}, + xs: { span : 4}, + sm: { span : 4}, }, wrapperCol:{ - xs: { span : 12}, - sm: { span : 12 }, + xs: { span : 10}, + sm: { span : 10}, } } return( @@ -133,8 +137,12 @@ export default class extends PureComponent{ )} - - + + { + this.state.isMultiSpec ? + : + } + {getFieldDecorator('stockQuantity')( diff --git a/antd-ova/src/pages/Goods/models/goods.js b/antd-ova/src/pages/Goods/models/goods.js index f307826..1cf9936 100644 --- a/antd-ova/src/pages/Goods/models/goods.js +++ b/antd-ova/src/pages/Goods/models/goods.js @@ -1,5 +1,6 @@ import { - queryCategory + queryCategory, + querySpec, } from '@/services/goods'; export default { @@ -10,7 +11,8 @@ export default { }, Category: { childs:[] - } + }, + Spec:[] }, effects: { *fillGoodsCreator({payload}, {put}){ @@ -32,6 +34,13 @@ export default { type: "reducersCategoryChild", payload: response }) + }, + *fetchSpec({payload},{call, put}){ + const response = yield call(querySpec, payload); + yield put({ + type: 'reducersSpec', + payload: response, + }) } }, reducers: { @@ -53,7 +62,6 @@ export default { } }, reducersCategoryChild(state, { payload }){ - console.log(state); return { ...state, Category: { @@ -61,6 +69,12 @@ export default { childs: payload.data } } + }, + reducersSpec(state, {payload}){ + return { + ...state, + Spec: payload.content + } } } } \ No newline at end of file diff --git a/antd-ova/src/services/goods.js b/antd-ova/src/services/goods.js index aa7f9b0..cb7674d 100644 --- a/antd-ova/src/services/goods.js +++ b/antd-ova/src/services/goods.js @@ -2,11 +2,16 @@ import request from '@/utils/request'; import qs from 'qs'; const API_BASE = "/ova-api"; +const CATEGORY_API = API_BASE+ "/seller/category" /** * * @param {pid:0} params */ export async function queryCategory(params){ - return request(`${API_BASE}/seller/category/query_category?${qs.stringify(params, { indices: false })}`); -} \ No newline at end of file + return request(`${CATEGORY_API}/query_category?${qs.stringify(params, { indices: false })}`); +} + +export async function querySpec(params){ + return request(`${CATEGORY_API}/query_spec?${qs.stringify(params, { indices: false })}`); +} \ No newline at end of file -- Gitee From 252d5b525be9398a07731cb876437ba4bf801d72 Mon Sep 17 00:00:00 2001 From: lijiantao Date: Fri, 15 Nov 2019 17:36:45 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=95=86=E5=93=81=E8=A7=84=E6=A0=BC?= =?UTF-8?q?=E5=BA=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/src/pages/Goods/Create/ChooseCate.js | 12 +- antd-ova/src/pages/Goods/Create/MultiSpec.js | 314 ++++++++++++++---- antd-ova/src/pages/Goods/Create/StepFirst.js | 200 ++++++++--- antd-ova/src/pages/Goods/Create/StockPrice.js | 122 +++++++ antd-ova/src/pages/Goods/models/goods.js | 15 + antd-ova/src/services/goods.js | 32 +- .../main/java/cn/ova/bo/SpecKeyValueBo.java | 6 +- .../dao/tenant/goods/OvaGoodsSpecKeyDao.java | 17 + .../tenant/goods/OvaGoodsSpecValueDao.java | 18 + .../entity/tenant/goods/OvaGoodsStock.java | 3 + .../cn/ova/web/goods/GoodsCategoryRest.java | 89 ++++- 11 files changed, 696 insertions(+), 132 deletions(-) create mode 100644 antd-ova/src/pages/Goods/Create/StockPrice.js create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecKeyDao.java create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecValueDao.java diff --git a/antd-ova/src/pages/Goods/Create/ChooseCate.js b/antd-ova/src/pages/Goods/Create/ChooseCate.js index 577bf77..89098f1 100644 --- a/antd-ova/src/pages/Goods/Create/ChooseCate.js +++ b/antd-ova/src/pages/Goods/Create/ChooseCate.js @@ -1,7 +1,7 @@ import { PureComponent } from "react"; import styles from "../style.less"; -import { Table, Row, Col, Modal } from "antd"; +import { Table, Row, Col, Modal, message } from "antd"; export default class extends PureComponent { @@ -33,7 +33,15 @@ export default class extends PureComponent { handlerModalOnOk=()=>{ - this.props.onOk(this.state.selectedKeys); + const { pCate, cCate} = this.state.selectedKeys; + if(Object.keys(pCate).length == 0){ + return message.error("请选择第一分类"); + } + if(Object.keys(cCate) == 0){ + return message.error("请选择第二分类"); + } + + this.props.onOk({ pCate, cCate}); this.props.onCancel(); } diff --git a/antd-ova/src/pages/Goods/Create/MultiSpec.js b/antd-ova/src/pages/Goods/Create/MultiSpec.js index 7868fca..193f285 100644 --- a/antd-ova/src/pages/Goods/Create/MultiSpec.js +++ b/antd-ova/src/pages/Goods/Create/MultiSpec.js @@ -5,28 +5,32 @@ import styles from "../style.less"; const { CheckableTag } = Tag; -export default class extends PureComponent{ +/** + * SpecKeys { cateId, id, specName, remark, specValues } + */ + +export default class extends PureComponent { state = { - completeSpec:[], + completeSpec: [], SpecKeys: [], } - componentDidMount(){ - const {Spec} = this.props; + componentDidMount() { + const { Spec } = this.props; let SpecKeys = []; let specValues = []; Spec.forEach(element => { - if(SpecKeys.some((value)=>value.specId == element.specId)){ - SpecKeys.find((value)=>value.specId == element.specId).specValues.push(element.specValue); - return ; + if (SpecKeys.some((value) => value.id == element.id)) { + SpecKeys.find((value) => value.id == element.id).specValues.push(element.specValue); + return; } SpecKeys.push({ cateId: element.cateId, - specId: element.specId, + id: element.id, specName: element.specName, remark: element.remark, - specValues:[ + specValues: [ element.specValue ] }); @@ -39,108 +43,288 @@ export default class extends PureComponent{ } //取出规格分类 - pickSpecKey(spec, completeSpec){ + pickSpecKey(spec, completeSpec) { let result = []; spec.forEach(element => { - if(completeSpec.some((value)=> value.specName == element.specName)){ - return ; + if (completeSpec.some((value) => value.specName == element.specName)) { + return; } - if(result.length == 0){ + if (result.length == 0) { result.push(element); - return ; + return; } - if(!result.some((value)=>value.specId == element.specId)){ + if (!result.some((value) => value.id == element.id)) { result.push(element); } }); return result; } - pickSpecValuesBySpecName(spec, specName){ - let result = spec.find((item)=> item.specName == specName); - if(result){ - return result.specValues; - } - return []; - } - - renderDataSource=()=>{ + renderDataSource = () => { const SpecKeys = this.state.SpecKeys; const completeSpec = this.state.completeSpec; - return SpecKeys.filter((item)=>!completeSpec.some((value)=>value.specName == item.specName)) - .map((item)=>{return item.specName}); - } - - handlerAddSpecValueOnClick=()=>{ - + return SpecKeys.filter((item) => !completeSpec.some((value) => value.specName == item.specName)) + .map((item) => { return item.specName }); } - handlerTagOnChange=(specId, value)=>{ - let {completeSpec} = this.state; - completeSpec.find((item)=> item.specId == specId).specValues.push(value); + /** + * 如果已选择就删除,如果未选择就保存 + */ + handlerTagOnChange = (specId, value) => { + let { completeSpec } = this.state; + let specValues = completeSpec.find((item) => item.id == specId).specValues; + const index = specValues.indexOf(value); + if (index > -1) { + specValues.splice(index, 1); + } else { + specValues.push(value); + } this.setState({ completeSpec: [ ...completeSpec ] + }); + this.props.onChange(completeSpec); + } + + handlerAddNewSpecValue=(specId, specValue, success)=>{ + const { dispatch } = this.props; + dispatch({ + type: "goods/addNewSpecValue", + payload:{ + specId:specId, + specValue:specValue, + }, + callback:(result)=>{ + if(result.success){ + let { SpecKeys } = this.state; + SpecKeys.find((item)=>item.id == specId).specValues.push(specValue); + this.handlerTagOnChange(specId, specValue); + this.setState({ + SpecKeys: [...SpecKeys] + }); + success(); + } + } }) } - renderCompleteSpecItem=()=>{ - const {completeSpec , SpecKeys} = this.state; + handlerRemoveSpecValue=(specId, specValue)=>{ + const { dispatch } = this.props; + dispatch({ + type: 'goods/removeSpecValue', + payload: { + specId:specId, + specValue:specValue, + }, + callback:(result)=>{ + if(result.success){ + this.handlerTagOnChange(specId, specValue); + } + } + }); + } - return completeSpec.map((item, index)=>{ + handlerOnRemoveCard=(specId)=>{ + const { completeSpec } = this.state; + let index = completeSpec.findIndex((ele)=> ele.id == specId); + completeSpec.splice(index, 1); + this.setState({completeSpec: [...completeSpec]}); + this.props.onChange(completeSpec); + } - return 移除}> - { - this.pickSpecValuesBySpecName(SpecKeys, item.specName).map((value, index)=>{ - let checked = item.specValues.some((v)=> v == value); - return {this.handlerTagOnChange(item.specId,value)}}>{value} - - }) - } - - 添加规格值 - - + renderCompleteSpecItem = () => { + const { completeSpec, SpecKeys } = this.state; + + return completeSpec.map((item, index) => { + + return }); } - handlerAutoCompleteOnSelect=(value, option)=>{ + + + handlerAutoCompleteOnSelect = (value, option) => { const Spec = this.state.SpecKeys; - let SpceItem = Spec.find((item)=>{ + let SpceItem = Spec.find((item) => { return item.specName == value }); + this._appendCompleteSpec(SpceItem); + } + + _appendCompleteSpec(spec){ let completeSpec = this.state.completeSpec; this.setState({ - completeSpec: [...completeSpec,{ - cateId: SpceItem.cateId, - specId: SpceItem.specId, - specName: SpceItem.specName, - specValues:[ ] + completeSpec: [...completeSpec, { + cateId: spec.cateId, + id: spec.id, + specName: spec.specName, + specValues: [] }] }) } - render(){ - + handlerAddSpecKey=()=>{ - return( - + const specName = this._specInput.state.value; + const {dispatch , cateId} = this.props; - {this.renderCompleteSpecItem()} + const { SpecKeys } = this.state; + if(SpecKeys.some((ele)=> ele.specName == specName)){ + return ; + } + dispatch({ + type: 'goods/addNewSpecKey', + payload:{ + cateId: cateId, + specName: specName + }, + callback:(result)=>{ + if(result.success){ + this._addSpecKeys(result.content); + } + } + }) + } + + _addSpecKeys(specKey){ + let { SpecKeys, completeSpec } = this.state; + SpecKeys.push({ + cateId: specKey.cateId, + id: specKey.id, + specName: specKey.specName, + remark: specKey.remark, + specValues: [ + ] + }); + this.setState({ + SpecKeys:[...SpecKeys] + }) + this._appendCompleteSpec(specKey); + } - = 2){ + return null; + } + return ( + - 新增} /> + this._specInput = input} + addonAfter={
新增
} />
- + ) + + } + + render() { + + return ( + + {this.renderCompleteSpecItem()} + {this.renderAutoComplete()} + + ) + } +} + +class SpecCard extends PureComponent{ + + state={ + specValue: '', + } + + handlerAddSpecValueOnClick=()=>{ + let { specValue} = this.state; + if(!specValue){ + return ; + } + const { CompleteSpec: { id }} = this.props; + + this.props.onAddNewSpecValue(id, specValue, ()=>{this._input.setState({value: ''})}); + + } + + handlerSpecValueOnClick = (specId, value) => { + this.props.onTagChange(specId, value); + } + + pickSpecValuesBySpecName(spec, specName) { + let result = spec.find((item) => item.specName == specName); + if (result) { + return result.specValues; + } + return []; + } + + handlerUnSelectedOnClose=(specId, specValue)=>{ + this.props.onRemoveSpecValue(specId, specValue); + } + + renderPopoverContent = (SpecValues, completeSpecValues, specId) => { + return ( +
+ this._input = input} onChange={(e)=>{this.setState({specValue: e.target.value})}} + addonAfter={
添加
} /> +
+ { + SpecValues.map((element, index) => { + let checked = completeSpecValues.some((v) => v == element); + return ( +
{ this.handlerSpecValueOnClick(specId, element) }} + style={{ display: 'inline-block', marginTop: '20px' }} + key={index}> + {e.stopPropagation();this.handlerUnSelectedOnClose(specId, element)}}>{element} +
+ ) + }) + } +
+
+ ) + } + + handlerRemoveSpecKeys=(e)=>{ + e.preventDefault(); + const {CompleteSpec: { id} }= this.props; + this.props.onRemoveCard(id); + } + + render(){ + const { CompleteSpec: { specName, id, specValues }, SpecKeys } = this.props; + return ( + 移除}> +
+ { + specValues.map((value, index) => { + return {this.props.onTagChange(id, value)}}>{value} + }) + } +
+ + +
) } diff --git a/antd-ova/src/pages/Goods/Create/StepFirst.js b/antd-ova/src/pages/Goods/Create/StepFirst.js index 12deac1..09df4d1 100644 --- a/antd-ova/src/pages/Goods/Create/StepFirst.js +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -1,5 +1,5 @@ import { PureComponent } from "react"; -import { Card, Form, Input, Button, Modal, Radio } from "antd"; +import { Card, Form, Input, Button, Modal, Radio, message } from "antd"; import styles from "../style.less"; import ChooseCate from "./ChooseCate"; @@ -7,24 +7,27 @@ import ChooseCate from "./ChooseCate"; import { connect } from 'dva'; import { isNewExpression } from "@babel/types"; import MultiSpec from "./MultiSpec"; +import StockPrice from "./StockPrice"; const FormItem = Form.Item; -@connect(({goods})=>({ +@connect(({ goods }) => ({ goods, })) @Form.create() -export default class extends PureComponent{ +export default class extends PureComponent { - state={ + state = { cateVisible: false, - selectCate:{}, //已选择的类目 - countName:0, + selectCate: {}, //已选择的类目 + countName: 0, isMultiSpec: false, + cateId: 0, + completeSpec:[], } - componentDidMount(){ + componentDidMount() { const { dispatch } = this.props; dispatch({ type: 'goods/fetchCategory', @@ -34,7 +37,7 @@ export default class extends PureComponent{ }) } - fetchCategory=(pid)=>{ + fetchCategory = (pid) => { const { dispatch } = this.props; dispatch({ type: 'goods/fetchCategoryChild', @@ -44,10 +47,10 @@ export default class extends PureComponent{ }) } - handlerSubmit=(success,error)=>{ + handlerSubmit = (success, error) => { const { form, dispatch } = this.props; - form.validateFields((err, fieldValues)=>{ - + form.validateFields((err, fieldValues) => { + // if(err){ // return error(); // } @@ -59,18 +62,20 @@ export default class extends PureComponent{ }); } - handlerChooseCategory=()=>{ - this.setState({cateVisible: true}) + handlerChooseCategory = () => { + this._cateInput.blur(); + this.setState({ cateVisible: true }) } - handlerModalOnCateOk=(selectKeys)=>{ - const { form: {setFieldsValue}, dispatch } = this.props; + handlerModalOnCateOk = (selectKeys) => { + const { form: { setFieldsValue }, dispatch } = this.props; //根据商品类目获取规格信息 + const cateId = selectKeys.cCate.id; dispatch({ type: 'goods/fetchSpec', payload: { - cateId: selectKeys.cCate.id + cateId: cateId } }); @@ -78,55 +83,91 @@ export default class extends PureComponent{ setFieldsValue({ cateId: cateIdValue }); - + this.setState({ cateId: cateId }); } - handlerNameOnChange=(e)=>{ + handlerNameOnChange = (e) => { const { value } = e.target; - this.setState({countName: value.length}); + this.setState({ countName: value.length }); } - handlerMultiSpecOnChange=(value)=>{ + handlerMultiSpecOnChange = (value) => { + if(value){ + //如果value中某一项的specValues为空,删掉 + const index = value.findIndex((ele)=> ele.specValues.length == 0); + if(index != -1){ + value.splice(index, 1); + } + this.setState({completeSpec:[...value]}); + } + } + handlerSpecVisible=()=>{ + const { form: { getFieldValue } } = this.props; + const cateId = getFieldValue("cateId"); + if(!cateId){ + return message.error('请选择商品类目'); + } + this.setState({ isMultiSpec: true }); } - render(){ + dealSpecsToGoodsStocks=()=>{ + const { completeSpec } = this.state; + return GoodsStock.dealSpecsToGoodsStocks(completeSpec); + } + handlerStockPriceOnchange=(goodsStock)=>{ + console.log(goodsStock); + } - const { form: {getFieldDecorator}, goods: {Category, Spec} } = this.props; + render() { + + const { form: { getFieldDecorator }, goods: { Category, Spec } } = this.props; const formItemLayout = { - labelCol:{ - xs: { span : 4}, - sm: { span : 4}, + labelCol: { + xs: { span: 4 }, + sm: { span: 4 }, }, - wrapperCol:{ - xs: { span : 10}, - sm: { span : 10}, + wrapperCol: { + xs: { span: 10 }, + sm: { span: 10 }, } } - return( + return (
- {getFieldDecorator('cateId',{ - rules:[{ + {getFieldDecorator('cateId', { + rules: [{ required: true, message: '请选择类目' }] })( - 选择类目} /> + this._cateInput = input} + onClick={(e) => { e.preventDefault(); this.handlerChooseCategory() }} + addonAfter={
选择类目
} /> )} + { + this.setState({ cateVisible: false }); + }} + onOk={this.handlerModalOnCateOk} + />
- {getFieldDecorator('name',{ - rules:[{ - required: true, - message: '请输入商品名称' - },{ + {getFieldDecorator('name', { + rules: [{ + required: true, + message: '请输入商品名称' + }, { max: 32, message: '商品名称不能超过32个字符' }], })( - @@ -137,29 +178,80 @@ export default class extends PureComponent{ )} - + { - this.state.isMultiSpec ? - : + this.state.isMultiSpec ? + : } - + - - {getFieldDecorator('stockQuantity')( - + + {getFieldDecorator('stockQuantity',{ + rules:[{ + required: true, + message: '请输入价格及库存' + }] + })( + )} - { - this.setState({ cateVisible: false }); - }} - onOk={this.handlerModalOnCateOk} - />
) } +} + + +/** + * goodsSpec: [{key: '规格名1', value: '规格值'}[,{key: '规格名2', value: '规格值'}]]可以为空 + */ + +export class GoodsStock { + constructor(goodsSpec, stockQuantity, salePrice, sku){ + this.goodsSpec = goodsSpec; + this.stockQuantity = stockQuantity; + this.salePrice = salePrice; + this.sku = sku; + } + + static dealSpecsToGoodsStocks(specs){ + const lenght = specs.length; + + let GoodsStocks = []; + if(lenght ==1){ + const specValues = specs[0].specValues; + specValues.forEach(element => { + GoodsStocks.push(new GoodsStock([{ + key: specs[0].specName, + value: element, + }])); + }); + }else if(lenght == 2) { + const spec1 = specs[0]; + const spec2 = specs[1]; + const specValues1 = spec1.specValues; + const specValues2 = spec2.specValues; + specValues1.forEach(element => { + specValues2.forEach((v)=>{ + let stock = [{ + key: spec1.specName, + value: element + },{ + key: spec2.specName, + value: v + }]; + GoodsStocks.push(new GoodsStock(stock )); + }); + }); + } + return GoodsStocks; + } } \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/Create/StockPrice.js b/antd-ova/src/pages/Goods/Create/StockPrice.js new file mode 100644 index 0000000..36cf10f --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StockPrice.js @@ -0,0 +1,122 @@ +import { PureComponent } from "react"; +import Block from "@/custom/Block"; +import { Table, Input } from "antd"; + + +/** + * completeSpec: [ { + cateId: spec.cateId, + id: spec.id, + specName: spec.specName, + specValues: ['',''] + }] + */ + +export default class extends PureComponent{ + + state={ + GoodsStock: [], + } + + componentWillReceiveProps(newProps){ + this.setState({ + GoodsStock: newProps.GoodsStock, + }) + } + + /** + * index 要改变的第index个元素 + * value 要改变的值,如 {sku: ''} + */ + handerInputOnChange=(index, value)=>{ + let GoodsStock = this.state.GoodsStock; + let current = GoodsStock[index]; + if(!current) current = {}; + current = { + ...current, + ...value + }; + GoodsStock[index] = current; + this.setState({ + GoodsStock: [...GoodsStock] + }) + this.props.onChange({...GoodsStock}) + } + + pickSpecKey(goodsStock){ + let specKey = []; + if(goodsStock.length > 0){ + const goodsSpec = goodsStock[0].goodsSpec; + goodsSpec.forEach((item)=>{ + specKey = [ + ...specKey, + item.key + ] + }); + } + return specKey; + } + + dealGoodsStock(goodsStock){ + const pickSpecKey = this.pickSpecKey(goodsStock); + let columns = []; + if(pickSpecKey.length > 0){ + pickSpecKey.forEach((item, index)=>{ + columns.push({ + title: item, + render:(record)=> {record.goodsSpec[index].value} + }) + }); + } + columns = [ + ...columns, + { + title: 'sku', + dataIndex: 'sku', + render:(text, record,index)=> { + return {this.handerInputOnChange(index, {sku: e.target.value})}}/> + } + },{ + title: '库存', + dataIndex: 'stockQuantity', + render:(text, record,index)=> {this.handerInputOnChange(index, {stockQuantity: e.target.value})}}/> + },{ + title: '销售价(元)', + dataIndex: 'salePrice', + render:(text, record,index)=> {this.handerInputOnChange(index, {salePrice: e.target.value})}}/> + } + ] + return { + columns: columns, + } + } + + render(){ + + const { CompleteSpecs, GoodsStock } = this.props; + const { columns } = this.dealGoodsStock(GoodsStock); + + return( +
+ {/* + + */} +
0 ? GoodsStock : ['']} + pagination={false} + /> + + ) + } +} + +class CustomInput extends React.Component{ + + render(){ + + return( + + ) + } +} \ No newline at end of file diff --git a/antd-ova/src/pages/Goods/models/goods.js b/antd-ova/src/pages/Goods/models/goods.js index 1cf9936..6b4302b 100644 --- a/antd-ova/src/pages/Goods/models/goods.js +++ b/antd-ova/src/pages/Goods/models/goods.js @@ -1,6 +1,9 @@ import { queryCategory, querySpec, + addSpecValue, + deleteSpecValue, + addSpecKey } from '@/services/goods'; export default { @@ -41,6 +44,18 @@ export default { type: 'reducersSpec', payload: response, }) + }, + *addNewSpecValue({payload, callback},{call, put}){ + const response = yield call(addSpecValue, payload); + if(callback) callback(response); + }, + *removeSpecValue({payload, callback}, {call}){ + const response = yield call(deleteSpecValue, payload); + if(callback) callback(response); + }, + *addNewSpecKey({payload, callback}, {call}){ + const response = yield call(addSpecKey, payload); + if(callback) callback(response); } }, reducers: { diff --git a/antd-ova/src/services/goods.js b/antd-ova/src/services/goods.js index cb7674d..93ffa10 100644 --- a/antd-ova/src/services/goods.js +++ b/antd-ova/src/services/goods.js @@ -1,5 +1,6 @@ import request from '@/utils/request'; import qs from 'qs'; +import { async } from 'q'; const API_BASE = "/ova-api"; const CATEGORY_API = API_BASE+ "/seller/category" @@ -14,4 +15,33 @@ export async function queryCategory(params){ export async function querySpec(params){ return request(`${CATEGORY_API}/query_spec?${qs.stringify(params, { indices: false })}`); -} \ No newline at end of file +} + +export async function addSpecValue(params){ + return request(`${CATEGORY_API}/add_spec_value`,{ + method: "POST", + requestType: 'form', + data: { + ...params + } + }) +} +export async function deleteSpecValue(params){ + return request(`${CATEGORY_API}/delete_spec_value`,{ + method: 'DELETE', + requestType: 'form', + data: { + ...params + } + }); +} + +export async function addSpecKey(params){ + return request(`${CATEGORY_API}/add_spec`,{ + method: 'POST', + requestType: 'form', + data: { + ...params + } + }) +} \ No newline at end of file diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java b/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java index 3f6791d..cf7aeb0 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java @@ -11,7 +11,7 @@ import lombok.Data; public class SpecKeyValueBo { private Long cateId; - private Long specId; + private Long id; private String specName; private int nameSort; private String remark; @@ -22,9 +22,9 @@ public class SpecKeyValueBo { public SpecKeyValueBo() { } - public SpecKeyValueBo(Long cateId, Long specId, String specName, int nameSort, String remark, String specValue, int valueSort) { + public SpecKeyValueBo(Long cateId, Long id, String specName, int nameSort, String remark, String specValue, int valueSort) { this.cateId = cateId; - this.specId = specId; + this.id = id; this.specName = specName; this.nameSort = nameSort; this.remark = remark; diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecKeyDao.java b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecKeyDao.java new file mode 100644 index 0000000..4fc2779 --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecKeyDao.java @@ -0,0 +1,17 @@ +package cn.ova.dao.tenant.goods; + +import cn.ova.core.repository.OvaBaseRepository; +import cn.ova.entity.tenant.goods.OvaGoodsSpecKey; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +/** + * @author lijiantao + * @date 2019-11-05 + * @description + */ +public interface OvaGoodsSpecKeyDao extends OvaBaseRepository { + + @Query("FROM OvaGoodsSpecKey WHERE cateId = :cateId AND specName= :specName") + OvaGoodsSpecKey findByCateIdAndSpecName(@Param("cateId") Long cateId, @Param("specName") String specName); +} diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecValueDao.java b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecValueDao.java new file mode 100644 index 0000000..a3ff85e --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsSpecValueDao.java @@ -0,0 +1,18 @@ +package cn.ova.dao.tenant.goods; + +import cn.ova.core.repository.OvaBaseRepository; +import cn.ova.entity.tenant.goods.OvaGoodsSpecValue; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +/** + * @author lijiantao + * @date 2019-11-05 + * @description + */ +public interface OvaGoodsSpecValueDao extends OvaBaseRepository { + + + @Query("FROM OvaGoodsSpecValue WHERE specId = :specId AND specValue = :specValue") + OvaGoodsSpecValue findBySpecIdAndValue(@Param("specId") Long specId , @Param("specValue") String specValue); +} diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java index 22b5cfd..afadd2a 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java @@ -24,6 +24,9 @@ public class OvaGoodsStock extends AbstractEntity { @Column(name = "goods_spec", length = 1024, nullable = false) private String goodsSpec; + @Column(name = "sku", length = 16) + private String sku; + @Column(name = "spec_sort") private int specSort; diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java index a38bd22..af45820 100644 --- a/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java +++ b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java @@ -4,19 +4,19 @@ import cn.ova.bo.SpecKeyValueBo; import cn.ova.core.response.OvaResponse; import cn.ova.core.response.pagination.PaginationData; import cn.ova.dao.tenant.goods.OvaGoodsCategoryDao; -import cn.ova.dto.goods.SpecKeyValueDto; -import cn.ova.dto.goods.SpecValue; +import cn.ova.dao.tenant.goods.OvaGoodsSpecKeyDao; +import cn.ova.dao.tenant.goods.OvaGoodsSpecValueDao; import cn.ova.entity.tenant.goods.OvaGoodsCategory; +import cn.ova.entity.tenant.goods.OvaGoodsSpecKey; +import cn.ova.entity.tenant.goods.OvaGoodsSpecValue; import io.swagger.annotations.Api; import org.apache.shiro.authz.annotation.RequiresRoles; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; /** * @author lijiantao @@ -32,6 +32,12 @@ public class GoodsCategoryRest { @Autowired private OvaGoodsCategoryDao ovaGoodsCategoryDao; + @Autowired + private OvaGoodsSpecValueDao ovaGoodsSpecValueDao; + + @Autowired + private OvaGoodsSpecKeyDao ovaGoodsSpecKeyDao; + @GetMapping("/query_category") public PaginationData queryCategory(Long pid){ @@ -50,4 +56,73 @@ public class GoodsCategoryRest { return OvaResponse.success("执行成功", allSpecKeyValue); } + + @PostMapping("/add_spec_value") + @Transactional(transactionManager = "tenantTransactionManager") + public OvaResponse addSpecValue(Long specId, String specValue){ + + if(specId == null ){ + return OvaResponse.error("参数错误"); + } + if(specId == 0){ + return OvaResponse.error("参数错误"); + } + if(StringUtils.isEmpty(specValue)){ + return OvaResponse.error("参数错误"); + } + + OvaGoodsSpecValue oldSpecValue = ovaGoodsSpecValueDao.findBySpecIdAndValue(specId, specValue); + if(oldSpecValue != null){ + return OvaResponse.error("规格值已存在"); + } + + OvaGoodsSpecValue goodsSpecValue = new OvaGoodsSpecValue(); + goodsSpecValue.setSpecId(specId); + goodsSpecValue.setSpecValue(specValue); + ovaGoodsSpecValueDao.save(goodsSpecValue); + + return OvaResponse.success(); + } + + @DeleteMapping("/delete_spec_value") + @Transactional(transactionManager = "tenantTransactionManager") + public OvaResponse deleteSpecValue(Long specId, String specValue){ + if(specId == null || specId == 0){ + return OvaResponse.error("参数错误"); + } + if(StringUtils.isEmpty(specValue)){ + return OvaResponse.error("参数错误"); + } + + OvaGoodsSpecValue oldSpecValue = ovaGoodsSpecValueDao.findBySpecIdAndValue(specId, specValue); + if(oldSpecValue == null){ + return OvaResponse.success("已删除"); + } + ovaGoodsSpecValueDao.delete(oldSpecValue); + return OvaResponse.success(); + } + + @PostMapping("/add_spec") + @Transactional(transactionManager = "tenantTransactionManager") + public OvaResponse addSpec(Long cateId, String specName){ + if(cateId == null || cateId == 0){ + return OvaResponse.error("参数错误"); + } + if(StringUtils.isEmpty(specName)){ + return OvaResponse.error("参数错误"); + } + + OvaGoodsSpecKey oldSpecKey = ovaGoodsSpecKeyDao.findByCateIdAndSpecName(cateId, specName); + if(oldSpecKey != null){ + return OvaResponse.error("规格已存在"); + } + + OvaGoodsSpecKey specKey= new OvaGoodsSpecKey(); + specKey.setCateId(cateId); + specKey.setSpecName(specName); + + ovaGoodsSpecKeyDao.save(specKey); + + return OvaResponse.success("保存成功", specKey); + } } -- Gitee From 59ae1a538b036d3311fec427343ca8b921eb1f29 Mon Sep 17 00:00:00 2001 From: lijiantao Date: Thu, 21 Nov 2019 18:00:01 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=95=86=E5=93=81=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- antd-ova/src/pages/Goods/Create/MultiSpec.js | 25 ++- antd-ova/src/pages/Goods/Create/StepFirst.js | 144 ++++++++++++------ antd-ova/src/pages/Goods/Create/StockPrice.js | 31 ++-- antd-ova/src/pages/Goods/models/goods.js | 10 +- .../cn/ova/entity/tenant/goods/OvaGoods.java | 6 +- .../java/cn/ova/dto/goods/GoodsCreator.java | 25 +++ 6 files changed, 168 insertions(+), 73 deletions(-) create mode 100644 ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/GoodsCreator.java diff --git a/antd-ova/src/pages/Goods/Create/MultiSpec.js b/antd-ova/src/pages/Goods/Create/MultiSpec.js index 193f285..a29eb1e 100644 --- a/antd-ova/src/pages/Goods/Create/MultiSpec.js +++ b/antd-ova/src/pages/Goods/Create/MultiSpec.js @@ -1,5 +1,5 @@ import { PureComponent } from "react"; -import { Card, Button, Input, AutoComplete, Popover, Tag, Icon } from "antd"; +import { Card, Button, Input, AutoComplete, Popover, Tag, Icon, message } from "antd"; import styles from "../style.less"; @@ -14,10 +14,13 @@ export default class extends PureComponent { state = { completeSpec: [], SpecKeys: [], + isMultiSpec: false, } - componentDidMount() { - const { Spec } = this.props; + componentWillReceiveProps(newProps) { + const { Spec, completeSpec } = newProps; + const oldcompleteSpec = this.state.completeSpec; + let isMultiSpec = false; let SpecKeys = []; let specValues = []; Spec.forEach(element => { @@ -35,13 +38,27 @@ export default class extends PureComponent { ] }); }); + if(completeSpec && completeSpec.length > 0){ + isMultiSpec=true; + } + this.setState({ SpecKeys: [ ...SpecKeys ], + completeSpec: [...completeSpec], + isMultiSpec: isMultiSpec, }) } + handlerSpecVisible=()=>{ + const { cateId } = this.props; + if(!cateId){ + return message.error('请选择商品类目'); + } + this.setState({ isMultiSpec: true }); + } + //取出规格分类 pickSpecKey(spec, completeSpec) { let result = []; @@ -236,10 +253,12 @@ export default class extends PureComponent { render() { return ( + this.state.isMultiSpec ? {this.renderCompleteSpecItem()} {this.renderAutoComplete()} + : ) } } diff --git a/antd-ova/src/pages/Goods/Create/StepFirst.js b/antd-ova/src/pages/Goods/Create/StepFirst.js index 09df4d1..1cdc209 100644 --- a/antd-ova/src/pages/Goods/Create/StepFirst.js +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -22,19 +22,28 @@ export default class extends PureComponent { cateVisible: false, selectCate: {}, //已选择的类目 countName: 0, - isMultiSpec: false, cateId: 0, completeSpec:[], + goodsStock: [], + GoodsCreator:{ + } } componentDidMount() { - const { dispatch } = this.props; + const { dispatch, goods: {GoodsCreator} } = this.props; + dispatch({ type: 'goods/fetchCategory', payload: { pid: 0 } - }) + }); + this.pickCompleteSpecByStock(GoodsCreator); + this.setState({GoodsCreator: GoodsCreator}); + } + + componentWillReceiveProps(newProps){ + } fetchCategory = (pid) => { @@ -49,15 +58,17 @@ export default class extends PureComponent { handlerSubmit = (success, error) => { const { form, dispatch } = this.props; + const { GoodsCreator } = this.state; form.validateFields((err, fieldValues) => { - // if(err){ - // return error(); - // } - // dispatch({ - // type: 'goods/fillGoodsCreator', - // payload: {...fieldValues} - // }) + if(err){ + return error(); + } + + dispatch({ + type: 'goods/fillGoodsCreator', + payload: {...GoodsCreator, ...fieldValues} + }) success(); }); } @@ -79,11 +90,13 @@ export default class extends PureComponent { } }); - let cateIdValue = `${selectKeys.pCate.name} - ${selectKeys.cCate.name}`; + let cateName = `${selectKeys.pCate.name} - ${selectKeys.cCate.name}`; setFieldsValue({ - cateId: cateIdValue + cateName: cateName }); - this.setState({ cateId: cateId }); + const {GoodsCreator} = this.state; + + this.setState({ GoodsCreator: { ...GoodsCreator, cateId: cateId} }); } handlerNameOnChange = (e) => { @@ -98,30 +111,71 @@ export default class extends PureComponent { if(index != -1){ value.splice(index, 1); } - this.setState({completeSpec:[...value]}); - } - } + const { GoodsCreator } = this.state; + this.setState({completeSpec:[...value], GoodsCreator: { ...GoodsCreator, goodsStock: GoodsStock.dealSpecsToGoodsStocks(value)}}); - handlerSpecVisible=()=>{ - const { form: { getFieldValue } } = this.props; - const cateId = getFieldValue("cateId"); - if(!cateId){ - return message.error('请选择商品类目'); } - this.setState({ isMultiSpec: true }); } - dealSpecsToGoodsStocks=()=>{ - const { completeSpec } = this.state; - return GoodsStock.dealSpecsToGoodsStocks(completeSpec); + pickCompleteSpecByStock(goodsCreator){ + + let completeSpec = []; + const {goodsStock, cateId} = goodsCreator; + + console.log(cateId); + goodsStock.forEach((ele)=>{ + if(ele.goodsSpec){ + const goodsSpec =ele.goodsSpec; + goodsSpec.forEach((v)=>{ + console.log(v); + let index = completeSpec.findIndex((i)=> i.specName == v.key); + if(index >= 0){ + let specValues = completeSpec[index].specValues; + if(!specValues.some((va)=> va == v.value)){ + specValues.push(v.value); + } + }else { + completeSpec.push({ + cateId: cateId, + id: v.id, + specName: v.key, + specValues: [v.value] + }) + } + + }); + } + }); + console.log(completeSpec); + this.setState({completeSpec: completeSpec}); } + handlerStockPriceOnchange=(goodsStock)=>{ - console.log(goodsStock); + const { GoodsCreator } = this.state; + this.setState({GoodsCreator: {...GoodsCreator, goodsStock: goodsStock}}); + } + + stockPriceValidator=(rule, value, callback)=>{ + if(!value){ return callback("请输入价格及库存");} + for(let i= 0; i< value.length; i++){ + const current = value[i]; + if(!current.salePrice){ + return callback("销售价格不能为空"); + } + if(!current.stockQuantity){ + return callback("库存不能为空"); + } + } + return callback(); + } render() { const { form: { getFieldDecorator }, goods: { Category, Spec } } = this.props; + + const { GoodsCreator} = this.state; + const formItemLayout = { labelCol: { xs: { span: 4 }, @@ -136,11 +190,12 @@ export default class extends PureComponent {
- {getFieldDecorator('cateId', { + {getFieldDecorator('cateName', { rules: [{ required: true, message: '请选择类目' - }] + }], + initialValue: GoodsCreator.cateName, })( this._cateInput = input} @@ -166,6 +221,7 @@ export default class extends PureComponent { max: 32, message: '商品名称不能超过32个字符' }], + initialValue: GoodsCreator.name })( - {getFieldDecorator('spu')( + {getFieldDecorator('spu',{ + initialValue: GoodsCreator.spu + })( )} - { - this.state.isMultiSpec ? - : - } - + - {getFieldDecorator('stockQuantity',{ + {getFieldDecorator('goodsStock',{ rules:[{ - required: true, - message: '请输入价格及库存' + validator: this.stockPriceValidator, }] })( )} @@ -211,7 +264,7 @@ export default class extends PureComponent { /** - * goodsSpec: [{key: '规格名1', value: '规格值'}[,{key: '规格名2', value: '规格值'}]]可以为空 + * goodsSpec: [{id: 1, key: '规格名1', value: '规格值'}[,{id: 1, key: '规格名2', value: '规格值'}]]可以为空 */ export class GoodsStock { @@ -230,6 +283,7 @@ export class GoodsStock { const specValues = specs[0].specValues; specValues.forEach(element => { GoodsStocks.push(new GoodsStock([{ + id: specs[0].id, key: specs[0].specName, value: element, }])); @@ -242,9 +296,11 @@ export class GoodsStock { specValues1.forEach(element => { specValues2.forEach((v)=>{ let stock = [{ + id: spec2.id, key: spec1.specName, value: element },{ + id: spec2.id, key: spec2.specName, value: v }]; diff --git a/antd-ova/src/pages/Goods/Create/StockPrice.js b/antd-ova/src/pages/Goods/Create/StockPrice.js index 36cf10f..15ee099 100644 --- a/antd-ova/src/pages/Goods/Create/StockPrice.js +++ b/antd-ova/src/pages/Goods/Create/StockPrice.js @@ -1,6 +1,6 @@ import { PureComponent } from "react"; import Block from "@/custom/Block"; -import { Table, Input } from "antd"; +import { Table, Input, InputNumber } from "antd"; /** @@ -40,19 +40,22 @@ export default class extends PureComponent{ this.setState({ GoodsStock: [...GoodsStock] }) - this.props.onChange({...GoodsStock}) + this.props.onChange(GoodsStock); } pickSpecKey(goodsStock){ let specKey = []; + if(!goodsStock) return specKey; if(goodsStock.length > 0){ const goodsSpec = goodsStock[0].goodsSpec; - goodsSpec.forEach((item)=>{ - specKey = [ - ...specKey, - item.key - ] - }); + if(goodsSpec){ + goodsSpec.forEach((item)=>{ + specKey = [ + ...specKey, + item.key + ] + }); + } } return specKey; } @@ -74,16 +77,17 @@ export default class extends PureComponent{ title: 'sku', dataIndex: 'sku', render:(text, record,index)=> { + console.log(text); return {this.handerInputOnChange(index, {sku: e.target.value})}}/> } },{ title: '库存', dataIndex: 'stockQuantity', - render:(text, record,index)=> {this.handerInputOnChange(index, {stockQuantity: e.target.value})}}/> + render:(text, record,index)=> {this.handerInputOnChange(index, {stockQuantity: v})}}/> },{ title: '销售价(元)', dataIndex: 'salePrice', - render:(text, record,index)=> {this.handerInputOnChange(index, {salePrice: e.target.value})}}/> + render:(text, record,index)=> {this.handerInputOnChange(index, {salePrice: v})}}/> } ] return { @@ -93,17 +97,14 @@ export default class extends PureComponent{ render(){ - const { CompleteSpecs, GoodsStock } = this.props; + const { GoodsStock } = this.props; const { columns } = this.dealGoodsStock(GoodsStock); return(
- {/* - - */}
0 ? GoodsStock : ['']} + dataSource={GoodsStock && GoodsStock.length >0 ? GoodsStock : ['']} pagination={false} /> diff --git a/antd-ova/src/pages/Goods/models/goods.js b/antd-ova/src/pages/Goods/models/goods.js index 6b4302b..917bb62 100644 --- a/antd-ova/src/pages/Goods/models/goods.js +++ b/antd-ova/src/pages/Goods/models/goods.js @@ -10,7 +10,7 @@ export default { namespace: "goods", state: { GoodsCreator: { - + goodsStock:[], }, Category: { childs:[] @@ -18,12 +18,6 @@ export default { Spec:[] }, effects: { - *fillGoodsCreator({payload}, {put}){ - yield put({ - type: 'reducersGoodsCreator', - payload: payload - }) - }, *fetchCategory({payload},{call, put}){ const response = yield call(queryCategory, payload); yield put({ @@ -59,7 +53,7 @@ export default { } }, reducers: { - reducersGoodsCreator(state, action){ + fillGoodsCreator(state, action){ return { ...state, GoodsCreator: { diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java index 56e0019..0b9311a 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java @@ -20,10 +20,10 @@ import java.math.BigDecimal; @Entity public class OvaGoods extends AbstractEntity { - //新的iPhoneXS就是一个SPU,而红色iPhoneXS就是一个SKU + //新的iPhoneXS就是一个SPU,而红色iPhoneXS就是一个SKU, sku 放到Stock表中 - @Column(name = "sku", length = 64) - private String sku; +// @Column(name = "sku", length = 64) +// private String sku; private String spu; diff --git a/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/GoodsCreator.java b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/GoodsCreator.java new file mode 100644 index 0000000..40090b8 --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/dto/goods/GoodsCreator.java @@ -0,0 +1,25 @@ +package cn.ova.dto.goods; + +import cn.ova.entity.tenant.goods.OvaGoodsStock; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * @author lijiantao + * @date 2019-11-18 + * @description + */ +@Data +public class GoodsCreator { + private Long goodsId; + private Long cateId; + private String cateName; //由父分类和子分类拼接 比如 鞋类 - 男鞋 + private String name; + private String detail; + private String img; + private BigDecimal stockQuantity; + + private List stocks; //OvaGoodsStock +} -- Gitee From 9d7d0c0f2ac7b74688c8ba106bafaf24dac3b8fa Mon Sep 17 00:00:00 2001 From: meng <154040976@qq.com> Date: Mon, 9 Dec 2019 23:06:24 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E9=A6=96=E9=A1=B5=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=E9=83=A8=E5=88=86=E7=BC=96=E5=86=99=EF=BC=8C?= =?UTF-8?q?=E7=A7=9F=E6=88=B7=E8=8E=B7=E5=8F=96jdbcTemlpate=20=E5=8F=AF?= =?UTF-8?q?=E9=80=9A=E8=BF=87OvaJdbcTemplate.get();=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E5=B0=8F=E7=A8=8B=E5=BA=8F=E6=97=A0?= =?UTF-8?q?=E9=9C=80=E6=9D=83=E9=99=90=E6=8B=A6=E6=88=AA=E8=BF=87=E6=BB=A4?= =?UTF-8?q?=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/tenant/goods/OvaGoodsLabel.java | 24 ++-- .../java/cn/ova/util/OvaJdbcTemplate.java | 22 ++++ .../src/main/java/cn/ova/init/InitData.java | 2 + .../ova/config/jpa/MasterDatabaseConfig.java | 6 + .../config/jpa/TenantDataSourceConfig.java | 2 +- .../ova/config/shiro/OvaApiWechatFilter.java | 52 ++++++++ .../ova/config/shiro/ShiroConfiguration.java | 6 + .../java/cn/ova/service/ApiGoodsService.java | 29 +++++ .../ova/service/impl/ApiGoodsServiceImpl.java | 62 ++++++++++ .../src/main/java/cn/ova/vo/GoodsVo.java | 112 ++++++++++++++++++ .../main/java/cn/ova/web/ApiIndexRest.java | 31 +++++ 11 files changed, 339 insertions(+), 9 deletions(-) create mode 100644 ova-boot/ova-dao/src/main/java/cn/ova/util/OvaJdbcTemplate.java create mode 100644 ova-boot/ova-web/src/main/java/cn/ova/config/shiro/OvaApiWechatFilter.java create mode 100644 ova-boot/ova-wechat/src/main/java/cn/ova/service/ApiGoodsService.java create mode 100644 ova-boot/ova-wechat/src/main/java/cn/ova/service/impl/ApiGoodsServiceImpl.java create mode 100644 ova-boot/ova-wechat/src/main/java/cn/ova/vo/GoodsVo.java create mode 100644 ova-boot/ova-wechat/src/main/java/cn/ova/web/ApiIndexRest.java diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsLabel.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsLabel.java index a8ba42e..57ab0b7 100644 --- a/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsLabel.java +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsLabel.java @@ -1,5 +1,6 @@ package cn.ova.entity.tenant.goods; +import cn.ova.core.base.AbstractEntity; import lombok.Data; import javax.persistence.*; @@ -12,16 +13,23 @@ import javax.persistence.*; @Data @Table(name = "ova_goods_label") @Entity -public class OvaGoodsLabel { +public class OvaGoodsLabel extends AbstractEntity { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "id", nullable = false) - private Long id; + /** + * 标签名称id 关联dict id + */ + @Column(name = "dict_id", length = 20, nullable = false) + private String dictId; + + /** + * 商品id + */ + @Column(name = "goods_id", length = 20, nullable = false) + private Long goodsId; /** - * 标签名称 + * 是否展示到小程序首页 */ - @Column(name = "la_name", length = 16, nullable = false) - private String laName; + @Column(name = "is_show", length = 16, nullable = false) + private String isShow; } diff --git a/ova-boot/ova-dao/src/main/java/cn/ova/util/OvaJdbcTemplate.java b/ova-boot/ova-dao/src/main/java/cn/ova/util/OvaJdbcTemplate.java new file mode 100644 index 0000000..b42d01f --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/util/OvaJdbcTemplate.java @@ -0,0 +1,22 @@ +package cn.ova.util; + +import cn.ova.config.DataSourceCache; +import cn.ova.core.util.TenantContextHolder; +import org.springframework.jdbc.core.JdbcTemplate; + +import javax.sql.DataSource; + +/** + * @author zxm + * @date 2019-12-09. + *

+ * 获取当前线程下jdbctemplate + */ +public class OvaJdbcTemplate { + + public static JdbcTemplate get() { + DataSource dataSource = DataSourceCache.dataSourceMap.get(TenantContextHolder.getTenant()); + return new JdbcTemplate(dataSource); + } + +} diff --git a/ova-boot/ova-root/src/main/java/cn/ova/init/InitData.java b/ova-boot/ova-root/src/main/java/cn/ova/init/InitData.java index b4cd637..1437335 100644 --- a/ova-boot/ova-root/src/main/java/cn/ova/init/InitData.java +++ b/ova-boot/ova-root/src/main/java/cn/ova/init/InitData.java @@ -3,6 +3,7 @@ package cn.ova.init; import cn.ova.core.util.Address; import cn.ova.core.util.AddressCache; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.CommandLineRunner; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; @@ -20,6 +21,7 @@ import java.util.stream.Collectors; @Component public class InitData implements CommandLineRunner { @Autowired + @Qualifier("masterJdbcTemplate") JdbcTemplate template; @Override diff --git a/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/MasterDatabaseConfig.java b/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/MasterDatabaseConfig.java index 5816f49..93308c9 100644 --- a/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/MasterDatabaseConfig.java +++ b/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/MasterDatabaseConfig.java @@ -13,6 +13,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -91,4 +92,9 @@ public class MasterDatabaseConfig { properties.put(Environment.HBM2DDL_AUTO, "update"); return properties; } + + @Bean("masterJdbcTemplate") + public JdbcTemplate template() { + return new JdbcTemplate(masterDatasource()); + } } \ No newline at end of file diff --git a/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/TenantDataSourceConfig.java b/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/TenantDataSourceConfig.java index 6a10d74..3651301 100644 --- a/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/TenantDataSourceConfig.java +++ b/ova-boot/ova-web/src/main/java/cn/ova/config/jpa/TenantDataSourceConfig.java @@ -8,7 +8,6 @@ import org.hibernate.MultiTenancyStrategy; import org.hibernate.cfg.Environment; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -54,6 +53,7 @@ public class TenantDataSourceConfig { return new MultiTenantConnectionProvider(); } + @Bean(name = "currentTenantIdentifierResolver") public CurrentTenantIdentifierResolver currentTenantIdentifierResolver() { return new OvaCurrentTenantIdentifierResolver(); diff --git a/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/OvaApiWechatFilter.java b/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/OvaApiWechatFilter.java new file mode 100644 index 0000000..b7ea6d4 --- /dev/null +++ b/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/OvaApiWechatFilter.java @@ -0,0 +1,52 @@ +package cn.ova.config.shiro; + +import cn.ova.core.shiro.LoginType; +import cn.ova.core.shiro.OvaUserToken; +import cn.ova.core.util.TenantContextHolder; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +/** + * @author zxm + * @date 2019-09-07. + * 拦截小程序用户标识 + */ +@Slf4j +public class OvaApiWechatFilter extends BasicHttpAuthenticationFilter { + @Override + protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, + Object o) { + + try { + String tenant = ((HttpServletRequest) servletRequest).getHeader("tenant"); + if (!StringUtils.isEmpty(tenant)) { + //设置租户数据源 + TenantContextHolder.setTenant(tenant); + return true; + } + } catch (Exception ignored) { + //无需打印 + } + return false; + } + + /** + * token校验失败时,转发到login,返回1401 代表未登录状态 + * + * @param request + * @param response + * @return + * @throws Exception + */ + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + //之所以转发到login 是因为小程序解析我们自定义的1402异常,来判定未登录状态 + request.getRequestDispatcher("/login").forward(request, response); + return false; + } +} diff --git a/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/ShiroConfiguration.java b/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/ShiroConfiguration.java index 2d7c9a5..a43b778 100644 --- a/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/ShiroConfiguration.java +++ b/ova-boot/ova-web/src/main/java/cn/ova/config/shiro/ShiroConfiguration.java @@ -106,6 +106,7 @@ public class ShiroConfiguration { Map filters = new HashMap<>(); filters.put("seller", ovaSellerFilter()); filters.put("wechat", ovaWechatFilter()); + filters.put("apiWechat", ovaApiWechatFilter()); filters.put("root", ovaRootFilter()); shiroFilterFactory.setFilters(filters); @@ -125,6 +126,7 @@ public class ShiroConfiguration { //拦截小程序登录后操作 filterMap.put("/w/**", "wechat,authc"); filterMap.put("/w/login", "anon"); + filterMap.put("/api/**", "apiWechat"); //用户预览放行 // filterMap.put("/o/**", "anon"); @@ -181,6 +183,10 @@ public class ShiroConfiguration { return new OvaWechatFilter(); } + public OvaApiWechatFilter ovaApiWechatFilter() { + return new OvaApiWechatFilter(); + } + /** * 超管请求拦截 * diff --git a/ova-boot/ova-wechat/src/main/java/cn/ova/service/ApiGoodsService.java b/ova-boot/ova-wechat/src/main/java/cn/ova/service/ApiGoodsService.java new file mode 100644 index 0000000..1917b42 --- /dev/null +++ b/ova-boot/ova-wechat/src/main/java/cn/ova/service/ApiGoodsService.java @@ -0,0 +1,29 @@ +package cn.ova.service; + +import cn.ova.core.util.Page; +import cn.ova.vo.GoodsVo; + +import java.util.List; +import java.util.Map; + +/** + * @author zxm + * @date 2019-12-08. + */ +public interface ApiGoodsService { + + + /** + * 标签分组商品 + * + * @return + */ + Map> goodsLabel(int labelNum, int goodsNum); + + /** + * 商品列表 + * + * @return list + */ + List goodsList(Page page); +} diff --git a/ova-boot/ova-wechat/src/main/java/cn/ova/service/impl/ApiGoodsServiceImpl.java b/ova-boot/ova-wechat/src/main/java/cn/ova/service/impl/ApiGoodsServiceImpl.java new file mode 100644 index 0000000..0425d5f --- /dev/null +++ b/ova-boot/ova-wechat/src/main/java/cn/ova/service/impl/ApiGoodsServiceImpl.java @@ -0,0 +1,62 @@ +package cn.ova.service.impl; + +import cn.ova.core.util.Page; +import cn.ova.dao.tenant.goods.OvaGoodsDao; +import cn.ova.dao.tenant.goods.OvaSaleGoodsDao; +import cn.ova.entity.tenant.goods.OvaGoods; +import cn.ova.entity.tenant.goods.OvaSaleGoods; +import cn.ova.service.ApiGoodsService; +import cn.ova.util.OvaJdbcTemplate; +import cn.ova.vo.GoodsVo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author zxm + * @date 2019-12-08. + * 主页业务 + */ +@Service +public class ApiGoodsServiceImpl implements ApiGoodsService { + + @Autowired + OvaGoodsDao goodsDao; + @Autowired + OvaSaleGoodsDao ovaSaleGoodsDao; + + /** + * 标签查询 逻辑需要讨论 + * + * @param labelNum 标签数量 + * @param goodsNum 商品数量 + * @return 商品列表 key 标签名称 value 商品列表 + */ + @Override + public Map> goodsLabel(int labelNum, int goodsNum) { + + JdbcTemplate jdbcTemplate = OvaJdbcTemplate.get(); + StringBuffer sql = new StringBuffer(); + sql.append("select label.goods_id goodsId,dict.dict_name dictName from ova_goods_label label left join ova_dict dict ") + .append(" on label.dict_id=dict.id ") + .append(" order by label.created "); + List> maps = jdbcTemplate.queryForList(sql.toString()); + Set goodsId = maps.stream(). + map(s -> Long.valueOf(s.get("goodsId").toString())).collect(Collectors.toSet()); + List ovaGoodsovaGoods = goodsDao.findAllById(new ArrayList<>(goodsId)); + List ovaSaleGoods = ovaSaleGoodsDao.findAllById(new ArrayList<>(goodsId)); + System.out.println(maps); + return null; + } + + @Override + public List goodsList(Page page) { + return null; + } +} diff --git a/ova-boot/ova-wechat/src/main/java/cn/ova/vo/GoodsVo.java b/ova-boot/ova-wechat/src/main/java/cn/ova/vo/GoodsVo.java new file mode 100644 index 0000000..862d201 --- /dev/null +++ b/ova-boot/ova-wechat/src/main/java/cn/ova/vo/GoodsVo.java @@ -0,0 +1,112 @@ +package cn.ova.vo; + +import lombok.Data; + +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * @author zxm + * @date 2019-12-08. + * 商品展示vo + */ +@Data +public class GoodsVo { + + private String goodsId; + + private String sku; + + private String name; + + private String detail; + + private String img; + /** + * 总库存 + */ + private BigDecimal stock_quantity; + /** + * 0 正常 1删除 + */ + private Byte status; + + private String orderNum; + + private Byte sellType; + + /** + * 价格 + */ + private BigDecimal salePrice; + + /** + * 积分价格 + */ + private int intePrice; + + /** + * 赠送积分 + */ + private int giveInte; + + /** + * 当前库存 + */ + private BigDecimal stockQuantity; + + /** + * 当前库存 + */ + private BigDecimal soldQuantity; + + /** + * 冻结库存 + */ + private BigDecimal frozenQuantity; + + /** + * 上架有效期 + */ + private Timestamp validDate; + + /** + * 预约时间 + */ + private Timestamp meetDate; + + /** + * 是否支持退货 0 支持 1不支持 + */ + private Byte isRefund; + + /** + * 1 上架 2 下架 3 删除 + */ + private Byte saleStatus; + + /** + * 备注 + */ + private String remark; + + /** + * 点击率 + */ + private int pv; + + /** + * 0 商家配送 1 用户自提 + */ + private Byte distType; + + /** + * 商品标签 + */ + private Long labelId; + + /** + * 商品类型 0 普通 1 预约 + */ + private Byte gtype; +} diff --git a/ova-boot/ova-wechat/src/main/java/cn/ova/web/ApiIndexRest.java b/ova-boot/ova-wechat/src/main/java/cn/ova/web/ApiIndexRest.java new file mode 100644 index 0000000..d617c67 --- /dev/null +++ b/ova-boot/ova-wechat/src/main/java/cn/ova/web/ApiIndexRest.java @@ -0,0 +1,31 @@ +package cn.ova.web; + +import cn.ova.core.response.OvaResponse; +import cn.ova.service.ApiGoodsService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @author zxm + * @date 2019-12-08. + * 主页信息 + */ +@RestController +@RequestMapping("/api") +public class ApiIndexRest { + @Autowired + ApiGoodsService goodsService; + + /** + * 主页信息 banner/热门。。。/列表 + * + * @return OvaResponse + */ + @GetMapping("/label") + public OvaResponse index() { + goodsService.goodsLabel(2,4); + return new OvaResponse(); + } +} -- Gitee