Commit 27cb99be authored by 张子雨's avatar 张子雨

feat: 中台一期

parent 3581b8d6
...@@ -273,6 +273,18 @@ export default { ...@@ -273,6 +273,18 @@ export default {
name: 'systemManageLog', name: 'systemManageLog',
component: './systemManage/Log', component: './systemManage/Log',
}, },
{
title: '商户管理后台-合同查看',
path: '/contractView',
name: 'contractView',
component: './contractView',
},
{
title: '商户管理后台-商家资料',
path: '/businessInfo',
name: 'businessInfo',
component: './businessManage/info',
},
{ {
component: './404', component: './404',
}, },
......
This source diff could not be displayed because it is too large. You can view the blob instead.
import React, { useState } from 'react';
import { Map, Marker, ZoomControl, CityListControl } from 'react-bmapgl';
import { Modal, Input } from 'antd';
export default props => {
const { visible, onSetPoint, onCancel, lngLat } = props;
const defaultLnglat = { lng: 116.404449, lat: 39.914889 };
if (lngLat) {
defaultLnglat.lng = lngLat.lng;
defaultLnglat.lat = lngLat.lat;
}
const [lnglatPoint, setLnglatPoint] = useState(defaultLnglat);
const [lnglatText, setLnglatText] = useState(`${defaultLnglat.lng},${defaultLnglat.lat}`);
const handleOk = () => {
onSetPoint(lnglatPoint);
onCancel(true);
};
const handleCancle = () => onCancel(true);
const onGetPoint = e => {
setLnglatPoint({
lng: e.latlng.lng,
lat: e.latlng.lat,
});
setLnglatText(`${e.latlng.lng},${e.latlng.lat}`);
};
return (
<Modal
title="门店信息"
visible={visible}
width="800px"
onOk={() => handleOk()}
onCancel={() => handleCancle()}
>
<div style={{ marginBottom: '20px' }}>
<Input value={lnglatText} placeholder="点击地图选择经纬度" />
</div>
<div style={{ width: '100%', height: '360px' }}>
<Map
center={lnglatPoint}
enableScrollWheelZoom
enableDoubleClickZoom
coordType="gcj02"
onClick={e => onGetPoint(e)}
zoom={15}
>
<Marker
position={lnglatPoint}
Icon
coordType="gcj02"
autoViewport
viewportOptions={{
zoomFactor: -12,
}}
/>
<CityListControl />
<ZoomControl />
</Map>
</div>
</Modal>
);
};
.table :global .ant-table-row-expand-icon-cell {
visibility: hidden;
}
.table :global .ant-table-expanded-row .ant-pro-table {
margin-left: -17px;
}
.logBtn {
display: inherit;
margin: 20px auto;
}
.pageHeader {
background-color: #fff;
border: 1px solid #ebedf0;
}
.listHeader {
display: flex;
}
.listHeader--item {
position: relative;
display: flex;
align-items: center;
width: 40px;
height: 40px;
text-align: center;
justify-content: center;
box-sizing: border-box;
margin-right: 20px;
font-size: 14px;
line-height: 14px;
border: 1px solid #333;
border-radius: 50%;
}
.listHeader--item::after {
position: absolute;
right: -21px;
width: 20px;
height: 1px;
background-color: #333;
content: '';
}
.listHeader--item:last-child::after {
width: 0;
height: 0;
}
import React from 'react';
import moment from 'moment';
import { PlusOutlined } from '@ant-design/icons';
import { notification, Tag, Tooltip, Input } from 'antd';
// import { reject } from 'lodash-es';
import {
uploadFile,
apiCategoryList,
apiAddrArea,
apiServiceFacility,
apiApplyDetail,
apiBusinessDetail,
apiBankList,
} from '../service';
export const wrapperCol = {
xs: { span: 24 },
sm: { span: 12 },
};
export const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 8 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 16 },
},
};
export const businessTypeDesc = {
1: '到家业务',
2: '实物业务',
3: '到店业务',
};
// 业务模式
export const businessModel = [
{ label: '到家外卖业务(外卖配送业务)', value: 1 },
{ label: '实物商品业务员', value: 2 },
{ label: '到店业务(服务类业务)', value: 3 },
];
// 获取申请信息
export async function getInfo(id, type) {
let api = apiApplyDetail;
if (['info', 'edit', 'revision'].includes(type)) {
api = apiBusinessDetail;
}
const [res] = await api(id);
let settlementType = 1;
if (res) {
if (res.facilities) {
res.customList = res.facilities.customList || [];
res.selfList = res.facilities.selfList || [];
}
res.accountOpenPermitImage = [{ uid: 0, url: res.accountOpenPermitImage }];
res.businessLicenseImage = [{ uid: 0, url: res.businessLicenseImage }];
res.idCardEmblemImage = [{ uid: 0, url: res.idCardEmblemImage }];
res.idCardPortraitImage = [{ uid: 0, url: res.idCardPortraitImage }];
res.primaryImage = [{ uid: 0, url: res.primaryImage }];
res.sealImage = [{ uid: 0, url: res.sealImage }];
if (res.categoryQualificateImage) {
res.categoryQualificateImage = [{ uid: 0, url: res.categoryQualificateImage }];
}
if (res.otherImage && res.otherImage.length) {
res.otherImage = res.otherImage.map((item, index) => ({
uid: index,
url: item,
}));
}
res.addr = [res.provinceId, res.cityId, res.countyId];
if (res.townId) {
res.addr.push(res.townId);
}
settlementType = +res.settlementType;
}
res.legalPersonPeriod = res.legalPersonPeriod.split('-').map(item => moment(item));
res.businessLicensePeriod = moment(res.businessLicensePeriod);
this.setState({
settlementType,
businessInfo: res,
});
}
// 删除图片
function delImg(keyName, e) {
this.setState(state => {
state.businessInfo[keyName].splice(e.uid, 1);
return {
businessInfo: state.businessInfo,
};
});
}
// 上传图片
export function uploadPropsFn(
{ keyName, limit = 1, maxSize = 1024 * 1024 * 5, maxSizeMsg = '文件大小不能超过5M!', type = 0 },
successCallback = () => {},
) {
const that = this;
let timer = null;
return {
maxSize,
async customRequest(info) {
const { file } = info;
if (info.file.size > maxSize) {
notification.error({ message: maxSizeMsg });
return;
}
if (that.state.businessInfo[keyName] && that.state.businessInfo[keyName].length >= limit) {
notification.error({ message: `最多只能上传${limit}个文件!` });
return;
}
const res = await uploadFile([file], type);
if (res.businessCode !== '0000') {
return;
}
const url = res.data?.[0];
that.setState(state => {
const imgList = state.businessInfo[keyName] || [];
const attachment = {
uid: imgList.length || 0,
name: file?.name,
status: 'done',
url,
};
imgList.push(attachment);
if (imgList.length <= limit) {
state.businessInfo[keyName] = imgList;
} else {
notification.error({ message: `最多只能上传${limit}个文件!` });
}
return {
businessInfo: state.businessInfo,
};
});
successCallback(keyName, url);
// 需要把上传的数据存储下来
},
disabled: this.state.disabled,
multiple: limit > 1,
listType: 'picture-card',
showUploadList: true,
accept: '.png,.bmp,.gif,.jpeg,.jpg',
onRemove: e => delImg.call(this, keyName, e),
beforeUpload: (e, flist) => {
const imgList = that.state.businessInfo[keyName] || [];
if (flist.length + imgList.length > limit) {
clearTimeout(timer);
timer = setTimeout(() => {
notification.error({ message: `最多只能上传${limit}个文件!` });
}, 100);
return false;
}
return true;
},
};
}
/** **** 自定义服务设施 start ***************************** */
// 关闭标签输入框
function handleClose(removedTag) {
this.setState(state => {
state.businessInfo.customList = state.businessInfo.customList.filter(tag => tag !== removedTag);
return {
businessInfo: state.businessInfo,
};
});
}
// 显示标签输入框
function showInput() {
this.setState({ tagVisible: true }, () => this.input.focus());
}
// 标签内容改变
function handleInputChange(e) {
if (e && e.target) {
this.setState({ tagValue: e.target.value });
}
}
// 保存标签
function handleInputConfirm() {
const { tagValue } = this.state;
if (tagValue) {
let { customList } = this.state.businessInfo;
if (tagValue && customList.indexOf(tagValue) === -1) {
customList = [...customList, tagValue];
}
this.setState(state => {
state.businessInfo.customList = customList;
return {
businessInfo: state.businessInfo,
tagVisible: false,
tagValue: '',
};
});
}
}
// 渲染标签
export function renderServiceTags() {
const that = this;
return (
<div>
{that.state.businessInfo.customList &&
that.state.businessInfo.customList.map(tag => {
const isLongTag = tag.length > 20;
const tagElem = (
<Tag key={tag} closable onClose={() => handleClose.call(that, tag)}>
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
</Tag>
);
return isLongTag ? (
<Tooltip title={tag} key={tag}>
{tagElem}
</Tooltip>
) : (
tagElem
);
})}
{that.state.tagVisible && (
<Input
// eslint-disable-next-line react/no-this-in-sfc
ref={this.saveInputRef}
type="text"
size="small"
style={{ width: 78 }}
value={that.state.tagValue}
onChange={e => handleInputChange.call(that, e)}
onBlur={e => handleInputConfirm.call(that, e)}
onPressEnter={e => handleInputConfirm.call(that, e)}
/>
)}
{!that.state.tagVisible && (
<Tag
onClick={() => showInput.call(that)}
style={{ background: '#fff', borderStyle: 'dashed' }}
>
<PlusOutlined /> 新增
</Tag>
)}
</div>
);
}
/** **** 自定义服务设施 end ***************************** */
// 获取主营类目
export async function getCategoryList() {
const [res] = await apiCategoryList();
if (res) {
this.setState({
categoryList: res,
});
}
}
// 获取服务设施
export async function getServiceFacility() {
const res = await apiServiceFacility();
if (res.data) {
this.setState({
serviceFacilitys: res.data,
});
}
}
// 开户行
export async function getBankList() {
const res = await apiBankList();
if (res.data) {
this.setState({
bankList: res.data,
});
}
}
// 获取地址省
export async function getAreaAddr() {
const data = await apiAddrArea();
const areaAddr = data.data || null;
if (areaAddr) {
const res = areaAddr.map(item => ({
isLeaf: false,
loading: false,
label: item.addrName,
value: item.addrId,
}));
// 编辑时 回显 市、区、街道
if (this.state.businessInfo.provinceId) {
const pros = res.filter(item => +item.value === +this.state.businessInfo.provinceId);
await loadData.call(this, pros);
const citys = pros[0].children.filter(
item => +item.value === +this.state.businessInfo.cityId,
);
await loadData.call(this, citys);
if (this.state.businessInfo.townId) {
const countys = citys[0].children.filter(
item => +item.value === +this.state.businessInfo.countyId,
);
await loadData.call(this, countys);
}
}
this.setState({
areaAddr: res,
});
}
}
// 获取市区街道
export async function loadData(selectedOptions) {
const targetOption = selectedOptions[selectedOptions.length - 1];
targetOption.loading = true;
const data = await apiAddrArea({
parentId: targetOption.value,
});
const areaAddr = data.data || null;
if (areaAddr) {
const children = areaAddr.map(item => ({
isLeaf: +item.addrLevel === 4,
loading: false,
label: item.addrName,
value: item.addrId,
}));
targetOption.loading = false;
if (children.length > 0) {
targetOption.children = children;
} else {
targetOption.isLeaf = true;
}
this.setState({
// eslint-disable-next-line react/no-access-state-in-setstate
areaAddr: [...this.state.areaAddr],
});
}
}
import React, { Component } from 'react';
import { history } from 'umi';
import moment from 'moment';
import { ArrowRightOutlined, UploadOutlined } from '@ant-design/icons';
import { Form } from '@ant-design/compatible';
import '@ant-design/compatible/assets/index.css';
import {
Select,
Input,
Radio,
Checkbox,
DatePicker,
Upload,
Button,
Card,
Row,
Col,
Cascader,
notification,
Spin,
Tabs,
} from 'antd';
import styles from './style.less';
import {
wrapperCol,
uploadPropsFn,
formItemLayout,
getCategoryList,
renderServiceTags,
loadData,
getAreaAddr,
getServiceFacility,
businessModel,
getInfo,
getBankList,
businessTypeDesc,
} from './data';
import { validatePhone, validateEMail, validNumber } from '@/utils/validator';
import { getErrorMessage } from '@/utils/utils';
import MapModal from '@/components/BaiduMap';
import { apiNewStoreInfo, apiEditStoreInfo, apiRecognize, apiRevision } from '../service';
import {
infoTypeFind,
infoTypeChecked,
infoTypeEdit,
infoTypeRevision,
infoTypeInfo,
} from '../staticdata';
const { Option } = Select;
const { Item: FormItem } = Form;
const { RangePicker } = DatePicker;
const { TabPane } = Tabs;
const applyTypeDesc = {
1: '用户提交申请:',
3: '易宝驳回:',
};
class BusinessInfo extends Component {
getFieldDecorator = this.props?.form?.getFieldDecorator;
setFieldsValue = this.props?.form?.setFieldsValue;
state = {
id: null,
type: infoTypeFind,
businessInfo: {
customList: [],
settlementType: 1,
companyType: '',
},
areaAddr: [], // 四级地址列表
categoryList: [], // 主要类目
serviceFacilitys: [], // 服务设施
bankList: [], // 开户行
// eslint-disable-next-line react/no-unused-state
tagVisible: false,
// eslint-disable-next-line react/no-unused-state
tagValue: '',
settlementType: 1,
loading: false,
visibleMap: false,
visibleLoading: false,
calculateType: [1, 1],
defaultType: '1',
visibleCalculate: false,
};
async componentDidMount() {
const { id, type } = this.props.location.query;
const info = {};
let businessType = [];
if (id) {
info.id = id;
info.type = type || infoTypeFind;
await getInfo.call(this, id, type);
businessType = this.state.businessInfo.productBusiness.map(item => this.getDataInfo(item));
}
// find 查看 checked审核 edit修改 info审核之后查看
if (id && [infoTypeFind, infoTypeInfo, infoTypeRevision].includes(type)) {
info.disabled = !0;
} else if (type === infoTypeRevision) {
// 订正 除了邮箱其他都禁止修改
info.disabled = !0;
info.emailDisabled = false;
}
this.setState(state => {
const businessInfo = Object.assign(
{
businessType,
},
state.businessInfo,
);
return {
...info,
businessInfo,
};
});
getAreaAddr.call(this);
// getCategoryList.call(this);
getServiceFacility.call(this);
getBankList.call(this);
}
// 审核的时候 切换业务模式 更改服务费率配置
onChangeBusinessModel = e => {
if (this.state.type !== infoTypeChecked) {
return false;
}
const arr = [];
e.forEach(item => {
if (item === 1 || item === 3) {
arr.push(item);
}
});
const businessType = arr.map(item => this.getDataInfo(item));
this.setState(state => {
const { businessInfo } = state;
businessInfo.businessType = businessType;
return {
businessInfo,
};
});
return console.log('.');
};
// 切换审核结果 - 显示/隐藏费率
onChangeAuditResult = e => {
this.setState({
visibleCalculate: e.target.value,
});
};
onTabChange = e => {
this.setState({
defaultType: e,
});
};
// eslint-disable-next-line react/sort-comp
getDataInfo = type => ({
key: type,
name: businessTypeDesc[type],
chargeMethod: 1,
calculateType: 1,
});
// 计费类型改变
onChangeCalculateType = (e, i) => {
this.setState(state => {
const { calculateType } = state;
calculateType[i] = +e;
return {
calculateType,
};
});
};
static getDerivedStateFromProps() {
return null;
}
// 帐号类型切换
onChangeSettlType(e) {
this.setState({
settlementType: e.target.value,
});
}
// 处理图片
dealImgInfo = async (type, url) => {
const imgType = {
businessLicenseImage: 2,
idCardPortraitImage: 5,
idCardEmblemImage: 4,
};
if (!url) {
return;
}
this.setState({
visibleLoading: true,
});
const data = await apiRecognize({
imageUrl: url,
imageType: imgType[type],
});
if (data.businessCode === '0000') {
const res = data.data;
const info = {};
this.setState(state => {
if (type === 'businessLicenseImage') {
info.socialCode = res.socialCode || '';
info.companyName = res.companyName || '';
info.businessLicensePeriod = moment(res.businessLicensePeriod) || '';
} else if (type === 'idCardPortraitImage') {
info.legalPersonName = res.legalPersonName || '';
info.legalPersonIdCard = res.legalPersonIdCard || '';
} else if (type === 'idCardEmblemImage' && res.legalPersonPeriod) {
info.legalPersonPeriod = res.legalPersonPeriod
.replace(/\./g, '/')
.split('-')
.map(o => moment(o));
}
return {
businessInfo: Object.assign(state.businessInfo, info),
};
});
this.props.form.setFieldsValue({
...info,
});
} else {
notification.error({ message: data.msg });
}
this.setState({
visibleLoading: false,
});
};
// 订正 - 修改邮箱
onRevision = () => {
const email = this.props.form.getFieldValue('contactEmail');
const contactPhone = this.props.form.getFieldValue('contactPhone');
if (email) {
validateEMail('', email, async e => {
if (!e) {
const [res, error] = await apiRevision({
id: this.state.id,
contactPhone,
contactEmail: email,
});
console.log('res :>> ', res);
if (!error) {
notification.success({ message: '订正完成!~' });
this.onCancel();
}
} else {
notification.warning({ message: '请输入正确的邮箱地址' });
}
});
} else {
notification.warning({ message: '请输入邮箱地址' });
}
};
/* eslint-disable no-return-assign */
saveInputRef = input => (this.input = input);
// 返回
onCancel = () => {
window.history.back();
};
// 提交
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields(async (err, values) => {
const obj = Object.assign({}, values); // , this.state.businessInfo
if (!err) {
const imgs = this.state.businessInfo;
obj.businessLicensePeriod = moment(obj.businessLicensePeriod).format('YYYY-MM-DD');
obj.legalPersonPeriod = obj.legalPersonPeriod
.map(o => moment(o).format('YYYY/MM/DD'))
.join('-');
obj.facilities = {
customList: this.state.businessInfo.customList,
selfList: obj.selfList,
};
const areaArr = ['provinceId', 'cityId', 'countyId', 'townId'];
obj.addr.forEach((item, i) => {
obj[areaArr[i]] = item;
});
if (this.state.settlementType === 1) {
obj.accountOpenPermitImage = imgs.accountOpenPermitImage[0].url;
}
if (obj.supplierRateDTOList && obj.supplierRateDTOList.length) {
obj.supplierRateDTOList.forEach(item => {
if (item.ratedate && item.ratedate.length) {
item.startDate = moment(item.ratedate[0]).format('YYYY-MM-DD');
item.endDate = moment(item.ratedate[1]).format('YYYY-MM-DD');
delete item.ratedate;
}
});
}
obj.businessLicenseImage = imgs.businessLicenseImage[0].url;
obj.idCardEmblemImage = imgs.idCardEmblemImage[0].url;
obj.idCardPortraitImage = imgs.idCardPortraitImage[0].url;
obj.primaryImage = imgs.primaryImage[0].url;
obj.sealImage = imgs.sealImage[0].url;
obj.applySource = 1;
if (imgs.otherImage && imgs.otherImage.length) {
obj.otherImage = imgs.otherImage.map(item => item.url);
} else {
delete obj.otherImage;
}
if (imgs.categoryQualificateImage && imgs.categoryQualificateImage.length) {
obj.categoryQualificateImage = imgs.categoryQualificateImage[0].url;
} else {
delete obj.categoryQualificateImage;
}
obj.legalPersonIdCard = obj.legalPersonIdCard?.toLocaleUpperCase() || '';
obj.bankAccountLicenseNum = obj.bankAccountLicenseNum?.toLocaleUpperCase() || '';
obj.socialCode = obj.socialCode?.toLocaleUpperCase() || '';
let api = apiNewStoreInfo;
if (this.state.id) {
obj.id = this.state.id;
if (this.state.type === infoTypeEdit) {
obj.headImage = obj.primaryImage;
api = apiEditStoreInfo;
}
} else {
obj.completed = !0;
}
this.setState({
loading: true,
});
console.log('obj :>>提交 ', obj);
// const [res, error] = await api(obj);
// if (!error) {
// console.log('res :>> ', res);
// const msg = this.state.type === infoTypeChecked ? '审核完成' : '保存成功';
// notification.success({ message: `${msg}!~` });
// if (this.state.id) {
// this.onCancel();
// } else {
// // 如果是新增 则返回商户审核页面
// history.push('/businessManage');
// }
// }
// this.setState({
// loading: false,
// });
} else {
const message = getErrorMessage(err);
notification.warning({ message });
}
});
};
onSetPoint = e => {
this.setFieldsValue({
latitude: e.lat,
longitude: e.lng,
});
};
openMap(e, disabled) {
if (!disabled) {
this.setState({
visibleMap: e,
});
}
}
// eslint-disable-next-line class-methods-use-this
disabledDate(current) {
return current && current < moment(moment().format('YYYY-MM-DD'));
}
render() {
const {
form: { getFieldDecorator },
} = this.props;
const { businessInfo, type } = this.state;
return (
<div className={styles.infoBox}>
<Form className="login-form" onSubmit={this.handleSubmit} {...formItemLayout}>
<Card title="基本信息">
<Row gutter={24}>
<Col span={24}>
<FormItem label="业务模式" labelCol={{ span: 4 }}>
{getFieldDecorator('productBusiness', {
rules: [{ required: true, message: '请选择业务模式!' }],
initialValue: businessInfo.productBusiness,
})(
<Checkbox.Group
options={businessModel}
onChange={this.onChangeBusinessModel}
/>,
)}
</FormItem>
</Col>
{/* <Col span={24}>
<FormItem label="商户名称" labelCol={{ span: 4 }}>
{getFieldDecorator('name', {
rules: [{ required: true, message: '请输入商户名称!' }],
initialValue: businessInfo.name,
})(<Input maxLength={32} disabled={disabled || } />)}
</FormItem>
</Col> */}
<Col span={24}>
<FormItem label="店铺区域" labelCol={{ span: 4 }}>
{getFieldDecorator('addr', {
rules: [{ required: true, type: 'array', message: '请选择店铺区域!' }],
initialValue: businessInfo.addr,
})(
<Cascader
options={this.state.areaAddr}
loadData={e => loadData.call(this, e)}
changeOnSelect
/>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="经营地址" labelCol={{ span: 4 }}>
{getFieldDecorator('detailAddress', {
rules: [{ required: true, message: '请输入经营地址!' }],
initialValue: businessInfo.detailAddress,
})(<Input maxLength={500} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="联系人姓名" labelCol={{ span: 8 }}>
{getFieldDecorator('contactName', {
rules: [{ required: true, message: '请输入联系人姓名!' }],
initialValue: businessInfo.contactName,
})(<Input maxLength={8} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="联系人手机号" labelCol={{ span: 5 }}>
{getFieldDecorator('contactPhone', {
rules: [
{ required: true, message: '请输入联系人手机号!' },
{ validator: validatePhone, message: '请输入正确的手机号!' },
],
initialValue: businessInfo.contactPhone,
})(<Input maxLength={11} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="联系人邮箱" labelCol={{ span: 8 }}>
{getFieldDecorator('contactEmail', {
rules: [
{ required: true, message: '请输入联系人邮箱!' },
{ validator: validateEMail, message: '请输入正确的邮箱!' },
],
initialValue: businessInfo.contactEmail,
})(<Input />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="客服电话" labelCol={{ span: 5 }}>
{getFieldDecorator('servicePhone', {
rules: [{ required: true, message: '请输入客服电话!' }],
initialValue: businessInfo.servicePhone,
})(<Input maxLength={11} />)}
</FormItem>
</Col>
<Col span={12} className={styles.imgList}>
<FormItem label="商户头图" labelCol={{ span: 8 }} wrapperCol={wrapperCol}>
{getFieldDecorator('primaryImage', {
rules: [{ required: true, message: '请上传商户头图!' }],
initialValue: businessInfo.primaryImage,
})(
<Upload
{...uploadPropsFn.call(this, { keyName: 'primaryImage', type: 1 })}
fileList={businessInfo.primaryImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="服务设施" labelCol={{ span: 4 }}>
{getFieldDecorator('selfList', {
initialValue: businessInfo.selfList,
})(
<Select mode="multiple">
{this.state.serviceFacilitys.map(item => (
<Option value={item.code} key={item.code}>
{item.desc}
</Option>
))}
</Select>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="自定义服务设施" labelCol={{ span: 4 }}>
{getFieldDecorator('customList', {
initialValue: businessInfo.customList,
})(renderServiceTags.call(this))}
</FormItem>
</Col>
</Row>
</Card>
<Card title="证照信息录入区">
<Row gutter={24}>
<Col span={24}>
<FormItem label="主营类目" labelCol={{ span: 4 }}>
{getFieldDecorator('mainCategoryId', {
// rules: [{ required: true, message: '请选择主营类目!' }],
initialValue: businessInfo.mainCategoryId,
})(
<Select>
{this.state.categoryList.map(item => (
<Option value={item.categoryId} key={item.categoryId}>
{item.categoryName}
</Option>
))}
</Select>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="企业类型" labelCol={{ span: 4 }}>
{getFieldDecorator('companyType', {
rules: [{ required: true, message: '请选择企业类型!' }],
initialValue: businessInfo.companyType,
})(
<Radio.Group>
<Radio value={1}>一般纳税人</Radio>
<Radio value={2}>小规模</Radio>
<Radio value={3}>个体工商</Radio>
</Radio.Group>,
)}
</FormItem>
</Col>
<Col span={24} className={styles.imgList}>
<FormItem label="营业执照" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('businessLicenseImage', {
rules: [{ required: true, message: '请上传营业执照!' }],
initialValue: businessInfo.businessLicenseImage,
})(
<Upload
{...uploadPropsFn.call(
this,
{ keyName: 'businessLicenseImage', type: 2 },
this.dealImgInfo,
)}
fileList={businessInfo.businessLicenseImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="公司名称" labelCol={{ span: 8 }}>
{getFieldDecorator('companyName', {
rules: [{ required: true, message: '请输入公司名称!' }],
initialValue: businessInfo.companyName,
})(<Input maxLength={50} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="统一社会信用代码" labelCol={{ span: 8 }}>
{getFieldDecorator('socialCode', {
rules: [{ required: true, message: '请输入统一社会信用代码!' }],
initialValue: businessInfo.socialCode,
})(<Input maxLength={32} />)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="营业执照有效期" labelCol={{ span: 4 }}>
{getFieldDecorator('businessLicensePeriod', {
rules: [{ required: true, message: '请选择营业执照有效期!' }],
initialValue: businessInfo.businessLicensePeriod,
})(<DatePicker maxLength={50} />)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="类目所需资质" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('categoryQualificateImage', {
initialValue: businessInfo.categoryQualificateImage,
})(
<Upload
{...uploadPropsFn.call(this, {
keyName: 'categoryQualificateImage',
type: 6,
})}
fileList={businessInfo.categoryQualificateImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="电子签章" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('sealImage', {
rules: [{ required: true, message: '请上传电子签章!' }],
initialValue: businessInfo.sealImage,
})(
<Upload
{...uploadPropsFn.call(this, {
keyName: 'sealImage',
type: 3,
maxSize: 1024 * 200,
maxSizeMsg: '文件大小不能超过200K',
limit: 1,
})}
fileList={businessInfo.sealImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
</Row>
</Card>
<Card title="法人信息录入区">
<Row gutter={24}>
<Col span={12} className={styles.imgList}>
<FormItem label="法人身份证人像面" labelCol={{ span: 8 }} wrapperCol={wrapperCol}>
{getFieldDecorator('idCardPortraitImage', {
rules: [{ required: true, message: '请上传身份证人像面!' }],
initialValue: businessInfo.idCardPortraitImage,
})(
<Upload
{...uploadPropsFn.call(
this,
{ keyName: 'idCardPortraitImage', type: 5 },
this.dealImgInfo,
)}
fileList={businessInfo.idCardPortraitImage}
>
<UploadOutlined />
<div>身份证人像面</div>
</Upload>,
)}
</FormItem>
</Col>
<Col span={12} className={styles.imgList}>
<FormItem label="法人身份证国徽面" labelCol={{ span: 8 }} wrapperCol={wrapperCol}>
{getFieldDecorator('idCardEmblemImage', {
rules: [{ required: true, message: '请上传身份证国徽面!' }],
initialValue: businessInfo.idCardEmblemImage,
})(
<Upload
{...uploadPropsFn.call(
this,
{ keyName: 'idCardEmblemImage', type: 4 },
this.dealImgInfo,
)}
fileList={businessInfo.idCardEmblemImage}
>
<UploadOutlined />
<div>身份证国徽面</div>
</Upload>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="证件姓名" labelCol={{ span: 8 }}>
{getFieldDecorator('legalPersonName', {
rules: [{ required: true, message: '请输入证件姓名!' }],
initialValue: businessInfo.legalPersonName,
})(<Input maxLength={8} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="身份证号码" labelCol={{ span: 8 }}>
{getFieldDecorator('legalPersonIdCard', {
rules: [{ required: true, message: '请输入身份证号码!' }],
initialValue: businessInfo.legalPersonIdCard,
})(<Input maxLength={18} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="身份证有效期" labelCol={{ span: 8 }}>
{getFieldDecorator('legalPersonPeriod', {
rules: [{ required: true, message: '请输入身份证有效期!' }],
initialValue: businessInfo.legalPersonPeriod,
})(<RangePicker />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="手机号" labelCol={{ span: 8 }}>
{getFieldDecorator('legalPersonPhone', {
rules: [
{ required: true, message: '请输入手机号!' },
{ validator: validatePhone, message: '请输入正确的手机号!' },
],
initialValue: businessInfo.legalPersonPhone,
})(<Input maxLength={11} />)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="其它证照" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('otherImage', {
initialValue: businessInfo.otherImage,
})(
<Upload
{...uploadPropsFn.call(this, { keyName: 'otherImage', limit: 9, type: 7 })}
fileList={businessInfo.otherImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
</Row>
</Card>
<Card title="结算信息录入区">
<Row gutter={24}>
<Col span={24}>
<FormItem label="账户类型" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('settlementType', {
rules: [{ required: true, message: '请选择账户类型!' }],
initialValue: businessInfo.settlementType,
})(
<Radio.Group onChange={e => this.onChangeSettlType(e)}>
<Radio value={1}>对公</Radio>
<Radio value={2}>对私(小微商户)</Radio>
</Radio.Group>,
)}
</FormItem>
</Col>
</Row>
{this.state.settlementType === 1 && (
<Row gutter={24}>
<Col span={12}>
<FormItem label="开户许可证" labelCol={{ span: 8 }} wrapperCol={wrapperCol}>
{getFieldDecorator('accountOpenPermitImage', {
rules: [{ required: true, message: '请上传开户许可证!' }],
initialValue: businessInfo.accountOpenPermitImage,
})(
<Upload
{...uploadPropsFn.call(this, {
keyName: 'accountOpenPermitImage',
type: 8,
})}
fileList={businessInfo.accountOpenPermitImage}
>
<UploadOutlined /> 上传文件
</Upload>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="开户许可证编号" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccountLicenseNum', {
rules: [{ required: true, message: '请输入开户许可证编号!' }],
initialValue: businessInfo.bankAccountLicenseNum,
})(<Input maxLength={32} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="开户名称" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccountName', {
rules: [{ required: true, message: '请输入开户名称!' }],
initialValue: businessInfo.bankAccountName,
})(<Input maxLength={32} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="开户行" labelCol={{ span: 8 }}>
{getFieldDecorator('accountBankName', {
rules: [{ required: true, message: '请选择开户行!' }],
initialValue: businessInfo.accountBankName,
})(
<Select
showSearch
filterOption={(input, option) =>
(option?.value ?? '').toLowerCase().includes(input.toLowerCase())
}
>
{this.state.bankList.map(item => (
<Option value={item.bankName} key={item.bankName}>
{item.bankName}
</Option>
))}
</Select>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="银行帐号" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccount', {
rules: [{ required: true, message: '请输入银行帐号!' }],
initialValue: businessInfo.bankAccount,
})(<Input maxLength={20} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="联行号" labelCol={{ span: 8 }}>
{getFieldDecorator('interbankNum', {
initialValue: businessInfo.interbankNum,
})(<Input maxLength={50} />)}
</FormItem>
</Col>
</Row>
)}
{this.state.settlementType === 2 && (
<Row gutter={24}>
<Col span={12}>
<FormItem label="银行卡类型" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccountType', {
rules: [{ required: true, message: '请选择银行卡类型!' }],
initialValue: businessInfo.bankAccountType,
})(
<Select>
<Option value={1} key={1}>
借记卡
</Option>
</Select>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="开户名称" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccountName', {
rules: [{ required: true, message: '请输入开户名称!' }],
initialValue: businessInfo.bankAccountName,
})(<Input maxLength={32} />)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="开户行" labelCol={{ span: 8 }}>
{getFieldDecorator('accountBankName', {
rules: [{ required: true, message: '请选择开户行!' }],
initialValue: businessInfo.accountBankName,
})(
<Select
showSearch
filterOption={(input, option) =>
(option?.value ?? '').toLowerCase().includes(input.toLowerCase())
}
>
{this.state.bankList.map(item => (
<Option value={item.bankName} key={item.bankName}>
{item.bankName}
</Option>
))}
</Select>,
)}
</FormItem>
</Col>
<Col span={12}>
<FormItem label="银行帐号" labelCol={{ span: 8 }}>
{getFieldDecorator('bankAccount', {
rules: [{ required: true, message: '请输入银行帐号!' }],
initialValue: businessInfo.bankAccount,
})(<Input maxLength={20} />)}
</FormItem>
</Col>
</Row>
)}
</Card>
<Card title="其他信息">
<Row gutter={24}>
<Col span={24}>
<FormItem label="礼包内容" labelCol={{ span: 4 }}>
{getFieldDecorator('giftPackageContent', {
// rules: [{ required: true, message: '请输入礼包内容!' }],
initialValue: businessInfo.giftPackageContent,
})(<Input style={{ width: '50%' }} />)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="邀请码" labelCol={{ span: 4 }}>
{getFieldDecorator('invitationCode', {
// rules: [{ required: true, message: '请输入礼包内容!' }],
initialValue: businessInfo.invitationCode,
})(<Input style={{ width: '50%' }} />)}
</FormItem>
</Col>
</Row>
</Card>
{this.state.type === infoTypeChecked && [
<Card title="信息审核区" key="checked">
<Row gutter={24}>
{businessInfo.applyType && (
<Col span={24}>
<FormItem label="上级节点" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{applyTypeDesc[businessInfo.applyType] || ''}
{businessInfo.remark}
</FormItem>
</Col>
)}
<Col span={24}>
<FormItem label="审核结果" labelCol={{ span: 4 }} wrapperCol={wrapperCol}>
{getFieldDecorator('auditResult', {
rules: [{ required: true, message: '请选择审核结果!' }],
initialValue: businessInfo.auditResult,
})(
<Radio.Group onChange={this.onChangeAuditResult}>
<Radio value>通过</Radio>
<Radio value={false}>驳回</Radio>
</Radio.Group>,
)}
</FormItem>
</Col>
<Col span={24}>
<FormItem label="审核结果" labelCol={{ span: 4 }}>
{getFieldDecorator('auditRemark', {
rules: [{ required: true, message: '请输入审核结果!' }],
initialValue: businessInfo.auditRemark,
})(<Input maxLength={500} />)}
</FormItem>
</Col>
</Row>
</Card>,
this.state.visibleCalculate && (
<Card title="商户服务费率配置" key="set">
<Tabs defaultActiveKey={this.state.defaultType} onChange={this.onTabChange}>
{businessInfo.businessType.map((item, i) => (
<TabPane tab={item.name} key={item.key}>
<Row gutter={24}>
<Col span={12}>
<Form.Item label="商户编码">
<span>{businessInfo.id}</span>
</Form.Item>
<Form.Item label="商户类型" hidden>
{getFieldDecorator(`supplierRateDTOList[${i}]['businessType']`, {
initialValue: item.key,
})(<Input />)}
</Form.Item>
{/* <Form.Item label="供应商ID" hidden>
{getFieldDecorator(`supplierRateDTOList[${i}]['supplierId']`, {
initialValue: businessInfo.businessType[i].supplierId,
})(<Input />)}
</Form.Item>
<Form.Item label="费率ID" hidden>
{getFieldDecorator(`supplierRateDTOList[${i}]['id']`, {
initialValue: businessInfo.businessType[i].id,
})(<Input />)}
</Form.Item> */}
</Col>
<Col span={12}>
<Form.Item label="商户名称">
<span>{businessInfo.name}</span>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="计费类型">
{getFieldDecorator(`supplierRateDTOList[${i}]['calculateType']`, {
initialValue: businessInfo.businessType[i].calculateType,
rules: [{ required: true, message: '请选择计费类型!' }],
})(
<Select
placeholder="请选择"
disabled={!!item.id}
onChange={e => this.onChangeCalculateType(e, i)}
>
<Option value={1}>单笔百分比</Option>
{/* <Option value={2}>单笔固定值</Option> */}
</Select>,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label={this.state.calculateType[i] === 1 ? '百分比' : ''}>
{getFieldDecorator(`supplierRateDTOList[${i}]['calculateValue']`, {
initialValue: businessInfo.businessType[i].calculateValue,
rules: [
{ required: true, message: '请输入百分比!' },
// { min: 0, message: '最小0' },
// { max: 0.9999, message: '最大输入0.9999' },
{ validator: validNumber, message: '请输入0~0.9999之间的小数' },
],
})(
<Input
maxLength={6}
placeholder={
this.state.calculateType[i] === 1
? '0.1=10%,直接写小数形式即可'
: ''
}
/>,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="收取方式">
{getFieldDecorator(`supplierRateDTOList[${i}]['chargeMethod']`, {
initialValue: businessInfo.businessType[i].chargeMethod,
rules: [{ required: true, message: '请选择收取方式!' }],
})(
<Select placeholder="请选择" disabled={!!item.id}>
<Option value={1}>坐扣</Option>
</Select>,
)}
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="有效期">
{getFieldDecorator(`supplierRateDTOList[${i}]['ratedate']`, {
initialValue: businessInfo.businessType[i].ratedate,
rules: [{ required: true, message: '请选择有效期!' }],
})(
<RangePicker format="YYYY/MM/DD" disabledDate={this.disabledDate} />,
)}
</Form.Item>
</Col>
</Row>
</TabPane>
))}
</Tabs>
</Card>
),
]}
<div className={styles.formBtns}>
<Row gutter={24}>
<Col span={4}></Col>
<Col span={20}>
{!this.state.id || [infoTypeEdit, infoTypeChecked].includes(this.state.type) ? (
<Button
type="primary"
size="large"
htmlType="submit"
loading={this.state.loading}
>
保存
</Button>
) : (
''
)}
{type === infoTypeRevision && (
<Button
type="primary"
size="large"
onClick={this.onRevision}
loading={this.state.loading}
>
保存
</Button>
)}
<Button size="large" onClick={this.onCancel}>
取消
</Button>
</Col>
</Row>
</div>
</Form>
<MapModal
visible={this.state.visibleMap}
onCancel={() => this.openMap(false)}
onSetPoint={e => this.onSetPoint(e)}
></MapModal>
{this.state.visibleLoading && (
<div className={styles.spinBox}>
<div className={styles.spinBoxWrapper}>
<Spin tip="Loading..." />
</div>
</div>
)}
</div>
);
}
}
export default Form.create()(BusinessInfo);
.textArea {
:global {
.ant-form-item-label {
width: 16%;
}
.ant-form-item-control-wrapper {
width: 80%;
}
}
}
.imgList {
:global {
.ant-upload-list-picture-card-container {
width: 200px;
}
.ant-upload-list-item {
width: 200px;
}
// .ant-upload.ant-upload-select-picture-card {
// width: 200px;
// }
}
}
.infoBox {
position: relative;
}
.spinBox {
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
}
.spinBoxWrapper {
position: fixed;
top: 50%;
left: 50%;
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 80px;
text-align: center;
transform: translate(-100px, -80px);
}
.addLink {
display: block;
margin: 20px 50px;
}
.formBtns {
padding: 20px 0;
background-color: #fff;
}
const Model = {
namespace: 'BusinessManage',
state: {},
effects: {},
reducers: {},
};
export default Model;
import request from '@/utils/request';
import config from '../../../config/env.config';
import qs from 'qs';
import { da } from 'date-fns/locale';
const { kdspApi } = config;
// 获取地址
export const apiAddrArea = params =>
request.post('/api/merchants/addresses/list', {
prefix: kdspApi,
data: params,
emulateJSON: true,
});
// 主营类目
export const apiCategoryList = params =>
request.post('/product/category/list', { prefix: kdspApi, params });
// 服务设施
export const apiServiceFacility = () =>
request.get('/api/merchants/suppliers/facilities/list', { prefix: kdspApi });
// 银行
export const apiBankList = () =>
request.get('/api/merchants/suppliers/banks/list', { prefix: kdspApi });
// 订正
export const apiRevision = params =>
request.post('/api/consoles/suppliers/register/revision', { prefix: kdspApi, data: params });
/**
* 上传文件
* imageType: 1-主头图,2-营业执照,3-电子签章,4-法人身份证国徽面,5-法人身份证人像面,6-类目所需资质,7-其它证件,8-开户许可证
* 0: 默认值 不校验
* */
export async function uploadFile(files, imageType = 0) {
const params = new FormData();
files.map(file => params.append('file', file));
params.append('imageType', imageType);
// image/upload
const data = await request.post('/api/merchants/images/upload', {
prefix: kdspApi,
data: params,
canRepeat: true,
});
return data;
}
// 新增商家端入驻申请
export const apiNewStoreInfo = params =>
request.post(`${kdspApi}/api/merchants/suppliers/register`, { prefix: kdspApi, data: params });
// 图片内容识别
export const apiRecognize = params =>
request.get(`/api/merchants/images/recognize?${qs.stringify(params)}`, { prefix: kdspApi });
// 编辑商户信息
export const apiEditStoreInfo = params =>
request.post(`${kdspApi}/api/merchants/suppliers/pops/edit`, { prefix: kdspApi, data: params });
// 查询申请详情
export const apiApplyDetail = applyId =>
request.get(`${kdspApi}/api/merchants/suppliers/register/detail?applyId=${applyId}`);
// 查询商户详情
export const apiBusinessDetail = businessId =>
request.get(`${kdspApi}/api/merchants/suppliers/pops/detail/${businessId}`);
import { Button, Popconfirm } from 'antd';
import React from 'react';
// import router from 'umi/router';
import { history } from 'umi';
// 状态:0-填写未完成,1-待审核,2-待易宝入网,3-易宝入网中,4-待易宝签约,5-待平台签约,6-完成,7-驳回
export const checkStatus = {
// 0: { text: '填写未完成' },
1: { text: '待审核' },
// 2: { text: '待易宝入网' },
3: { text: '易宝入网中' },
4: { text: '待易宝签约' },
5: { text: '待平台签约' },
// 6: { text: '完成' },
// 7: { text: '驳回' },
};
// 详情类型
export const infoTypeFind = 'find'; // 查看
export const infoTypeChecked = 'checked'; // 审核
export const infoTypeEdit = 'edit'; // 编辑
export const infoTypeRevision = 'revision'; // 订正
export const infoTypeInfo = 'info'; // 审核之后查看
export const infoTypeAdd = 'add'; // 添加
// 商户类型
export const supplierType = {
pop: { text: 'POP商户' },
供应商: { text: '供应商' },
};
export const toInfo = ({ id }, type = 'find') => {
history.push(`/BusinessInfo?id=${id}&type=${type}`);
};
export const businessTypeDesc = {
1: '到家业务',
2: '实物业务',
3: '到店业务',
};
.table {
:global {
.ant-table-row-expand-icon-cell {
visibility: hidden;
}
.ant-table-expanded-row {
.ant-pro-table {
margin-left: -17px;
}
}
}
}
.logBtn {
display: inherit;
margin: 20px auto;
}
.pageHeader {
background-color: #fff;
border: 1px solid rgb(235, 237, 240);
}
.listHeader {
display: flex;
&--item {
position: relative;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 40px;
height: 40px;
margin-right: 20px;
font-size: 14px;
line-height: 14px;
text-align: center;
border: 1px solid #333;
border-radius: 50%;
&::after {
position: absolute;
right: -21px;
width: 20px;
height: 1px;
background-color: #333;
content: '';
}
&:last-child::after {
width: 0;
height: 0;
}
}
}
...@@ -8,6 +8,7 @@ import { weekOptions, weekDefault, layout } from '../data'; ...@@ -8,6 +8,7 @@ import { weekOptions, weekDefault, layout } from '../data';
import MapModal from '@/components/GaoDeMap'; import MapModal from '@/components/GaoDeMap';
import style from './style.less'; import style from './style.less';
import { isCheckNumberLine } from '@/utils/validator'; import { isCheckNumberLine } from '@/utils/validator';
import Upload from '../../components/upload';
const FormItem = Form.Item; const FormItem = Form.Item;
...@@ -17,6 +18,7 @@ const StoreModal = props => { ...@@ -17,6 +18,7 @@ const StoreModal = props => {
onCancel, onCancel,
form: { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields, resetFields }, form: { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields, resetFields },
formInfo, formInfo,
status,
} = props; } = props;
const [areaAddr, setAreaAddr] = useState([]); const [areaAddr, setAreaAddr] = useState([]);
const [visibleMap, setVisibleMap] = useState(false); const [visibleMap, setVisibleMap] = useState(false);
...@@ -26,9 +28,13 @@ const StoreModal = props => { ...@@ -26,9 +28,13 @@ const StoreModal = props => {
provice: '', provice: '',
address: '', address: '',
}); });
const [disabled, setDisabled] = useState(false);
const divDom = useRef(); const divDom = useRef();
useEffect(() => {
setDisabled(props.status);
}, [props.status]);
const handleCancel = isSuccess => { const handleCancel = isSuccess => {
resetFields(); resetFields();
onCancel(isSuccess); onCancel(isSuccess);
...@@ -197,6 +203,8 @@ const StoreModal = props => { ...@@ -197,6 +203,8 @@ const StoreModal = props => {
setAreaAddr([...arr]); setAreaAddr([...arr]);
}; };
const normFile = fileList => fileList;
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
resetFields(); resetFields();
...@@ -241,6 +249,14 @@ const StoreModal = props => { ...@@ -241,6 +249,14 @@ const StoreModal = props => {
onCancel={() => handleCancel()} onCancel={() => handleCancel()}
> >
<Form {...layout} name="formData"> <Form {...layout} name="formData">
<FormItem label="门店头像">
{getFieldDecorator('supplement', {
rules: [{ required: true, message: '请上传门店头像' }],
initialValue: formData.shopHeadImage || [],
valuePropName: 'fileList',
getValueFromEvent: normFile,
})(<Upload max={1} accept=".jpg,.png,.jpeg" disabled={disabled} />)}
</FormItem>
<FormItem <FormItem
label="门店名称" label="门店名称"
name="name" name="name"
...@@ -249,7 +265,7 @@ const StoreModal = props => { ...@@ -249,7 +265,7 @@ const StoreModal = props => {
{getFieldDecorator('name', { {getFieldDecorator('name', {
rules: [{ required: true, message: '请输入门店名称!' }], rules: [{ required: true, message: '请输入门店名称!' }],
initialValue: formData.name, initialValue: formData.name,
})(<Input placeholder="请输入门店名称" allowClear maxLength={20} />)} })(<Input placeholder="请输入门店名称" allowClear maxLength={20} disabled={disabled} />)}
</FormItem> </FormItem>
<FormItem label="门店电话" name="phone"> <FormItem label="门店电话" name="phone">
{getFieldDecorator('phone', { {getFieldDecorator('phone', {
...@@ -258,7 +274,7 @@ const StoreModal = props => { ...@@ -258,7 +274,7 @@ const StoreModal = props => {
{ validator: isCheckNumberLine, message: '请输入正确的门店电话!' }, { validator: isCheckNumberLine, message: '请输入正确的门店电话!' },
], ],
initialValue: formData.phone, initialValue: formData.phone,
})(<Input placeholder="请输入门店电话" allowClear maxLength={20} />)} })(<Input placeholder="请输入门店电话" allowClear maxLength={20} disabled={disabled} />)}
</FormItem> </FormItem>
<FormItem label="营业时间" required> <FormItem label="营业时间" required>
{times && {times &&
...@@ -269,18 +285,25 @@ const StoreModal = props => { ...@@ -269,18 +285,25 @@ const StoreModal = props => {
{getFieldDecorator(item.name, { {getFieldDecorator(item.name, {
rules: [{ required: true, message: '请选择营业时间!' }], rules: [{ required: true, message: '请选择营业时间!' }],
initialValue: formData[item.name], initialValue: formData[item.name],
})(<TimePicker.RangePicker format="HH:mm" />)} })(<TimePicker.RangePicker format="HH:mm" disabled={disabled} />)}
</FormItem> </FormItem>
</div> </div>
{i > 0 ? ( {!disabled &&
<div className={style.timerWrapperRight} onClick={() => onTimeMinus(i)}> (i > 0 ? (
<MinusSquareFilled style={{ color: '#ff4d4f', fontSize: '30px' }} /> <div className={style.timerWrapperRight} onClick={() => onTimeMinus(i)}>
</div> <MinusSquareFilled
) : ( style={{ color: '#ff4d4f', fontSize: '30px' }}
<div className={style.timerWrapperRight} onClick={() => onTimePlus()}> disabled={disabled}
<PlusSquareFilled style={{ color: '#1890ff', fontSize: '30px' }} /> />
</div> </div>
)} ) : (
<div className={style.timerWrapperRight} onClick={() => onTimePlus()}>
<PlusSquareFilled
style={{ color: '#1890ff', fontSize: '30px' }}
disabled={disabled}
/>
</div>
))}
</div> </div>
))} ))}
</FormItem> </FormItem>
...@@ -288,7 +311,7 @@ const StoreModal = props => { ...@@ -288,7 +311,7 @@ const StoreModal = props => {
{getFieldDecorator('week', { {getFieldDecorator('week', {
rules: [{ required: true, message: '请选择营业日!' }], rules: [{ required: true, message: '请选择营业日!' }],
initialValue: formData.week || weekDefault, initialValue: formData.week || weekDefault,
})(<Checkbox.Group options={weekOptions} />)} })(<Checkbox.Group options={weekOptions} disabled={disabled} />)}
</FormItem> </FormItem>
<FormItem label="店铺区域"> <FormItem label="店铺区域">
{getFieldDecorator('addr', { {getFieldDecorator('addr', {
...@@ -301,6 +324,7 @@ const StoreModal = props => { ...@@ -301,6 +324,7 @@ const StoreModal = props => {
placeholder="请选择店铺区域" placeholder="请选择店铺区域"
loadData={e => loadData(e)} loadData={e => loadData(e)}
changeOnSelect changeOnSelect
disabled={disabled}
/>, />,
)} )}
</FormItem> </FormItem>
...@@ -308,7 +332,14 @@ const StoreModal = props => { ...@@ -308,7 +332,14 @@ const StoreModal = props => {
{getFieldDecorator('address', { {getFieldDecorator('address', {
rules: [{ required: true, message: '请输入详细地址!' }], rules: [{ required: true, message: '请输入详细地址!' }],
initialValue: formData.address, initialValue: formData.address,
})(<Input placeholder="请输入详细地址,不包含省市区地址" allowClear maxLength={50} />)} })(
<Input
placeholder="请输入详细地址,不包含省市区地址"
allowClear
maxLength={50}
disabled={disabled}
/>,
)}
</FormItem> </FormItem>
<FormItem label="经纬度"> <FormItem label="经纬度">
{getFieldDecorator('lnglat', { {getFieldDecorator('lnglat', {
...@@ -320,6 +351,7 @@ const StoreModal = props => { ...@@ -320,6 +351,7 @@ const StoreModal = props => {
readOnly readOnly
onClick={() => openMap(true)} onClick={() => openMap(true)}
maxLength={100} maxLength={100}
disabled={disabled}
/>, />,
)} )}
</FormItem> </FormItem>
...@@ -328,12 +360,17 @@ const StoreModal = props => { ...@@ -328,12 +360,17 @@ const StoreModal = props => {
rules: [{ required: true, message: '请选择是否启用!' }], rules: [{ required: true, message: '请选择是否启用!' }],
initialValue: formData.state, initialValue: formData.state,
})( })(
<Radio.Group> <Radio.Group disabled={disabled}>
<Radio value={1}></Radio> <Radio value={1}></Radio>
<Radio value={0}></Radio> <Radio value={0}></Radio>
</Radio.Group>, </Radio.Group>,
)} )}
</FormItem> </FormItem>
<FormItem label="门店公告">
{getFieldDecorator('publicNotice', {
initialValue: formData.publicNotice,
})(<Input placeholder="请输入门店公告" maxLength={120} disabled={disabled} />)}
</FormItem>
</Form> </Form>
<MapModal <MapModal
visible={visibleMap} visible={visibleMap}
......
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
import { notification, Button, Form, Input, Cascader, Col, Row, Table, Pagination } from 'antd'; import {
notification,
Button,
Form,
Input,
Cascader,
Col,
Row,
Table,
Pagination,
Modal,
} from 'antd';
import _ from 'lodash'; import _ from 'lodash';
import { el } from 'date-fns/locale';
import { searchList, apiEnableStore, apiAddrArea } from './services'; import { searchList, apiEnableStore, apiAddrArea } from './services';
import { stateDesc, weeks, layout } from './data'; import { stateDesc, weeks, layout } from './data';
import StoreModal from './components/storeModal'; import StoreModal from './components/storeModal';
import style from './style.less'; import style from './style.less';
const { confirm } = Modal;
export default () => { export default () => {
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [storeInfo, setStoreInfo] = useState({}); const [storeInfo, setStoreInfo] = useState({});
const [areaAddr, setAreaAddr] = useState([]); const [areaAddr, setAreaAddr] = useState([]);
const [status, setStatus] = useState();
const [dataList, setDataList] = useState([]); const [dataList, setDataList] = useState([]);
const [pageNo, setPageNo] = useState(1); const [pageNo, setPageNo] = useState(1);
const [totalNum, setTotalNum] = useState(0); const [totalNum, setTotalNum] = useState(0);
...@@ -20,8 +34,11 @@ export default () => { ...@@ -20,8 +34,11 @@ export default () => {
setStoreInfo({}); setStoreInfo({});
setVisible(true); setVisible(true);
}; };
const onShowInfo = info => { const onShowInfo = (info, val) => {
setStoreInfo(info); setStoreInfo(info);
const value = val !== 'edit';
console.log(value);
setStatus(value);
setVisible(true); setVisible(true);
}; };
...@@ -101,7 +118,8 @@ export default () => { ...@@ -101,7 +118,8 @@ export default () => {
setStoreInfo({}); setStoreInfo({});
setVisible(false); setVisible(false);
}; };
const onEnableState = async ({ id, state }) => {
const enableStore = async (id, state) => {
const enable = +state === 1 ? 0 : 1; const enable = +state === 1 ? 0 : 1;
const res = await apiEnableStore({ id, state: enable }); const res = await apiEnableStore({ id, state: enable });
if (res === '0000') { if (res === '0000') {
...@@ -109,11 +127,25 @@ export default () => { ...@@ -109,11 +127,25 @@ export default () => {
onSearch(refSearch.current?.getFieldValue?.() || {}); onSearch(refSearch.current?.getFieldValue?.() || {});
} }
}; };
const onEnableState = async ({ id, state }) => {
if (state) {
confirm({
title: '确认要禁用这家门店吗?',
content: '禁用后用户将无法看到该店铺',
onOk() {
enableStore(id, state);
},
});
} else {
enableStore(id, state);
}
};
const onReset = () => { const onReset = () => {
if (refSearch.current && refSearch.current.resetFields) { if (refSearch.current && refSearch.current.resetFields) {
refSearch.current.resetFields(); refSearch.current.resetFields();
} }
getList();
}; };
const onPageChange = (e, size) => { const onPageChange = (e, size) => {
...@@ -233,14 +265,19 @@ export default () => { ...@@ -233,14 +265,19 @@ export default () => {
dataIndex: 'action', dataIndex: 'action',
width: 170, width: 170,
fixed: 'right', fixed: 'right',
render: (val, r) => [ render: (val, r) => (
<Button key="enable1" onClick={() => onEnableState(r)} type="primary"> <div className={style.actionBtn}>
{+r.state ? '禁用' : '启用'} <Button key="look" onClick={() => onShowInfo(r)}>
</Button>, 查看
<Button key="seek" style={{ marginLeft: '10px' }} onClick={() => onShowInfo(r)}> </Button>
查看 <Button key="seek" onClick={() => onShowInfo(r, 'edit')}>
</Button>, 修改
], </Button>
<Button key="enable1" onClick={() => onEnableState(r)} type="primary">
{+r.state ? '禁用' : '启用'}
</Button>
</div>
),
}, },
]; ];
return ( return (
...@@ -285,7 +322,7 @@ export default () => { ...@@ -285,7 +322,7 @@ export default () => {
pagination={false} pagination={false}
scroll={{ x: '100%' }} scroll={{ x: '100%' }}
/> />
{dataList && dataList.length && ( {dataList && dataList.length ? (
<div className={style.pageBox}> <div className={style.pageBox}>
<Pagination <Pagination
style={{ marginBottom: 10 }} style={{ marginBottom: 10 }}
...@@ -298,8 +335,8 @@ export default () => { ...@@ -298,8 +335,8 @@ export default () => {
onShowSizeChange={onPageChange} onShowSizeChange={onPageChange}
/> />
</div> </div>
)} ) : null}
<StoreModal visible={visible} onCancel={closeModal} formInfo={storeInfo} /> <StoreModal visible={visible} onCancel={closeModal} formInfo={storeInfo} status={status} />
</div> </div>
); );
}; };
...@@ -13,3 +13,13 @@ ...@@ -13,3 +13,13 @@
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
border-top: 0; border-top: 0;
} }
.actionBtn {
display: flex;
flex-direction: column;
align-items: center;
button {
width: 75px;
margin-bottom: 5px;
}
}
import { PlusOutlined } from '@ant-design/icons'; import { PlusOutlined } from '@ant-design/icons';
import { Upload, Modal, message } from 'antd'; import { Upload, Modal, notification } from 'antd';
import React from 'react'; import React from 'react';
import config from '../../../config/env.config'; import config from '../../../config/env.config';
import { qiniuToken } from '@/services/qiniu'; import { qiniuToken } from '@/services/qiniu';
...@@ -7,7 +7,6 @@ import { qiniuToken } from '@/services/qiniu'; ...@@ -7,7 +7,6 @@ import { qiniuToken } from '@/services/qiniu';
const qiniu = require('@/utils/qiniu.min.js'); const qiniu = require('@/utils/qiniu.min.js');
const { qiniuHost } = config; const { qiniuHost } = config;
function getBase64(file) { function getBase64(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const reader = new FileReader(); const reader = new FileReader();
...@@ -26,9 +25,25 @@ class PicturesWall extends React.Component { ...@@ -26,9 +25,25 @@ class PicturesWall extends React.Component {
}; };
async componentDidMount() { async componentDidMount() {
this.initFileList(this.props.fileList || []);
token = await qiniuToken(); token = await qiniuToken();
} }
componentWillReceiveProps(nextProps) {
this.initFileList(nextProps.fileList || []);
}
initFileList = fileList => {
const fileLists =
fileList.map((item, index) => ({
url: item,
name: '',
uid: index,
status: 'done',
})) || [];
this.setState({ fileList: fileLists });
};
handleCancel = () => this.setState({ previewVisible: false }); handleCancel = () => this.setState({ previewVisible: false });
handlePreview = async file => { handlePreview = async file => {
...@@ -43,17 +58,37 @@ class PicturesWall extends React.Component { ...@@ -43,17 +58,37 @@ class PicturesWall extends React.Component {
}); });
}; };
handleChange = info => { handleChange = ({ fileList }) => {
const lastFile = (info.fileList.length && info.fileList[info.fileList.length - 1]) || []; const file = fileList.filter(item => item.url);
const types = ['application/pdf', 'image/png', 'image/jpeg']; this.setState({ fileList: [...file] });
if (lastFile && types.indexOf(lastFile.type) === -1) { const urlList = file.map(item => item.url);
message.error('文件格式错误!'); this.props.onChange(urlList);
}
const fileList = info.fileList.filter(item => types.indexOf(item.type) !== -1);
this.setState({ fileList });
}; };
customRequest = ({ file, onError, onSuccess }) => { imageSize = async file =>
new Promise((resolve, reject) => {
const fileObj = file;
// 获取上传的图片的宽高
const reader = new FileReader();
reader.readAsDataURL(fileObj);
reader.onload = evt => {
const replaceSrc = evt.target.result;
const imageObj = new Image();
imageObj.src = replaceSrc;
imageObj.onload = () => {
const { width } = imageObj;
const { height } = imageObj;
file.width = width;
file.height = height;
resolve(file);
};
};
reader.onerror = error => reject(error);
});
customRequest = async ({ file, onError, onSuccess }) => {
const imgSize = await this.imageSize(file);
const vm = this;
const observable = qiniu.upload(file, null, token); const observable = qiniu.upload(file, null, token);
const observer = { const observer = {
next() { next() {
...@@ -67,6 +102,17 @@ class PicturesWall extends React.Component { ...@@ -67,6 +102,17 @@ class PicturesWall extends React.Component {
const comFile = file; const comFile = file;
const url = `${qiniuHost}/${res.hash}`; const url = `${qiniuHost}/${res.hash}`;
comFile.url = url; comFile.url = url;
const list = vm.state.fileList;
list.push({
url: file.url,
name: file.name,
uid: list.length,
status: 'done',
});
vm.setState({ fileList: [...list] });
const urlList = list.map(item => item.url);
vm.props.onChange(urlList);
onSuccess(comFile); onSuccess(comFile);
// ... // ...
}, },
...@@ -94,15 +140,17 @@ class PicturesWall extends React.Component { ...@@ -94,15 +140,17 @@ class PicturesWall extends React.Component {
</div> </div>
); );
const { max } = this.props; const { max } = this.props;
return ( return (
<div className="clearfix"> <div className="clearfix">
<Upload <Upload
{...this.props}
customRequest={this.customRequest} customRequest={this.customRequest}
listType="picture-card" listType="picture-card"
fileList={fileList} fileList={fileList}
onPreview={this.handlePreview} onPreview={this.handlePreview}
onChange={this.handleChange} onChange={this.handleChange}
{...this.props} multiple
> >
{max && fileList.length >= max ? null : uploadButton} {max && fileList.length >= max ? null : uploadButton}
</Upload> </Upload>
......
import React, { useState, useRef } from 'react';
import ProTable from '@ant-design/pro-table';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { notification, Button } from 'antd';
import { query } from './services';
const ContractView = () => {
// 查看
const onLook = ({ contractPdfUrl }) => {
console.log(contractPdfUrl);
};
// 下载
const ondown = ({ contractPdfUrl }) => {
console.log(contractPdfUrl);
};
const columns = [
{
title: '合同名称',
dataIndex: 'contractName',
key: 'contractName',
align: 'center',
},
{
title: '签约时间',
dataIndex: 'signDate',
key: 'signDate',
align: 'center',
hideInSearch: true,
},
{
title: '合同状态',
dataIndex: 'state',
key: 'state',
align: 'center',
filters: false,
valueEnum: {
0: '失效',
1: '有效',
},
},
{
title: '操作',
dataIndex: 'action',
width: 200,
align: 'center',
hideInSearch: true,
render: (text, record) => (
<>
<Button
key="edit"
type="primary"
onClick={() => onLook(record)}
style={{ marginRight: '10px' }}
>
查看
</Button>
<Button key="del" type="primary" onClick={() => ondown(record)}>
下载
</Button>
</>
),
},
];
return (
<PageHeaderWrapper>
<ProTable
search={{
collapsed: false,
collapseRender: () => null,
}}
columns={columns}
request={params => query({ ...params })}
rowKey={r => r.appealNo}
expandIconColumnIndex={10}
bordered
toolBarRender={false}
scroll={{ x: '100%', y: 400 }}
/>
</PageHeaderWrapper>
);
};
export default ContractView;
import { stringify } from 'querystring';
import request from '@/utils/request';
import _ from 'lodash';
import config from '../../../config/env.config';
const { goodsApi } = config;
// 分页查询所有数据
export async function query(params) {
const param = {
pageNo: params.current || 1,
pageSize: params.pageSize || 20,
};
const data = await request.post('/api/kdsp/template/page', {
prefix: goodsApi,
data: stringify(_.omitBy(param, v => !v)),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
if (data.data) {
return {
total: data.data.total,
data: data.data.forbiddenAreaTemplateList,
};
}
return {
total: 0,
data: [],
};
}
// 添加区域受限模板
export async function getAddTemplate(param) {
const data = await request.post('/api/kdsp/add/template', {
prefix: goodsApi,
data: param,
});
return data;
}
// 获取区域地址
export async function areaList(params) {
const { data } = await request.get('/api/merchants/addresses/list', {
prefix: goodsApi,
params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
});
return data;
}
// 根据模板id查询受限区域
export async function forbiddenAddress(params) {
const data = await request.post('/api/kdsp/edit/template', {
prefix: goodsApi,
data: params,
});
return data;
}
// 根据模板id查询受限区域
export async function addressTree(params) {
const data = await request.post('/api/kdsp/forbidden/address', {
prefix: goodsApi,
params,
});
return data;
}
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