index.jsx 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. import React, { Component } from "react";
  2. import {
  3. Button,
  4. DatePicker,
  5. Form,
  6. Input,
  7. message,
  8. Select,
  9. Spin,
  10. Table,
  11. Tabs,
  12. Tooltip
  13. } from "antd";
  14. import moment from "moment";
  15. import ShowModalDiv from "@/showModal.jsx";
  16. import { ShowModal, getContactType } from "@/tools.js";
  17. import { ChooseList } from "../../../order/orderNew/chooseList";
  18. import $ from "jquery/src/ajax";
  19. import IntentionDetail from "../../NEW/intentionCustomer/intentionDetail/intentionDetail";
  20. import { getProvince } from '@/NewDicProvinceList';
  21. import Cascaders from "../../../../common/cascaders";
  22. const { TabPane } = Tabs;
  23. const { RangePicker } = DatePicker;
  24. class FollowUpSummary extends Component {
  25. constructor(props) {
  26. super(props);
  27. this.state = {
  28. loading: false,
  29. changeList: [],
  30. columns: [
  31. {
  32. title: "客户名称",
  33. dataIndex: "nickname",
  34. key: "nickname",
  35. render: text => {
  36. return (
  37. <Tooltip title={text}>
  38. <div style={{
  39. maxWidth: '150px',
  40. overflow: 'hidden',
  41. textOverflow: "ellipsis",
  42. whiteSpace: 'nowrap',
  43. }}>{text}</div>
  44. </Tooltip>
  45. )
  46. }
  47. },
  48. {
  49. title: '客户类型',
  50. dataIndex: 'shareType',
  51. key: 'shareType',
  52. render: text => {
  53. // 0-私有 1-公共 2 签单 3外联
  54. return (
  55. text === 0 ? '私有客户' :
  56. text === 1 ? '公共客户' :
  57. text === 2 ? '签单客户' :
  58. text === 3 ? '外联客户' : ''
  59. )
  60. }
  61. },
  62. {
  63. title: '客户初始时间',
  64. dataIndex: 'startTimes',
  65. key: 'startTimes',
  66. },
  67. {
  68. title: "跟进方式",
  69. dataIndex: "contactType",
  70. key: "contactType",
  71. render: (text) => {
  72. return getContactType(text);
  73. },
  74. },
  75. {
  76. title: "跟进人",
  77. dataIndex: "followName",
  78. key: "followName",
  79. },
  80. {
  81. title: "跟进部门",
  82. dataIndex: "followDep",
  83. key: "followDep",
  84. },
  85. {
  86. title: "跟进说明",
  87. dataIndex: "result",
  88. key: "result",
  89. width: 150,
  90. render: (text, record) => {
  91. return (
  92. <Tooltip placement="topLeft" title={<div style={{ wordBreak: "break-all" }}>{text}</div>}>
  93. <div style={{
  94. cursor: "pointer",
  95. width: '150px',
  96. whiteSpace: 'nowrap',
  97. overflow: 'hidden',
  98. textOverflow: 'ellipsis',
  99. }}>
  100. {text}
  101. </div>
  102. </Tooltip>
  103. );
  104. },
  105. },
  106. {
  107. title: "跟进时间",
  108. dataIndex: "followTimes",
  109. key: "followTimes",
  110. },
  111. {
  112. title: "次数",
  113. dataIndex: "followCount",
  114. key: "followCount",
  115. },
  116. {
  117. title: "指导意见",
  118. dataIndex: "guidance",
  119. key: "guidance",
  120. width: 150,
  121. render: (text, record) => {
  122. return (
  123. <Tooltip placement="topLeft" title={<div style={{ wordBreak: "break-all" }}>{(record.guidanceName ? '(' + record.guidanceName + ')' : '') + text}</div>}>
  124. <div style={{
  125. cursor: "pointer",
  126. width: '150px',
  127. whiteSpace: 'nowrap',
  128. overflow: 'hidden',
  129. textOverflow: 'ellipsis',
  130. }}>
  131. {record.guidanceName ? '(' + record.guidanceName + ')' : null}
  132. {text}
  133. </div>
  134. </Tooltip>
  135. );
  136. },
  137. },
  138. {
  139. title: "指导时间",
  140. dataIndex: "guidanceTimes",
  141. key: "guidanceTimes",
  142. render: (text) => {
  143. return (
  144. <span>{text ? text : ''}</span>
  145. )
  146. }
  147. }
  148. ],
  149. dataSource: [],
  150. pagination: {
  151. defaultCurrent: 1,
  152. defaultPageSize: 10,
  153. showQuickJumper: true,
  154. pageSize: 10,
  155. onChange: function (page) {
  156. this.loadData(page);
  157. }.bind(this),
  158. showTotal: function (total) {
  159. return "共" + total + "条数据";
  160. },
  161. },
  162. releaseDate: [],
  163. releaseDate1: [],
  164. releaseDate2: [],
  165. userName: undefined,
  166. followName: undefined,
  167. userType: undefined,
  168. contactType: undefined,
  169. deps: undefined,
  170. shiroType: props.shiroType,
  171. }
  172. this.reset = this.reset.bind(this);
  173. this.loadData = this.loadData.bind(this);
  174. this.selectSuperId = this.selectSuperId.bind(this);
  175. this.category = this.category.bind(this);
  176. this.closeDesc = this.closeDesc.bind(this);
  177. this.tableRowClick = this.tableRowClick.bind(this);
  178. this.export = this.export.bind(this);
  179. }
  180. componentWillReceiveProps(prevProps) {
  181. if (prevProps.shiroType !== this.state.shiroType) {
  182. this.setState({
  183. shiroType: prevProps.shiroType
  184. }, () => {
  185. this.reset();
  186. // this.selectSuperId();
  187. })
  188. }
  189. }
  190. componentDidMount() {
  191. this.props.shiroType != 2 && this.loadData();
  192. // this.selectSuperId();
  193. }
  194. loadData(pageNo) {
  195. if (this.state.userName == undefined &&
  196. this.state.followName == undefined &&
  197. this.state.userType == undefined &&
  198. this.state.contactType == undefined &&
  199. this.state.deps == undefined &&
  200. this.state.releaseDate.length == 0 &&
  201. this.state.releaseDate1.length == 0 &&
  202. this.state.releaseDate2.length == 0 &&
  203. this.props.shiroType == 2
  204. ) {
  205. message.warning("请先填写筛选条件!");
  206. return
  207. }
  208. let data = {
  209. pageNo: pageNo || 1,
  210. pageSize: this.state.pagination.pageSize,
  211. userName: this.state.userName || undefined,
  212. followName: this.state.followName || undefined,
  213. userType: isNaN(parseInt(this.state.userType)) ? undefined : this.state.userType,
  214. contactType: isNaN(parseInt(this.state.contactType)) ? undefined : this.state.contactType,
  215. deps: this.state.deps || undefined,
  216. followStartTime: this.state.releaseDate[0] ? this.state.releaseDate[0] : undefined,
  217. followEndTime: this.state.releaseDate[1] ? this.state.releaseDate[1] : undefined,
  218. createStartTime: this.state.releaseDate1[0] ? this.state.releaseDate1[0] : undefined,
  219. createEndTime: this.state.releaseDate1[1] ? this.state.releaseDate1[1] : undefined,
  220. guidanceStartTime: this.state.releaseDate2[0] ? this.state.releaseDate2[0] : undefined,
  221. guidanceEndTime: this.state.releaseDate2[1] ? this.state.releaseDate2[1] : undefined,
  222. shiroType: this.state.shiroType
  223. };
  224. this.setState({
  225. loading: true,
  226. });
  227. $.ajax({
  228. method: "get",
  229. dataType: "json",
  230. crossDomain: false,
  231. url: globalConfig.context + '/api/admin/userFollowList',
  232. data,
  233. success: function (data) {
  234. ShowModal(this);
  235. if (data.error.length === 0) {
  236. let theArr = [];
  237. for (let i = 0; i < data.data.list.length; i++) {
  238. let thisdata = data.data.list[i];
  239. let diqu = getProvince(thisdata.province, thisdata.city, thisdata.area)
  240. thisdata.key = i;
  241. thisdata.lastFollowTime = thisdata.lastFollowTime && thisdata.lastFollowTime.split(" ")[0];
  242. thisdata.transferTime = thisdata.transferTime && thisdata.transferTime.split(" ")[0];
  243. thisdata.surplusFollowTime = thisdata.surplusFollowTime && thisdata.surplusFollowTime.split(" ")[0];
  244. thisdata.surplusSignTime = thisdata.surplusSignTime && thisdata.surplusSignTime.split(" ")[0];
  245. thisdata.locationProvince = diqu;
  246. thisdata.uid = thisdata.id;
  247. theArr.push(thisdata);
  248. }
  249. this.state.pagination.current = data.data.pageNo;
  250. this.state.pagination.total = data.data.totalCount;
  251. this.setState({
  252. pageNo: data.data.pageNo,
  253. dataSource: theArr,
  254. pagination: this.state.pagination,
  255. });
  256. } else {
  257. message.warning(data.error[0].message);
  258. }
  259. }.bind(this),
  260. }).always(
  261. function () {
  262. this.setState({
  263. loading: false,
  264. });
  265. }.bind(this)
  266. );
  267. };
  268. selectSuperId() {
  269. this.state.data = []
  270. $.ajax({
  271. method: "get",
  272. dataType: "json",
  273. crossDomain: false,
  274. url: globalConfig.context + "/api/admin/organization/selectSuperId",
  275. data: {},
  276. success: function (data) {
  277. if (data.error.length === 0) {
  278. let theArr = [];
  279. for (let i = 0; i < data.data.length; i++) {
  280. let theData = data.data[i];
  281. theArr.push(
  282. <Select.Option value={theData.id} key={theData.name}>{theData.name}</Select.Option>
  283. );
  284. }
  285. this.setState({
  286. contactsOption: theArr,
  287. });
  288. } else {
  289. message.warning(data.error[0].message);
  290. }
  291. }.bind(this),
  292. }).always(function () { }.bind(this));
  293. }
  294. //品类数据获取
  295. category() {
  296. $.ajax({
  297. method: "get",
  298. dataType: "json",
  299. crossDomain: false,
  300. url: globalConfig.context + "/api/admin/Varieties/getSuperList",
  301. data: {},
  302. success: function (data) {
  303. let thedata = data.data;
  304. let theArr = [];
  305. if (!thedata) {
  306. if (data.error && data.error.length) {
  307. message.warning(data.error[0].message);
  308. }
  309. } else {
  310. thedata.map(function (item, index) {
  311. theArr.push({
  312. value: item.id,
  313. key: item.cname,
  314. });
  315. });
  316. }
  317. this.setState({
  318. categoryArr: theArr,
  319. });
  320. }.bind(this),
  321. });
  322. }
  323. tableRowClick(record) {
  324. this.category();
  325. this.setState({
  326. rowData: record,
  327. modalVisible: true,
  328. modalName: record.nickname,
  329. })
  330. }
  331. closeDesc(e, s) {
  332. this.setState({
  333. visitModul: e,
  334. modalVisible: e,
  335. showDesc: e,
  336. tabsKey: '',
  337. })
  338. if (s) {
  339. this.props.shiroType != 2 && this.loadData(this.state.pageNo);
  340. }
  341. }
  342. export() {
  343. this.setState({
  344. exportExecLoading: true
  345. })
  346. let loading = message.loading('加载中...');
  347. let data = {
  348. userName: this.state.userName || undefined,
  349. followName: this.state.followName || undefined,
  350. userType: isNaN(parseInt(this.state.userType)) ? undefined : this.state.userType,
  351. contactType: isNaN(parseInt(this.state.contactType)) ? undefined : this.state.contactType,
  352. deps: this.state.deps || undefined,
  353. followStartTime: this.state.releaseDate[0] ? this.state.releaseDate[0] : undefined,
  354. followEndTime: this.state.releaseDate[1] ? this.state.releaseDate[1] : undefined,
  355. createStartTime: this.state.releaseDate1[0] ? this.state.releaseDate1[0] : undefined,
  356. createEndTime: this.state.releaseDate1[1] ? this.state.releaseDate1[1] : undefined,
  357. guidanceStartTime: this.state.releaseDate2[0] ? this.state.releaseDate2[0] : undefined,
  358. guidanceEndTime: this.state.releaseDate2[1] ? this.state.releaseDate2[1] : undefined,
  359. shiroType: this.state.shiroType
  360. };
  361. for (let i in data) {
  362. if (typeof data[i] === "undefined") {
  363. delete data[i]
  364. }
  365. }
  366. $.ajax({
  367. method: "get",
  368. dataType: "json",
  369. crossDomain: false,
  370. url: globalConfig.context + "/api/admin/userFollowListExport",
  371. data,
  372. success: function (data) {
  373. if (data.error.length === 0) {
  374. this.download(data.data);
  375. } else {
  376. message.warning(data.error[0].message);
  377. }
  378. }.bind(this),
  379. }).always(function () {
  380. loading();
  381. this.setState({
  382. exportExecLoading: false
  383. })
  384. }.bind(this));
  385. }
  386. download(fileName) {
  387. window.location.href = globalConfig.context + "/open/download?fileName=" + fileName
  388. }
  389. reset() {
  390. this.setState({
  391. userName: undefined,
  392. followName: undefined,
  393. userType: undefined,
  394. contactType: undefined,
  395. deps: undefined,
  396. releaseDate: [],
  397. releaseDate1: [],
  398. releaseDate2: [],
  399. dataSource: [],
  400. }, () => {
  401. this.Cascaders.empty();
  402. this.props.shiroType != 2 && this.loadData();
  403. })
  404. }
  405. render() {
  406. return (
  407. <div className="user-content">
  408. <ShowModalDiv ShowModal={this.state.showModal} />
  409. <div className="content-title" style={{ marginBottom: 10 }}>
  410. <span style={{ fontWeight: 900, fontSize: 16 }}>客户跟进汇总</span>
  411. </div>
  412. <Tabs defaultActiveKey="1" className="test">
  413. <TabPane tab="搜索" key="1">
  414. <div className="user-search">
  415. <Form layout="inline">
  416. <Form.Item style={{ marginTop: '10px' }}>
  417. <Input
  418. placeholder="客户名称"
  419. value={this.state.userName}
  420. style={{ width: 150, marginRight: 10 }}
  421. onChange={(e) => {
  422. this.setState({ userName: e.target.value });
  423. }}
  424. />
  425. </Form.Item>
  426. <Form.Item style={{ marginTop: '10px' }}>
  427. <Input
  428. placeholder="跟进人名称"
  429. value={this.state.followName}
  430. style={{ width: 150, marginRight: 10 }}
  431. onChange={(e) => {
  432. this.setState({ followName: e.target.value });
  433. }}
  434. />
  435. </Form.Item>
  436. <Form.Item>
  437. <Select
  438. placeholder="选择客户类型"
  439. style={{ width: 100, marginRight: 10 }}
  440. value={this.state.userType}
  441. onChange={
  442. (e) => {
  443. this.setState({ userType: e })
  444. }}
  445. >
  446. {/*0所有 1私有客户2 公共客户 3签单客户4外联客户*/}
  447. <Select.Option value={0}>所有</Select.Option>
  448. <Select.Option value={1}>私有客户</Select.Option>
  449. <Select.Option value={2}>公共客户</Select.Option>
  450. <Select.Option value={3}>签单客户</Select.Option>
  451. <Select.Option value={4}>外联客户</Select.Option>
  452. </Select>
  453. </Form.Item>
  454. <Form.Item>
  455. <Select
  456. placeholder="选择跟进方式"
  457. style={{ width: 100, marginRight: 10 }}
  458. value={this.state.contactType}
  459. onChange={(e) => { this.setState({ contactType: e }) }}
  460. >
  461. <Select.Option value={0}>外出</Select.Option>
  462. <Select.Option value={1}>电话</Select.Option>
  463. <Select.Option value={2}>QQ</Select.Option>
  464. <Select.Option value={3}>微信</Select.Option>
  465. <Select.Option value={4}>邮箱</Select.Option>
  466. <Select.Option value={5}>公出打卡</Select.Option>
  467. </Select>
  468. </Form.Item>
  469. <Form.Item style={{ marginTop: '10px' }}>
  470. <Cascaders
  471. ref={ref => this.Cascaders = ref}
  472. placeholder="选择跟进部门"
  473. id="id"
  474. name="name"
  475. children="list"
  476. height={32}
  477. onSel={(e) => {
  478. this.setState({
  479. deps: JSON.stringify(e)
  480. })
  481. }}
  482. />
  483. {/* <Select
  484. placeholder="选择跟进部门"
  485. style={{ width: '200px', marginRight: '10px' }}
  486. value={this.state.depId}
  487. onChange={
  488. (e) => {
  489. this.setState({ depId: e })
  490. }}
  491. notFoundContent="未获取到上级组织列表"
  492. >
  493. {this.state.contactsOption}
  494. </Select> */}
  495. </Form.Item>
  496. <Form.Item label='跟进时间:' style={{ marginTop: '10px' }}>
  497. <RangePicker
  498. style={{ marginRight: '10px' }}
  499. value={[
  500. this.state.releaseDate[0]
  501. ? moment(this.state.releaseDate[0])
  502. : null,
  503. this.state.releaseDate[1]
  504. ? moment(this.state.releaseDate[1])
  505. : null,
  506. ]}
  507. onChange={(data, dataString) => {
  508. this.setState({ releaseDate: dataString });
  509. }}
  510. />
  511. </Form.Item>
  512. <Form.Item label='客户初始时间:' style={{ marginTop: '10px' }}>
  513. <RangePicker
  514. style={{ marginRight: '10px' }}
  515. value={[
  516. this.state.releaseDate1[0]
  517. ? moment(this.state.releaseDate1[0])
  518. : null,
  519. this.state.releaseDate1[1]
  520. ? moment(this.state.releaseDate1[1])
  521. : null,
  522. ]}
  523. onChange={(data, dataString) => {
  524. this.setState({ releaseDate1: dataString });
  525. }}
  526. />
  527. </Form.Item>
  528. <Form.Item label='指导时间:' style={{ marginTop: '10px' }}>
  529. <RangePicker
  530. style={{ marginRight: '10px' }}
  531. value={[
  532. this.state.releaseDate2[0]
  533. ? moment(this.state.releaseDate2[0])
  534. : null,
  535. this.state.releaseDate2[1]
  536. ? moment(this.state.releaseDate2[1])
  537. : null,
  538. ]}
  539. onChange={(data, dataString) => {
  540. this.setState({ releaseDate2: dataString });
  541. }}
  542. />
  543. </Form.Item>
  544. </Form>
  545. <Button
  546. type="primary"
  547. style={{ marginLeft: "10px", marginRight: 10 }}
  548. onClick={() => {
  549. this.loadData();
  550. }}
  551. >
  552. 搜索
  553. </Button>
  554. <Button onClick={this.reset}>重置</Button>
  555. </div>
  556. </TabPane>
  557. <TabPane tab="更改表格显示数据" key="2">
  558. <div style={{ marginLeft: 10 }}>
  559. <ChooseList
  560. columns={this.state.columns}
  561. changeFn={this.changeList}
  562. changeList={this.state.changeList}
  563. top={55}
  564. margin={11}
  565. />
  566. </div>
  567. </TabPane>
  568. <TabPane tab="导出" key="3">
  569. <Button style={{ float: "left", margin: 10 }} onClick={this.export}>
  570. 导出excel
  571. </Button>
  572. </TabPane>
  573. </Tabs>
  574. <div className="patent-table">
  575. <Spin spinning={this.state.loading}>
  576. <Table
  577. columns={
  578. this.state.changeList.length
  579. ? this.state.changeList
  580. : this.state.columns
  581. }
  582. dataSource={this.state.dataSource}
  583. pagination={this.state.pagination}
  584. onRowClick={this.tableRowClick}
  585. style={{
  586. cursor: 'pointer',
  587. }}
  588. />
  589. </Spin>
  590. </div>
  591. <IntentionDetail
  592. isCustomerAdmin={this.props.isCustomerAdmin}
  593. categoryArr={this.state.categoryArr}
  594. IntentionData={this.state.rowData}
  595. modalVisible={this.state.modalVisible}
  596. isGuidanceLv={this.props.isGuidanceLv}
  597. isEditGuidanceLv={this.props.isEditGuidanceLv}
  598. name={this.state.modalName}
  599. closeDesc={this.closeDesc}
  600. />
  601. </div>
  602. )
  603. }
  604. }
  605. export default FollowUpSummary;