Commit d7f5d2a2 authored by GuanHua's avatar GuanHua

feat:新增渠道能力页面和接口对接

parent a5a99d4e
......@@ -19,6 +19,15 @@ const mallRoute = {
component: '@/pages/lxMall/commodity',
},
{
// 订单
path: `/order`,
name: 'order',
key: 'order',
hide: true,
hideHeader: true,
component: '@/pages/lxMall/order',
},
{
// 在线求购
path: `/buy`,
name: 'onlineshopping',
......
/*
* 店铺能力路由
* @Author: ghua
* @Date: 2020-07-10 16:16:37
* @Last Modified by: ghua
* @Last Modified time: 2020-07-10 16:48:50
*/
const ShopRoute = {
path: '/memberCenter/channelAbility',
name: 'channelAbility',
key: 'channelAbility',
icon: 'smile',
routes: [
{
path: '/memberCenter/channelAbility/infoManage',
name: 'shopInfoManage',
key: 'shopInfoManage',
component: '@/pages/channel/channelInfo',
},
{
path: '/memberCenter/channelAbility/template',
name: 'shopTemplate',
key: 'shopTemplate',
component: '@/pages/channel/channelTemplate',
},
{
path: '/memberCenter/channelAbility/template/detail',
name: 'shopTemplate',
key: 'shopTemplate',
hideInMenu: true,
component: '@/pages/channel/templateDetail',
}
]
}
export default ShopRoute
\ No newline at end of file
......@@ -7,10 +7,11 @@
import CommodityRoute from './commodityRoute' // 商品能力路由
import MemberRoute from './memberRoute' // 会员能力路由
import ShopRoute from './shopRoute' // 店铺能力路由
import ChannelRoute from './channelRoute' // 渠道能力路由
import TranactionRoute from './tranactionRoute' // 交易能力路由
import LogisticsRoute from './logisticsRoutes' // 物流能力路由
const routes = [CommodityRoute, MemberRoute, ShopRoute, TranactionRoute, LogisticsRoute]
const routes = [CommodityRoute, MemberRoute, ShopRoute, ChannelRoute, TranactionRoute, LogisticsRoute]
const memberCenterRoute = {
path: '/memberCenter',
......@@ -25,6 +26,10 @@ const memberCenterRoute = {
redirect: '/memberCenter/shopAbility/infoManage'
},
{
path: '/memberCenter/channelAbility',
redirect: '/memberCenter/channelAbility/infoManage'
},
{
path: `/memberCenter/home`,
name: 'home',
icon: 'smile',
......
......@@ -75,6 +75,11 @@ export default {
'menu.shopAbility.shopInfoManage': '创建店铺',
'menu.shopAbility.shopTemplate': '店铺装修模板',
// 渠道能力
'menu.channelAbility': '渠道',
'menu.channelAbility.shopInfoManage': '创建渠道商城',
'menu.channelAbility.shopTemplate': '渠道商城装修模板',
// 交易能力
'menu.tranactionAbility': '交易',
'menu.tranactionAbility.stockSellStorage': '进销存',
......
.shop_info {
background-color: #ffffff;
padding: 32px 24px;
border-radius: 8px;
.add_template_form {
:global {
.ant-form-item-label>label::after {
display: none;
}
}
}
.form_item {
width: 572px;
resize: none;
}
.form_item_wrap {
display: flex;
align-items: center;
.size_require {
color: #97A0AF;
}
}
.img_list {
display: flex;
}
.shop_url {
color: #6B778C;
margin-top: 16px;
font-size: 14px;
&>label {
color: #172B4D;
margin-left: 8px;
margin-right: 15px;
}
.copy_icon {
cursor: pointer;
}
}
.upload_btn {
position: relative;
width: 104px;
height: 104px;
display: flex;
align-items: center;
justify-content: center;
color: #6B778C;
flex-direction: column;
background: rgba(250, 251, 252, 1);
border-radius: 2px;
border: 1px dashed rgba(223, 225, 230, 1);
cursor: pointer;
margin-right: 24px;
overflow: hidden;
&.upload {
border: 1px solid rgba(223, 225, 230, 1);
background: #ffffff;
}
.upload_img {
height: 100%;
width: 100%;
display: block;
margin: 0 auto;
background-size: auto 100%;
background-position: center center;
background-repeat: no-repeat;
}
&>img {
width: 100%;
height: 100%;
}
&.large {
width: 175px;
height: 120px;
}
&>p {
margin-top: 12px;
}
.delete_btn {
position: absolute;
width: 24px;
height: 24px;
border-radius: 4px;
background: rgba(0, 0, 0, 0.45);
top: 8px;
right: 8px;
color: #ffffff;
text-align: center;
line-height: 24px;
&:hover {
cursor: pointer;
opacity: .8;
}
}
}
}
\ No newline at end of file
This diff is collapsed.
.shop_center_template {
.add_card {
display: flex;
height: 100%;
border-radius: 2px;
border: 1px dashed rgba(223, 225, 230, 1);
background: rgba(250, 251, 252, 1);
align-items: center;
justify-content: center;
cursor: pointer;
flex-direction: column;
&:hover {
border: 1px dashed rgba(200, 200, 230, 1);
}
.add_card_btn {
display: flex;
justify-content: center;
align-items: center;
width: 48px;
height: 48px;
background: rgba(235, 236, 240, 1);
border-radius: 50%;
margin-bottom: 24px;
font-size: 22px;
color: #97A0AF;
}
&>p {
color: #6B778C;
}
}
}
\ No newline at end of file
import React, { useEffect, useState } from 'react'
import { Row, Col, message } from 'antd'
import { history } from 'umi'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import TemplateItem from '../components/templateItem'
import { PublicApi } from '@/services/api'
import { GetTemplateShopFindAllShelfShopTemplateResponse } from '@/services'
import styles from './index.less'
const ShopTemplate: React.FC = () => {
const [templateList, setTemplateList] = useState<GetTemplateShopFindAllShelfShopTemplateResponse>([])
useEffect(() => {
fetchAllShelfShopTemplate()
}, [])
const fetchAllShelfShopTemplate = () => {
PublicApi.getTemplateChannelFindAllShelfChannelTemplate().then(res => {
if (res.code === 1000) {
setTemplateList(res.data)
} else if (res.code === 47001) {
message.info("您还未创建渠道商城,请先创建渠道商城")
history.push('/memberCenter/channekAbility/infoManage')
}
})
}
return (
<PageHeaderWrapper>
<div className={styles.shop_center_template}>
<Row gutter={24} className={styles.template_list}>
{
templateList.map(item => (
<Col span={6} key={item.id}>
<TemplateItem templateInfo={item} type="shop" />
</Col>
))
}
</Row>
</div>
</PageHeaderWrapper>
)
}
export default ShopTemplate
.city_select_line {
display: flex;
&:not(:last-child) {
margin-bottom: 16px;
}
.opration_btn {
width: 32px;
height: 32px;
background: rgba(250, 251, 252, 1);
border: 1px solid rgba(235, 236, 240, 1);
color: #6B778C;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
margin-right: 16px;
cursor: pointer;
&:hover {
opacity: .8;
}
&.add {
background: rgba(0, 179, 122, 1);
border: 1px solid rgba(0, 179, 122, 1);
color: #ffffff;
}
}
}
\ No newline at end of file
import React, { memo, useState, Fragment, forwardRef, useEffect } from 'react'
import { Select } from 'antd'
import { PlusOutlined, MinusOutlined } from '@ant-design/icons'
import { PublicApi } from '@/services/api'
import cx from 'classnames'
import styles from './index.less'
import { isEmpty } from '@formily/antd/esm/shared'
interface CitySelectPropsType {
selectData: Array<{
provinceCode: number;
province: string;
cityCode: number;
city: string;
}>;
onAdd: Function;
onReduce: Function;
onChange: Function;
}
interface selectItemType {
index: number;
lable: string;
value: number;
}
const { Option } = Select;
const CityCascader: React.FC<CitySelectPropsType> = (props) => {
const { selectData, onAdd, onReduce, onChange } = props
const [provinceData, setProvinceData] = useState([])
const [cityData, setCityData] = useState({})
const [cities, setCities] = useState([])
useEffect(() => {
fetchAreaList()
}, [])
const getProviceById = (id: number) => {
let result: number = 0
provinceData && provinceData.map(item => {
if (item.value === id) {
result = item
}
})
return result
}
const getCityById = (id: number, provinceCode: string) => {
let result: number = 0
!isEmpty(cityData) && cityData[provinceCode].map(item => {
if (item.value === id) {
result = item
}
})
return result
}
const fetchAreaList = () => {
PublicApi.getManageAreaAll().then(res => {
initProvinceAndCityData(res.data)
})
}
const initProvinceAndCityData = (areaList: any) => {
if (!areaList) {
return
}
let tempProvinceData = []
let tempCityData = {}
for (let item of areaList) {
tempProvinceData.push({
lable: item.name,
value: item.code
})
if (!!item.areaResponses) {
let tempCityList = []
for (let cityItem of item.areaResponses) {
tempCityList.push({
lable: cityItem.name,
value: cityItem.code
})
}
tempCityData[item.code] = tempCityList
}
}
setProvinceData(tempProvinceData)
setCityData(tempCityData)
}
const handleProvinceChange = (value: number, index: number) => {
let newData = JSON.parse(JSON.stringify(selectData))
let proviceById: any = getProviceById(value)
setCities(cityData[proviceById.value])
newData.map((item: any) => {
if (item.index === index) {
item.provinceCode = value
item.province = proviceById.lable
item.cityCode = cityData[proviceById.value][0].value
item.city = cityData[proviceById.value][0].lable
}
return item
})
onChange(newData)
}
const onSecondCityChange = (value: number, provinceCode: string, index: number) => {
let newData = JSON.parse(JSON.stringify(selectData))
const cityById: any = getCityById(value, provinceCode)
newData.map((item: any) => {
if (item.index === index) {
item.cityCode = cityById.value
item.city = cityById.lable
}
return item
})
onChange(newData)
}
const handleAddNewSelect = () => {
onAdd({ index: selectData.length + 1, provinceCode: 0, province: '', cityCode: 0, city: '' })
}
const handleReduceSelect = (index: number) => {
if (selectData.length > 1) {
onReduce(index)
}
}
return (
<Fragment>
{
selectData && selectData.map((item: any, index) => (
<div className={styles.city_select_line} key={`selectDataItem-${index}`}>
<Select
style={{ width: 278 }}
value={item.provinceCode ? item.provinceCode : undefined}
onChange={(value) => handleProvinceChange(value, item.index)}
placeholder="请选择"
>
{provinceData.map(item => (
<Option value={item.value} key={item.value}>{item.lable}</Option>
))}
</Select>
<Select
style={{ width: 278, marginLeft: 16, marginRight: 24 }}
value={item.cityCode ? item.cityCode : undefined}
onChange={(value) => onSecondCityChange(value, item.provinceCode, item.index)}
placeholder="请选择"
>
{(item.provinceCode && !isEmpty(cityData)) ? cityData[item.provinceCode].map((item: any) => (
<Option value={item.value} key={item.value}>{item.lable}</Option>
)) : null}
</Select>
{
index === selectData.length - 1 && (
<div className={cx(styles.opration_btn, styles.add)} onClick={() => handleAddNewSelect()}>
<PlusOutlined />
</div>
)
}
<div className={styles.opration_btn} onClick={() => handleReduceSelect(item.index)}>
<MinusOutlined />
</div>
</div>
))
}
</Fragment>
)
}
const CitySelect: React.FC<CitySelectPropsType> = forwardRef((props, ref) => {
const { selectData, onAdd, onReduce, onChange } = props
return (
<div className={styles.city_select}>
<CityCascader selectData={selectData} onAdd={onAdd} onReduce={onReduce} onChange={onChange} />
</div>
)
})
export default CitySelect
.template_item {
// width: 386px;
background-color: #ffffff;
border-radius: 8px;
overflow: hidden;
height: 100%;
padding-bottom: 24px;
.img_box {
position: relative;
// height: 218px;
height: 0;
padding-bottom: 67%;
overflow: hidden;
background-size: auto 100%;
background-position: center center;
background-repeat: no-repeat;
&:hover {
.img_box_mask {
opacity: 1;
}
}
.img_box_mask {
position: absolute;
width: 100%;
opacity: 0;
transition: all .5s;
height: 100%;
background: rgba(255, 255, 255, 0.45);
z-index: 8;
.detail_btn {
position: relative;
display: block;
left: 0;
right: 0;
top: 50%;
margin: 0 auto;
margin-top: -20px;
width: 240px;
height: 40px;
background: rgba(0, 0, 0, 0.85);
color: #ffffff;
text-align: center;
line-height: 40px;
font-weight: 500;
cursor: pointer;
&:hover {
opacity: .9;
}
}
}
.type_tag {
position: absolute;
top: 0;
width: 72px;
height: 24px;
color: #ffffff;
text-align: center;
line-height: 24px;
font-size: 14px;
background: #4279DF;
border-radius: 8px 0px 8px 0px;
z-index: 3;
&.h5 {
background: #6554C0;
}
}
&>img {
// height: 100%;
width: 100%;
}
}
.template_info {
padding: 0 24px;
.template_info_name {
display: flex;
align-items: center;
color: #172B4D;
font-weight: bold;
line-height: 24px;
padding: 16px 0;
.tag {
padding: 0 8px;
height: 24px;
background: rgba(244, 245, 247, 1);
border-radius: 4px;
margin-left: 8px;
color: #42526E;
font-weight: 400;
}
}
.template_info_content {
display: flex;
align-items: flex-end;
height: 52px;
&.goods {
height: 32px;
}
.template_info_content_text_wrap {
flex: 1;
font-size: 14px;
line-height: 22px;
.template_info_content_text_line {
&:not(:last-child) {
margin-bottom: 8px;
}
&>label {
color: #6B778C;
margin-right: 8px;
}
&>span {
color: #172B4D;
}
}
}
.template_item_btn {
width: 88px;
height: 32px;
display: flex;
justify-content: center;
align-items: center;
background: rgba(250, 251, 252, 1);
border: 1px solid rgba(235, 236, 240, 1);
cursor: pointer;
color: #42526E;
font-size: 14px;
// margin-top: auto;
margin-left: auto;
&.active {
background: #00B37A;
border: 1px solid #00B37A;
color: #ffffff;
}
&>label {
margin-left: 8px;
cursor: pointer;
}
&:hover {
opacity: .8;
}
}
}
}
}
\ No newline at end of file
import React from 'react'
import { PlayCircleOutlined } from '@ant-design/icons'
import cx from 'classnames'
import { Link } from 'umi'
import default_img from '@/assets/imgs/template_default_img.png'
import styles from './index.less'
interface TemplateItemPropsType {
templateInfo: any;
type: string;
}
const Environment_Status = {
0: {
name: "所有"
},
1: {
name: "PC "
},
2: {
name: "H5 "
},
3: {
name: "APP "
}
}
const TemplateItem: React.FC<TemplateItemPropsType> = (props) => {
const { templateInfo, type } = props
return (
<div className={styles.template_item}>
<div className={styles.img_box} style={{ backgroundImage: `url(${templateInfo.templatePicUrl})` }}>
<div className={styles.img_box_mask}>
<Link to={`/memberCenter/channelAbility/template/detail?type=${type}&id=${templateInfo.id}`} className={styles.detail_btn}>查看详情</Link>
</div>
<div className={cx(styles.type_tag, templateInfo.environment === 2 ? styles.h5 : '')}>{Environment_Status[templateInfo.environment].name}</div>
</div>
<div className={styles.template_info}>
<div className={styles.template_info_name}>
<span>{templateInfo.templateName}</span>
{
templateInfo.isDefault && <div className={styles.tag}>默认模板</div>
}
</div>
<div className={cx(styles.template_info_content, type === 'goods' ? styles.goods : '')}>
<div className={styles.template_info_content_text_wrap}>
<div className={styles.template_info_content_text_line}>
<label>使用站点:</label>
<span>{templateInfo.siteName}</span>
</div>
<div className={styles.template_info_content_text_line}>
<label>使用商城:</label>
<span>{templateInfo.shopName}</span>
</div>
</div>
<div className={cx(styles.template_item_btn, templateInfo.use === 1 ? styles.active : '')}>
<PlayCircleOutlined />
<label>{templateInfo.use === 1 ? '启用中' : '启用'}</label>
</div>
</div>
</div>
</div>
)
}
export default TemplateItem
.selectBox {
width: 100%;
}
.text_line {
margin-bottom: 8px;
&>span {
color: #6B778C;
}
&>label {
color: #172B4D;
margin: 0 3px;
}
}
\ No newline at end of file
import React from 'react'
import { Modal, Form, Select, Checkbox } from 'antd'
import styles from './index.less'
import detailInfo from '@/pages/logistics/components/orderSearchDetail'
interface UseModalPropsType {
visible: boolean;
onOk: Function;
onCancel: Function;
title: string;
dataInfo: any;
confirmLoading?: boolean;
}
const UseModal: React.FC<UseModalPropsType> = (props) => {
const { visible, onOk, onCancel, title, dataInfo = {}, confirmLoading = false } = props
return (
<Modal
width={576}
title={title}
visible={visible}
confirmLoading={confirmLoading}
onOk={() => onOk()}
centered
onCancel={() => onCancel()}
>
{
dataInfo.inUseTemplateName ? (
<>
<div className={styles.text_line}>
<span>您选择的站点</span>
<label>{dataInfo.siteName}-{dataInfo.shopName}</label>
<span>现在使用的模板是</span>
<label>{dataInfo.inUseTemplateName}</label>
<span>模板,</span>
</div>
<div className={styles.text_line}>
<span>您是否使用</span>
<label>{dataInfo.templateName}</label>
<span>模板,来替换您正在使用的模板</span>
</div>
</>
) : (
<div className={styles.text_line}>
<span>您是否使用</span>
<label>{dataInfo.templateName}</label>
<span>模板?</span>
</div>
)
}
</Modal>
)
}
export default UseModal
.template_detail {
height: 224px;
background-color: #ffffff;
display: flex;
border-radius: 8px;
align-items: center;
.back_btn {
color: #6B778C;
margin-left: 27px;
font-size: 16px;
margin-top: 40px;
cursor: pointer;
align-self: flex-start;
}
.template_info_wrap {
display: flex;
margin-left: 36px;
flex: 1;
align-items: center;
.template_img_box {
position: relative;
width: 250px;
height: 165px;
border-radius: 8px 8px 0px 0px;
overflow: hidden;
.type_tag {
position: absolute;
top: 0;
width: 72px;
height: 24px;
color: #ffffff;
text-align: center;
line-height: 24px;
font-size: 14px;
background: #4279DF;
border-radius: 8px 0px 8px 0px;
z-index: 3;
&.h5 {
background: #6554C0;
}
}
&>img {
height: 100%;
width: auto;
display: block;
margin: 0 auto;
}
}
.template_info {
margin-left: 24px;
.template_info_line {
line-height: 22px;
&:not(:last-child) {
margin-bottom: 8px;
}
&>label {
color: #6B778C;
}
&>span {
color: #172B4D;
}
}
}
}
.btn {
margin-left: 24px;
padding: 0 20px;
min-width: 88px;
height: 40px;
background: rgba(250, 251, 252, 1);
border: 1px solid rgba(235, 236, 240, 1);
color: #42526E;
cursor: pointer;
line-height: 38px;
text-align: center;
&>label {
margin-left: 5px;
cursor: pointer;
}
&.fit {
background: #6B778C;
color: #ffffff;
}
&.use {
background: #00B37A;
color: #ffffff;
}
&:hover {
opacity: .8;
}
&:last-child {
margin-right: 48px;
}
}
}
\ No newline at end of file
import React, { useState, useEffect } from 'react'
import { history } from 'umi';
import { LayoutOutlined, EyeOutlined, PushpinOutlined } from '@ant-design/icons'
import cx from 'classnames'
import DetailPage from '@/components/DetailPage'
import UseModal from '../components/useModal'
import { PublicApi } from '@/services/api'
import { Environment_Status } from '@/constants'
import { GetTemplateShopFindShopTemplateDetailsResponse } from '@/services'
import default_img from '@/assets/imgs/template_default_img.png'
import styles from './index.less'
interface TemplateDetailPropsType {
location: {
query: {
id: number;
type: string; // 商城模板:shopCenter ;店铺模板:shop; 商品描述模板: goods
}
}
}
const TemplateDetail: React.FC<TemplateDetailPropsType> = (props) => {
const { query: { type, id } } = props.location
const [detailInfo, setDetailInfo] = useState<GetTemplateShopFindShopTemplateDetailsResponse>()
const [useModalVisible, setUseModalVisible] = useState<boolean>(false)
const [confirmLoading, setConfirmLoading] = useState(false)
useEffect(() => {
fetchDetail()
}, [])
const fetchDetail = () => {
//@ts-ignore
PublicApi.getTemplateChannelFindChannelTemplateDetails({ id }).then(res => {
setDetailInfo(res.data)
})
}
/**
* 使用模板
*/
const handleConfirmUse = () => {
setConfirmLoading(true)
//@ts-ignore
PublicApi.postTemplateChannelUseChannelTemplate({ id }).then(res => {
if (res.code === 1000) {
setUseModalVisible(false)
fetchDetail()
}
setConfirmLoading(false)
}).catch(() => {
setConfirmLoading(false)
})
}
return (
<DetailPage
title="查看模板"
>
<div className={styles.template_detail}>
<div className={styles.template_info_wrap}>
<div className={styles.template_img_box}>
<div className={cx(styles.type_tag)}>{Environment_Status[detailInfo?.environment]}</div>
<img src={default_img} />
</div>
<div className={styles.template_info}>
<div className={styles.template_info_line}>
<label>模板名称:</label>
<span>{detailInfo?.templateName}</span>
</div>
<div className={styles.template_info_line}>
<label>适用环境:</label>
<span>{Environment_Status[detailInfo?.environment]}</span>
</div>
<div className={styles.template_info_line}>
<label>模板描述:</label>
<span>{detailInfo?.templateDescribe}</span>
</div>
<div className={styles.template_info_line}>
<label>使用站点:</label>
<span>{detailInfo?.siteName}</span>
</div>
<div className={styles.template_info_line}>
<label>使用商城:</label>
<span>{detailInfo?.shopName}</span>
</div>
</div>
</div>
<div className={styles.btn}>
<EyeOutlined />
<label>预览</label>
</div>
<div className={cx(styles.btn, styles.fit)}>
<LayoutOutlined />
<label>渠道商城装修</label>
</div>
<div className={cx(styles.btn, detailInfo?.use === 1 ? styles.use : '')} onClick={() => detailInfo?.use !== 1 ? setUseModalVisible(true) : {}}>
<PushpinOutlined />
<label>{detailInfo?.use === 1 ? '使用中' : '使用'}</label>
</div>
<UseModal
title="使用店铺模板"
visible={useModalVisible}
dataInfo={detailInfo}
confirmLoading={confirmLoading}
onOk={() => handleConfirmUse()}
onCancel={() => setUseModalVisible(false)}
/>
</div>
</DetailPage>
)
}
export default TemplateDetail
......@@ -270,21 +270,42 @@
display: flex;
height: 150px;
align-items: center;
border-bottom: 1px dashed #EEEEEE;
&_info {
flex: 1;
padding-left: 50px;
&_icon {
display: inline-block;
width: 32px;
height: 32px;
background-image: url(/static/imgs/success_icon.png);
background-size: 100% 100%;
background-repeat: no-repeat;
vertical-align: middle;
margin-right: 16px;
}
&_title {
font-size: 16px;
color: #333333;
font-weight: bold;
}
&_text {
margin-top: 7px;
font-size: 12px;
color: #666666;
padding-left: 48px;
&>b {
font-size: 20px;
color: #D32F2F;
margin: 0 5px;
}
}
}
&_btn {
......
......@@ -2,7 +2,9 @@ import React, { useState } from 'react'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { Tooltip } from 'antd'
import cx from 'classnames'
import { history } from 'umi'
import DialogModal from '../components/DialogModal'
import InterestedCommodity from '../components/InterestedCommodity'
import Exhibition from './components/Exhibition'
import BrowseRecords from './components/BrowseRecords'
import Interested from './components/Interested'
......@@ -15,6 +17,7 @@ import './index.less'
const CommodityDetail = (props) => {
// type : prompt:现货商品;inquiry:询价商品;integral:积分商品
const { query: { id, type = "prompt" } } = props.location
const [addSuccessVisible, setAddSuccessVisible] = useState<boolean>(false)
const COMMODITY_TYPE = {
prompt: 'prompt',
......@@ -59,8 +62,8 @@ const CommodityDetail = (props) => {
case 'prompt':
return (
<>
<div className="product_info_btn_item buy">立即订购</div>
<div className="product_info_btn_item add"><img className="btn_icon" src={jinhuodanIcon} />加入进货单</div>
<div className="product_info_btn_item buy" onClick={() => history.push('/order')}>立即订购</div>
<div className="product_info_btn_item add" onClick={() => setAddSuccessVisible(true)} ><img className="btn_icon" src={jinhuodanIcon} />加入进货单</div>
</>
)
case 'inquiry':
......@@ -229,7 +232,8 @@ const CommodityDetail = (props) => {
</div>
<DialogModal
title="添加成功"
visible={false}
visible={addSuccessVisible}
onCancel={() => setAddSuccessVisible(false)}
>
<div className="add_success">
<div className="add_success_info">
......@@ -246,6 +250,7 @@ const CommodityDetail = (props) => {
<div className="add_success_btn primary">去结算</div>
<div className="add_success_btn">继续购物</div>
</div>
<InterestedCommodity />
</DialogModal>
</div>
)
......
@import '../../../../theme/style/common.less';
@mall_main_color: var(--mall_main_color);
.common_header {
position: relative;
background-color: #FFF;
width: 100%;
.common_header_container {
.common_page_container();
height: 110px;
display: flex;
align-items: center;
.logo {
padding-left: 14px;
&>img {
width: 145px;
height: 50px;
}
}
.common_header_split {
width: 1px;
height: 32px;
background-color: #F5F5F5;
margin: 0 20px;
}
.common_header_title {
font-size: 24px;
font-weight: 600;
color: #333333;
}
}
}
\ No newline at end of file
import React from 'react'
import { Link } from 'umi'
import logo from '@/theme/imgs/logo_w.png'
import styles from './index.less'
interface ShopHeaderPropsType {
title?: string;
}
const CommonHeader: React.FC<ShopHeaderPropsType> = (props) => {
const { title } = props
return (
<div className={styles.common_header}>
<div className={styles.common_header_container}>
<div className="logo">
<Link to="/">
<img src={logo} />
</Link>
</div>
<div className={styles.common_header_split}></div>
<div className={styles.common_header_title}>{title}</div>
</div>
</div>
)
}
export default CommonHeader
import React from 'react'
import React, { useEffect } from 'react'
import { Modal } from 'antd'
import styles from './index.less'
interface DialogModalModalPropsType {
visible: boolean;
title?: string;
onCancel: any;
}
const DialogModal: React.FC<DialogModalModalPropsType> = (props) => {
const { visible = false, title, children } = props
const { visible = false, title, children, onCancel } = props
useEffect(() => {
console.log(visible, "visible")
}, [visible])
return (
<Modal
......@@ -18,6 +22,7 @@ const DialogModal: React.FC<DialogModalModalPropsType> = (props) => {
footer={null}
centered
width={600}
onCancel={onCancel}
>
<div>
{children}
......
.interested_commodity {
padding-bottom: 25px;
&_title {
height: 52px;
display: flex;
align-items: center;
&>span {
flex: 1;
font-size: 12px;
color: #666666;
}
}
&_pagination {
display: flex;
&_btn {
width: 24px;
height: 24px;
text-align: center;
line-height: 24px;
border: 1px solid #CCCCCC;
color: #999999;
cursor: pointer;
margin-left: 10px;
&.disabled {
border: 1px solid rgba(238, 238, 238, 1);
color: #CCCCCC;
}
}
}
&_list {
display: flex;
margin: 0 -7.5px;
&_item {
margin: 0 7.5px;
&_imgbox {
position: relative;
&_img {
width: 100px;
height: 100px;
background-repeat: no-repeat;
background-size: 100% auto;
background-position: center center;
}
}
&_name {
font-size: 12px;
color: #333333;
text-align: left;
margin-top: 5px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-overflow: ellipsis;
overflow: hidden;
-webkit-box-orient: vertical;
word-wrap: break-word;
word-break: break-all;
}
&_price {
font-size: 14px;
color: #D32F2F;
&>i {
font-style: normal;
font-size: 12px;
margin-right: 3px;
}
}
}
}
}
\ No newline at end of file
import React from 'react'
import { LeftOutlined, RightOutlined } from '@ant-design/icons'
import cx from 'classnames'
import styles from './index.less'
import url from '*.svg'
const InterestedCommodity: React.FC = () => {
let mockList = []
for (let i = 0; i < 5; i++) {
mockList.push({
url: "https://woodmartcdn-cec2.kxcdn.com/wp-content/uploads/2016/09/product-furniture-1.jpg",
name: '0.8-1.0mm黑色手纹硬度适中偏软偏软偏软',
price: '79.00'
})
}
return (
<div className={styles.interested_commodity}>
<div className={styles.interested_commodity_title}>
<span>您可能也感兴趣:</span>
<div className={styles.interested_commodity_pagination}>
<div className={cx(styles.interested_commodity_pagination_btn, styles.disabled)}><LeftOutlined /></div>
<div className={cx(styles.interested_commodity_pagination_btn)}><RightOutlined /></div>
</div>
</div>
<div className={styles.interested_commodity_list}>
{
mockList.map(item => (
<div className={styles.interested_commodity_list_item}>
<div className={styles.interested_commodity_list_item_imgbox}>
<div className={styles.interested_commodity_list_item_imgbox_img} style={{ backgroundImage: `url(${item.url})` }}></div>
</div>
<div className={styles.interested_commodity_list_item_name}>{item.name}</div>
<div className={styles.interested_commodity_list_item_price}>
<i></i>
{item.price}
</div>
</div>
))
}
</div>
</div>
)
}
export default InterestedCommodity
......@@ -23,14 +23,14 @@ interface LXMallLayoutPropsType {
const LXMallLayout: React.FC<LXMallLayoutPropsType> = (props) => {
const { children, location } = props
// const getMenuRouter = (routes: any, pathname: any) => {
// let list = routes.filter((item: any) => pathname.indexOf(item.key) > -1)
// return list[0]
// }
const getMenuRouter = (routes: any, pathname: any) => {
let list = routes.filter((item: any) => pathname.indexOf(item.key) > -1)
return list[0] || {}
}
const { formatMessage } = useIntl();
const basicInfo = getMenuData(props.route.routes, { locale: true }, formatMessage)
const menuData = basicInfo.menuData ? basicInfo.menuData.filter(item => !item.redirect) : []
// const menuRouter = getMenuRouter(menuData, location.pathname)
const menuRouter = getMenuRouter(menuData, location.pathname)
useEffect(() => {
let body = document.getElementsByTagName('body')[0];
body.className = `theme-mall-science`;
......@@ -40,8 +40,14 @@ const LXMallLayout: React.FC<LXMallLayoutPropsType> = (props) => {
<div className={styles.lxmall_page}>
<TopBar langComponent={<SelectLang />} />
<div className={styles.content}>
<Header />
<MainNav menuData={menuData} pathname={location.pathname} type="mall" />
{
!menuRouter?.hideHeader && (
<>
<Header />
<MainNav menuData={menuData} pathname={location.pathname} type="mall" />
</>
)
}
{children}
</div>
<Footer />
......
@import '../common.less';
.address {
.address_raido_group {
display: block;
width: 100%;
}
&_list {
&_radio {
display: flex;
height: 36px;
align-items: center;
margin-top: 10px;
border: 1px solid #ffffff;
padding-left: 17px;
:global {
.ant-radio-inner {
&:hover {
border-color: var(--mall_main_color);
}
}
.ant-radio-checked .ant-radio-inner {
border-color: var(--mall_main_color);
}
.ant-radio-inner::after {
background-color: var(--mall_main_color);
}
}
&:hover {
background-color: #FAFAFA;
.adderss_list_radio_line .set_default_address {
display: block;
}
}
.adderss_list_radio_line {
display: flex;
align-items: center;
.default_address {
width: 64px;
height: 16px;
line-height: 16px;
text-align: center;
background: rgba(238, 238, 238, 1);
font-size: 12px;
color: #666666;
}
.set_default_address {
font-size: 12px;
display: none;
color: #666666;
}
&>span,
&>div {
display: block;
margin: 0 10px;
}
}
}
}
}
\ No newline at end of file
import React from 'react'
import { Radio } from 'antd'
import styles from './index.less'
const Address: React.FC = () => {
const mock_data = [
{
id: 1,
name: '蒯美政',
address: '广东省广州市海珠区新港东路1068号中洲中心北塔6楼',
mobile: '185 2929 6758',
isDefault: 1,
},
{
id: 2,
name: '蒯美政',
address: '广东省广州市海珠区新港东路1068号中洲中心北塔6楼',
mobile: '185 2929 6758',
isDefault: 0,
},
{
id: 3,
name: '蒯美政',
address: '广东省广州市海珠区新港东路1068号中洲中心北塔6楼',
mobile: '185 2929 6758',
isDefault: 0,
}
]
return (
<div className={styles.address}>
<div className={styles.common_title}>
<span>收货地址</span>
<div className={styles.common_title_btn}>新增收货地址</div>
</div>
<Radio.Group className={styles.address_raido_group} >
<div className={styles.address_list}>
{
mock_data.map(item => (
<Radio className={styles.address_list_radio} value={item.id}>
<div className={styles.adderss_list_radio_line}>
<span>{item.name}</span>
<span>{item.address}</span>
<span>{item.mobile}</span>
{
item.isDefault === 1 ? <div className={styles.default_address}>默认地址</div> :
<div className={styles.set_default_address}>设为默认地址</div>
}
</div>
</Radio>
))
}
</div>
</Radio.Group>
</div>
)
}
export default Address
.common_title {
font-size: 14px;
color: #333333;
padding: 15px 0 11px 0;
border-bottom: 2px solid #EEEEEE;
line-height: 14px;
display: flex;
margin-bottom: 5px;
&>span {
font-weight: 500;
}
&_btn {
margin-left: auto;
cursor: pointer;
&:hover {
opacity: .8;
}
}
}
\ No newline at end of file
@import '../common.less';
.contract {}
\ No newline at end of file
import React from 'react'
import styles from './index.less'
const Contract: React.FC = () => {
return (
<div className={styles.contract}>
<div className={styles.common_title}>
<span>电子合同信息</span>
</div>
Contract
</div>
)
}
export default Contract
@import '../common.less';
.distributionway {}
\ No newline at end of file
import React from 'react'
import styles from './index.less'
const DistributionWay: React.FC = () => {
return (
<div className={styles.distributionWay}>
<div className={styles.common_title}>
<span>配送方式</span>
</div>
DistributionWay
</div>
)
}
export default DistributionWay
.order {
&_container {
width: 1200px;
margin: 0 auto;
}
}
\ No newline at end of file
import React from 'react'
import CommonHeader from '../components/CommonHeader'
import Address from './address'
import PayWay from './payway'
import DistributionWay from './distributionway'
import Contract from './contract'
import Invoice from './invoice'
import styles from './index.less'
interface OrderPropsType {
}
const Order: React.FC<OrderPropsType> = (props) => {
return (
<div className={styles.order}>
<CommonHeader title="订单结算" />
<div className={styles.order_container}>
<Address />
<PayWay />
<DistributionWay />
<Invoice />
<Contract />
</div>
</div>
)
}
export default Order
@import '../common.less';
.invoice {}
\ No newline at end of file
import React from 'react'
import styles from './index.less'
const Invoice: React.FC = () => {
return (
<div className={styles.invoice}>
<div className={styles.common_title}>
<span>发票信息</span>
</div>
Invoice
</div>
)
}
export default Invoice
@import '../common.less';
.payway {}
\ No newline at end of file
import React from 'react'
import styles from './index.less'
const PayWay: React.FC = () => {
return (
<div className={styles.payway}>
<div className={styles.common_title}>
<span>支付方式</span>
</div>
PayWay
</div>
)
}
export default PayWay
......@@ -57,7 +57,7 @@ const ShopInfo: React.FC<ShopInfoPropsType> = (props) => {
PublicApi.getTemplateShopFindShop().then(res => {
const data = res.data
if (res.code === 1000) {
setSelectCityData(initMemberShopArea(data.memberShopAreas) || defaultCityData)
setSelectCityData(initMemberShopArea(data.memberShopAreas))
setLogo(data.logo)
setShopId(data.shopId)
setWorkshopPics(data.workshopPics || [])
......@@ -67,7 +67,7 @@ const ShopInfo: React.FC<ShopInfoPropsType> = (props) => {
describe: data.describe,
customerUrl: data.customerUrl,
logo: data.logo,
memberShopAreas: initMemberShopArea(data.memberShopAreas) || defaultCityData,
memberShopAreas: initMemberShopArea(data.memberShopAreas),
workshopPics: data.workshopPics || [],
honorPics: data.honorPics || []
})
......@@ -76,13 +76,14 @@ const ShopInfo: React.FC<ShopInfoPropsType> = (props) => {
}
const initMemberShopArea = (data) => {
if (!!data) {
if (!isEmpty(data)) {
return data.map((item, index) => {
item.index = index
return item
})
} else {
return [defaultCityData]
}
return data
}
const handleAddNewCitySelect = (item: any) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment