Commit 6fec3ca3 authored by 武广's avatar 武广

Merge branch 'feat/constructionOne' of git.quantgroup.cn:ui/merchant-manage-ui...

Merge branch 'feat/constructionOne' of git.quantgroup.cn:ui/merchant-manage-ui into feature/20230327_public_takeaway
parents 3129b404 0f7c1776
......@@ -273,6 +273,18 @@ export default {
name: 'systemManageLog',
component: './systemManage/Log',
},
{
title: '商户管理后台-合同查看',
path: '/contractView',
name: 'contractView',
component: './contractView',
},
{
title: '商户管理后台-商家资料',
path: '/businessInfo',
name: 'businessInfo',
component: './businessManage/info',
},
{
component: './404',
},
......
This diff is collapsed.
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>
);
};
This diff is collapsed.
This diff is collapsed.
.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 {
display: flex;
align-items: center;
justify-content: space-evenly;
width: 100%;
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, goodsApi } = config;
// 获取地址
export const apiAddrArea = params =>
request.get(`/api/merchants/addresses/list?${qs.stringify(params)}`, {
prefix: kdspApi,
});
// 主营类目
export async function apiCategoryList(param) {
return request.post('/api/merchants/suppliers/main-category/list', {
data: param,
prefix: goodsApi,
});
}
// 服务设施
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 apiRecognize = params =>
request.get(`/api/merchants/images/recognize?${qs.stringify(params)}`, { prefix: kdspApi });
// 编辑商户信息
export const apiEditStoreInfo = params =>
request.post('/api/merchants/suppliers/edit', { prefix: kdspApi, data: params });
// 查询商户详情
export const apiBusinessDetail = businessId =>
request.get('/api/merchants/suppliers/pops/detail', { prefix: kdspApi });
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;
}
}
}
......@@ -4,10 +4,11 @@ import moment from 'moment';
import { PlusSquareFilled, MinusSquareFilled } from '@ant-design/icons';
import { Modal, Input, TimePicker, Checkbox, Cascader, Radio, notification } from 'antd';
import { apiAddrArea, apiCreatStore, apiEditStore } from '../services';
import { weekOptions, weekDefault, layout } from '../data';
import { weekOptions, weekDefault, layout, businessModel } from '../data';
import MapModal from '@/components/GaoDeMap';
import style from './style.less';
import { isCheckNumberLine } from '@/utils/validator';
import Upload from '../../components/upload';
const FormItem = Form.Item;
......@@ -17,6 +18,8 @@ const StoreModal = props => {
onCancel,
form: { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields, resetFields },
formInfo,
status,
productBusiness,
} = props;
const [areaAddr, setAreaAddr] = useState([]);
const [visibleMap, setVisibleMap] = useState(false);
......@@ -26,9 +29,22 @@ const StoreModal = props => {
provice: '',
address: '',
});
const [disabled, setDisabled] = useState(false);
const [isDisabled, setIsDisabled] = useState(true);
const divDom = useRef();
useEffect(() => {
setDisabled(props.status);
}, [props.status]);
useEffect(() => {
if (props.productBusiness.length) {
const val = props.productBusiness.includes(2) || props.productBusiness.includes(3);
setIsDisabled(val);
}
}, [props.productBusiness]);
const handleCancel = isSuccess => {
resetFields();
onCancel(isSuccess);
......@@ -43,6 +59,10 @@ const StoreModal = props => {
params[areaArr[i]] = item;
});
}
if (params.shopHeadImage.length) {
// eslint-disable-next-line prefer-destructuring
params.shopHeadImage = params.shopHeadImage[0];
}
if (params.lnglat) {
const arr = params.lnglat.split(',');
if (arr.length === 2) {
......@@ -197,6 +217,8 @@ const StoreModal = props => {
setAreaAddr([...arr]);
};
const normFile = fileList => fileList;
useEffect(() => {
if (visible) {
resetFields();
......@@ -215,9 +237,11 @@ const StoreModal = props => {
}
info.lnglat = `${info.longitude},${info.latitude}`;
info.addr = [info.provinceId, info.cityId, info.countyId];
info.shopHeadImage = [info.shopHeadImage] || [];
if (info.townId) {
info.addr.push(info.townId);
}
console.log(info);
setTimes(harr);
setFormData(info);
getLazyAddr(info);
......@@ -234,13 +258,28 @@ const StoreModal = props => {
<Modal
title="门店信息"
visible={visible}
width="800px"
width="1000px"
destroyOnClose
maskClosable={false}
onOk={() => onSubmit()}
onCancel={() => handleCancel()}
>
<Form {...layout} name="formData">
<FormItem label="业务模式">
{getFieldDecorator('productBusiness', {
initialValue: productBusiness,
})(<Checkbox.Group disabled options={businessModel} />)}
</FormItem>
{isDisabled && (
<FormItem label="门店头像">
{getFieldDecorator('shopHeadImage', {
rules: [{ required: true, message: '请上传门店头像' }],
initialValue: formData.shopHeadImage || [],
valuePropName: 'fileList',
getValueFromEvent: normFile,
})(<Upload max={1} accept=".jpg,.png,.jpeg" disabled={disabled} />)}
</FormItem>
)}
<FormItem
label="门店名称"
name="name"
......@@ -249,7 +288,7 @@ const StoreModal = props => {
{getFieldDecorator('name', {
rules: [{ required: true, message: '请输入门店名称!' }],
initialValue: formData.name,
})(<Input placeholder="请输入门店名称" allowClear maxLength={20} />)}
})(<Input placeholder="请输入门店名称" allowClear maxLength={20} disabled={disabled} />)}
</FormItem>
<FormItem label="门店电话" name="phone">
{getFieldDecorator('phone', {
......@@ -258,7 +297,7 @@ const StoreModal = props => {
{ validator: isCheckNumberLine, message: '请输入正确的门店电话!' },
],
initialValue: formData.phone,
})(<Input placeholder="请输入门店电话" allowClear maxLength={20} />)}
})(<Input placeholder="请输入门店电话" allowClear maxLength={20} disabled={disabled} />)}
</FormItem>
<FormItem label="营业时间" required>
{times &&
......@@ -269,18 +308,25 @@ const StoreModal = props => {
{getFieldDecorator(item.name, {
rules: [{ required: true, message: '请选择营业时间!' }],
initialValue: formData[item.name],
})(<TimePicker.RangePicker format="HH:mm" />)}
})(<TimePicker.RangePicker format="HH:mm" disabled={disabled} />)}
</FormItem>
</div>
{i > 0 ? (
<div className={style.timerWrapperRight} onClick={() => onTimeMinus(i)}>
<MinusSquareFilled style={{ color: '#ff4d4f', fontSize: '30px' }} />
</div>
) : (
<div className={style.timerWrapperRight} onClick={() => onTimePlus()}>
<PlusSquareFilled style={{ color: '#1890ff', fontSize: '30px' }} />
</div>
)}
{!disabled &&
(i > 0 ? (
<div className={style.timerWrapperRight} onClick={() => onTimeMinus(i)}>
<MinusSquareFilled
style={{ color: '#ff4d4f', fontSize: '30px' }}
disabled={disabled}
/>
</div>
) : (
<div className={style.timerWrapperRight} onClick={() => onTimePlus()}>
<PlusSquareFilled
style={{ color: '#1890ff', fontSize: '30px' }}
disabled={disabled}
/>
</div>
))}
</div>
))}
</FormItem>
......@@ -288,7 +334,7 @@ const StoreModal = props => {
{getFieldDecorator('week', {
rules: [{ required: true, message: '请选择营业日!' }],
initialValue: formData.week || weekDefault,
})(<Checkbox.Group options={weekOptions} />)}
})(<Checkbox.Group options={weekOptions} disabled={disabled} />)}
</FormItem>
<FormItem label="店铺区域">
{getFieldDecorator('addr', {
......@@ -301,6 +347,7 @@ const StoreModal = props => {
placeholder="请选择店铺区域"
loadData={e => loadData(e)}
changeOnSelect
disabled={disabled}
/>,
)}
</FormItem>
......@@ -308,7 +355,14 @@ const StoreModal = props => {
{getFieldDecorator('address', {
rules: [{ required: true, message: '请输入详细地址!' }],
initialValue: formData.address,
})(<Input placeholder="请输入详细地址,不包含省市区地址" allowClear maxLength={50} />)}
})(
<Input
placeholder="请输入详细地址,不包含省市区地址"
allowClear
maxLength={50}
disabled={disabled}
/>,
)}
</FormItem>
<FormItem label="经纬度">
{getFieldDecorator('lnglat', {
......@@ -320,6 +374,7 @@ const StoreModal = props => {
readOnly
onClick={() => openMap(true)}
maxLength={100}
disabled={disabled}
/>,
)}
</FormItem>
......@@ -328,12 +383,19 @@ const StoreModal = props => {
rules: [{ required: true, message: '请选择是否启用!' }],
initialValue: formData.state,
})(
<Radio.Group>
<Radio.Group disabled={disabled}>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</Radio.Group>,
)}
</FormItem>
{isDisabled && (
<FormItem label="门店公告">
{getFieldDecorator('publicNotice', {
initialValue: formData.publicNotice,
})(<Input placeholder="请输入门店公告" maxLength={120} disabled={disabled} />)}
</FormItem>
)}
</Form>
<MapModal
visible={visibleMap}
......
......@@ -17,3 +17,13 @@ export const layout = {
labelCol: { span: 6 },
wrapperCol: { span: 16 },
};
// 业务模式
export const businessModel = [
{ label: '到家外卖业务(外卖配送业务)', value: 1 },
{ label: '实物商品业务员', value: 2 },
{ label: '到店业务(服务类业务)', value: 3 },
];
// 营业日
export const businessStatus = [{ label: '停业', value: 2 }, { label: '营业中', value: 1 }];
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,
Select,
} from 'antd';
import _ from 'lodash';
import { searchList, apiEnableStore, apiAddrArea } from './services';
import { stateDesc, weeks, layout } from './data';
import { el } from 'date-fns/locale';
import { searchList, apiEnableStore, apiAddrArea, apiproductBusiness } from './services';
import { stateDesc, weeks, layout, businessStatus, businessModel } from './data';
import StoreModal from './components/storeModal';
import style from './style.less';
const { Option } = Select;
const { confirm } = Modal;
export default () => {
const [visible, setVisible] = useState(false);
const [storeInfo, setStoreInfo] = useState({});
const [areaAddr, setAreaAddr] = useState([]);
const [status, setStatus] = useState();
const [dataList, setDataList] = useState([]);
const [pageNo, setPageNo] = useState(1);
const [totalNum, setTotalNum] = useState(0);
const [pageSize, setPageSize] = useState(20);
const [productBusiness, setProductBusiness] = useState([]);
const refSearch = useRef();
const divDom = useRef();
// 获取业务模式
const getBusiness = async () => {
const res = await apiproductBusiness();
setProductBusiness(res);
};
const onCreate = () => {
setStoreInfo({});
setVisible(true);
getBusiness();
};
const onShowInfo = info => {
const onShowInfo = (info, val) => {
setStoreInfo(info);
const value = val !== 'edit';
setStatus(value);
setVisible(true);
getBusiness();
};
// 获取市区街道
......@@ -92,16 +119,22 @@ export default () => {
params[ids[i]] = item;
});
}
if (val.businessStatus) {
params.businessStatus = val.businessStatus;
}
getList(params);
};
const closeModal = isReload => {
if (isReload) {
onSearch(refSearch.current?.getFieldValue?.() || {});
}
setStatus(false);
setStoreInfo({});
setVisible(false);
};
const onEnableState = async ({ id, state }) => {
const enableStore = async (id, state) => {
const enable = +state === 1 ? 0 : 1;
const res = await apiEnableStore({ id, state: enable });
if (res === '0000') {
......@@ -109,11 +142,25 @@ export default () => {
onSearch(refSearch.current?.getFieldValue?.() || {});
}
};
const onEnableState = async ({ id, state }) => {
if (state) {
confirm({
title: '确认要禁用这家门店吗?',
content: '禁用后用户将无法看到该店铺',
onOk() {
enableStore(id, state);
},
});
} else {
enableStore(id, state);
}
};
const onReset = () => {
if (refSearch.current && refSearch.current.resetFields) {
refSearch.current.resetFields();
}
getList();
};
const onPageChange = (e, size) => {
......@@ -164,83 +211,74 @@ export default () => {
const columns = [
{
title: '门店名称',
dataIndex: 'name',
title: '业务模式',
dataIndex: 'productBusiness',
width: 120,
align: 'center',
render: v => {
let str = '';
v.forEach(it => {
businessModel.forEach(item => {
if (+it === +item.value) {
str += `${item.label}`;
}
});
});
return str;
},
},
{
title: '门店电话',
dataIndex: 'phone',
hideInSearch: true,
title: '门店名称',
dataIndex: 'name',
width: 120,
align: 'center',
},
{
title: '营业时间',
dataIndex: 'businessHours',
hideInSearch: true,
width: 150,
render: businessHours => (
<div>
<div>{getWeekSlots(businessHours.weeks)}</div>
<div>
{businessHours.hoursItems.map(item => (
<div key={item.begin}>
<span>{item.begin}</span>-<span>{item.end}</span>
</div>
))}
</div>
</div>
),
},
{
title: '地区',
dataIndex: 'addr',
width: 200,
hideInSearch: true,
render: (addr, r) => (
<span>{`${r.provinceName}${r.cityName}${r.countyName}${r.townName || ''}`}</span>
),
title: '营业状态',
dataIndex: 'businessStatus',
width: 80,
align: 'center',
render: val => businessStatus.find(item => item.value === val)?.label || '-',
},
{
title: '详细地址',
dataIndex: 'address',
hideInSearch: true,
width: 150,
title: '创建时间',
dataIndex: 'createdAt',
width: 120,
align: 'center',
},
{
title: '经纬度',
dataIndex: 'latlng',
hideInSearch: true,
width: 120,
render: (latlng, r) => <span>{`${r.longitude},${r.latitude}`}</span>,
title: '门店电话',
dataIndex: 'phone',
align: 'center',
width: 100,
},
{
title: '状态',
title: '门店状态',
dataIndex: 'state',
hideInSearch: true,
width: 120,
align: 'center',
width: 80,
render: v => <span>{`${stateDesc[v]}`}</span>,
},
{
title: '创建时间',
dataIndex: 'createdAt',
hideInSearch: true,
width: 120,
},
{
title: '操作',
hideInSearch: true,
dataIndex: 'action',
width: 170,
width: 200,
fixed: 'right',
render: (val, r) => [
<Button key="enable1" onClick={() => onEnableState(r)} type="primary">
{+r.state ? '禁用' : '启用'}
</Button>,
<Button key="seek" style={{ marginLeft: '10px' }} onClick={() => onShowInfo(r)}>
查看
</Button>,
],
render: (val, r) => (
<div className={style.actionBtn}>
<Button key="look" onClick={() => onShowInfo(r)}>
查看
</Button>
<Button key="seek" onClick={() => onShowInfo(r, 'edit')}>
修改
</Button>
<Button key="enable1" onClick={() => onEnableState(r)} type="primary">
{+r.state ? '禁用' : '启用'}
</Button>
</div>
),
},
];
return (
......@@ -264,17 +302,28 @@ export default () => {
</Form.Item>
</Col>
<Col span={8}>
<Button type="primary" htmlType="submit" size="middle">
搜索
</Button>
<Button size="middle" className={style.searchBtn} onClick={() => onReset()}>
重置
</Button>
<Button type="primary" size="middle" onClick={() => onCreate()}>
新建
</Button>
<Form.Item label="营业状态" name="businessStatus">
<Select>
{businessStatus.map(item => (
<Option label={item.label} value={item.value} key={item.value}>
{item.label}
</Option>
))}
</Select>
</Form.Item>
</Col>
</Row>
<div className={style.search}>
<Button type="primary" htmlType="submit" size="middle">
搜索
</Button>
<Button size="middle" className={style.searchBtn} onClick={() => onReset()}>
重置
</Button>
<Button type="primary" size="middle" onClick={() => onCreate()}>
新建
</Button>
</div>
</Form>
</div>
<Table
......@@ -285,7 +334,7 @@ export default () => {
pagination={false}
scroll={{ x: '100%' }}
/>
{dataList && dataList.length && (
{dataList && dataList.length ? (
<div className={style.pageBox}>
<Pagination
style={{ marginBottom: 10 }}
......@@ -298,8 +347,14 @@ export default () => {
onShowSizeChange={onPageChange}
/>
</div>
)}
<StoreModal visible={visible} onCancel={closeModal} formInfo={storeInfo} />
) : null}
<StoreModal
visible={visible}
onCancel={closeModal}
formInfo={storeInfo}
status={status}
productBusiness={productBusiness}
/>
</div>
);
};
......@@ -65,3 +65,11 @@ export async function apiEditStore(params) {
});
return data.businessCode;
}
// 获取商户业务模式
export async function apiproductBusiness() {
const data = await request.get('/api/merchants/suppliers/product-business/list', {
prefix: kdspApi,
});
return data.data;
}
.serachForm {
margin-bottom: 20px;
padding: 20px 50px 0 10px;
padding: 20px 50px 10px 10px;
background-color: #fff;
}
.search {
display: flex;
justify-content: end;
}
.searchBtn {
margin: 0 10px;
}
......@@ -13,3 +17,14 @@
border: 1px solid #f0f0f0;
border-top: 0;
}
.actionBtn {
display: flex;
align-items: center;
// flex-direction: column;
justify-content: space-around;
button {
width: 75px;
margin-bottom: 5px;
}
}
import { PlusOutlined } from '@ant-design/icons';
import { Upload, Modal, message } from 'antd';
import { Upload, Modal, notification } from 'antd';
import React from 'react';
import config from '../../../config/env.config';
import { qiniuToken } from '@/services/qiniu';
......@@ -7,7 +7,6 @@ import { qiniuToken } from '@/services/qiniu';
const qiniu = require('@/utils/qiniu.min.js');
const { qiniuHost } = config;
function getBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
......@@ -26,9 +25,26 @@ class PicturesWall extends React.Component {
};
async componentDidMount() {
this.initFileList(this.props.fileList || []);
token = await qiniuToken();
}
static getDerivedStateFromProps(nextProps) {
new PicturesWall(nextProps).initFileList();
return null;
}
initFileList = fileList => {
const fileLists =
fileList?.map((item, index) => ({
url: item,
name: '',
uid: index,
status: 'done',
})) || [];
this.setState({ fileList: fileLists });
};
handleCancel = () => this.setState({ previewVisible: false });
handlePreview = async file => {
......@@ -43,17 +59,37 @@ class PicturesWall extends React.Component {
});
};
handleChange = info => {
const lastFile = (info.fileList.length && info.fileList[info.fileList.length - 1]) || [];
const types = ['application/pdf', 'image/png', 'image/jpeg'];
if (lastFile && types.indexOf(lastFile.type) === -1) {
message.error('文件格式错误!');
}
const fileList = info.fileList.filter(item => types.indexOf(item.type) !== -1);
this.setState({ fileList });
handleChange = ({ fileList }) => {
const file = fileList.filter(item => item.url);
this.setState({ fileList: [...file] });
const urlList = file.map(item => item.url);
this.props.onChange(urlList);
};
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 observer = {
next() {
......@@ -67,6 +103,17 @@ class PicturesWall extends React.Component {
const comFile = file;
const url = `${qiniuHost}/${res.hash}`;
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);
// ...
},
......@@ -94,15 +141,17 @@ class PicturesWall extends React.Component {
</div>
);
const { max } = this.props;
return (
<div className="clearfix">
<Upload
{...this.props}
customRequest={this.customRequest}
listType="picture-card"
fileList={fileList}
onPreview={this.handlePreview}
onChange={this.handleChange}
{...this.props}
multiple
>
{max && fileList.length >= max ? null : uploadButton}
</Upload>
......
import React, { useState, useRef } from 'react';
import ProTable from '@ant-design/pro-table';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { notification, Button, Modal, Image, message } from 'antd';
import { query } from './services';
const ContractView = () => {
const [visible, setVisible] = useState(false);
const [url, setUrl] = useState();
// 查看
const onLook = ({ contractPdfUrl }) => {
if (contractPdfUrl) {
setUrl(contractPdfUrl);
setVisible(true);
} else {
message.error('暂无合同');
}
};
// 下载
const ondown = ({ contractPdfUrl }) => {
if (contractPdfUrl) {
window.open(contractPdfUrl);
} else {
message.error('暂无合同');
}
};
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 }}
/>
<Modal visible={visible} width="1000px" onCancel={() => setVisible(false)}>
<iframe src={url} height="500" width="95%" title="合同"></iframe>
</Modal>
</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 = {
...params,
pageIndex: params.current,
pageSize: params.pageSize || 20,
};
const data = await request.post('/api/merchants/suppliers/contract/list', {
prefix: goodsApi,
data: param,
headers: {
'Content-Type': 'application/json;charset=UTF-8',
},
});
if (data.data) {
return {
data: data.data,
};
}
return {
total: 0,
data: [],
};
}
/* eslint-disable prefer-destructuring */
import { parse } from 'querystring';
import pathRegexp from 'path-to-regexp';
import moment from 'moment';
......@@ -127,3 +128,25 @@ export const getClientInfo = () => {
};
export const getObjectType = v => Object.prototype.toString.call(v).replace(/\[object |]/g, '');
// 获取长表单错误提示
export const getErrorMessage = err => {
const message = '请检查表单数据!';
// eslint-disable-next-line wrap-iife
// (function getMsg(v) {
// if (Array.isArray(v)) {
// getMsg(v[0]);
// } else {
// const keys = Object.keys(v);
// if (Array.isArray(v[keys[0]])) {
// getMsg(v[keys[0]][0]);
// } else if (v[keys[0]].errors && v[keys[0]].errors.length) {
// // eslint-disable-next-line no-const-assign
// message = v[keys[0]].errors[0].message;
// } else {
// getMsg(v);
// }
// }
// })(err);
return 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