diff --git a/antd-ova/config/router.config.js b/antd-ova/config/router.config.js index ca35b49c37225b2bf6494c562de1e296eb5bf6c8..ebd0b69c64d4043a51a189acba4ffcfafc3fc1b2 100644 --- a/antd-ova/config/router.config.js +++ b/antd-ova/config/router.config.js @@ -39,23 +39,32 @@ export default [ },{ path: '/system/role/add/:id', component: './System/Role/edit/Index' - } - ] - },{ - path: '/seller', - name: 'seller', - routes:[ - { - path:'/seller/member', - name: 'member', - component: './Seller/Member/Index' - }, + },{ + path: '/goods', + name: "goods", + routes: [ { - path:'/seller/member/:id', - name: 'member.detail', - hideInMenu: 'true', - component: './Seller/Member/Detail' - } + path:'/goods/list', + name: 'goodslist', + component: "./Goods/List", + },{ + path: '/goods/create', + component: './Goods/Create', + },{ + path: '/seller', + name: 'seller', + routes:[ + { + path:'/seller/member', + name: 'member', + component: './Seller/Member/Index' + }, + { + path:'/seller/member/:id', + name: 'member.detail', + hideInMenu: 'true', + component: './Seller/Member/Detail' + } ] }, { diff --git a/antd-ova/package.json b/antd-ova/package.json index 50f3160fd30a7dce0ac1b5af247a10151d720857..5261bc12f806c2f05f83cfb66776c68d6a3110e3 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/OvaConfig.js b/antd-ova/src/OvaConfig.js index 6c6db6c5a09de46214496a67799292c8539fabda..fd338de0f0d86ef0e4b2d567308b5e1bb92e72ad 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/custom/BraftEditor.js b/antd-ova/src/custom/BraftEditor.js new file mode 100644 index 0000000000000000000000000000000000000000..8b4796cfedb53f862ac8c1a2ad0b8eb655705782 --- /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 0000000000000000000000000000000000000000..aea4a1f060346e8a8c8ddcc9ddf7dff534542555 --- /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/locales/zh-CN/menu.js b/antd-ova/src/locales/zh-CN/menu.js index 341c2f0014bd0c7fd8803706572b378af561abb7..c0b86371e3a5285b790131af02121548d0eb6704 100644 --- a/antd-ova/src/locales/zh-CN/menu.js +++ b/antd-ova/src/locales/zh-CN/menu.js @@ -4,7 +4,8 @@ export default { 'menu.system.operator': '操作员管理', 'menu.system.role': '角色管理', 'menu.account.center': '个人中心', - + 'menu.goods':'商品管理', + 'menu.goods.goodslist':'全部商品', 'menu.seller': '会员管理', 'menu.seller.member': '会员查询', 'menu.seller.member.detail': '会员详情', diff --git a/antd-ova/src/models/login.js b/antd-ova/src/models/login.js index 88f772aee5f379a7b828581a9266956914bb9c1a..b78a76c0bc85795e1f711c3b338d257bda602d74 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 0000000000000000000000000000000000000000..ecc379cd9f98dde002261ecef3aa2689487778a0 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create.js @@ -0,0 +1,88 @@ +import { PureComponent, Fragment } from "react"; +import PageHeaderWrapper from "@/components/PageHeaderWrapper"; +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: , +},{ + 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(){ + + return + + + + {CreateStep.map((value)=>)} + + + {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 0000000000000000000000000000000000000000..89098f136e2c75338773e00f2120e74db910d4d2 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/ChooseCate.js @@ -0,0 +1,149 @@ +import { PureComponent } from "react"; + +import styles from "../style.less"; +import { Table, Row, Col, Modal, message } 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=()=>{ + + 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(); + } + + 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/MultiSpec.js b/antd-ova/src/pages/Goods/Create/MultiSpec.js new file mode 100644 index 0000000000000000000000000000000000000000..a29eb1e0c8e51afd49eadcbe60318ee875d10924 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/MultiSpec.js @@ -0,0 +1,350 @@ +import { PureComponent } from "react"; +import { Card, Button, Input, AutoComplete, Popover, Tag, Icon, message } from "antd"; + +import styles from "../style.less"; + +const { CheckableTag } = Tag; + +/** + * SpecKeys { cateId, id, specName, remark, specValues } + */ + +export default class extends PureComponent { + + state = { + completeSpec: [], + SpecKeys: [], + isMultiSpec: false, + } + + componentWillReceiveProps(newProps) { + const { Spec, completeSpec } = newProps; + const oldcompleteSpec = this.state.completeSpec; + let isMultiSpec = false; + let SpecKeys = []; + let specValues = []; + Spec.forEach(element => { + 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, + id: element.id, + specName: element.specName, + remark: element.remark, + specValues: [ + element.specValue + ] + }); + }); + 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 = []; + 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.id == element.id)) { + result.push(element); + } + }); + return result; + } + + 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 }); + } + + /** + * 如果已选择就删除,如果未选择就保存 + */ + 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(); + } + } + }) + } + + 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); + } + } + }); + } + + 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); + } + + renderCompleteSpecItem = () => { + const { completeSpec, SpecKeys } = this.state; + + return completeSpec.map((item, index) => { + + return + }); + } + + + + handlerAutoCompleteOnSelect = (value, option) => { + const Spec = this.state.SpecKeys; + let SpceItem = Spec.find((item) => { + return item.specName == value + }); + this._appendCompleteSpec(SpceItem); + } + + _appendCompleteSpec(spec){ + let completeSpec = this.state.completeSpec; + this.setState({ + completeSpec: [...completeSpec, { + cateId: spec.cateId, + id: spec.id, + specName: spec.specName, + specValues: [] + }] + }) + } + + handlerAddSpecKey=()=>{ + + const specName = this._specInput.state.value; + const {dispatch , cateId} = this.props; + + 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); + } + + renderAutoComplete(){ + const { completeSpec } = this.state; + if(completeSpec.length >= 2){ + return null; + } + return ( + + this._specInput = input} + addonAfter={
新增
} /> +
+ ) + + } + + render() { + + return ( + this.state.isMultiSpec ? + + {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} + }) + } +
+ + + +
+ ) + } +} \ 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 0000000000000000000000000000000000000000..1cdc209e42c9a4b86b3d3b78b419139be9ea9a52 --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepFirst.js @@ -0,0 +1,313 @@ +import { PureComponent } from "react"; +import { Card, Form, Input, Button, Modal, Radio, message } from "antd"; + +import styles from "../style.less"; +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 }) => ({ + goods, +})) +@Form.create() +export default class extends PureComponent { + + state = { + cateVisible: false, + selectCate: {}, //已选择的类目 + countName: 0, + cateId: 0, + completeSpec:[], + goodsStock: [], + GoodsCreator:{ + } + } + + componentDidMount() { + const { dispatch, goods: {GoodsCreator} } = this.props; + + dispatch({ + type: 'goods/fetchCategory', + payload: { + pid: 0 + } + }); + this.pickCompleteSpecByStock(GoodsCreator); + this.setState({GoodsCreator: GoodsCreator}); + } + + componentWillReceiveProps(newProps){ + + } + + fetchCategory = (pid) => { + const { dispatch } = this.props; + dispatch({ + type: 'goods/fetchCategoryChild', + payload: { + pid: pid + } + }) + } + + 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: {...GoodsCreator, ...fieldValues} + }) + success(); + }); + } + + handlerChooseCategory = () => { + this._cateInput.blur(); + this.setState({ cateVisible: true }) + } + + handlerModalOnCateOk = (selectKeys) => { + const { form: { setFieldsValue }, dispatch } = this.props; + + //根据商品类目获取规格信息 + const cateId = selectKeys.cCate.id; + dispatch({ + type: 'goods/fetchSpec', + payload: { + cateId: cateId + } + }); + + let cateName = `${selectKeys.pCate.name} - ${selectKeys.cCate.name}`; + setFieldsValue({ + cateName: cateName + }); + const {GoodsCreator} = this.state; + + this.setState({ GoodsCreator: { ...GoodsCreator, cateId: cateId} }); + } + + handlerNameOnChange = (e) => { + const { value } = e.target; + this.setState({ countName: value.length }); + } + + handlerMultiSpecOnChange = (value) => { + if(value){ + //如果value中某一项的specValues为空,删掉 + const index = value.findIndex((ele)=> ele.specValues.length == 0); + if(index != -1){ + value.splice(index, 1); + } + const { GoodsCreator } = this.state; + this.setState({completeSpec:[...value], GoodsCreator: { ...GoodsCreator, goodsStock: GoodsStock.dealSpecsToGoodsStocks(value)}}); + + } + } + + 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)=>{ + 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 }, + sm: { span: 4 }, + }, + wrapperCol: { + xs: { span: 10 }, + sm: { span: 10 }, + } + } + return ( + +
+ + {getFieldDecorator('cateName', { + rules: [{ + required: true, + message: '请选择类目' + }], + initialValue: GoodsCreator.cateName, + })( + this._cateInput = input} + onClick={(e) => { e.preventDefault(); this.handlerChooseCategory() }} + addonAfter={
选择类目
} /> + )} + { + this.setState({ cateVisible: false }); + }} + onOk={this.handlerModalOnCateOk} + /> +
+ + {getFieldDecorator('name', { + rules: [{ + required: true, + message: '请输入商品名称' + }, { + max: 32, + message: '商品名称不能超过32个字符' + }], + initialValue: GoodsCreator.name + })( + + )} + + + {getFieldDecorator('spu',{ + initialValue: GoodsCreator.spu + })( + + )} + + + + + + {getFieldDecorator('goodsStock',{ + rules:[{ + validator: this.stockPriceValidator, + }] + })( + + )} + + +
+ ) + } +} + + +/** + * goodsSpec: [{id: 1, key: '规格名1', value: '规格值'}[,{id: 1, 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([{ + id: specs[0].id, + 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 = [{ + id: spec2.id, + key: spec1.specName, + value: element + },{ + id: spec2.id, + 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/StepSecond.js b/antd-ova/src/pages/Goods/Create/StepSecond.js new file mode 100644 index 0000000000000000000000000000000000000000..d1af0aee2bd149d8956a72c6a566cbee0a63622b --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StepSecond.js @@ -0,0 +1,75 @@ +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, getFieldDecorator}} = this.props; + + return( + +
+ + + + + {getFieldDecorator('img')( + + )} + + + {/* { + 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 0000000000000000000000000000000000000000..4bd6f11c2ed1d7b4546339a2f4d51c125d97a2ce --- /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/StockPrice.js b/antd-ova/src/pages/Goods/Create/StockPrice.js new file mode 100644 index 0000000000000000000000000000000000000000..15ee0991bd203f27b451abb679f0c214e42936ba --- /dev/null +++ b/antd-ova/src/pages/Goods/Create/StockPrice.js @@ -0,0 +1,123 @@ +import { PureComponent } from "react"; +import Block from "@/custom/Block"; +import { Table, Input, InputNumber } 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) return specKey; + if(goodsStock.length > 0){ + const goodsSpec = goodsStock[0].goodsSpec; + if(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)=> { + console.log(text); + return {this.handerInputOnChange(index, {sku: e.target.value})}}/> + } + },{ + title: '库存', + dataIndex: 'stockQuantity', + render:(text, record,index)=> {this.handerInputOnChange(index, {stockQuantity: v})}}/> + },{ + title: '销售价(元)', + dataIndex: 'salePrice', + render:(text, record,index)=> {this.handerInputOnChange(index, {salePrice: v})}}/> + } + ] + return { + columns: columns, + } + } + + render(){ + + const { 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/List.js b/antd-ova/src/pages/Goods/List.js new file mode 100644 index 0000000000000000000000000000000000000000..22bdc3e471992901e29f64064fa07b494969c09c --- /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/antd-ova/src/pages/Goods/models/goods.js b/antd-ova/src/pages/Goods/models/goods.js new file mode 100644 index 0000000000000000000000000000000000000000..917bb622b06e2196f6017d5adb75c947f80da728 --- /dev/null +++ b/antd-ova/src/pages/Goods/models/goods.js @@ -0,0 +1,89 @@ +import { + queryCategory, + querySpec, + addSpecValue, + deleteSpecValue, + addSpecKey +} from '@/services/goods'; + +export default { + namespace: "goods", + state: { + GoodsCreator: { + goodsStock:[], + }, + Category: { + childs:[] + }, + Spec:[] + }, + effects: { + *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 + }) + }, + *fetchSpec({payload},{call, put}){ + const response = yield call(querySpec, payload); + yield put({ + 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: { + fillGoodsCreator(state, action){ + return { + ...state, + GoodsCreator: { + ...state.GoodsCreator, + ...action.payload + } + } + }, + reducersCategory(state, {payload}){ + return { + ...state, + Category: { + ...payload + } + } + }, + reducersCategoryChild(state, { payload }){ + return { + ...state, + Category: { + ...state.Category, + childs: payload.data + } + } + }, + reducersSpec(state, {payload}){ + return { + ...state, + Spec: payload.content + } + } + } +} \ 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 0000000000000000000000000000000000000000..9f7349d50e642ed24554e771bf9729cc8d36ae35 --- /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 0000000000000000000000000000000000000000..93ffa1065a52aac16286642e80be88586d91fb2c --- /dev/null +++ b/antd-ova/src/services/goods.js @@ -0,0 +1,47 @@ +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" + +/** + * + * @param {pid:0} params + */ +export async function queryCategory(params){ + 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 })}`); +} + +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-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 ed06a8f68a106ae86e050bf2ec5c3c4b0a6bb4d4..a2b263ac39ec01cb7b43ee79be0548cbcf36e1f9 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/bo/SpecKeyValueBo.java b/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java new file mode 100644 index 0000000000000000000000000000000000000000..cf7aeb08036da6d308813cafd7f94262a5782083 --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/bo/SpecKeyValueBo.java @@ -0,0 +1,34 @@ +package cn.ova.bo; + +import lombok.Data; + +/** + * @author lijiantao + * @date 2019-11-06 + * @description + */ +@Data +public class SpecKeyValueBo { + + private Long cateId; + private Long id; + private String specName; + private int nameSort; + private String remark; + + private String specValue; + private int valueSort; + + public SpecKeyValueBo() { + } + + public SpecKeyValueBo(Long cateId, Long id, String specName, int nameSort, String remark, String specValue, int valueSort) { + this.cateId = cateId; + this.id = id; + this.specName = specName; + this.nameSort = nameSort; + this.remark = remark; + this.specValue = specValue; + this.valueSort = valueSort; + } +} 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 0000000000000000000000000000000000000000..5e1ad402bffecfb8e25783b43cee484214c03a62 --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/dao/tenant/goods/OvaGoodsCategoryDao.java @@ -0,0 +1,24 @@ +package cn.ova.dao.tenant.goods; + +import cn.ova.bo.SpecKeyValueBo; +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); + + @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 09f37ffbcb768a9688c9d8cc3d7dfd7279e37739..9ce177477cf964c5d6e906a1a799e5c0d5fb268b 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/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 0000000000000000000000000000000000000000..4fc27791be10c798793b633fb58cc630dc3784e2 --- /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 0000000000000000000000000000000000000000..a3ff85ed9ad27dfd522a85521de23ce2a7ee2169 --- /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/OvaGoods.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoods.java index fb3aae23210157b06a7b12cf853687737a561602..0b9311a13420baf0208e7938a83bc895b31d19ec 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,14 +20,24 @@ import java.math.BigDecimal; @Entity public class OvaGoods extends AbstractEntity { - @Column(name = "sku", length = 64) - private String sku; + //新的iPhoneXS就是一个SPU,而红色iPhoneXS就是一个SKU, sku 放到Stock表中 - @Column(name = "g_name", nullable = false) +// @Column(name = "sku", length = 64) +// private String sku; + + private String spu; + + @Column(name = "g_name", length = 64, nullable = false) private String name; @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; @@ -35,7 +45,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删除 @@ -47,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/OvaGoodsCategory.java b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsCategory.java new file mode 100644 index 0000000000000000000000000000000000000000..7d283bf61ca2a9b46e64575ff29e5485e9d83a25 --- /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-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 a8ba42e296530d9ca1849a8da50cb33499ba09a5..57ab0b7bc372aa24ce66ee79b81ef364d3b8db5e 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/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 0000000000000000000000000000000000000000..d082903323b440d5fb87ea761b0212aa6a8116a6 --- /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 0000000000000000000000000000000000000000..53ef485bf0e94e194d898eec79311b495002e8ce --- /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 0000000000000000000000000000000000000000..afadd2a3263f4d671a28fefbe9d3c0b4f83430fa --- /dev/null +++ b/ova-boot/ova-dao/src/main/java/cn/ova/entity/tenant/goods/OvaGoodsStock.java @@ -0,0 +1,39 @@ +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 = "sku", length = 16) + private String sku; + + @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-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 0000000000000000000000000000000000000000..b42d01fc67d1d8f77e617c693e75a56317172c57 --- /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 b4cd6379cdb07775bf1dcc8aa0008ba6105ea987..1437335a34b9e8a872aef95228efcdb300bed4eb 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-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 0000000000000000000000000000000000000000..40090b8feaa4ca7e75a9080e80696a4738657289 --- /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 +} 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 0000000000000000000000000000000000000000..90c1db13b44a9c08b130cd2033b59f876e6bc8da --- /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 0000000000000000000000000000000000000000..e22b9fba0ee3eb807dabd376deb5a38623a6abce --- /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 new file mode 100644 index 0000000000000000000000000000000000000000..af45820696bedbf38096412b4503bc7f18537cd0 --- /dev/null +++ b/ova-boot/ova-seller/src/main/java/cn/ova/web/goods/GoodsCategoryRest.java @@ -0,0 +1,128 @@ +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.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.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.*; + +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; + + @Autowired + private OvaGoodsSpecValueDao ovaGoodsSpecValueDao; + + @Autowired + private OvaGoodsSpecKeyDao ovaGoodsSpecKeyDao; + + @GetMapping("/query_category") + public PaginationData queryCategory(Long pid){ + + if(pid == null){ + pid = 0L; + } + List result = ovaGoodsCategoryDao.findByPid(pid); + + return new PaginationData(result) ; + } + + @GetMapping("/query_spec") + public OvaResponse querySpec(Long cateId){ + + List allSpecKeyValue = ovaGoodsCategoryDao.queryAllSpecKeyByCateId(cateId); + + 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); + } +} 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 0000000000000000000000000000000000000000..c6fbee26a8503607ab26d81d37b97221849a2243 --- /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 { + + + +} 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 5816f49685d12b75883b161d2129888c9bb417f5..93308c955ef4f9a5d55ecfd7035a5676762af0d5 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 6a10d746e3852fab273d9e3de0f0d15cf8f56fe2..36513017ad64c46bba9117a6903adc5a6822b805 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 0000000000000000000000000000000000000000..b7ea6d4b7fa3f80f5f8dc8bfef3eb47b0f4b7056 --- /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 2d7c9a54c038627c6675ca983c3632e23c6ca3cb..a43b778b87897af7fd158d1d3ec2533f10d1eeef 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-web/src/main/resources/application.yml b/ova-boot/ova-web/src/main/resources/application.yml index 147ffb85ec03143457573196aab5e066788878be..81ebaf889ac5e44395e6355e895b58ea7eff2fa6 100644 --- a/ova-boot/ova-web/src/main/resources/application.yml +++ b/ova-boot/ova-web/src/main/resources/application.yml @@ -31,8 +31,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/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 0000000000000000000000000000000000000000..1917b429c895ec67c0c0a89c8b0c2e80cc51b940 --- /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 0000000000000000000000000000000000000000..0425d5fea5b021754338973dc5086c943a2b10f1 --- /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 0000000000000000000000000000000000000000..862d2019be16038de3ea431f05d526a19a53ecc9 --- /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 0000000000000000000000000000000000000000..d617c67747d9c54a4d50c968c438902abb87416f --- /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(); + } +} diff --git a/ova-boot/pom.xml b/ova-boot/pom.xml index e8a9a75cadcc9c88886ec1b03da7634dd8db29e6..d03c584f1655c49c6a8adc56f2775234dbdfddaa 100644 --- a/ova-boot/pom.xml +++ b/ova-boot/pom.xml @@ -179,6 +179,8 @@ com.alibaba.druid.pool.DruidDataSource logs + 192.168.1.231 + 6379