Commit 585967c2 authored by wangxuelai's avatar wangxuelai

'获客导入添加'

parent 1516015b
......@@ -223,5 +223,7 @@ export default {
},
crm: {
crmList: `${dakaapi}member/crm/clues`,
uploadTasks: `${dakaapi}member/erp/upload_tasks`,
bindSjdAccount: `${dakaapi}member/sjd/bind`,
},
};
......@@ -11,6 +11,8 @@ import {
} from '../utils/index';
import * as crmAjax from '../services/crm';
import errorcode from '../common/errorcode';
import * as newregister from '../services/newregister';
import * as uploader from '../services/uploader';
import * as courseAjax from '../services/course';
export default {
namespace: 'crm',
......@@ -29,6 +31,18 @@ export default {
},
crmTotal: 0,
crmList: [],
clueImportShow: false,
bindSjdAccountShow: false,
loadingUploadTask: false,
uploadTaskList: [],
taskListQueryParams: {
page: 1,
perPage: 20,
},
uploadTaskTotal: 0,
countdown: 60,
counting: false,
gettingVerifyCoding: false,
},
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
......@@ -45,6 +59,53 @@ export default {
},
});
},
* queryUploadTasks({ payload }, { call, put, select }) {
const { sid } = yield select(state => state.webapp);
const { params } = payload;
const { loadingUploadTask, taskListQueryParams } = yield select(state => state.crm);
const newTaskListQueryParams = Object.assign(
taskListQueryParams,
params,
);
yield put({
type: 'updateState',
payload: {
loadingUploadTask: true,
},
});
const uploadTasksList = yield call(crmAjax.uploadTasks, {
type: 1,
school_id: sid,
page: taskListQueryParams.page,
perPage: taskListQueryParams.perPage,
});
yield put({
type: 'updateState',
payload: {
loadingUploadTask: false,
},
});
const { code, data } = uploadTasksList;
if (code == 200) {
yield put({
type: 'updateState',
payload: {
uploadTaskTotal: data.total,
uploadTaskList: data.list,
taskListQueryParams: {
...newTaskListQueryParams,
},
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data: uploadTasksList,
},
});
}
},
* queryCrmList({ payload }, { call, put, select }) {
const { params } = payload;
const { sid } = yield select(state => state.webapp);
......@@ -79,6 +140,111 @@ export default {
});
}
},
* getverifycode({ payload }, { call, put, select }) {
const { countdown, counting, gettingVerifyCoding } = yield select(state => state.crm);
// const { timer } = yield select(state => state.usersetting);
const { mobile } = payload;
let newCountdowm = countdown;
let newCounting = counting;
yield put({
type: 'updateState',
payload: {
gettingVerifyCoding: true,
counting: false,
},
});
const verifycodehide = message.loading('正在获取验证码....', 0);
const data = yield call(newregister.getVerifyCode, { mobile, sms_type: 10 });
if (data.code === 200) {
setTimeout(verifycodehide);
message.success('验证码获取成功', 1);
yield put({
type: 'updateState',
payload: {
gettingVerifyCoding: false,
},
});
newCounting = true;
yield put({
type: 'updateState',
payload: {
counting: newCounting,
},
});
const setTimer = setInterval(() => {
newCountdowm--;
if (newCountdowm <= 0) {
newCountdowm = 60;
newCounting = false;
clearInterval(setTimer);
}
payload.dispatch({
type: 'crm/updateState',
payload: {
countdown: newCountdowm,
counting: newCounting,
timer: setTimer,
},
});
}, 1000);
} else {
setTimeout(verifycodehide);
yield put({
type: 'updateState',
payload: {
gettingVerifyCoding: false,
counting: false,
countdown: 60,
},
});
message.error(data.msg, 1);
}
},
* sureBindSjdAccount({ payload }, { call, put, select }) {
const { bindSjdAccountSubmitting } = yield select(state => state.crm);
const { mobile, code, callback } = payload;
if (bindSjdAccountSubmitting) {
return;
}
yield put({
type: 'updateState',
payload: {
bindSjdAccountSubmitting: true,
},
});
const loading = message.loading('商家岛账号绑定中...');
const bindData = yield call(crmAjax.bindSjdAccount, {
mobile,
code,
});
setTimeout(loading);
yield put({
type: 'updateState',
payload: {
bindSjdAccountSubmitting: false,
},
});
const { code: ajaxcode, data } = bindData;
if (ajaxcode == 200) {
message.success('绑定成功', 1);
if (callback && (typeof callback == 'function')) {
callback();
}
yield put({
type: 'updateState',
payload: {
bindSjdAccountShow: false,
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data: bindData,
},
});
}
},
* reset({ payload }, { call, put, select }) {
const { copyClassListQueryParams } = yield select(state => state.classmgt);
yield put({
......@@ -109,6 +275,92 @@ export default {
pathname: `/sjd/crmdetail/${id}`,
}));
},
* querysignature({ payload }, { call, put, select }) {
const { userInfo, sid } = yield select(state => state.webapp);
const {
files,
} = payload;
const file = files ? files[0] : null;
const REGEXP_IMAGE = /^image\/\w+/;
const params = { prefix: 'excel', token: userInfo.token, schoolId: sid };
let signature = {};
if (file) {
const uploaderLoading = message.loading('正在上传学员');
const uploadSignature = yield call(uploader.uploadExcelSignature, params);
signature = uploadSignature.data;
yield put({
type: 'uploadexcel',
payload: {
signature,
files,
},
});
}
},
* uploadexcel({ payload }, { call, put }) {
const {
signature, files,
} = payload;
const file = files ? files[0] : null;
const filename = `${signature.dir}${getRandomFilename(file.name)}`;
const params = {
key: filename,
policy: signature.policy,
OSSAccessKeyId: signature.accessid,
signature: signature.signature,
file,
url: signature.host,
};
const uploadExcel = yield call(uploader.uploadImg, params);
const fileName = `https://shangjiadao.oss-cn-hangzhou.aliyuncs.com/${filename}`;
console.log(file, 'file');
yield put({
type: 'uploadStudents',
payload: {
file_name: fileName,
file_info: JSON.stringify({
name: file.name || '',
size: file.size || '',
type: file.type || '',
}),
},
});
},
* uploadStudents({ payload }, { call, put, select }) {
const { file_name, file_info } = payload;
const { sid } = yield select(state => state.webapp);
const importData = yield call(crmAjax.uploadStudents, {
file_name,
file_info,
school_id: sid,
type: 1,
});
const { code, data } = importData;
if (code == 200) {
yield put({
type: 'queryUploadTasks',
payload: {
params: {},
},
});
yield put({
type: 'queryCrmList',
payload: {
params: {},
},
});
} else {
yield put({
type: 'webapp/errorrequestresolve',
payload: {
data: importData,
},
});
}
yield put({
type: 'updateState',
});
},
* pageInit({ payload }, { call, put, select }) {
yield put({
type: 'updateState',
......
import React from 'react';
import { connect } from 'dva';
import { Row, Col, Modal, Form, Input, Button, message } from 'antd';
import pageStyles from './index.less';
import Cropper from '../../components/Cropper';
import { pageIn, imagify } from '../../utils/index';
const { Search } = Input;
const FormItem = Form.Item;
class BindSjdAccount extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
componentDidMount() {
}
componentWillUnmount() {
const { dispatch } = this.props;
}
sureBindWx = () => {
const { form, submit } = this.props;
form.validateFields((err, values) => {
if (!err) {
submit(values, () => {
form.resetFields();
});
}
});
}
close = () => {
const { form, close } = this.props;
form.resetFields();
close();
}
sendVerifyCode = () => {
const { form, sendVerifyCode, counting } = this.props;
if (counting) {
return;
}
form.validateFields(['mobile'], {}, (err, values) => {
if (!err) {
sendVerifyCode(values, () => {
form.resetFields();
});
}
});
}
render() {
const {
nickname,
visible,
nicknameSubmitting,
countdown,
counting,
gettingVerifyCoding,
submitting,
} = this.props;
const { getFieldDecorator } = this.props.form;
return (
<div>
<Modal
visible={visible}
title="关联账户"
cancelText="关闭"
zIndex={110}
onOk={this.sureBindWx}
onCancel={this.close}
maskClosable={false}
okText="立即关联"
okButtonProps={{ size: 'small' }}
cancelButtonProps={{ size: 'small' }}
confirmLoading={submitting}
width={390}
>
<Form className="modalform" labelAlign="left">
<Form.Item
label="手机号"
hasFeedback
labelCol={{
xs: { span: 24 },
sm: { span: 5 },
}}
wrapperCol={{
xs: { span: 24 },
sm: { span: 19 },
}}
>
{getFieldDecorator('mobile', {
rules: [
{
required: true,
message: '请输入手机号码',
},
{ pattern: /^1[3456789]{1}[0-9]{9}$/, message: '请输入正确的手机号码!' },
],
})(<Input type="text" maxLength={20} placeholder="请输入商家岛账号" />)}
</Form.Item>
<Form.Item
label="验证码"
labelCol={{
xs: { span: 24 },
sm: { span: 5 },
}}
wrapperCol={{
xs: { span: 24 },
sm: { span: 19 },
}}
>
<Row gutter={8}>
<Col span={14}>
{getFieldDecorator('code', {
rules: [
{ required: true, message: '请输入四位数字验证码' },
{ pattern: /^[0-9]{4}$/, message: '验证码是4位数字验证码' },
],
})(<Input type="text" maxLength={4} placeholder="请输入验证码" />)}
</Col>
<Col span={10} style={{ color: '#1890FF', cursor: 'pointer', fontSize: '14px' }}>
<div className={`${pageStyles.verycodebtn} ${counting ? pageStyles.verycodebtndisable : ''}`} onClick={this.sendVerifyCode}>{counting ? `${countdown}秒后重新获取` : '发送验证码'}</div>
</Col>
</Row>
</Form.Item>
</Form>
</Modal>
</div>
);
}
}
BindSjdAccount.propTypes = {
};
const UpdateNickname = Form.create()(BindSjdAccount);
export default UpdateNickname;
......@@ -20,9 +20,10 @@ import {
} from 'antd';
import moment from 'moment';
import { routerRedux } from 'dva/router';
import pageStyle from './index.less';
import pageStyle from './ClueImport.less';
import { pageIn, hasBtnPower, btnPermission } from '../../utils/index';
import BtnPermission from '../../components/BtnPermission';
import { download } from '../../utils/download';
const { Option } = Select;
const { TextArea } = Input;
const { Search } = Input;
......@@ -33,123 +34,68 @@ class ClueImport extends React.Component {
this.state = {
};
}
downLoadExcelTemp = () => {
window.open('https://shangjiadao.oss-cn-hangzhou.aliyuncs.com/qingxiao/biz/exceltemp/潜客管理导入模板.xlsx');
// download('https://shangjiadao.oss-cn-hangzhou.aliyuncs.com/qingxiao/biz/exceltemp/%E6%BD%9C%E5%AE%A2%E7%AE%A1%E7%90%86%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx', '潜客管理导入模板.xlsx');
// download('https://shangjiadao.oss-cn-hangzhou.aliyuncs.com/qingxiao/biz/exceltemp/%E6%BD%9C%E5%AE%A2%E7%AE%A1%E7%90%86%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF.xlsx');
}
render() {
const {
visible,
close,
goBindSjdAccount,
loading,
list,
query,
total,
sizeChange,
changePagination,
upload,
refresh,
} = this.props;
const columns = [
{
title: '手机号',
dataIndex: 'mobile',
key: 'mobile',
render: (text, record) => {
return (
<span className="hreflink">{text}</span>
);
},
},
{
title: '意向课程',
dataIndex: 'intent_course.title',
key: 'intent_course.title',
title: '文件名',
dataIndex: 'file_info',
key: 'file_info',
render: (text, record) => {
let fileInfo = {};
try {
fileInfo = JSON.parse(record.file_info);
} catch (e) {
fileInfo = {};
}
return (
<span>{text || '-'}</span>
<span className="hreflink">{fileInfo.name || record.file_name}</span>
);
},
},
{
title: '来源渠道',
dataIndex: 'source_type',
key: 'source_type',
render: (text, record) => {
switch (text) {
case 1:
return '在线购买';
case 2:
return '在线招生';
case 3:
return '来电咨询';
case 4:
return '地推';
case 5:
return '外呼电话';
case 6:
return '转介绍';
case 7:
return '客户直访';
case 8:
return '其他';
default:
return '-';
}
},
},
{
title: '录入时间',
title: '上传时间',
dataIndex: 'created_at',
key: 'created_at',
render: (text, record) => {
return (
<span>{text || '-'}</span>
);
},
},
{
title: '活动标题',
dataIndex: 'customers',
key: 'customers',
title: '操作人',
dataIndex: 'final_follow',
key: 'final_follow',
render: (text, record) => {
return (
<div >
{record.customers.activity_title ? record.customers.activity_title : '-'}
</div>
<span>{(record.school_teacher && record.school_teacher.nickname) || ''}</span>
);
},
},
{
title: '跟进状态',
title: '状态',
dataIndex: 'status',
key: 'status',
render: (text, record) => {
switch (text) {
case 1:
return '待跟进';
case 2:
return '跟进中';
case 3:
return '已完成';
case 4:
return '无效';
case 5:
return '已成功';
default:
return '-';
}
},
},
{
title: '最后跟进人',
dataIndex: 'final_follow.nickname',
key: 'nickname',
render: (text, record) => {
return (
<span>{text || '-'}</span>
);
},
},
{
title: '操作',
dataIndex: 'c',
key: 'c',
render: (text, record) => {
return (
<div className={pageStyle.tableoperatebox}>
<span className="hreflink">购课</span>
<Divider type="vertical" />
<span className="hreflink">跟进</span>
</div>
<span>
{record.status == 1 && '正在上传'}
{record.status == 2 && '上传成功'}
{record.status == 3 && '上传失败'}
</span>
);
},
},
......@@ -159,44 +105,53 @@ class ClueImport extends React.Component {
title="潜在学员信息导入"
visible={visible}
onCancel={close}
zIndex={109}
width={887}
bodyStyle={{
paddingTop: 18,
paddingBottom: 18,
paddingBottom: 0,
}}
className="clueimportmodal"
footer={<Button size="small" type="primary" style={{ width: 75 }} onClick={close}>关闭</Button>}
>
<div>
<Button size="small" type="primary" style={{ marginRight: 20 }}>关联商家岛账号</Button>
<Button size="small" type="primary" style={{ marginRight: 20 }}>上传表格</Button>
<Button size="small" type="primary"style={{ marginRight: 5 }}>下载模板</Button>
<Tooltip placement="top" title="下载规定模板,按照顺序要求填写潜在学员信息,即可上传">
<Icon type="question-circle" theme="filled" style={{ opacity: 0.5, fontSize: 18, cursor: 'pointer' }} />
</Tooltip>
<div style={{ marginBottom: 20, display: 'flex', justifyContent: 'space-between' }} >
<div>
<Button size="small" type="primary" style={{ marginRight: 20 }} onClick={goBindSjdAccount}>关联商家岛账号</Button>
<Button size="small" type="primary" style={{ marginRight: 20, position: 'relative' }}><input onChange={upload} type="file" className={pageStyle.uploadExcel} accept=".xls, .xlsx" />上传表格</Button>
<Button size="small" type="primary"style={{ marginRight: 5 }} onClick={this.downLoadExcelTemp}>下载模板</Button>
<Tooltip placement="top" title="下载规定模板,按照顺序要求填写潜在学员信息,即可上传">
<Icon type="question-circle" theme="filled" style={{ opacity: 0.5, fontSize: 18, cursor: 'pointer' }} />
</Tooltip>
</div>
<div>
<Tooltip placement="top" title="点击更新文件上传进度">
<Icon type="sync" style={{ marginLeft: 150, fontSize: 18, cursor: 'pointer' }} onClick={refresh} />
</Tooltip>
</div>
</div>
{/* <div className={pageStyle.tablebox}>
<Table
rowKey="id"
dataSource={crmList}
columns={columns}
scroll={{ x: 'max-content' }}
pagination={false}
bordered
footer={null}
/>
<Table
rowKey="id"
dataSource={list}
columns={columns}
scroll={{ x: 'max-content' }}
pagination={false}
loading={loading}
footer={null}
/>
<div className={pageStyle.tablebox}>
<div className={pageStyle.tablefooterbox}>
<span className={pageStyle.tablefooterstatic}>共{crmTotal}条数据</span>
<span className={pageStyle.tablefooterstatic}>{total}条数据</span>
<Pagination
showSizeChanger
showQuickJumper
onShowSizeChange={this.sizeChange}
total={Number(crmTotal)}
onChange={this.changePagination}
current={Number(crmParams.page) || 1}
pageSize={crmParams.perPage}
onShowSizeChange={sizeChange}
total={total}
onChange={changePagination}
current={Number(query.page) || 1}
pageSize={Number(query.perPage)}
/>
</div>
</div> */}
</div>
</Modal>
);
}
......
@import '../../less/variables.less';
.container {
background-color: #fff;
border-radius: 2px;
padding: 20px;
}
.headerbox{
background-color: #fff;
.headerbtn {
margin: 0 16px 0 0;
}
padding-bottom: 18px;
}
.searchrow {
.formitem {
display: flex;
align-items: center;
margin-bottom: 16px;
.formitemlabel {
color: #000000;
font-size: 14px;
line-height: 1;
min-width: 70px;
white-space: nowrap;
}
}
}
.selectitem {
display: block;
}
.searchbtnbox {
height: 54px;
display: flex;
align-items: flex-end;
}
.resetbtn {
margin-right: 16px;
}
.tablebox {
background: #fff;
:global {
.ant-table-fixed {
border-bottom: 1px solid #E8E8E8 !important;
}
.ant-table tbody tr:nth-child(2n) {
background-color: #FBFBFB;
}
.ant-table-thead > tr > th, .ant-table-tbody > tr > td {
padding: 11px 10px;
}
.ant-table-bordered .ant-table-tbody tr td {
border-bottom: none;
border-right: none!important;
}
.ant-table-bordered .ant-table-thead tr th {
border-bottom: none;
border-right: none!important;
}
.ant-table-bordered .ant-table-thead tr th:last-child {
border-right: 1px solid #e8e8e8!important;
:global {
.clueimportmodal {
.ant-table {
.ant-table-tbody {
.ant-table-row:last-child {
// td {
// border-bottom: none;
// }
}
}
.ant-table-placeholder {
border-bottom: none;
}
}
.ant-table-bordered .ant-table-tbody tr td:last-child {
border-right: 1px solid #e8e8e8!important;
}
.ant-table-bordered .ant-table-tbody tr:last-child {
border-bottom: 1px solid #e8e8e8!important;
}
}
}
.divideline {
color: #E9E9E9;
padding: 0 8px;
}
.alink {
color: #1890FF;
}
.classNamebox {
max-width: 250px;
word-break: break-all;
color: #1890FF;
cursor: pointer;
// background-color: #fff;
}
.tableoperatebox {
min-width: 160px;
line-height: 30px;
}
.endsearchcol {
margin-bottom: 18px;
}
.endclassfooter {
display: flex;
align-items: center;
justify-content: space-between;
}
.classroomitem {
margin-bottom: 5px;
.classroom {
color:rgba(0,0,0,0.85);
}
.aLink {
color: #1890FF;
padding-left: 21px;
}
}
.activeamount{
background-color: #cccccc;
color: #666666;
text-align: center;
line-height: 50px;
font-size: 20px;
}
.rightList {
display: flex;
align-items: center;
height: 32px;
.resetIcon {
width: 14px;
height: 14px;
cursor: pointer;
margin-right: 15px;
}
.expend {
font-size:13px;
font-family:PingFangSC-Regular,PingFang SC;
font-weight:400;
color:rgba(102,102,102,1);
display: inline-block;
cursor: pointer;
}
}
.tablefooterbox {
color: rgba(0,0,0,0.6);
......@@ -138,49 +23,19 @@
background-color: #fff;
align-items: center;
justify-content: space-between;
padding-left: 14px;
padding-right: 14px;
margin-top: 10px;
// padding-left: 14px;
// padding-right: 14px;
// margin-top: 10px;
.tablefooterstatic {
color:rgba(0,0,0,0.65);
font-size: 14px;
}
}
.tabList {
display: flex;
border-bottom: 1px solid #E8E8E8;
margin-bottom: 18px;
.tabItem {
font-size:13px;
font-weight:400;
color:rgba(102,102,102,1);
line-height:18px;
padding: 0 30px 10px;
cursor: pointer;
position: relative;
&:hover {
font-weight:600;
color:#1890FF;
}
}
.tabItemActive {
font-size:13px;
font-weight:600;
color:#1890FF;
line-height:18px;
padding: 0 30px 10px;
cursor: pointer;
position: relative;
font-family:PingFangSC-Semibold,PingFang SC;
&:after {
content: '';
display: block;
width: 30%;
height: 2px;
background-color: #1890FF;
position: absolute;
bottom: 0;
left: 35%;
}
}
}
.uploadExcel {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
opacity: 0;
}
\ No newline at end of file
......@@ -24,6 +24,7 @@ import pageStyle from './index.less';
import { pageIn, hasBtnPower, btnPermission } from '../../utils/index';
import BtnPermission from '../../components/BtnPermission';
import ClueImport from './ClueImport';
import BindSjdAccount from './BindSjdAccount';
const { Option } = Select;
const { TextArea } = Input;
const { Search } = Input;
......@@ -123,7 +124,28 @@ class Crm extends React.Component {
});
}
closeClueImport = () => {
console.log('哈哈哈');
const { dispatch } = this.props;
dispatch({
type: 'crm/updateState',
payload: {
clueImportShow: false,
},
});
}
toImportClue = () => {
const { dispatch } = this.props;
dispatch({
type: 'crm/updateState',
payload: {
clueImportShow: true,
},
});
dispatch({
type: 'crm/queryUploadTasks',
payload: {
params: {},
},
});
}
goDetail = (record) => {
const { dispatch } = this.props;
......@@ -134,12 +156,109 @@ class Crm extends React.Component {
},
});
}
closeBindSjdAccount = () => {
const { dispatch } = this.props;
dispatch({
type: 'crm/updateState',
payload: {
bindSjdAccountShow: false,
},
});
}
goBindSjdAccount = () => {
const { dispatch } = this.props;
dispatch({
type: 'crm/updateState',
payload: {
bindSjdAccountShow: true,
},
});
}
taskListSizeChange = (page, perPage) => {
const { dispatch } = this.props;
dispatch({
type: 'crm/queryUploadTasks',
payload: {
params: {
page: 1,
perPage,
},
},
});
}
taskListChangePagination = (page, perPage) => {
const { dispatch } = this.props;
dispatch({
type: 'crm/queryUploadTasks',
payload: {
params: {
page,
perPage,
},
},
});
}
sureBindSjdAccount = (val, callback) => {
const { dispatch } = this.props;
dispatch({
type: 'crm/sureBindSjdAccount',
payload: {
...val,
callback,
},
});
}
sendVerifyCode = (value) => {
const { dispatch } = this.props;
dispatch({
type: 'crm/getverifycode',
payload: {
mobile: value.mobile,
dispatch,
},
});
}
uploadExcel = (e) => {
const { files } = e.target;
const { dispatch } = this.props;
dispatch({
type: 'crm/querysignature',
payload: {
files,
},
});
}
refreshUploadStatus = () => {
const { dispatch } = this.props;
dispatch({
type: 'crm/queryUploadTasks',
payload: {
params: {},
},
});
dispatch({
type: 'crm/queryCrmList',
payload: {
params: {},
},
});
}
render() {
const {
userPermission,
crmList,
crmTotal,
crmParams,
clueImportShow,
bindSjdAccountShow,
loadingUploadTask,
uploadTaskList,
taskListQueryParams,
uploadTaskTotal,
countdown,
counting,
gettingVerifyCoding,
bindSjdAccountSubmitting,
} = this.props;
const { isExpendMore } = this.state;
const columns = [
......@@ -262,7 +381,7 @@ class Crm extends React.Component {
<div className={pageStyle.container}>
<div className={pageStyle.headerbox}>
<Button size="small" className={pageStyle.headerbtn} type="primary" onClick={this.goAddCrm}>添加潜在学员</Button>
<Button size="small" className={pageStyle.headerbtn}>一键导入</Button>
<Button size="small" className={pageStyle.headerbtn} onClick={this.toImportClue}>一键导入</Button>
</div>
<div className={pageStyle.searchbox}>
<Row
......@@ -366,8 +485,27 @@ class Crm extends React.Component {
</div>
</div>
<ClueImport
visible
visible={clueImportShow}
close={this.closeClueImport}
goBindSjdAccount={this.goBindSjdAccount}
loading={loadingUploadTask}
list={uploadTaskList}
query={taskListQueryParams}
total={uploadTaskTotal}
sizeChange={this.taskListSizeChange}
changePagination={this.taskListChangePagination}
upload={this.uploadExcel}
refresh={this.refreshUploadStatus}
/>
<BindSjdAccount
visible={bindSjdAccountShow}
submit={this.sureBindSjdAccount}
close={this.closeBindSjdAccount}
sendVerifyCode={this.sendVerifyCode}
countdown={countdown}
counting={counting}
submitting={bindSjdAccountSubmitting}
gettingVerifyCoding={gettingVerifyCoding}
/>
</div>
);
......@@ -383,6 +521,16 @@ function mapStateToProps(state) {
crmList,
crmTotal,
crmParams,
clueImportShow,
bindSjdAccountShow,
loadingUploadTask,
uploadTaskList,
taskListQueryParams,
uploadTaskTotal,
countdown,
counting,
gettingVerifyCoding,
bindSjdAccountSubmitting,
} = state.crm;
const {
guideStep,
......@@ -398,6 +546,16 @@ function mapStateToProps(state) {
crmList,
crmTotal,
crmParams,
clueImportShow,
bindSjdAccountShow,
loadingUploadTask,
uploadTaskList,
taskListQueryParams,
uploadTaskTotal,
countdown,
counting,
gettingVerifyCoding,
bindSjdAccountSubmitting,
};
}
export default connect(mapStateToProps)(CrmForm);
......
......@@ -24,3 +24,26 @@ export function crmEdit(params) {
data,
});
}
export function uploadTasks(params) {
const data = qs.stringify(params);
return request({
url: `${api.crm.uploadTasks}?${data}`,
method: 'GET',
});
}
export function uploadStudents(params) {
const data = qs.stringify(params);
return request({
url: `${api.crm.uploadTasks}`,
method: 'POST',
data,
});
}
export function bindSjdAccount(params) {
const data = qs.stringify(params);
return request({
url: `${api.crm.bindSjdAccount}`,
method: 'POST',
data,
});
}
......@@ -25,6 +25,7 @@ export function uploadVideoSignature({ type, token, schoolId }) {
},
});
}
export function uploadVideo(params) {
const {
OSSAccessKeyId,
......@@ -61,6 +62,17 @@ export function uploadImageSignature({ type, token, schoolId }) {
},
});
}
export function uploadExcelSignature({ prefix, token, schoolId }) {
return request({
url: `${api.imgupload}`,
method: 'GET',
params: {
prefix,
token,
school_id: schoolId,
},
});
}
export function uploadImg(params, progressCallback, cancelToken) {
const {
OSSAccessKeyId,
......
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