statistics.jsx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. import React, { Component } from "react";
  2. import {
  3. AutoComplete,
  4. Button,
  5. DatePicker,
  6. Input,
  7. message,
  8. Modal,
  9. Select,
  10. Spin,
  11. Table,
  12. Tabs,
  13. Tag,
  14. Tooltip,
  15. } from "antd";
  16. import { ShowModal, getPercentage } from "@/tools";
  17. import { salesList, } from "@/dataDic"
  18. import { ChooseList } from "../../order/orderNew/chooseList";
  19. import $ from "jquery/src/ajax";
  20. import "./index.less";
  21. import moment from "moment";
  22. import DetailList from "./detaillist";
  23. const { TabPane } = Tabs;
  24. const { RangePicker } = DatePicker;
  25. class SignStatistics extends Component {
  26. constructor(props) {
  27. super(props);
  28. this.state = {
  29. pageNo: 1,
  30. loading: false,
  31. changeList: undefined,
  32. columns: [
  33. {
  34. title: "营销员",
  35. dataIndex: "name",
  36. key: "name",
  37. },
  38. {
  39. title: "签单客户",
  40. dataIndex: "userCount",
  41. key: "userCount",
  42. },
  43. {
  44. title: "签单个数",
  45. dataIndex: "orderCount",
  46. key: "orderCount",
  47. onCellClick: (r) => {
  48. let cellData = {};
  49. cellData["aid"] = r.id
  50. cellData["aname"] = r.name
  51. this.setState({
  52. showDetail: true,
  53. rowData: cellData,
  54. })
  55. },
  56. render: (text) =>
  57. <div
  58. style={{
  59. color: "#58A3FF",
  60. textDecoration: "underline",
  61. cursor: "pointer"
  62. }}>
  63. {text}
  64. </div>
  65. },
  66. {
  67. title: "签单总金额(万元)",
  68. dataIndex: "totalAmount",
  69. key: "totalAmount",
  70. },
  71. {
  72. title: "新签数",
  73. dataIndex: "newSignNumber",
  74. key: "newSignNumber",
  75. onCellClick: (r) => {
  76. let cellData = {};
  77. cellData["aid"] = r.id
  78. cellData["aname"] = r.name
  79. cellData["orderType"] = "1"
  80. this.setState({
  81. showDetail: true,
  82. rowData: cellData,
  83. })
  84. },
  85. render: (text) =>
  86. <div
  87. style={{
  88. color: "#58A3FF",
  89. textDecoration: "underline",
  90. cursor: "pointer"
  91. }}>
  92. {text}
  93. </div>
  94. },
  95. {
  96. title: "新签率",
  97. dataIndex: "newRatio",
  98. key: "newRatio",
  99. render: (text) =>
  100. <span >
  101. {getPercentage(text)}
  102. </span>
  103. },
  104. {
  105. title: "复购数",
  106. dataIndex: "repeatSignNumber",
  107. key: "repeatSignNumber",
  108. onCellClick: (r) => {
  109. let cellData = {};
  110. cellData["aid"] = r.id
  111. cellData["aname"] = r.name
  112. cellData["orderType"] = "2"
  113. this.setState({
  114. showDetail: true,
  115. rowData: cellData,
  116. })
  117. },
  118. render: (text) =>
  119. <div
  120. style={{
  121. color: "#58A3FF",
  122. textDecoration: "underline",
  123. cursor: "pointer"
  124. }}>
  125. {text}
  126. </div>
  127. },
  128. {
  129. title: "复购率",
  130. dataIndex: "repeatRatio",
  131. key: "repeatRatio",
  132. render: (text) =>
  133. <span >
  134. {getPercentage(text)}
  135. </span>
  136. },
  137. {
  138. title: "渠道签单数",
  139. dataIndex: "channelSignNumber",
  140. key: "channelSignNumber",
  141. onCellClick: (r) => {
  142. let cellData = {};
  143. cellData["aid"] = r.id
  144. cellData["aname"] = r.name
  145. cellData["orderType"] = "3"
  146. this.setState({
  147. showDetail: true,
  148. rowData: cellData,
  149. })
  150. },
  151. render: (text) =>
  152. <div
  153. style={{
  154. color: "#58A3FF",
  155. textDecoration: "underline",
  156. cursor: "pointer"
  157. }}>
  158. {text}
  159. </div>
  160. },
  161. {
  162. title: "渠道签单率",
  163. dataIndex: "channelRatio",
  164. key: "channelRatio",
  165. render: (text) =>
  166. <span >
  167. {getPercentage(text)}
  168. </span>
  169. },
  170. ],
  171. pagination: {
  172. defaultCurrent: 1,
  173. defaultPageSize: 10,
  174. showQuickJumper: true,
  175. pageSize: 99999,
  176. onChange: function (page) {
  177. this.loadData(page);
  178. }.bind(this),
  179. showTotal: function (total) {
  180. return "共" + total + "条数据";
  181. },
  182. },
  183. dataSource: [],
  184. searchInfor: {},
  185. params: {},
  186. showDetail: false,
  187. companyList: [],
  188. };
  189. this.loadData = this.loadData.bind(this);
  190. this.resetAll = this.resetAll.bind(this);
  191. this.changeList = this.changeList.bind(this);
  192. this.selectSuperId = this.selectSuperId.bind(this);
  193. this.supervisor = this.supervisor.bind(this);
  194. this.httpChange = this.httpChange.bind(this);
  195. this.blurChange = this.blurChange.bind(this);
  196. this.selectAuto = this.selectAuto.bind(this);
  197. this.exportExec = this.exportExec.bind(this);
  198. }
  199. //获取上级组织
  200. selectSuperId() {
  201. $.ajax({
  202. method: "get",
  203. dataType: "json",
  204. crossDomain: false,
  205. url: globalConfig.context + "/api/admin/organization/selectSuperId",
  206. data: {},
  207. success: function (data) {
  208. let theArr = [];
  209. if (data.error && data.error.length === 0) {
  210. for (let i = 0; i < data.data.length; i++) {
  211. let theData = data.data[i];
  212. theArr.push(
  213. <Select.Option value={theData.id} key={theData.id}>
  214. {theData.name}
  215. </Select.Option>
  216. );
  217. }
  218. this.setState({
  219. contactsOption: theArr,
  220. companyList: data.data,
  221. searchInfor: Object.assign(this.state.searchInfor, {
  222. depId: data.data[0].id,
  223. }),
  224. }, () => {
  225. this.loadData();
  226. });
  227. } else {
  228. message.warning(data.error[0].message);
  229. }
  230. }.bind(this),
  231. }).always(
  232. function () {
  233. this.setState({
  234. // loading: false,
  235. });
  236. }.bind(this)
  237. );
  238. }
  239. changeList(arr) {
  240. const newArr = [];
  241. this.state.columns.forEach((item) => {
  242. arr.forEach((val) => {
  243. if (val === item.title) {
  244. newArr.push(item);
  245. }
  246. });
  247. });
  248. this.setState({
  249. changeList: newArr,
  250. });
  251. }
  252. // 搜索
  253. submit() {
  254. this.setState({
  255. params: this.state.searchInfor
  256. })
  257. this.loadData()
  258. }
  259. loadData(pageNo) {
  260. const { searchInfor, pagination } = this.state;
  261. this.setState({
  262. loading: true,
  263. });
  264. let datas = Object.assign(searchInfor, {
  265. pageNo: pageNo || 1,
  266. pageSize: pagination.pageSize,
  267. });
  268. $.ajax({
  269. method: "get",
  270. dataType: "json",
  271. crossDomain: false,
  272. url: globalConfig.context + "/api/admin/statistis/signStatistics",
  273. data: datas,
  274. success: function (data) {
  275. ShowModal(this);
  276. if (data.error && data.error.length === 0) {
  277. if (data.data.list) {
  278. pagination.current = data.data.pageNo;
  279. pagination.total = data.data.totalCount;
  280. if (data.data && data.data.list && !data.data.list.length) {
  281. pagination.current = 0;
  282. pagination.total = 0;
  283. }
  284. this.setState({
  285. dataSource: data.data.list,
  286. pagination: this.state.pagination,
  287. pageNo: data.data.pageNo,
  288. });
  289. } else {
  290. this.setState({
  291. dataSource: data.data,
  292. pagination: false,
  293. });
  294. }
  295. } else {
  296. message.warning(data.error[0].message);
  297. }
  298. this.setState({
  299. loading: false,
  300. });
  301. }.bind(this),
  302. }).always(
  303. function () {
  304. this.setState({
  305. loading: false,
  306. });
  307. }.bind(this)
  308. );
  309. }
  310. resetAll() {
  311. const { companyList } = this.state
  312. this.setState(
  313. {
  314. searchInfor: { depId: companyList[0].id },
  315. params: JSON.parse(JSON.stringify({})),
  316. aname: "",
  317. },
  318. () => {
  319. this.loadData();
  320. }
  321. );
  322. }
  323. supervisor(e) {
  324. $.ajax({
  325. method: "get",
  326. dataType: "json",
  327. crossDomain: false,
  328. url: globalConfig.context + "/api/admin/customer/listAdminByName",
  329. data: {
  330. adminName: e,
  331. status: "2",
  332. },
  333. success: function (data) {
  334. if (data.error && data.error.length === 0) {
  335. this.setState({
  336. customerArr: data.data,
  337. });
  338. } else {
  339. message.warning(data.error[0].message);
  340. }
  341. }.bind(this),
  342. }).always(function () { }.bind(this));
  343. }
  344. httpChange(e) {
  345. if (e.length >= 1) {
  346. this.supervisor(e);
  347. }
  348. this.setState({
  349. aname: e,
  350. });
  351. }
  352. selectAuto(value, options) {
  353. this.setState({
  354. aname: value,
  355. });
  356. }
  357. blurChange(e) {
  358. const { searchInfor } = this.state
  359. let theType = undefined;
  360. let contactLists = this.state.customerArr || [];
  361. if (e) {
  362. contactLists.map(function (item) {
  363. if (item.name == e.toString()) {
  364. theType = item.id;
  365. }
  366. });
  367. }
  368. this.setState({
  369. searchInfor: Object.assign(searchInfor, {
  370. aid: theType,
  371. }),
  372. });
  373. }
  374. // 导出Excel
  375. exportExec() {
  376. this.setState({
  377. exportPendingLoading: true,
  378. });
  379. message.config({
  380. duration: 20,
  381. });
  382. let loading = message.loading("下载中...");
  383. let data = this.state.searchInfor;
  384. $.ajax({
  385. method: "get",
  386. dataType: "json",
  387. crossDomain: false,
  388. url:
  389. globalConfig.context + "/api/admin/statistis/signStatistics/export",
  390. data,
  391. success: function (data) {
  392. if (data.error.length === 0) {
  393. this.download(data.data);
  394. } else {
  395. message.warning(data.error[0].message);
  396. }
  397. }.bind(this),
  398. }).always(
  399. function () {
  400. loading();
  401. this.setState({
  402. exportPendingLoading: false,
  403. });
  404. }.bind(this)
  405. );
  406. }
  407. // 下载
  408. download(fileName) {
  409. window.location.href =
  410. globalConfig.context + "/open/download?fileName=" + fileName;
  411. }
  412. // 关闭弹窗
  413. closeDesc() {
  414. this.setState({
  415. showDetail: false,
  416. params: {},
  417. });
  418. this.loadData(this.state.pageNo);
  419. }
  420. componentWillMount() {
  421. this.selectSuperId();
  422. }
  423. render() {
  424. const { searchInfor, showDetail, rowData, params, dataSource } = this.state
  425. const dataSources = this.state.customerArr || [];
  426. const options = dataSources.map((group) => (
  427. <Select.Option key={group.id} value={group.name}>
  428. {group.name}
  429. </Select.Option>
  430. ));
  431. return (
  432. <div>
  433. <div className="user-content">
  434. <div className="content-title">
  435. <span style={{ fontWeight: 900, fontSize: 16 }}>签单客户数据统计(销售角度)</span>
  436. </div>
  437. <Tabs defaultActiveKey="1" className="test">
  438. <TabPane tab="搜索" key="1">
  439. <div
  440. className="user-search"
  441. style={{
  442. marginTop: "10px",
  443. marginLeft: "10px",
  444. marginRight: "10px",
  445. }}
  446. >
  447. <span style={{ marginRight: "10px" }}>
  448. <Select
  449. placeholder="选择部门"
  450. style={{ width: 200 }}
  451. value={searchInfor.depId}
  452. onChange={(e) => {
  453. this.setState({
  454. searchInfor: Object.assign(searchInfor, {
  455. depId: e,
  456. }),
  457. });
  458. }}
  459. notFoundContent="未获取到上级组织列表"
  460. >
  461. {this.state.contactsOption}
  462. </Select>
  463. </span>
  464. <span style={{ marginRight: "10px" }}>
  465. <AutoComplete
  466. className="certain-category-search"
  467. dropdownClassName="certain-category-search-dropdown"
  468. dropdownMatchSelectWidth={false}
  469. style={{ width: 160 }}
  470. dataSource={options}
  471. placeholder="输入姓名"
  472. value={this.state.aname}
  473. onChange={this.httpChange}
  474. filterOption={true}
  475. onBlur={this.blurChange}
  476. onSelect={this.selectAuto}
  477. >
  478. <Input />
  479. </AutoComplete>
  480. </span>
  481. <span style={{ marginRight: "10px" }}>
  482. <Select
  483. style={{ width: 160 }}
  484. placeholder="签单金额"
  485. value={searchInfor.amountType}
  486. onChange={(e) => {
  487. this.setState({
  488. searchInfor: Object.assign(searchInfor, {
  489. amountType: e,
  490. }),
  491. });
  492. }}
  493. >
  494. <Option value="0">全部</Option>
  495. <Option value="1">小于10万</Option>
  496. <Option value="2">10-20万</Option>
  497. <Option value="3">20-30万</Option>
  498. <Option value="4">30万以上</Option>
  499. </Select>
  500. </span>
  501. <span style={{ marginRight: "10px" }}>
  502. <span style={{ marginRight: "5px", marginBottom: "10px" }}>
  503. 签单时间 :
  504. </span>
  505. <RangePicker
  506. style={{ marginRight: "10px", marginBottom: "10px" }}
  507. value={[
  508. searchInfor.signTimeStart
  509. ? moment(searchInfor.signTimeStart)
  510. : null,
  511. searchInfor.signTimeEnd ? moment(searchInfor.signTimeEnd) : null,
  512. ]}
  513. onChange={(data, dataString) => {
  514. this.setState({
  515. searchInfor: Object.assign(searchInfor, {
  516. signTimeStart: dataString[0],
  517. signTimeEnd: dataString[1],
  518. }),
  519. });
  520. }}
  521. />
  522. </span>
  523. <Button
  524. type="primary"
  525. onClick={() => {
  526. this.submit()
  527. }}
  528. style={{ marginRight: "10px", marginBottom: "10px" }}
  529. >
  530. 搜索
  531. </Button>
  532. <Button
  533. onClick={this.resetAll}
  534. style={{ marginRight: "10px", marginBottom: "10px" }}
  535. >
  536. 重置
  537. </Button>
  538. </div>
  539. </TabPane>
  540. <TabPane tab="更改表格显示数据" key="2">
  541. <div style={{ marginLeft: 10 }}>
  542. <Spin spinning={this.state.loading}>
  543. <ChooseList
  544. columns={this.state.columns}
  545. changeFn={this.changeList}
  546. changeList={this.state.changeList}
  547. top={55}
  548. margin={11}
  549. />
  550. </Spin>
  551. </div>
  552. </TabPane>
  553. <TabPane tab="导出" key="3">
  554. <div style={{ float: "left" }}>
  555. <Button
  556. type="primary"
  557. loading={this.state.exportPendingLoading}
  558. onClick={this.exportExec}
  559. style={{ margin: 10 }}
  560. >
  561. 导出Excel
  562. </Button>
  563. </div>
  564. </TabPane>
  565. </Tabs>
  566. <div className="patent-table">
  567. <div style={{ padding: "0px 10px 10px" }}>
  568. 总计:签单客户&nbsp;
  569. <span style={{ color: "#58A3FF" }}>{dataSource.reduce((prev, next) => { return prev + next.userCount }, 0)}</span>&nbsp;个,签单个数&nbsp;
  570. <span style={{ color: "#58A3FF" }}>{dataSource.reduce((prev, next) => { return prev + next.orderCount }, 0)}</span>&nbsp;个
  571. </div>
  572. <Spin spinning={this.state.loading}>
  573. <Table
  574. bordered
  575. size="middle"
  576. columns={
  577. this.state.changeList
  578. ? this.state.changeList
  579. : this.state.columns
  580. }
  581. dataSource={dataSource}
  582. pagination={false}
  583. />
  584. </Spin>
  585. </div>
  586. </div>
  587. {
  588. showDetail &&
  589. <Modal
  590. visible={showDetail}
  591. title={<div>
  592. <span style={{ marginRight: 20 }}>客户订单列表</span>
  593. <span style={{ color: "red" }}>归属人:{rowData["aname"]}</span>
  594. </div>}
  595. width="90%"
  596. footer={null}
  597. onCancel={this.closeDesc.bind(this)}
  598. >
  599. <DetailList
  600. data={Object.assign(rowData, params)}
  601. />
  602. </Modal>
  603. }
  604. </div>
  605. );
  606. }
  607. }
  608. export default SignStatistics;