Commit 135b04fb authored by XieZhiXiong's avatar XieZhiXiong
parents fc35dd85 a0ab05f7
{"userRegister":{"useType":{"memberType":[{"id":1,"typeName":"企业会员"},{"id":3,"typeName":"渠道企业会员"},{"id":4,"typeName":"渠道个人会员"},{"id":2,"typeName":"个人会员"}],"businessType":[{"id":1,"typeName":"采购"},{"id":39,"typeName":"供货"},{"id":40,"typeName":"供货商消费者"},{"id":41,"typeName":"供货商消费者渠道会员"}]}},"web":{"shopInfo":[]},"global":{"siteId":602,"siteUrl":"http://localhost:4396","logo":"https://shushangyun01.oss-cn-shenzhen.aliyuncs.com/4db4e7c5424c471c968ab540bce027f31597319423082.png","countryList":[{"name":"简体中文-ZH","key":"zh-CN","icon":"http://lingxi-frontend-test.oss-cn-hangzhou.aliyuncs.com/images/china.png"},{"name":"English-EN","key":"en-US","icon":"http://lingxi-frontend-test.oss-cn-hangzhou.aliyuncs.com/images/us.png"},{"name":"日本語-JP","key":"jp","icon":"http://lingxi-frontend-test.oss-cn-hangzhou.aliyuncs.com/images/japen.png"},{"name":"한국어-KO","key":"ko","icon":"http://lingxi-frontend-test.oss-cn-hangzhou.aliyuncs.com/images/koren.png"}]}}
......@@ -43,6 +43,7 @@
"moment": "^2.27.0",
"prettier": "^1.19.1",
"qrcode": "^1.4.4",
"query-string": "^6.13.1",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-fontawesome": "^1.7.1",
......
......@@ -2,6 +2,7 @@ import { IRoutes } from '.';
import { history, RequestConfig, Redirect } from 'umi';
import React from 'react'
import MobxProvider from './store'
import queryString from 'query-string'
import '@/global/styles/reset.less'; // 重置antd样式
import '@/global/styles/global.less'; // 导入全局样式
......@@ -9,7 +10,7 @@ import '@/global/styles/global.less'; // 导入全局样式
import 'antd/dist/antd.less'
import { isDev } from '@/constants'
import { setup } from '@formily/antd-components';
import { getRouters, getAuth, asyncRouter, setAuth, setRouters } from './utils/auth';
import { getRouters, getAuth, asyncRouter, setAuth, setRouters, removeAuth, removeRouters } from './utils/auth';
import { PublicApi } from './services/api';
setup()
......@@ -66,13 +67,20 @@ export function render(oldRender: Function) {
const authInfo = getAuth()
if (authInfo) {
PublicApi.getMemberLoginReget().then(res => {
const { data } = res
setAuth({
memberId: data.memberId,
userId: data.userId,
token: data.token
})
setRouters(data.urls)
const { data, code } = res
if (code === 1000) {
setAuth({
memberId: data.memberId,
userId: data.userId,
token: data.token
})
setRouters(data.urls)
} else {
removeAuth()
removeRouters()
history.push('/user/login')
}
oldRender()
})
} else {
......@@ -89,20 +97,33 @@ export function render(oldRender: Function) {
*/
export function onRouteChange({ routes, matchedRoutes, location, action }) {
console.log('onRouteChange')
if (isDev) {
return;
}
// if (isDev) {
// return;
// }
if (whiteLists.includes(location.pathname)) return;
const routeAuthUrls = getRouters()
// 是否登录
if (getAuth()) {
if (routeAuthUrls.includes(location.pathname)) {
} else {
// 无权限访问时
history.replace('/memberCenter/noAuth')
const { query, pathname } = location
// 固定配置, 出现此参数说明需携带参数校验权限路由
if (query.page_type && routeAuthUrls.find(authPath => {
const parseUrl = queryString.parseUrl(authPath)
const { query: selfQuery, url } = parseUrl
// 当页面出现参数page_type时, 需进入深度校验, 即对应的参数和路径匹配
return url === pathname && selfQuery.page_type === query.page_type
})) {
// 深度匹配成功, 可正常访问
return ;
}
// 是否在路由权限列表里
if (routeAuthUrls.includes(pathname)) {
return ;
}
// 无权限访问时
history.replace('/memberCenter/noAuth')
} else {
history.replace('/user/login')
}
......
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { Input, Space, Select, Button } from 'antd';
import { CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import { useFieldState, FormPath, FormEffectHooks } from '@formily/antd';
import { useFieldState, FormPath, FormEffectHooks, useFormEffects } from '@formily/antd';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { PublicApi } from '@/services/api';
/**
* 筛选项 搜索和远程数据结合的select
* search的值暂存至schema的props下的searchValue
* option数据暂存至schema的props下的dataOption
*/
const { Option } = Select
// export interface SearchProps {
......@@ -14,35 +20,32 @@ const { Option } = Select
// }
const CustomInputSearch = props => {
console.log(props);
const justifyAlign = props.props['x-component-props'].align || 'flex-end';
const [brandData, setBrandData] = useState<any>([])
const [brandValue, setBrandValue] = useState(undefined)
const handleBrandSearch = (value: any) => { // end value
console.log(value, '搜索值')
if (value) {
PublicApi.getProductSelectGetSelectBrand({ name: value }).then(res => {
if (res.code === 1000)
setBrandData(res.data)
})
} else {
setBrandData([])
}
}
console.log(props, 'props')
const { form } = props
const justifyAlign = props.props['x-component-props'].align || 'flex-end'
const option = props.props['x-component-props'].dataOption
const [dataOption, setDataOption] = useState<any>([])
// 只能在组件中获取对应的值
useEffect(() => {
setDataOption(option)
}, [option])
const handleValueSearch = (value: any) => {
form.setFieldState(props.props.key, state => {
state.props["x-component-props"].searchValue = value // search的值暂存至schema的props下的searchValue
})
}
return (
<Space size={20} style={{ justifyContent: justifyAlign, width: '100%' }}>
<Select
// value={brandValue}
onSearch={value => handleBrandSearch(value)}
onSearch={value => handleValueSearch(value)}
onChange={v => props.mutators.change(v)}
value={props.value}
{...props.props['x-component-props']}
>
{brandData.map(d => <Option value={d.id} key={d.id}>{d.name}</Option>)}
{dataOption.map(d => <Option value={d.id} key={d.id}>{d.name}</Option>)}
</Select>
</Space>
);
......
import React from 'react';
import { Radio, Tooltip } from 'antd';
const CustomCheckbox = props => {
const { layout } = props
return (
<Radio.Group value={props.value} onChange={props.onChange} className={layout === 'column' ? 'identityRadio' : 'businessRadio'} name={props.name}>
{
props.dataSource && props.dataSource.map((v, i) => <Tooltip title={v.label} placement='leftTop' key={v.value + i}><Radio.Button value={v.value} >{v.label}</Radio.Button></Tooltip>)
}
</Radio.Group>
)
}
export default CustomCheckbox
\ No newline at end of file
......@@ -3,12 +3,14 @@ import UploadImage from "@/components/UploadImage"
const CustomUpload = (props) => {
const { mutators } = props
const uploadProps = props.props['x-component-props'] || {}
return <UploadImage
imgUrl={props.value}
onChange={data => {
// 这里能拿到change后的data值
mutators.change(data)
}}
{...uploadProps}
/>
}
......
import React from 'react'
import { Row, Input, Col, Button } from 'antd';
import useCountDown from '@/utils/hooks';
const Phone = (props) => {
const {text, isActive, start} = useCountDown({
maxTime: 60,
minTime: 0,
initText: '获取验证码',
onEnd: () => {},
decayRate: 1,
delay: 1 * 1000
})
const { value } = props
return (
<Row style={{width: '100%'}}>
<Col flex={1}>
<Input
value={value || ''}
onChange={e => props.mutators.change(e.target.value)}
{...props.props['x-component-props']}
/>
</Col>
<Col style={{marginLeft: 8}}>
<Button disabled={isActive} style={{minWidth: 110, marginLeft: 8}} size='large' onClick={start}>{text}</Button>
</Col>
</Row>
)
}
Phone.defaultProps = {}
Phone.isFieldComponent = true;
export default Phone
\ No newline at end of file
......@@ -18,8 +18,10 @@ import CustomRegistryPhone from './components/CustomRegistryPhone';
import CustomRelevance from './components/CustomRelevance';
import Children from './components/Children';
import CircleBox from './components/CircleBox';
import Phone from './components/Phone';
import CustomRadio from './components/CustomRadio';
import './index.less'
import { Input } from '@formily/antd-components';
import { Checkbox } from '@formily/antd-components';
export interface NiceFormProps extends IAntdSchemaFormProps {}
......@@ -78,10 +80,12 @@ const schemaLayout = createControllerBox("schemaLayout", (_props) => {
const NiceForm: React.FC<NiceFormProps> = props => {
const { children, components, ...reset } = props;
const customComponents = {
CheckboxSingle: Checkbox,
CustomUpload,
CustomStatus,
CustomAddArray,
CustomSlider,
CustomRadio,
Search,
CustomInputSearch,
Submit,
......@@ -93,7 +97,8 @@ const NiceForm: React.FC<NiceFormProps> = props => {
Children,
CircleBox,
SchemaFormButtonGroup,
FlexBox
FlexBox,
Phone,
};
const defineComponents = Object.assign(customComponents, components);
......
......@@ -4,6 +4,7 @@ import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'
import { UploadFile, UploadChangeParam } from 'antd/lib/upload/interface'
import cx from 'classnames'
import styles from './index.less'
import { UPLOAD_TYPE } from '@/constants'
interface UploadImagePorpsType {
imgUrl: string;
......@@ -12,10 +13,11 @@ interface UploadImagePorpsType {
disabled?: boolean;
large?: boolean;
fileMaxSize?: number;
showDesc?: boolean
}
const UploadImage: React.FC<UploadImagePorpsType> = forwardRef((props, ref) => {
const { imgUrl, onChange, size = "386x256", disabled = false, large = false, fileMaxSize = 200 } = props
const { imgUrl, onChange, showDesc = true, size = "386x256", disabled = false, large = false, fileMaxSize = 200 } = props
const [loading, setLoading] = useState<boolean>(false)
const beforeUpload = (file: UploadFile) => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
......@@ -34,7 +36,7 @@ const UploadImage: React.FC<UploadImagePorpsType> = forwardRef((props, ref) => {
action: '/api/file/file/upload',
headers: {},
data: {
fileType: 1
fileType: UPLOAD_TYPE
},
disabled: loading || disabled,
showUploadList: false,
......@@ -72,9 +74,12 @@ const UploadImage: React.FC<UploadImagePorpsType> = forwardRef((props, ref) => {
}
</div>}
</Upload>
<div className={styles.size_require}>
<p>支持JPG/PNG/JPEG, <br />最大不超过 {fileMaxSize}K, <br />尺寸:{size}</p>
</div>
{
showDesc &&
<div className={styles.size_require}>
<p>支持JPG/PNG/JPEG, <br />最大不超过 {fileMaxSize}K, <br />尺寸:{size}</p>
</div>
}
</div>
)
})
......
......@@ -10,6 +10,7 @@ export const MALL_TYPE = {
// 本地环境跳过权限校验
export const isDev = process.env.NODE_ENV === "development"
// export const isDev = false
export const Environment_Status = {
0: "所有",
......
@import './mixins/layout.less';
#root {
// 去除input type为number时的箭头
.ant-input-number-handler-wrap {
display: none;
}
.common_checkbox {
&:hover,
......
......@@ -148,26 +148,7 @@ const CategoryAttributes: React.FC<{}> = () => {
align: 'center',
dataIndex: 'isEnable',
key: 'isEnable',
render: (text: any, record: any) => {
let component: ReactNode = null
component = (
<Popconfirm
title="确定要执行这个操作?"
onConfirm={() => confirm(record)}
onCancel={cancel}
okText="是"
cancelText="否"
>
<Button
type="link"
style={text ? { color: '#00B37A' } : { color: 'red' }}
>
{text ? <>有效 <PlayCircleOutlined /></> : <>无效 <PauseCircleOutlined /></>}
</Button>
</Popconfirm>
)
return component
}
render: (text: any, record: any) => text ? '有效' : '无效'
},
{
title: '操作',
......@@ -261,7 +242,8 @@ const CategoryAttributes: React.FC<{}> = () => {
linkTableRowData.forEach((item, index) => {
linkArray.push(item.id)
})
console.log(linkArray)
// console.log(linkArray, goodsRowCtl)
goodsRowCtl.setSelectedRowKeys(linkArray)
setSelectedTableRowKeys(linkArray)
}
......
......@@ -36,7 +36,8 @@ const AddProducts: React.FC<{}> = (props) => {
setProductName,
setAttributeLists,
clearData,
setProductInfoByEdit
setProductInfoByEdit,
isAllAttributePic
} = ProductStore
useEffect(()=>{
......@@ -69,7 +70,6 @@ const AddProducts: React.FC<{}> = (props) => {
await __.current.validateFields()
)
})
// console.log(data,'data')
Promise.all(data).then((values) => {
// 提交的数据进行处理
// console.log(values, productSelectAttribute, productAttributeAndImageParams, '所有数据')
......@@ -77,25 +77,30 @@ const AddProducts: React.FC<{}> = (props) => {
delete _itme.attributeName
delete _itme.isPrice
})
if(productAttributeAndImageParams.length>0){
productAttributeAndImageParams.map(_item => {
if(_item.goodsCustomerAttributeList.length>0){
_item.goodsCustomerAttributeList.map(__item => {
delete __item.customerAttributeName
__item.customerAttributeValueId = __item.id
})
}
if(_item.commodityPic.length>0){
_item.commodityPic = _item.commodityPic.map(__item => {
return __item?.response?.data || __item?.url // 编辑情况下兼顾手动添加图片列表属性
})
}else{
return message.error("每项请至少上传一张商品图片!")
}
})
}
else{
return message.error("每项请至少上传一张商品图片!")
try{
if(productAttributeAndImageParams.length>0){
console.log(productAttributeAndImageParams,'____')
productAttributeAndImageParams.map(_item => {
if(_item.goodsCustomerAttributeList.length>0){
_item.goodsCustomerAttributeList.map(__item => {
delete __item.customerAttributeName
__item.customerAttributeValueId = __item.id
})
}
if(_item.commodityPic.length>0){
_item.commodityPic = _item.commodityPic.map(__item => {
return __item?.response?.data || __item?.url // 编辑情况下兼顾手动添加图片列表属性
})
}else{
throw new Error('每项请至少上传一张商品图片!')
}
})
}
else{
throw new Error('每项请至少上传一张商品图片!')
}
}catch(e){
return e
}
let _bacsicForm = {...values[0]}
_bacsicForm.customerCategoryId = _bacsicForm.customerCategoryId[_bacsicForm.customerCategoryId.length-1]
......@@ -106,26 +111,30 @@ const AddProducts: React.FC<{}> = (props) => {
...values[4],
commodityAttributeList: productSelectAttribute,
unitPriceAndPicList: productAttributeAndImageParams,
commodityRemark: productDescription
commodityRemark: productDescription,
isAllAttributePic: isAllAttributePic,
}
_params.minOrder = Number(_params.minOrder)
_params.logistics.weight = Number(_params.logistics.weight)
// 处理地址
let _commodityAreaList:any = []
// console.log(_params, '_params')
_params.commodityAreaList.length > 0 && _params.commodityAreaList.map(_itme => {
if(_itme){
let _temp: any = {}
let pobj = areaOption.filter(_=>_.code===_itme[0])[0]
let cobj = pobj.areaResponses.filter(__=>__.code===_itme[1])[0]
_temp.provinceCode = pobj.code
_temp.provinceName = pobj.name,
_temp.cityCode = cobj.code,
_temp.cityName = cobj.name,
_temp.provinceCode = pobj?.code || null
_temp.provinceName = pobj?.name || null
_temp.cityCode = cobj?.code || null
_temp.cityName = cobj?.name || null
// 增加不限市区字段
cobj?.code ? _temp.isAllCity = false : _temp.isAllCity = true
_commodityAreaList.push(_temp)
// console.log(_itme, _temp, '地址的每一项')
}
})
// 增加不限区域字段
_commodityAreaList.length > 0 ? _params.isAllArea = false : _params.isAllArea = true
_params.commodityAreaList = _commodityAreaList
const { id } = history.location.query
_params.id = id ? id : null
......@@ -133,17 +142,20 @@ const AddProducts: React.FC<{}> = (props) => {
PublicApi.postProductCommoditySaveOrUpdateCommodity(_params).then(res => {
if(res.code === 1000){
setIsEnableCheck(false)
//@ts-ignore
setReponseId(res.data)
history.goBack()
}
})
}).then( e => {
console.log(e, 'e')
if(e)
message.error(e.message)
}).catch(error => {
message.error("请完善表单必填项!")
console.log(error, '_error')
})
message.error(error.message)
})
}catch(e){
message.error(e.message)
console.log(e,'error')
}
}
......@@ -189,7 +201,7 @@ const AddProducts: React.FC<{}> = (props) => {
onRef={(refs)=>setFormRefs([...formRefs, refs])}
/>
</TabPane>
<TabPane tab="商品图片" key="5" style={{ border: '1px solid rgba(223,225,230,1)' }}>
<TabPane tab="商品图片" key="5">
<ProductImageForm />
</TabPane>
<TabPane tab="商品描述" key="6">
......
import React, { useState, useEffect, useRef } from 'react'
import { history } from 'umi'
import { Form, Select, Radio, Input, Checkbox } from 'antd'
import { Form, Select, Radio, Input, Checkbox, InputNumber } from 'antd'
import { PublicApi } from '@/services/api'
import { GetLogisticsSelectListCompanyResponse, GetLogisticsSelectListShipperAddressResponse, GetLogisticsSelectListFreightTemplateResponse } from '@/services'
import { store } from '@/store'
......@@ -112,19 +112,22 @@ const LogisticsForm: React.FC<Iprops> = (props) => {
</Radio.Group>
</Form.Item>
<Form.Item
name="weight"
label="重量"
rules={[
{
required: true,
type: 'number',
message: '请填入重量',
min: 0,
transform: (value) => Number(value)
},
]}
style={{position: 'relative'}}
>
<Input suffix="KG" placeholder="请输入重量" />
<Form.Item
name="weight"
rules={[
{
required: true,
message: '请正确输入重量',
}
]}
noStyle
>
<InputNumber min={0} style={{width:'100%'}} placeholder="请输入重量" />
</Form.Item>
<span style={{position:'absolute', right:5, top:5, opacity: 0.6}}>KG</span>
</Form.Item></>
}
{
......
......@@ -56,7 +56,7 @@ const ProductAttributeForm: React.FC<Iprops> = (props) => {
* @param {Number, Array, e} value type为1:数字id,type为2:数组id,type为3:事件对象
* @param {Object} attrItem 属性数据对象
*/
const onChange = (value, attrItem) => { // 编辑情况下 这里只生成一个 关联表格会有问题
const onChange = (value, attrItem) => {
let params = { customerAttributeId: attrItem.id, attributeName: attrItem.name, isPrice: attrItem.isPrice, customerAttributeValueList: [] }
console.log(params, 'params')
if(attrItem.type!==3){
......@@ -103,12 +103,12 @@ const ProductAttributeForm: React.FC<Iprops> = (props) => {
/* 编辑情况下,利用商品信息中的属性值转换为结果参数,用于后续表格生成 */
const constructProductSelectAttribute = () => {
let _selectAttributeByEdit = productInfoByEdit.commodityAttributeList.map((item, index) => {
// console.log(item,'__edit__',attributeLists[index])
console.log(item,'__edit__',attributeLists[index])
return {
attributeName: item.customerAttribute.name,
customerAttributeId: item.customerAttribute.id,
customerAttributeValueList: item.customerAttributeValueList,
isPrice: attributeLists.filter(_item => _item.name === item.customerAttribute.name)[0].isPrice
isPrice: attributeLists.filter(_item => _item.name === item.customerAttribute.name)[0]?.isPrice
}
})
console.log(_selectAttributeByEdit, '__selectAttributeByEdit__', attributeLists)
......@@ -130,7 +130,7 @@ const ProductAttributeForm: React.FC<Iprops> = (props) => {
}]}
>
<Select
placeholder="请选择面料"
placeholder="请选择"
allowClear
onChange={(v)=>onChange(v, attrItem)}
>
......
import React, { useState, useEffect } from 'react'
import {history} from 'umi'
import { Button, Form, Select, Checkbox, message, Input, Table, Modal, Row, Col, Alert, Upload } from 'antd'
import { Button, Form, Select, Checkbox, message, Input, Table, Modal, Row, Col, Alert, Upload, Radio } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import CustomTabs, { ItemPane } from '@/components/CustomTabs'
import styles from './index.less'
......@@ -43,23 +43,19 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
const [previewVisible, setPreviewVisible] = useState(false)
const [previewImage, setPreviewImage] = useState('')
const [previewTitle, setPreviewTitle] = useState('')
const [setImageType, setSetImageType] = useState<boolean>(true)
const { ProductStore } = store
const { priceAttributeParams, productInfoByEdit, setProductAttributeAndImageParams } = ProductStore
const { priceAttributeParams, productInfoByEdit, setProductAttributeAndImageParams, setIsAllAttributePic } = ProductStore
/* 给数据添加图片字段 */
useEffect(()=>{
// console.log('!!!', priceAttributeParams)
// let _priceAttributeParams = priceAttributeParams.map(_item=>{
// let _obj = {..._item}
// _obj.commodityPic = [] // 编辑情况下 经行处理
// return _obj
// })
let _priceAttributeParams: any = []
if(productInfoByEdit?.id){ // id判断是否新增还是编辑
setSetImageType(productInfoByEdit.isAllAttributePic || true)
let _commodityPicList = productInfoByEdit.unitPriceAndPicList.map(_ => _.commodityPic)
_priceAttributeParams = priceAttributeParams.map((_item, _index) => {
// console.log(_commodityPicList[_index]) // 为图片字符串数组手动添加 uid 和 status
// 为图片字符串数组手动添加 uid 和 status
let _commodityPicItem = Array.isArray(_commodityPicList[_index]) ? _commodityPicList[_index].map((__ele, __i) => {
return {
uid: __i * -1,
......@@ -81,14 +77,22 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
// console.log('???', _priceAttributeParams)
if(_priceAttributeParams?.length>0 && _priceAttributeParams[0]?.goodsCustomerAttributeList?.length!=0){
setDefaultChecked(0)
}else{
setDefaultChecked(-1)
}
clickItemTab(-1)
setPriceAttributeParamsByRender(_priceAttributeParams)
setProductAttributeAndImageParams(_priceAttributeParams)
console.log(_priceAttributeParams, '_p')
// 初始化若是按所有属性共用做显示处理
if(setImageType){
setCommonImageList(_priceAttributeParams[0].commodityPic)
}
},[priceAttributeParams])
const clickItemTab = (_index: number) => {
// console.log(_index, '点击项')
console.log(_index, '点击项')
setDefaultChecked(_index)
// console.log(priceAttributeParams, 'params')
}
......@@ -110,16 +114,15 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
}
const beforeUpload = (file: UploadFile) => {
console.log(file,'file')
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
if (!isJpgOrPng) {
message.error('仅支持上传JPEG/JPG/PNG文件!')
}
const isLt2M = file.size / 1024 < 600;
if (!isLt2M) {
message.error('上传图片不超过2MB!');
const isLimit = file.size / 1024 < 600;
if (!isLimit) {
message.error('上传图片不超过600K!');
}
return isJpgOrPng && isLt2M && isSize(file, 800, 800);
return isJpgOrPng && isLimit && isSize(file, 800, 800);
}
//检测尺寸
const isSize = (file, w, h) => {
......@@ -153,31 +156,66 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1))
}
const handleChange = ({ fileList }, index) => {
// console.log(priceAttributeParamsByRender, fileList, index, 'files change')
const handleChange = ({ file, fileList }, index) => {
let _priceAttributeParams = [...priceAttributeParamsByRender]
if(index===-1){ // -1表示所有属性共用 也表示表格只有默认的一行
console.log(_priceAttributeParams, '图片更改初始数据')
// if(index===-1){ // -1表示所有属性共用 也表示表格只有默认的一行 // 无需判断 不管是共用还是不共用都需要逐条写入fileList
setCommonImageList(fileList)
_priceAttributeParams[0].commodityPic = fileList
}else{
// _priceAttributeParams[0].commodityPic = fileList
// }else{
_priceAttributeParams[index].commodityPic = fileList
// }
if(!file?.status && file?.status !== 'done'){
// 不符合要求的 移除没有'done'状态的图片
if(index === -1){
let ttt = _priceAttributeParams[0].commodityPic.filter(_ => _.status === 'done')
setCommonImageList(ttt)
_priceAttributeParams[0].commodityPic = ttt
}else{
let ttt = _priceAttributeParams[index].commodityPic.filter(_ => _.status === 'done')
_priceAttributeParams[index].commodityPic = ttt
}
}
console.log(_priceAttributeParams, '图片更改之后数据')
setPriceAttributeParamsByRender(_priceAttributeParams)
setProductAttributeAndImageParams(_priceAttributeParams)
// console.log(_priceAttributeParams, '_priceAttributeParams')
}
return (<>
<div>
const onChangeSetImageType = (e) => {
setSetImageType(e.target.value)
setIsAllAttributePic(e.target.value)
if(e.target.value)
clickItemTab(-1)
else
clickItemTab(0)
// 切换 清空图片数组
let _priceAttributeParams = [...priceAttributeParamsByRender]
_priceAttributeParams.map(item => {
item.commodityPic = []
})
setPriceAttributeParamsByRender(_priceAttributeParams)
setProductAttributeAndImageParams(_priceAttributeParams)
setCommonImageList([])
}
return (<div>
<div style={{marginBottom:15}}>设置方式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<Radio.Group onChange={onChangeSetImageType} value={setImageType}>
<Radio value={true}>所有属性共用商品图片(默认)</Radio>
<Radio value={false}>按属性设置商品图片</Radio>
</Radio.Group>
</div>
<div style={{ border: '1px solid rgba(223,225,230,1)' }}>
<Row>
<Col span={4} className={styles.colBox}>
<ul>
{priceAttributeParamsByRender?.length>0 && priceAttributeParamsByRender[0]?.goodsCustomerAttributeList?.length!=0 ? <span className={styles.tipTitle}>按特定属性添加图片</span>
: <li className={defaultChecked == -1 ? styles.activedLi : ""} onClick={()=>clickItemTab(-1)}>
<span>所有属性共用</span>
</li>
}
{
!setImageType ? <span className={styles.tipTitle}>按特定属性添加图片</span>
: <li className={defaultChecked == -1 ? styles.activedLi : ""} onClick={()=>clickItemTab(-1)}>
<span>所有属性共用</span>
</li>
}
{ !setImageType &&
priceAttributeParamsByRender?.length>0 && priceAttributeParamsByRender.map(
(item, index) => {
return Array.isArray(item.goodsCustomerAttributeList) &&
......@@ -195,6 +233,7 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
</Col>
<Col span={20} style={{ padding: 24 }}>
{
!setImageType &&
priceAttributeParamsByRender?.length>0 && priceAttributeParamsByRender[0]?.goodsCustomerAttributeList?.length!=0 ? priceAttributeParamsByRender.map((item, index) =>
<div key={index+100} style={defaultChecked == index ? {display: 'block'} : {display: 'none'}}>
<div className={styles.pictureCardBox}>
......@@ -223,7 +262,7 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
style={{ backgroundColor: '#F0F8FF', color: '#1B9AEE' }}
/>
</div>
)
)
: <div style={defaultChecked == -1 ? {display: 'block'} : {display: 'none'}}>
<div className={styles.pictureCardBox}>
<div className="clearfix">
......@@ -263,7 +302,7 @@ const ProductImageForm: React.FC<Iprops> = (props) => {
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
</>)
</div>)
}
export default observer(ProductImageForm)
\ No newline at end of file
......@@ -37,7 +37,7 @@ const SelectGoodsForm: React.FC<Iprops> = (props) => {
const { id } = history.location.query
if(id){
let _goodsArr: any = productInfoByEdit?.unitPriceAndPicList.map(_ => _.goods)
let goodsArr: any = _goodsArr.length>0 && Object.values(_goodsArr.reduce((item, next)=>{
let goodsArr: any = _goodsArr.toString() && _goodsArr.length>0 && Object.values(_goodsArr.reduce((item, next)=>{
item[next.id] = next;
return item
},{}))
......
......@@ -21,6 +21,9 @@ import { FORM_FILTER_PATH } from '@/formSchema/const'
import { createFormActions, FormEffectHooks } from '@formily/antd'
import { channelSchema } from './schema/channelSchema'
import { useAsyncInitSelect } from '@/formSchema/effects/useAsyncInitSelect'
import { PublicApi } from '@/services/api'
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect'
import { searchBrandOptionEffect, searchCustomerCategoryOptionEffect } from './effect'
// 定义选择的行数据的类型
interface Item {
......@@ -267,6 +270,12 @@ const DirectChannel: React.FC<{}> = () => {
}
}
// const fetchSelectBrand = async (params) => {
// const { data } = await PublicApi.getProductSelectGetSelectBrand({ name: params })
// console.log(params, data)
// return data
// }
const menuMore = (
<Menu onClick={(param) => handleMenuClick(param)}>
<Menu.Item key="2" icon={<VerticalAlignTopOutlined />}>
......@@ -320,13 +329,12 @@ const DirectChannel: React.FC<{}> = () => {
'name',
FORM_FILTER_PATH,
)
FormEffectHooks.onFieldInputChange$('brandId').subscribe(state => {
console.log(state, 'state')
FormEffectHooks.onFieldChange$('brandId').subscribe(state => {
searchBrandOptionEffect(actions, 'brandId')
})
FormEffectHooks.onFieldChange$('customerCategoryId').subscribe(state => {
searchCustomerCategoryOptionEffect(actions, 'customerCategoryId')
})
// useAsyncInitSelect(
// ['memberType', 'roleId', 'level', 'source'],
// fetchSearchItems,
// );
}}
schema={channelSchema}
/>
......
import React, { useEffect } from 'react'
import { ISchemaFormActions, FormEffectHooks, IFormActions } from '@formily/antd';
import { PublicApi } from '@/services/api';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
const { onFieldValueChange$ } = FormEffectHooks
// 高级筛选schema中用于输入搜索品牌的Effect
export const searchBrandOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
// console.log(state.props['x-component-props'].searchValue, 'pagesearchvalue') // 此处可以实时获取到输入并暂存在schema props的值
PublicApi.getProductSelectGetSelectBrand({ name: state.props['x-component-props'].searchValue }).then(res => {
context.setFieldState(fieldName, state => {
state.props['x-component-props'].dataOption = res.data
})
})
})
}
// 高级筛选schema中用于输入搜索商品品类的Effect
export const searchCustomerCategoryOptionEffect = (context: any, fieldName: string) => {
context.getFieldState(fieldName, state => {
PublicApi.getProductSelectGetSelectCustomerCategory({ name: state.props['x-component-props'].searchValue }).then(res => {
context.setFieldState(fieldName, state => {
state.props['x-component-props'].dataOption = res.data
})
})
})
}
\ No newline at end of file
import React, { useState, useEffect, useRef, ReactNode } from 'react'
import { history } from 'umi'
import { Button, Form, Card, Modal, Result, Progress, Select, Tooltip, Checkbox, Row, Col, Dropdown, Input, Menu, Popconfirm } from 'antd'
import { Button, Form, Card, Modal, Result, Progress, Select, Tooltip, Checkbox, Row, Col, Dropdown, Input, Menu, Popconfirm, message } from 'antd'
import { PageHeaderWrapper } from '@ant-design/pro-layout'
import {
PlusOutlined,
......@@ -222,7 +222,7 @@ const Products: React.FC<{}> = () => {
</Menu.Item>
{(record.status === 4 || record.status === 6) ? <Menu.Item><Button type='link' onClick={() => clickUp(1, record.id)}>上架</Button></Menu.Item> : ''}
{record.status === 5 ? <Menu.Item><Button type='link' onClick={() => clickUp(0, record.id)}>下架</Button></Menu.Item> : ''}
{record.status === 3 ? <Menu.Item><Button type='link' onClick={() => clickModify(record.id)}>修改</Button></Menu.Item> : ''}
{record.status === 3 || record.status === 1 ? <Menu.Item><Button type='link' onClick={() => clickModify(record.id)}>修改</Button></Menu.Item> : ''}
<Menu.Item>
<Button type='link' onClick={()=>clickCopy(record)}>复制</Button>
</Menu.Item>
......@@ -412,7 +412,14 @@ const Products: React.FC<{}> = () => {
}
const onChangeUpShop = (values) => {
setCheckedValues(values)
// 判断上架之前是否有店铺 有即可以上下架
PublicApi.getTemplateShopFindShop().then(res => {
if(res.data.logo){
setCheckedValues(values)
}else{
message.error('您还没有开通店铺,无法上下架商品!')
}
})
}
const clickUp = (param: any, id: any) => { // param: 0 下架 1上架
......@@ -620,7 +627,7 @@ const Products: React.FC<{}> = () => {
defaultActiveFirstOption={false}
filterOption={false}
onSearch={handleBrandSearch}
onChange={handleBrandChange}
onChange={handleBrandChange}
notFoundContent={null}
style={{width:'100%'}}
>
......
......@@ -61,28 +61,89 @@ export const channelSchema: ISchema = {
filterOption: false,
notFoundContent: null,
style: { width: '174px', lineHeight: '32px' },
value: null,
searchValue: null,
dataOption: [],
},
},
customerCategoryId: {
type: 'string',
enum: [],
'x-component': 'CustomInputSearch',
'x-component-props': {
placeholder: '商品品类',
showSearch: true,
showArrow: true,
defaultActiveFirstOption: false,
filterOption: false,
notFoundContent: null,
style: { width: '174px', lineHeight: '32px' },
searchValue: null,
dataOption: []
},
},
status: {
type: 'string',
enum: [],
enum: [
{
label: '待提交审核',
value: 1,
},
{
label: '待审核',
value: 2,
}
],
'x-component-props': {
placeholder: '商品状态'
placeholder: '商品状态',
style: { width: '174px' },
},
},
price: {
type: 'string',
// price: {
// type: 'string',
// 'x-component-props': {
// placeholder: '商品价格'
// },
// },
'NO_NAME_FIELD_$2': {
type: 'object',
'x-component': 'layout',
'x-component-props': {
placeholder: '商品价格'
style: { width: '174px', display: 'flex', justifyContent: 'flex-start' },
},
properties: {
min: {
type: 'string',
"x-component-props": {
placeholder: '最低价',
type: 'number',
min: 0,
style: { width: '70px', textAlign: 'center', borderRight: 0 }
}
},
"gap": {
type: 'string',
"x-component-props": {
style: {
width: '34px',
borderLeft: 0,
borderRight: 0,
pointerEvents: 'none',
backgroundColor: '#fff',
textAlign: 'center'
},
placeholder: "~",
disabled: true,
}
},
max: {
type: 'string',
"x-component-props": {
placeholder: '最高价',
type: 'number',
min: 0,
style: { width: '70px', textAlign: 'center', borderLeft: 0 }
}
},
}
},
submit: {
'x-component': 'Submit',
......
......@@ -212,14 +212,23 @@ const viewProducts: React.FC<{}> = () => {
</Descriptions>
</>
/* 定价类型 */
//1-现货价格,2-价格需要询价,3-积分兑换商品
const renderPriceType = (type: number) => {
if(type === 1 ) return '现货价格'
if(type === 2 ) return '价格需要询价'
if(type === 3 ) return '积分兑换商品'
}
const renderDeliveryType = (type: number) => {
if(type === 1) return '物流(默认)'
if(type === 2) return '自提'
if(type === 3) return '无需配送'
}
const renderCarriageType = (type: number) => {
if(type === 1) return '卖家承担运费(默认)'
if(type === 2) return '买家承担运费'
}
/* 构建表格数据 */
const constructTableData = (productName: string, unitPriceAndPicList: GetProductCommodityGetCommodityResponse["unitPriceAndPicList"]) => {
// 构建列
......@@ -365,15 +374,15 @@ const viewProducts: React.FC<{}> = () => {
<p>配送方式:</p>
</Col>
<Col span={20}>
<p>物流(默认)</p>
<p>{renderDeliveryType(productDetail?.logistics?.deliveryType)}</p>
</Col>
</Row>
<Row>
<Col span={4}>
<p>方式:</p>
<p>方式:</p>
</Col>
<Col span={20}>
<p>买家承担运费</p>
<p>{renderCarriageType(productDetail?.logistics?.carriageType)}</p>
</Col>
</Row>
<Row>
......
......@@ -85,7 +85,7 @@ const LoginWrap: React.FC = () => {
</Form.Item>)
}
<Form.Item>
<Button type='primary' size='large' htmlType='submit' block>点击登录</Button>
<Button type='primary' size='large' htmlType='submit' block>登录</Button>
</Form.Item>
</Form>
}
......
This diff is collapsed.
import { ISchema } from '@formily/antd';
import { PATTERN_MAPS } from '@/constants/regExp';
import { GlobalConfig } from '@/global/config';
export const registerStep0Schema: ISchema = {
type: 'object',
properties: {
REGISTER_STEP: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
className: 'registerForm',
full: true
},
properties: {
phone: {
type: 'string',
required: true,
"x-rules": [
{
pattern: PATTERN_MAPS.phone,
message: '请填写手机号'
}
],
"x-component-props": {
placeholder: '请输入您的手机号码',
size: 'large'
},
"x-props": {
addonBefore: "{{phoneBefore}}"
}
},
smsCode: {
type: 'string',
"x-component": 'Phone',
required: true,
"x-rules": [
{
pattern: PATTERN_MAPS.smsCode,
message: '请输入正确的6位验证码'
}
],
"x-component-props": {
size: 'large',
}
},
password: {
type: 'password',
required: true,
"x-rules": [
{
pattern: PATTERN_MAPS.password,
message: '请输入正确的密码'
}
],
"x-component-props": {
placeholder: '请设置你的登录密码',
size: 'large',
}
},
confirmPassword: {
type: 'password',
required: true,
"x-rules": [
{
pattern: PATTERN_MAPS.password,
message: '请输入正确的密码'
}
],
"x-component-props": {
placeholder: '请再次输入你的登录密码',
size: 'large',
}
},
email: {
type: 'string',
"x-rules": [
{
pattern: PATTERN_MAPS.email,
message: '请输入正确的邮箱'
}
],
"x-component-props": {
placeholder: '请输入你的邮箱(选填)',
size: 'large',
type: 'email'
}
},
isRead: {
required: true,
"x-component": 'CheckboxSingle',
"x-component-props": {
children: "{{checkBoxChildren}}"
}
}
}
},
}
}
export const registerStep1Schema: ISchema = {
type: 'object',
properties: {
REGISTER_STEP: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
className: 'formBoxStep2'
},
properties: {
BLOCK_LAYOUT1: {
type: 'object',
"x-component": 'block',
"x-component-props": {
title: "{{memberTypeTitle}}",
className: 'mr_t-40'
},
properties: {
typeId: {
type: 'string',
required: true,
"x-component": 'CustomRadio',
"x-component-props": {
layout: 'column'
},
enum: GlobalConfig.userRegister.useType.memberType.map(v => {
return {
value: v.id,
label: v.typeName
}
})
},
}
},
BLOCK_LAYOUT2: {
type: 'object',
"x-component": 'block',
"x-component-props": {
title: "{{businessTypeTitle}}",
className: 'mr_t-40'
},
properties: {
businessTypeId: {
type: 'string',
required: true,
"x-component": 'CustomRadio',
"x-component-props": {
layout: 'row'
},
enum: GlobalConfig.userRegister.useType.businessType.map(v => {
return {
value: v.id,
label: v.typeName
}
})
},
}
}
},
}
}
}
export default {
schema0: registerStep0Schema,
schema1: registerStep1Schema
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -13,6 +13,7 @@ class ProductStore implements IProductModule {
@observable public areaOption: any[] = [];
@observable public productInfoByEdit: GetProductCommodityGetCommodityResponse;
@observable public productDescription: IDecsParams;
@observable public isAllAttributePic: boolean = null; // 是否所有属性共用
/** 计算操作 **/
// 加工接口返回的数据,用户编辑回显数据
......@@ -37,11 +38,16 @@ class ProductStore implements IProductModule {
let attributeIdArr = attributeArr.map(item => item.id)
let attributeValueIdArr = attributeValueArr.map(item => item.map(_item => _item.id))
let tempObj = {}
console.log(attributeArr, attributeValueArr, this.attributeLists, this.productSelectAttribute,'store Item')
attributeIdArr.map((item, index) => {
if(attributeValueIdArr[index].length>1){
tempObj[item] = attributeValueIdArr[index]
}else{
tempObj[item] = attributeValueIdArr[index][0]
// 类型为2如果是一个的话 为配合checkbox Group也要生成数组
if(this.attributeLists.filter(_item => _item.id === item)[0]?.type === 2) // 多选
tempObj[item] = attributeValueIdArr[index]
else
tempObj[item] = attributeValueIdArr[index][0]
}
})
return tempObj
......@@ -125,6 +131,11 @@ class ProductStore implements IProductModule {
public setProductDescription(data: IDecsParams) {
this.productDescription = data
}
@action.bound
public setIsAllAttributePic(data: boolean) {
this.isAllAttributePic = data
}
}
......
import { ReactText } from 'react';
import React, { ReactText } from 'react';
import moment from 'moment';
import deepClone from 'clone'
import { ISchema } from '@formily/antd';
import { UPLOAD_TYPE } from '@/constants';
import queryString from 'query-string'
function isArray(arr: any) {
return Array.isArray(arr)
......@@ -239,6 +242,102 @@ export const findTreeKeys = (arr: any[], keyword?: ReactText) => {
return results
}
// 转化object 成schema
export const transFormSchema = (data: any[]): ISchema => {
return {
type: 'object',
properties: {
'MEGA_LAYOUT2': {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
className: 'formBoxStep2'
},
properties: {
detail: {
type: 'object',
properties: data.reduce((prev, next, index) => {
prev[`NO_SUBMIT_BLOCK${index}`] = {
type: 'object',
"x-component": 'block',
"x-component-props": {
className: 'mr_t-40',
title: <span className={'commonPanelTitle'}>{next.groupName}</span>
},
properties: {
[`NO_SUBMIT_BLOCK_MEGA${index}`]: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
columns: 2,
grid: true,
autoRow: true,
size: 'large',
className: 'mr_t-24'
},
properties: next.elements.reduce((subP, subN, subI) => {
subP[subN.fieldName] = getFieldType(subN)
return subP
}, {})
}
}
}
return prev
}, {})
}
}
}
}
}
}
// 获取字段类型,改为schema可识别的
export const getFieldType = (field) => {
if (field.fieldType === 'upload') {
return {
type: 'string',
"x-component": "CustomUpload",
"x-mega-props": {
span: 2
},
required: field.fieldEmpty === 0,
title: field.fieldCNName,
"x-component-props": {
showDesc: false
}
}
} else {
return {
type: 'string',
"x-mega-props": {
span: 1
},
"x-component": "CustomInput",
required: field.fieldEmpty === 0,
"x-rules": field.checkRules.map(v => {
return {
message: v.msg,
pattern: v.rulePattern
}
}),
maxLength: field.fieldLength,
"x-component-props": {
help: field.fieldRemark,
placeholder: `请输入${field.fieldCNName}`,
size: 'large'
}
}
}
}
export const getQueryStringParams = (url?: string) => {
const nowUrl = url || window.location.href
const firstIndex = nowUrl.indexOf('?')
const searchParam = url ? url.substring(firstIndex) : window.location.search
return queryString.parse(searchParam)
}
export default {
isArray,
isObject,
......
......@@ -115,11 +115,8 @@ class ApiRequest {
options.ctlType === 'message' && message.success(res.message)
resolve(res)
} else {
// 未登录
if (res.code === 1101) {
history.push('/user/login')
reject()
}
// 使用resolve将数据返回, 请求时需手动处理data为null的情况
resolve(res)
message.error(res.message)
}
......
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