Bläddra i källkod

外呼系统团队

dev01 2 månader sedan
förälder
incheckning
b0007694bc

+ 2 - 2
js/component/common/nowProjectStatus/index.jsx

@@ -276,7 +276,7 @@ class NowProjectStatus extends Component {
                           : d === "setUpAmount"
                           ? "立项金额(万元):"
                           : d === "exampleNumber"
-                          ? "公网络链接:"
+                          ? "公网络链接:"
                           : ""}
                         {this.state.dataInfor[v.id] &&
                           this.state.dataInfor[v.id][d]}
@@ -323,7 +323,7 @@ class NowProjectStatus extends Component {
                             : d === "setUpAmount"
                             ? "立项金额(万元)"
                             : d === "exampleNumber"
-                            ? "公网络链接:"
+                            ? "公网络链接:"
                             : ""}
                         </span>
                         <Input

+ 1 - 1
js/component/common/nowProjectStatus/type.jsx

@@ -106,7 +106,7 @@ const highTechColumns = [
     id: 8,
     name: '已拟公示',
     valueType: ['date', 'exampleNumber'],
-    placeholder: '请输入公网络链接'
+    placeholder: '请输入公网络链接'
   },
   // {
   //   id: 28,

+ 5 - 0
js/component/dataDic.js

@@ -4215,6 +4215,11 @@ module.exports = {
       id: 5,
       color: '#1E90FF'
     },
+    {
+      title: '待审核',
+      id: 6,
+      color: '#1d4fea'
+    },
   ],
   //会员服务年限
   vipYear: [

+ 23 - 11
js/component/manageCenter/customer/NEW/components/outbound/index.jsx

@@ -13,6 +13,7 @@ class Outbound extends Component {
       rVisible: false,
       tVisible: false,
       status: false,
+      id: null,
       uList: [],
       tList: [],
       transAgent: "",
@@ -136,8 +137,10 @@ class Outbound extends Component {
   }
 
   onOk() {
+    const { uid } = this.props
     this.setState({
-      status: true
+      status: true,
+      id: uid,
     })
     this.callNumber()
   }
@@ -171,7 +174,8 @@ class Outbound extends Component {
   }
   // 私有-客户联系方式列表
   findCustomerContacts() {
-    const { uid } = this.props
+    const { uid, isOwn = 0 } = this.props
+    // isOwn
     $.ajax({
       method: "get",
       dataType: "json",
@@ -179,6 +183,7 @@ class Outbound extends Component {
       url: globalConfig.context + "/api/admin/customer/findCustomerContacts",
       data: {
         uid,
+        type: isOwn,
       }
     }).done(function (data) {
       if (!data.error.length) {
@@ -243,6 +248,11 @@ class Outbound extends Component {
         })
         message.success(data.data)
       } else {
+        this.setState({
+          status: false,
+          id: null,
+        })
+        this.webSocket.close();
         message.warning(data.error[0].message);
       };
 
@@ -327,16 +337,17 @@ class Outbound extends Component {
   }
 
   render() {
-    const { status, pVisible, rVisible, tVisible, transAgent, tList, mobile, uList } = this.state
-    const { type, } = this.props
-    // history 只查看呼叫记录
-    // private 私有呼叫,支持呼叫转移
-    // public 公共库呼叫
+    const { id, status, pVisible, rVisible, tVisible, transAgent, tList, mobile, uList } = this.state
+    const { type, uid, noTransfer = false } = this.props
+    //noTransfer 
+    //type= history 只查看呼叫记录
+    //type= private 私有呼叫
+    //type= public 公共库呼叫
     return (
       <span>
         {type != "history" &&
           <Button
-            style={{ background: !status ? "green" : "red", border: 0 }}
+            style={{ background: ((id == uid) && status) ? "red" : "green", border: 0 }}
             type="primary"
             loading={pVisible}
             onClick={() => {
@@ -348,8 +359,8 @@ class Outbound extends Component {
                 ? this.getDefaultMobile()
                 : this.findCustomerContacts()
             }}
-          >{!pVisible && <Icon type="phone" />} {!status ? '呼叫' : '正在通话中'}</Button>}
-        {type == "private" && status &&
+          >{!pVisible && <Icon type="phone" />} {((id == uid) && status) ? '正在通话中' : '呼叫'}</Button>}
+        {type == "private" && status && (id == uid) && !noTransfer &&
           <Button
             style={{ background: "green", border: 0, marginLeft: 20 }}
             type="primary"
@@ -379,7 +390,7 @@ class Outbound extends Component {
             })
           }}
         >
-          <div className="contacts">
+          <div className="contacts" style={{ position: "relative" }}>
             <Select
               style={{ width: 200 }}
               value={mobile}
@@ -395,6 +406,7 @@ class Outbound extends Component {
                 )
               }
             </Select>
+            {uList.length > 1 && <span style={{ color: 'red', position: "absolute", right: 0, top: 4 }}>有多电话可选!</span>}
           </div>
         </Modal>
         <Modal

+ 9 - 17
js/component/manageCenter/customer/NEW/intentionCustomer/clue.jsx

@@ -97,23 +97,14 @@ const LimitedProject = React.createClass({
           },
         },
         {
-          title: "导入时间",
-          dataIndex: "clueTime",
-          key: "clueTime",
-          isSelect: "jl",
-          render: (text, record) => {
-            return (
-              <div>
-                {text}
-              </div>
-            );
-          },
+          title: "线索释放天数",
+          dataIndex: "days",
+          key: "days",
         },
         {
-          title: "转时间",
+          title: "转入时间",
           dataIndex: "clueTransferTime",
           key: "clueTransferTime",
-          isSelect: "yxy",
           render: (text, record) => {
             return (
               <div>
@@ -130,8 +121,10 @@ const LimitedProject = React.createClass({
             return (
               <div>
                 <Outbound
-                  type="public"
+                  type="private"
+                  noTransfer={true}
                   uid={record.id}
+                  isOwn={1}
                 />
                 {
                   ((record.clueProcess == 1 && this.props.intentionState == 2) ||
@@ -237,7 +230,7 @@ const LimitedProject = React.createClass({
                     content: (
                       <span>
                         {data.data.errorCount}个客户信息导入失败!
-                        <div style={{ color: "red" }} dangerouslySetInnerHTML={{ __html: data.data.msg }}/>
+                        <div style={{ color: "red" }} dangerouslySetInnerHTML={{ __html: data.data.msg }} />
                       </span>
                     ),
                     onOk() { },
@@ -638,7 +631,6 @@ const LimitedProject = React.createClass({
       dataType: "json",
       crossDomain: false,
       url: globalConfig.context + "/api/admin/userClue/exportTemplate",
-      data: {},
       success: function (data) {
         if (data.error.length === 0) {
           this.download(data.data);
@@ -658,7 +650,7 @@ const LimitedProject = React.createClass({
 
   download(fileName) {
     window.location.href =
-      globalConfig.context + "/open/download?fileName=" + fileName;
+      globalConfig.context + "/open/download?fileName=" + fileName + "&delete=false";
   },
 
   followUp(e) {

+ 18 - 0
js/component/manageCenter/customer/content.jsx

@@ -511,6 +511,24 @@ class Content extends Component {
           });
         });
         break;
+      // 外呼统计
+      case "outbound":
+        let Outbound = require('./outbound/index').default;
+        require.ensure([], () => {
+          this.setState({
+            component: <Outbound handlekey={this.getKey.bind(this)} />,
+          });
+        });
+        break;
+      // 外呼明细
+      case "outboundDetail":
+        let Detail = require('./outbound/detail').default;
+        require.ensure([], () => {
+          this.setState({
+            component: <Detail />,
+          });
+        });
+        break;
       //客户资料
       case 'crm':
         require.ensure([], () => {

+ 363 - 0
js/component/manageCenter/customer/outbound/detail.jsx

@@ -0,0 +1,363 @@
+import React from 'react';
+import $ from 'jquery/src/ajax';
+import {
+  Form, Button, Input, Select, Spin, Table,
+  message, DatePicker, Tabs, TreeSelect
+} from 'antd';
+import moment from 'moment';
+import { ShowModal } from "@/tools";
+import { ChooseList } from "../../order/orderNew/chooseList";
+
+const { TabPane } = Tabs
+const { RangePicker } = DatePicker
+const OutboundDetail = Form.create()(React.createClass({
+  getInitialState() {
+    return {
+      searchValues: {}, // 列表筛选条件
+      loading: false, //加载动画
+      changeList: undefined, // 更改后的表格显示数据
+      dataSource: [], // 列表数据
+      teamList: [], // 团队列表
+      pagination: {
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        showQuickJumper: true,
+        pageSize: 10,
+        onChange: function (page) {
+          this.loadData(page);
+        }.bind(this),
+        showTotal: function (total) {
+          return '共' + total + '条数据';
+        }
+      },
+      columns: [
+        {
+          title: '姓名',
+          dataIndex: 'name',
+          key: 'name',
+        },
+        {
+          title: '所属团队',
+          dataIndex: 'teamName',
+          key: 'teamName',
+        },
+        {
+          title: '拨出次数',
+          dataIndex: 'callSum',
+          key: 'callSum',
+        },
+        {
+          title: '接通次数',
+          dataIndex: 'connectSum',
+          key: 'connectSum',
+        },
+        {
+          title: '有效次数',
+          dataIndex: 'validSum',
+          key: 'validSum',
+        },
+        {
+          title: '时长',
+          dataIndex: 'callDurationSum',
+          key: 'callDurationSum',
+          render: (text, record) => {
+            return (
+              <div>
+                {this.isTime(text)}
+              </div>
+            )
+          }
+        },
+        {
+          title: '时间',
+          dataIndex: 'dayDate',
+          key: 'dayDate',
+        },
+
+      ],
+      visible: "",
+    };
+  },
+
+  componentWillMount() {
+    this.salesTeam();
+    let params = this.getParametersFromCookies();
+    if (params.teamId) {
+      const { searchValues } = this.state
+      let obj = {
+        teamId: Number(params.teamId),
+        startTime: params.startTime,
+        endTime: params.endTime,
+      }
+      this.setState({
+        searchValues: Object.assign(searchValues, obj),
+      }, () => {
+        this.loadData();
+      });
+    } else {
+      this.loadData();
+    }
+  },
+
+  getParametersFromCookies() {
+    let params = {};
+    let ca = document.cookie.split(';');
+    for (let i = 0; i < ca.length; i++) {
+      let c = ca[i];
+      while (c.charAt(0) === ' ') c = c.substring(1, c.length);
+      let eqPos = c.indexOf('=');
+      if (eqPos > -1) {
+        let paramName = c.substring(0, eqPos);
+        let paramValue = decodeURIComponent(c.substring(eqPos + 1));
+        params[paramName] = paramValue;
+      }
+    }
+    return params;
+  },
+
+  // 列表接口
+  loadData(pageNo) {
+    const { searchValues, pagination } = this.state;
+    this.setState({
+      loading: true,
+    });
+    let datas = Object.assign(searchValues, {
+      pageNo: pageNo || 1,
+      pageSize: pagination.pageSize,
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/userOutbound/listCallDay",
+      data: datas,
+      success: function (data) {
+        ShowModal(this);
+        this.setState({
+          loading: false,
+        });
+        let theArr = [];
+        if (data.error && data.error.length === 0) {
+          if (data.data) {
+            pagination.current = data.data.pageNo;
+            pagination.total = data.data.totalCount;
+            if (data.data && data.data.list && !data.data.list.length) {
+              pagination.current = 0
+              pagination.total = 0
+            };
+            this.setState({
+              dataSource: data.data.list,
+              pagination: this.state.pagination,
+              pageNo: data.data.pageNo,
+            });
+          }
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  // 团队
+  salesTeam() {
+    this.setState({
+      loading: true
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/salesTeam/lvlList",
+      data: {},
+      success: function (data) {
+        this.setState({
+          loading: false,
+        });
+        if (data.error && data.error.length === 0) {
+          let list = data.data
+          this.setState({
+            teamList: list ? this.handleTreeData(list) : []
+          });
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(function () {
+      this.setState({
+        loading: false
+      });
+    }.bind(this));
+  },
+
+  // 树状默认数据处理
+  handleTreeData(treeData) {
+    let nodeDta = [];
+    treeData.map(item => {
+      let treeObj = {};
+      treeObj.key = item.id
+      treeObj.id = item.id
+      treeObj.value = item.id
+      treeObj.label = item.name
+      treeObj.title = item.name
+      treeObj.lvl = item.lvl
+      item.list ? treeObj.children = this.handleTreeData(item.list) : null;
+      nodeDta.push(treeObj)
+    })
+    return nodeDta
+  },
+
+  search() {
+    this.loadData();
+  },
+
+  reset() {
+    this.setState({
+      searchValues: {}
+    }, () => {
+      this.loadData();
+    })
+  },
+
+  changeList(arr) {
+    const newArr = [];
+    this.state.columns.forEach(item => {
+      arr.forEach(val => {
+        if (val === item.title) {
+          newArr.push(item);
+        }
+      });
+    });
+    this.setState({
+      changeList: newArr
+    });
+  },
+
+  isTime(second) {
+    let time = "0秒"
+    if (second > 3600) {
+      time = moment.utc(second * 1000).format('h小时m分s秒')
+    } else if (second > 60) {
+      time = moment.utc(second * 1000).format('m分s秒')
+    } else if (second > 0) {
+      time = moment.utc(second * 1000).format('s秒')
+    }
+    return time
+  },
+
+  render() {
+    const { searchValues, teamList } = this.state
+    return (
+      <div className="user-content">
+        <div className="content-title">
+          <Tabs defaultActiveKey="1" onChange={this.callback} className="test">
+            <TabPane tab="搜索" key="1">
+              <div className="user-search" style={{ paddingBottom: 10 }}>
+                <Input
+                  placeholder="请输入姓名"
+                  style={{ width: "180px" }}
+                  value={searchValues["name"]
+                    ? searchValues["name"]
+                    : ""}
+                  onChange={e => {
+                    searchValues["name"] = e.target.value;
+                    this.setState({
+                      searchValues: searchValues,
+                    });
+                  }}
+                />
+                <TreeSelect
+                  style={{ width: 180 }}
+                  value={searchValues["teamId"]
+                    ? searchValues["teamId"]
+                    : undefined}
+                  dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
+                  treeData={teamList}
+                  placeholder="请选择团队"
+                  showSearch
+                  treeNodeFilterProp="title"
+                  onChange={(e) => {
+                    searchValues["teamId"] = e;
+                    this.setState({
+                      searchValues,
+                    });
+                  }}
+                />
+                <Select
+                  placeholder="有效次数"
+                  style={{ width: 180 }}
+                  value={searchValues["quantityType"]
+                    ? searchValues["quantityType"]
+                    : undefined}
+                  onChange={e => {
+                    searchValues["quantityType"] = e;
+                    this.setState({
+                      searchValues,
+                    });
+                  }}
+                >
+                  <Select.Option value={1}>10次以下</Select.Option>
+                  <Select.Option value={2}>10-20次</Select.Option>
+                  <Select.Option value={3}>20-50次</Select.Option>
+                  <Select.Option value={4}>50次以上</Select.Option>
+                </Select>
+                <RangePicker
+                  style={{ width: 300 }}
+                  value={[
+                    searchValues["startTime"] ? moment(searchValues["startTime"]) : null,
+                    searchValues["endTime"] ? moment(searchValues["endTime"]) : null,
+                  ]}
+                  onChange={(data, dataString) => {
+                    searchValues["startTime"] = dataString[0];
+                    searchValues["endTime"] = dataString[1];
+                    this.setState({
+                      searchValues,
+                    });
+                  }}
+                />
+                <Button
+                  type="primary"
+                  onClick={this.search}
+                  style={{ margin: "0 10px" }}
+                >搜索</Button>
+                <Button onClick={this.reset}>重置</Button>
+              </div>
+            </TabPane>
+            <TabPane tab="更改表格显示数据" key="2">
+              <div style={{ marginLeft: 10 }}>
+                <ChooseList
+                  columns={this.state.columns}
+                  changeFn={this.changeList}
+                  changeList={this.state.changeList}
+                  top={55}
+                  margin={11}
+                />
+              </div>
+            </TabPane>
+          </Tabs>
+          <div className="patent-table">
+            <Spin spinning={this.state.loading}>
+              <Table
+                bordered
+                columns={
+                  this.state.changeList
+                    ? this.state.changeList
+                    : this.state.columns
+                }
+                dataSource={this.state.dataSource}
+                pagination={this.state.pagination}
+              />
+            </Spin>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}));
+
+export default OutboundDetail;

+ 295 - 0
js/component/manageCenter/customer/outbound/index.jsx

@@ -0,0 +1,295 @@
+import React from 'react';
+import ajax from 'jquery/src/ajax/xhr.js';
+import $ from 'jquery/src/ajax';
+import moment from 'moment';
+import '@/manageCenter/financialManage/distribute/public.less';
+import { Button, Spin, DatePicker, Radio, message, Icon } from 'antd';
+import { getToday, ShowModal } from '@/tools';
+import ShowModalDiv from "@/showModal.jsx";
+import './index.less';
+
+const RadioButton = Radio.Button;
+const RadioGroup = Radio.Group;
+const { RangePicker } = DatePicker
+
+const Outbound = React.createClass({
+
+  getInitialState() {
+    return {
+      status: 1,
+      releaseDate: getToday(1),
+      dataList: [],
+      htmlMenus: [],
+    }
+  },
+
+  componentWillMount() {
+    this.loadData();
+    this.mainMenu();
+  },
+
+  mainMenu() {
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/selectNavList",
+      data: {},
+      success: function (data) {
+        if (!data.data) {
+          if (data.error && data.error.length) {
+            message.warning(data.error[0].message);
+            return;
+          }
+        }
+        let menu = data.data;
+        this.setState({
+          htmlMenus: menu,
+        });
+      }.bind(this),
+    }).always(
+      function (data) {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  loadData() {
+    const { releaseDate } = this.state
+    this.setState({
+      loading: true,
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/statistics/salesTeam",
+      data: {
+        startTime: releaseDate[0],
+        endTime: releaseDate[1],
+      },
+      success: function (data) {
+        ShowModal(this);
+        this.setState({
+          loading: false,
+        });
+        if (data.error && data.error.length === 0) {
+          this.setState({
+            dataList: data.data
+          })
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  clean() {
+    this.setState({
+      loading: true,
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/statistics/salesTeam/clean",
+      success: function (data) {
+        if (data.error && data.error.length === 0) {
+          ShowModal(this);
+          this.setState({
+            loading: false,
+          });
+          this.loadData();
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  search() {
+    this.loadData();
+  },
+
+  reset() {
+    this.state.releaseDate = []
+    this.loadData();
+  },
+
+  getNewUrl(url, cd) {
+    const { htmlMenus = [] } = this.state
+    let id = ''
+    htmlMenus.map(function (item) {
+      if (item.url == url) {
+        id = item.id;
+      }
+    });
+    return `${url}?rid=${id}#${cd}`
+  },
+
+  isTime(second) {
+    let time = "0秒"
+    if (second > 3600) {
+      time = moment.utc(second * 1000).format('h小时m分s秒')
+    } else if (second > 60) {
+      time = moment.utc(second * 1000).format('m分s秒')
+    } else if (second > 0) {
+      time = moment.utc(second * 1000).format('s秒')
+    }
+    return time
+  },
+
+  setParametersInCookies(params) {
+    for (let paramName in params) {
+      if (params.hasOwnProperty(paramName)) {
+        let paramValue = params[paramName];
+        let expires = "";
+        let now = new Date();
+        let date = new Date(now.getTime() + 5 * 1000);
+        expires = "; expires=" + date.toUTCString();
+        document.cookie = paramName + "=" + encodeURIComponent(paramValue) + expires + "; path=/";
+      }
+    }
+  },
+
+  onOpen(teamId) {
+    // const url = "outboundDetail"
+    // this.props.handlekey(url)
+    const { releaseDate } = this.state
+    const params = {
+      teamId,
+      startTime: releaseDate[0],
+      endTime: releaseDate[1]
+    };
+    this.setParametersInCookies(params)
+    const url = this.getNewUrl("/admin/customer.html", `outboundDetail`)
+    window.open(url, '_blank')
+  },
+
+  render() {
+    const { status, dataList } = this.state
+    return (
+      <div className="user-content">
+        <ShowModalDiv ShowModal={this.state.showModal} onClose={() => { this.setState({ showModal: false }) }} />
+        <div className="content-title" style={{ marginBottom: 10 }}>
+          <span style={{ fontWeight: 900, fontSize: 16 }}>外呼统计</span>
+        </div>
+        <div className="user-search">
+          <RadioGroup value={status}
+            onChange={e => {
+              this.setState({
+                status: e.target.value
+              })
+              if (e.target.value == 0) {
+                this.setState({
+                  releaseDate: []
+                })
+              } else {
+                this.setState({
+                  releaseDate: getToday(e.target.value)
+                }, () => {
+                  this.loadData()
+                })
+              }
+            }}
+          >
+            <RadioButton value={1}>今日</RadioButton>
+            <RadioButton value={2}>昨日</RadioButton>
+            <RadioButton value={3}>近7日</RadioButton>
+            <RadioButton value={4}>近15日</RadioButton>
+            <RadioButton value={5}>近30日</RadioButton>
+            <RadioButton value={0}>自定义</RadioButton>
+          </RadioGroup>
+          {
+            status == 0 &&
+            <span>
+              <RangePicker
+                style={{ width: 200, marginLeft: 15 }}
+                value={[
+                  this.state.releaseDate[0]
+                    ? moment(this.state.releaseDate[0])
+                    : null,
+                  this.state.releaseDate[1]
+                    ? moment(this.state.releaseDate[1])
+                    : null,
+                ]}
+                onChange={(data, dataString) => {
+                  this.setState({ releaseDate: dataString })
+                }}
+              />
+              <Button style={{ margin: "0 15px" }} type="primary" onClick={this.search}>搜索</Button>
+              <Button onClick={this.reset}>重置</Button>
+            </span>
+          }
+          <Button style={{ margin: "0 15px" }} type="primary" onClick={this.clean}>刷新</Button>
+        </div>
+        <div className="patent-table">
+          <Spin spinning={this.state.loading}>
+            <div className='plist'>
+              {
+                dataList.map(item =>
+                  <div className='plitems' style={{ background: ["", "#99FFCC", "#FFCC99", "#99CCFF"][item.lvl] }} key={item.id}>
+                    <div className='pleft'>
+                      <div className='round'><Icon type="phone" style={{ fontSize: 40, color: "#fff" }} /></div>
+                      <div>{item.name}</div>
+                      <div>({["", "一级", "二级", "三级"][item.lvl]})</div>
+                    </div>
+                    <div>
+                      <div>
+                        <span>• 团队人数:</span>
+                        <a onClick={this.onOpen.bind(this,item.id)}>
+                          <span style={{ textDecoration: "underline", color: "#0000FF" }}>{item.teamPeopleSum}</span>
+                        </a>
+                      </div>
+                      <div>
+                        <span>• 拨出次数:</span>
+                        <a onClick={this.onOpen.bind(this,item.id)}>
+                          <span style={{ textDecoration: "underline", color: "#0000FF" }}>{item.teamCallSum}</span>
+                        </a>
+                      </div>
+                      <div>
+                        <span>• 接通次数:</span>
+                        <a onClick={this.onOpen.bind(this,item.id)}>
+                          <span style={{ textDecoration: "underline", color: "#0000FF" }}>{item.teamConnectSum}</span>
+                        </a>
+                      </div>
+                      <div>
+                        <span>• 有效次数:</span>
+                        <a onClick={this.onOpen.bind(this,item.id)}>
+                          <span style={{ textDecoration: "underline", color: "#0000FF" }}>{item.teamValidSum}</span>
+                        </a>
+                      </div>
+                      <div>
+                        <span>• 时长:</span>
+                        <a onClick={this.onOpen.bind(this,item.id)}>
+                          <span style={{ textDecoration: "underline", color: "#0000FF" }}>{this.isTime(item.teamCallDurationSum)}</span>
+                        </a>
+                      </div>
+                    </div>
+                  </div>
+                )
+              }
+
+            </div>
+          </Spin>
+        </div>
+      </div>
+    );
+  },
+});
+
+export default Outbound;

+ 57 - 0
js/component/manageCenter/customer/outbound/index.less

@@ -0,0 +1,57 @@
+.patent-table {
+  display: flex;
+  flex-direction: column;
+
+  .plist {
+    display: flex;
+    flex-direction: row;
+    flex-wrap: wrap;
+
+    .plitems {
+      width: 23%;
+      margin: 15px 1%;
+      border-radius: 20px;
+      padding: 25px;
+      font-size: 16px;
+      display: flex;
+      flex-direction: row;
+      position: relative;
+
+      .pleft {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding-right: 25px;
+
+        .round {
+          width: 60px;
+          height: 60px;
+          background: green;
+          border-radius: 50%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          margin-bottom: 25px;
+
+        }
+
+      }
+
+      .refresh {
+        position: absolute;
+        right: 25px;
+        top: 25px;
+        background: green;
+        color: #fff;
+        padding: 8px 10px;
+        border-radius: 8px;
+        cursor: pointer;
+
+      }
+
+    }
+
+  }
+
+}

+ 2 - 2
js/component/manageCenter/index/content.jsx

@@ -731,10 +731,10 @@ const Content = React.createClass({
         });
         break;
       case "contacts":
-        let Module = require('./contacts/index').default;
+        let Contacts = require('./contacts/index').default;
         require.ensure([], () => {
           this.setState({
-            component: <Module />,
+            component: <Contacts />,
           });
         });
         break;

+ 47 - 2
js/component/manageCenter/index/statistics/index.less

@@ -19,7 +19,7 @@
         .plisum {
           color: #0000FF;
           text-decoration: underline;
-          
+
         }
 
       }
@@ -40,13 +40,58 @@
         }
       }
 
-      .list{
+      .list {
         font-size: 16px;
         margin-top: 15px;
       }
 
     }
 
+    .plitems {
+      width: 23%;
+      margin: 15px 1%;
+      border-radius: 20px;
+      padding: 25px;
+      font-size: 16px;
+      display: flex;
+      flex-direction: row;
+      position: relative;
+
+      .pleft{
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        padding-right: 25px;
+
+        .round{
+          width: 60px;
+          height: 60px;
+          background: green;
+          border-radius: 50%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          margin-bottom: 25px;
+
+        }
+
+      }
+
+      .refresh{
+        position: absolute;
+        right: 25px;
+        top: 25px;
+        background: green;
+        color: #fff;
+        padding: 8px 10px;
+        border-radius: 8px;
+        cursor: pointer;
+
+      }
+
+    }
+
   }
 
 }

+ 110 - 28
js/component/manageCenter/index/statistics/yxy.jsx

@@ -3,7 +3,7 @@ import ajax from 'jquery/src/ajax/xhr.js';
 import $ from 'jquery/src/ajax';
 import moment from 'moment';
 import '@/manageCenter/financialManage/distribute/public.less';
-import { Button, Spin, DatePicker, Radio, message } from 'antd';
+import { Button, Spin, DatePicker, Radio, message, Icon } from 'antd';
 import { getToday, ShowModal } from '@/tools';
 import ShowModalDiv from "@/showModal.jsx";
 import './index.less';
@@ -127,6 +127,35 @@ const Statistics = React.createClass({
     );
   },
 
+  clean() {
+    this.setState({
+      loading: true,
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/statistics/salesTeam/clean",
+      success: function (data) {
+        if (data.error && data.error.length === 0) {
+          ShowModal(this);
+          this.setState({
+            loading: false,
+          });
+          this.loadData();
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
   search() {
     this.loadData();
   },
@@ -147,24 +176,55 @@ const Statistics = React.createClass({
     return `${url}?rid=${id}#${cd}`
   },
 
+  isTime(second) {
+    let time = "0秒"
+    if (second > 3600) {
+      time = moment.utc(second * 1000).format('h小时m分s秒')
+    } else if (second > 60) {
+      time = moment.utc(second * 1000).format('m分s秒')
+    } else if (second > 0) {
+      time = moment.utc(second * 1000).format('s秒')
+    }
+    return time
+  },
+
   render() {
     const { status, info, data } = this.state
     const list = [
-      { color: "#99FFFF", title: "全部签单客户数:", sum: info.signSum, tit: "签单客户数", number: info.rangeSignSum, url: this.getNewUrl("/admin/customer.html", "companySign") },
-      { color: "#FFFFCC", title: "全部私有客户数:", sum: info.privateSum, tit: "私有客户数", number: info.rangePrivateSum, url: this.getNewUrl("/admin/customer.html", "companyIntention") },
-      { color: "#FFCCCC", title: "全部渠道数:", sum: info.channelSum, tit: "私有渠道数", number: info.rangeChannelSum, url: this.getNewUrl("/admin/channelList.html", "channelunit") },
-      { color: "#99CCFF", title: "全部公出数:", sum: info.publicReleaseSum, tit: "公出企业数", number: info.rangePublicReleaseSum, url: "" },
-      { color: "#99FFCC", title: "全部跟进客户数:", sum: info.followSum, tit: "跟进客户数", number: info.rangeFollowSum, url: this.getNewUrl("/admin/customer.html", "followUpSummaryOrdinary") },
-      { color: "#CC99CC", title: "全部订单数:", sum: info.orderSum, tit: "订单数", number: info.rangeOrderSum, url: this.getNewUrl("/admin/order.html", "billing") },
-      { color: "#99CCCC", title: "全部应收款:", sum: info.receivables, tit: "应收款", number: info.rangeReceivables, url: this.getNewUrl("/admin/order.html", "press") },
+      { type: 0, color: "#99FFFF", title: "全部签单客户数:", sum: info.signSum, tit: "签单客户数", number: info.rangeSignSum, url: this.getNewUrl("/admin/customer.html", "companySign") },
+      { type: 0, color: "#FFFFCC", title: "全部私有客户数:", sum: info.privateSum, tit: "私有客户数", number: info.rangePrivateSum, url: this.getNewUrl("/admin/customer.html", "companyIntention") },
+      { type: 0, color: "#FFCCCC", title: "全部渠道数:", sum: info.channelSum, tit: "私有渠道数", number: info.rangeChannelSum, url: this.getNewUrl("/admin/channelList.html", "channelunit") },
+      { type: 0, color: "#99CCFF", title: "全部公出数:", sum: info.publicReleaseSum, tit: "公出企业数", number: info.rangePublicReleaseSum, url: "" },
+      { type: 0, color: "#99FFCC", title: "全部跟进客户数:", sum: info.followSum, tit: "跟进客户数", number: info.rangeFollowSum, url: this.getNewUrl("/admin/customer.html", "followUpSummaryOrdinary") },
+      { type: 0, color: "#CC99CC", title: "全部订单数:", sum: info.orderSum, tit: "订单数", number: info.rangeOrderSum, url: this.getNewUrl("/admin/order.html", "billing") },
+      { type: 0, color: "#99CCCC", title: "全部应收款:", sum: info.receivables, tit: "应收款", number: info.rangeReceivables, url: this.getNewUrl("/admin/order.html", "press") },
       {
-        color: "#FFCC99", title: "待紧急处理事项",
+        type: 0, color: "#FFCC99", title: "待紧急处理事项",
         list: [
           { key: "被驳回订单:", value: info.rejectSum, url: this.getNewUrl("/admin/order.html", "reject") },
           { key: "待变更订单:", value: info.changeSum, url: this.getNewUrl("/admin/order.html", "contractChangeYxy") },
           { key: "待核对专利:", value: info.projectCheckSum, url: this.getNewUrl("/admin/project.html", "businessManagement") },
           { key: "暂停项目:", value: info.projectStopSum, url: this.getNewUrl("/admin/order.html", "mysuspend") },]
       },
+      {
+        type: 1, color: "#FFCC99", title: "本人",
+        list: [
+          { key: "• 拨出次数:", value: info.callSum, url: "" },
+          { key: "• 接通次数:", value: info.connectSum, url: "" },
+          { key: "• 有效次数:", value: info.validSum, url: "" },
+          { key: "• 时长:", value: this.isTime(info.callDurationSum), url: "" },
+        ]
+      },
+      {
+        type: 1, color: "#FFCC99", title: "本团队",
+        list: [
+          { key: "• 团队人数:", value: info.teamPeopleSum, url: "" },
+          { key: "• 拨出次数:", value: info.teamCallSum, url: "" },
+          { key: "• 接通次数:", value: info.teamConnectSum, url: "" },
+          { key: "• 有效次数:", value: info.teamValidSum, url: "" },
+          { key: "• 时长:", value: this.isTime(info.teamCallDurationSum), url: "" },
+        ]
+      }
     ]
     const option = {
       title: {
@@ -290,37 +350,59 @@ const Statistics = React.createClass({
           <Spin spinning={this.state.loading}>
             <div className='plist'>
               {
-                list.map((item, index) =>
-                  <div className='plitem' style={{ background: item.color }} key={index}>
-                    <div className='plititle'>
-                      <span style={{ fontWeight: item.title == "待紧急处理事项" && "bold" }}>{item.title}</span>
-                      {/* <span className='plisum'>{item.sum}</span> */}
-                      <a href={globalConfig.context + item.url}>
-                        <span className='plisum'>{item.sum}</span>
-                      </a>
-                    </div>
-                    {
-                      item.title == "待紧急处理事项"
-                        ? <div className='list'>
+                list.map((item, index) => {
+                  return item.type == 0
+                    ? <div className='plitem' style={{ background: item.color }} key={index}>
+                      <div className='plititle'>
+                        <span style={{ fontWeight: item.title == "待紧急处理事项" && "bold" }}>{item.title}</span>
+                        <a href={globalConfig.context + item.url}>
+                          <span className='plisum'>{item.sum}</span>
+                        </a>
+                      </div>
+                      {
+                        item.title == "待紧急处理事项"
+                          ? <div className='list'>
+                            {
+                              item.list.map((t, i) =>
+                                <div key={i}>
+                                  <span>{t.key}</span>
+                                  <a href={globalConfig.context + t.url}>
+                                    <span style={{ textDecoration: "underline", color: "#0000FF" }}>{t.value}</span>
+                                  </a>
+                                </div>
+                              )
+                            }
+                          </div>
+                          : <div className='count'>
+                            <a href={globalConfig.context + item.url}><div className='plinum'>{item.number}</div></a>
+                            <div className='plitit'>{item.tit}</div>
+                          </div>
+                      }
+                    </div> :
+                    (item.type == 1 && item.list[0].value !== null)
+                      ? <div className='plitems' style={{ background: item.color }} key={index}>
+                        <div className='pleft'>
+                          <div className='round'><Icon type="phone" style={{ fontSize: 40, color: "#fff" }} /></div>
+                          <div>{item.title}</div>
+                        </div>
+                        <div>
                           {
                             item.list.map((t, i) =>
                               <div key={i}>
                                 <span>{t.key}</span>
-                                <a href={globalConfig.context + t.url}>
+                                <a href="">
                                   <span style={{ textDecoration: "underline", color: "#0000FF" }}>{t.value}</span>
                                 </a>
                               </div>
                             )
                           }
                         </div>
-                        : <div className='count'>
-                          <a href={globalConfig.context + item.url}><div className='plinum'>{item.number}</div></a>
-                          <div className='plitit'>{item.tit}</div>
-                        </div>
-                    }
-                  </div>
+                        {/* <div className='refresh' onClick={this.clean}>刷新</div> */}
+                      </div> : null
+                }
                 )
               }
+
             </div>
           </Spin>
           <ReactEcharts option={option} echarts={echarts} />

+ 2 - 1
js/component/manageCenter/order/orderNew/addService.jsx

@@ -6981,7 +6981,7 @@ const NewService = Form.create()(
                                         sign="content"
                                         deleteApi="/api/admin/order/deleteOrderImg"
                                       />
-                                      <p> <span style={{ color: "red", display: "inline-block" }}>(请将合同中的服务内容,截图上传!含服务年限,时间节点等;)</span>图片建议:要清晰。</p>
+
                                     </div> :
                                     this.state.contentUrl.length > 0 ?
                                       <div>
@@ -6991,6 +6991,7 @@ const NewService = Form.create()(
                                           ItemWidth={"96px"}
                                         />
                                       </div> : "暂无附件!"}
+                                  <p> <span style={{ color: "red", display: "inline-block" }}>(注:必需上传服务内容、服务年限、时间节点、乙方权利与责任、违约条款、保密条款!)</span>图片建议:要清晰。</p>
                                 </div>
                               </FormItem>
                             </div>

+ 44 - 0
js/component/manageCenter/order/orderNew/billing.jsx

@@ -772,6 +772,28 @@ const MyService = Form.create()(
                   ) : (
                     ""
                   )}
+                  {record.status == 3 &&
+                    <Popconfirm
+                      title="您确定要取消开票吗?"
+                      onConfirm={() => {
+                        this.cancel(record);
+                      }}
+                      okText="确定"
+                      cancelText="取消"
+                    >
+                      <Button
+                        type="danger"
+                        style={{
+                          marginLeft: "10px",
+                        }}
+                        onClick={(e) => {
+                          e.stopPropagation();
+                        }}
+                      >
+                        取消开票
+                      </Button>
+                    </Popconfirm>
+                  }
                   <LogPopup id={record.id} />
                 </div>
               );
@@ -1207,6 +1229,28 @@ const MyService = Form.create()(
       );
     },
 
+    cancel(record) {
+      $.ajax({
+        method: "POST",
+        dataType: "json",
+        crossDomain: false,
+        url: globalConfig.context + "/api/admin/orderInvoice/delete",
+        data: {
+          id: record.id
+        }
+      }).done(function (data) {
+        this.setState({
+          loading: false
+        });
+        if (!data.error.length) {
+          message.success('操作成功!');
+          this.inRecordData();
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this));
+    },
+
     submitApp() {
       if (this.state.status === 3) {
         this.setState({

+ 1 - 1
js/component/manageCenter/order/orderNew/contentUrl.jsx

@@ -82,7 +82,6 @@ class contentUrl extends Component {
                   url="/api/admin/order/uploadOrderImg"
                   sign=""
                 />
-                <p><span style={{ color: "red", display: "inline-block" }}>(请将合同中的服务内容,截图上传!含服务年限,时间节点等;)</span>图片建议:要清晰。</p>
               </div> :
               !!contentUrl && contentUrl.length > 0 ?
                 <div>
@@ -93,6 +92,7 @@ class contentUrl extends Component {
                   />
                 </div>
                 : ""}
+            <p> <span style={{ color: "red", display: "inline-block" }}>(注:必需上传服务内容、服务年限、时间节点、乙方权利与责任、违约条款、保密条款!)</span>图片建议:要清晰。</p>
           </div>
         </FormItem>
       </div>

+ 1 - 0
js/component/manageCenter/order/orderNew/inquiry.jsx

@@ -4719,6 +4719,7 @@ const IntentionCustomer = Form.create()(
                                 sign="content"
                                 deleteApi="/api/admin/order/deleteOrderImg"
                               />
+                              <p> <span style={{ color: "red", display: "inline-block" }}>(注:必需上传服务内容、服务年限、时间节点、乙方权利与责任、违约条款、保密条款!)</span>图片建议:要清晰。</p>
                             </FormItem>
                           </div>
                           : <ContentUrl

+ 1 - 1
js/component/manageCenter/order/orderNew/reject.jsx

@@ -2704,7 +2704,7 @@ const IntentionCustomer = Form.create()(
                           sign="content"
                           deleteApi="/api/admin/order/deleteOrderImg"
                         />
-                        <p><span style={{ color: "red", display: "inline-block" }}>(请将合同中的服务内容,截图上传!含服务年限,时间节点等;)</span>图片建议:要清晰。</p>
+                        <p> <span style={{ color: "red", display: "inline-block" }}>(注:必需上传服务内容、服务年限、时间节点、乙方权利与责任、违约条款、保密条款!)</span>图片建议:要清晰。</p>
                       </FormItem>
 
                       <Property

+ 8 - 0
js/component/manageCenter/set/content.jsx

@@ -120,6 +120,14 @@ class Content extends Component {
           });
         });
         break;
+      case 'team':
+        require.ensure([], () => {
+          const Team = require('./userManagementS/team').default;
+          this.setState({
+            component: <Team />
+          });
+        });
+        break;
       case 'bar':
         require.ensure([], () => {
           const Bar = require('./amoeba/barList').default;

+ 54 - 14
js/component/manageCenter/set/userManagementS/newUser.jsx

@@ -163,6 +163,7 @@ const Newuser = Form.create()(React.createClass({
           expenseSuperExamine: this.state.expenseSuperExamine, // 报销是否需要上级审核
           publicCarbonCopy: this.state.publicCarbonCopy,// 公出抄送
           callNo: this.state.callNo, // 外呼编号
+          teamId: this.state.teamId, // 团队
         }),
         publicReviewerIds: getNewArray(this.state.Business, "reviewerId").toString(),// 公出审核
         assistReviewerIds: getNewArray(this.state.Coorder, "reviewerId").toString(),// 协单审核
@@ -287,7 +288,8 @@ const Newuser = Form.create()(React.createClass({
             expenseSuperExamine: thisdata.expenseSuperExamine, // 报销是否需要上级主管审核
             publicCarbonCopy: thisdata.publicCarbonCopy, // 公出抄送
             publicCarbonCopyName: thisdata.publicCarbonCopyName,
-            callNo:thisdata.callNo, // 外呼编号
+            callNo: thisdata.callNo, // 外呼编号
+            teamId: thisdata.teamId, // 团队
           });
         }.bind(this),
       }).always(function () {
@@ -817,7 +819,7 @@ const Newuser = Form.create()(React.createClass({
                     label="地区" >
                     <Select
                       multiple
-                      style={{ width: '580px' }}
+                      style={{ width: '685px' }}
                       placeholder="选择地区"
                       filterOption={(input, option) => { return option.props.children.indexOf(input) >= 0 }}
                       value={this.state.district}
@@ -836,18 +838,6 @@ const Newuser = Form.create()(React.createClass({
                   <FormItem
                     className="half-item"
                     {...formItemLayout}
-                    label="用户头像"
-                  >
-                    <PicturesWall
-                      domId={'newUser1'}
-                      pictureSign="customer_sys_file"
-                      fileList={this.getOrgCodeUrl}
-                      pictureUrl={this.state.orgCodeUrl} />
-                    <p>图片建议:要清晰。</p>
-                  </FormItem>
-                  <FormItem
-                    className="half-item"
-                    {...formItemLayout}
                     label="分巴"
                   >
                     <TreeSelect
@@ -865,6 +855,56 @@ const Newuser = Form.create()(React.createClass({
                       }}
                     />
                   </FormItem>
+                  <FormItem
+                    className="half-item"
+                    {...formItemLayout}
+                    label="团队"
+                  >
+                    <TreeSelect
+                      style={{ width: 200 }}
+                      value={this.state.teamId}
+                      dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
+                      treeData={this.props.teamList}
+                      placeholder="请选择团队"
+                      showSearch
+                      treeNodeFilterProp="title"
+                      onChange={(e) => {
+                        this.setState({
+                          teamId: e,
+                        });
+                      }}
+                    />
+                    {/* <Select
+                      placeholder="上级团队"
+                      style={{ width: 200 }}
+                      value={this.state.teamId}
+                      onChange={e => {
+                        this.setState({
+                          teamId: e,
+                        });
+                      }}
+                    >
+                      {this.props.teamList.map(function (item) {
+                        return (
+                          <Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>
+                        );
+                      })}
+                    </Select> */}
+                  </FormItem>
+                </div>
+                <div className="clearfix">
+                  <FormItem
+                    className="half-item"
+                    {...formItemLayout}
+                    label="用户头像"
+                  >
+                    <PicturesWall
+                      domId={'newUser1'}
+                      pictureSign="customer_sys_file"
+                      fileList={this.getOrgCodeUrl}
+                      pictureUrl={this.state.orgCodeUrl} />
+                    <p>图片建议:要清晰。</p>
+                  </FormItem>
                 </div>
               </div>
               <FormItem wrapperCol={{ span: 12, offset: 4 }}>

+ 672 - 0
js/component/manageCenter/set/userManagementS/team.jsx

@@ -0,0 +1,672 @@
+import React from 'react';
+import ReactDom from 'react-dom';
+import ajax from 'jquery/src/ajax/xhr.js';
+import $ from 'jquery/src/ajax';
+import {
+  Form, Icon, Button, Input, Select, AutoComplete, Spin, Table,
+  message, DatePicker, Modal, TreeSelect, Popconfirm, Tabs
+} from 'antd';
+import Newuser from "./newUser.jsx"
+import { ShowModal } from "@/tools";
+import { ChooseList } from "../../order/orderNew/chooseList";
+
+const { TabPane } = Tabs
+const Team = Form.create()(React.createClass({
+  getInitialState() {
+    return {
+      info: {},
+      searchValues: {}, // 列表筛选条件
+      loading: false, //加载动画
+      changeList: undefined, // 更改后的表格显示数据
+      departmentArr: [], // 部门
+      dataSource: [], // 列表数据
+      teamList: [], // 上级
+      fjlist: [],
+      pagination: {
+        defaultCurrent: 1,
+        defaultPageSize: 10,
+        showQuickJumper: true,
+        pageSize: 10,
+        onChange: function (page) {
+          this.loadData(page);
+        }.bind(this),
+        showTotal: function (total) {
+          return '共' + total + '条数据';
+        }
+      },
+      columns: [
+        {
+          title: '团队名称',
+          dataIndex: 'name',
+          key: 'name',
+        },
+        {
+          title: '队长',
+          dataIndex: 'adminName',
+          key: 'adminName',
+        },
+        {
+          title: '等级',
+          dataIndex: 'lvl',
+          key: 'lvl',
+          render: (text, record) => {
+            return (
+              <div>
+                {["", "一级", "二级", "三级"][text]}
+              </div>
+            )
+          }
+        },
+        {
+          title: '部门',
+          dataIndex: 'depName',
+          key: 'depName',
+        },
+        {
+          title: '上级团队',
+          dataIndex: 'superName',
+          key: 'superName',
+        },
+        {
+          title: '状态',
+          dataIndex: 'status',
+          key: 'status',
+          render: (text, record) => {
+            return (
+              <div>
+                {["正常", "解散"][text]}
+              </div>
+            )
+          }
+        },
+
+      ],
+      visible: "",
+    };
+  },
+
+  componentWillMount() {
+    this.loadData();
+    this.departmentList();
+  },
+
+  // 列表接口
+  loadData(pageNo) {
+    const { searchValues, pagination } = this.state;
+    this.setState({
+      loading: true,
+    });
+    let datas = Object.assign(searchValues, {
+      pageNo: pageNo || 1,
+      pageSize: pagination.pageSize,
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/salesTeam/pageList",
+      data: datas,
+      success: function (data) {
+        ShowModal(this);
+        this.setState({
+          loading: false,
+        });
+        let theArr = [];
+        if (data.error && data.error.length === 0) {
+          if (data.data) {
+            pagination.current = data.data.pageNo;
+            pagination.total = data.data.totalCount;
+            if (data.data && data.data.list && !data.data.list.length) {
+              pagination.current = 0
+              pagination.total = 0
+            };
+            this.setState({
+              dataSource: data.data.list,
+              pagination: this.state.pagination,
+              pageNo: data.data.pageNo,
+            });
+          }
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  // 部门
+  departmentList() {
+    this.setState({
+      loading: true
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/organization/selectSuperId",
+      data: {
+
+      },
+      success: function (data) {
+        let thedata = data.data;
+        let theArr = [];
+        if (!thedata) {
+          if (data.error && data.error.length) {
+            message.warning(data.error[0].message);
+          };
+          thedata = {};
+        } else {
+          thedata.map(function (item, index) {
+            theArr.push({
+              key: index,
+              name: item.name,
+              id: item.id,
+              depNo: item.depNo
+            })
+          })
+        }
+        this.setState({
+          departmentArr: theArr,
+        })
+      }.bind(this),
+    }).always(function () {
+      this.setState({
+        loading: false
+      });
+    }.bind(this));
+  },
+
+  // 团队
+  salesTeam(lvl) {
+    this.setState({
+      loading: true
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/salesTeam/list",
+      data: {
+        lvl: lvl - 1
+      },
+      success: function (data) {
+        let thedata = data.data;
+        let theArr = [];
+        if (!thedata) {
+          if (data.error && data.error.length) {
+            message.warning(data.error[0].message);
+          };
+          thedata = {};
+        } else {
+          thedata.map(function (item, index) {
+            theArr.push({
+              name: item.name,
+              id: item.id,
+            })
+          })
+        }
+        this.setState({
+          teamList: theArr,
+        })
+      }.bind(this),
+    }).always(function () {
+      this.setState({
+        loading: false
+      });
+    }.bind(this));
+  },
+
+  followUp(e) {
+    const { info } = this.state;
+    this.setState({
+      info: Object.assign(info, {
+        adminName: e,
+      }),
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/customer/listAdminByName",
+      data: {
+        adminName: e,
+      },
+      success: function (data) {
+        let thedata = data.data;
+        if (!thedata) {
+          if (data.error && data.error.length) {
+            message.warning(data.error[0].message);
+          }
+          thedata = {};
+        }
+        this.setState({
+          fjlist: thedata,
+        });
+      }.bind(this),
+    }).always(
+      function () {
+        this.setState({
+          loading: false,
+        });
+      }.bind(this)
+    );
+  },
+
+  selectF(value) {
+    const { info, fjlist } = this.state;
+    const newdataSources = JSON.stringify(fjlist) == "{}" ? [] : fjlist;
+    info["aid"] = newdataSources.find((item) => item.name == value).id;
+    this.setState({
+      info
+    });
+  },
+
+  tableRowClick(record, index) {
+    this.salesTeam(record.lvl)
+    this.setState({
+      visible: "edit",
+      info: record,
+    })
+  },
+
+  search() {
+    this.loadData();
+  },
+
+  reset() {
+    this.setState({
+      searchValues: {}
+    }, () => {
+      this.loadData();
+    })
+  },
+
+  changeList(arr) {
+    const newArr = [];
+    this.state.columns.forEach(item => {
+      arr.forEach(val => {
+        if (val === item.title) {
+          newArr.push(item);
+        }
+      });
+    });
+    this.setState({
+      changeList: newArr
+    });
+  },
+
+  // 保存
+  handleOk() {
+    const { info } = this.state
+    if (!info.name) {
+      message.warn("团队名称不能为空!")
+      return
+    }
+    if (!info.adminName) {
+      message.warn("队长姓名不能为空!")
+      return
+    }
+    if (!info.lvl) {
+      message.warn("请选择等级!")
+      return
+    }
+    if (!info.depId) {
+      message.warn("请选择部门!")
+      return
+    }
+    // if (!info.superId) {
+    //   message.warn("请选择上级团队!")
+    //   return
+    // }
+    if (!info.status && info.status != 0) {
+      message.warn("请选择状态!")
+      return
+    }
+    let obj = {
+      id: info.id,
+      name: info.name,
+      aid: info.aid,
+      lvl: info.lvl,
+      depId: info.depId,
+      superId: info.superId,
+      status: info.status,
+    }
+    this.setState({
+      loading: true
+    });
+    $.ajax({
+      method: "POST",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + (!info.id ? "/api/admin/salesTeam/add" : "/api/admin/salesTeam/update"),
+      data: obj
+    }).done(function (data) {
+      this.setState({
+        loading: false
+      });
+      if (!data.error.length) {
+        message.success('保存成功!');
+        this.handleCancel();
+        this.loadData();
+      } else {
+        message.warning(data.error[0].message);
+      }
+    }.bind(this));
+  },
+
+  handleCancel() {
+    this.setState({
+      visible: "",
+      info: {},
+    })
+  },
+
+  render() {
+    const { searchValues, departmentArr, teamList, info } = this.state
+    const FormItem = Form.Item
+    const formItemLayout = {
+      labelCol: { span: 8 },
+      wrapperCol: { span: 14 },
+    };
+    const newdataSources = this.state.fjlist || [];
+    const newoptions = newdataSources.map((group) => (
+      <Select.Option key={group.id} value={group.name}>
+        {group.name}
+      </Select.Option>
+    ));
+    return (
+      <div className="user-content">
+        <div className="content-title">
+          <Tabs defaultActiveKey="1" onChange={this.callback} className="test">
+            <TabPane tab="搜索" key="1">
+              <div className="user-search" style={{ paddingBottom: 10 }}>
+                <Input
+                  placeholder="用户姓名"
+                  style={{ width: "180px" }}
+                  value={searchValues["userName"]
+                    ? searchValues["userName"]
+                    : ""}
+                  onChange={e => {
+                    searchValues["userName"] = e.target.value;
+                    this.setState({
+                      searchValues: searchValues,
+                    });
+                  }}
+                />
+                <Select
+                  placeholder="部门"
+                  style={{ width: 180 }}
+                  value={searchValues["depId"]
+                    ? searchValues["depId"]
+                    : undefined}
+                  onChange={e => {
+                    searchValues["depId"] = e;
+                    this.setState({
+                      searchValues,
+                    });
+                  }}
+                >
+                  {departmentArr.map(function (item) {
+                    return (
+                      <Select.Option key={item.id}>{item.name}</Select.Option>
+                    );
+                  })}
+                </Select>
+                <Select
+                  placeholder="状态"
+                  style={{ width: 180 }}
+                  value={searchValues["status"]
+                    ? searchValues["status"]
+                    : undefined}
+                  onChange={e => {
+                    searchValues["status"] = e;
+                    this.setState({
+                      searchValues,
+                    });
+                  }}
+                >
+                  <Select.Option value="0">正常</Select.Option>
+                  <Select.Option value="1">解散</Select.Option>
+                </Select>
+                <Button
+                  type="primary"
+                  onClick={this.search}
+                  style={{ margin: "0 10px" }}
+                >搜索</Button>
+                <Button onClick={this.reset}>重置</Button>
+                <Button
+                  type="primary"
+                  style={{
+                    marginBottom: '15px',
+                    position: "absolute",
+                    right: 0,
+                  }}
+                  onClick={() => {
+                    this.setState({
+                      visible: "add"
+                    })
+                  }}
+                >
+                  新增团队
+                </Button>
+              </div>
+            </TabPane>
+            <TabPane tab="更改表格显示数据" key="2">
+              <div style={{ marginLeft: 10 }}>
+                <ChooseList
+                  columns={this.state.columns}
+                  changeFn={this.changeList}
+                  changeList={this.state.changeList}
+                  top={55}
+                  margin={11}
+                />
+              </div>
+            </TabPane>
+          </Tabs>
+          <div className="patent-table">
+            <Spin spinning={this.state.loading}>
+              <Table
+                bordered
+                columns={
+                  this.state.changeList
+                    ? this.state.changeList
+                    : this.state.columns
+                }
+                style={{
+                  cursor: 'pointer',
+                }}
+                dataSource={this.state.dataSource}
+                pagination={this.state.pagination}
+                onRowDoubleClick={this.tableRowClick}
+              />
+            </Spin>
+          </div>
+
+          <Modal
+            title={this.state.visible == "add"
+              ? "新建团队" : this.state.visible == "edit"
+                ? "编辑团队" : "????"}
+            width={610}
+            visible={this.state.visible != ""}
+            footer={null}
+            onCancel={this.handleCancel}
+          >
+            <Form
+              layout="horizontal"
+            >
+              <Spin spinning={this.state.loading}>
+                <div className="clearfix">
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="团队名称"
+                  >
+                    <Input
+                      placeholder="团队名称"
+                      value={info["name"] ? info["name"] : undefined}
+                      style={{ width: "230px" }}
+                      onChange={(e) => {
+                        info["name"] = e.target.value;
+                        this.setState({ info });
+                      }}
+                      required="required"
+                    />
+                  </FormItem>
+
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="队长"
+                  >
+                    <AutoComplete
+                      className="certain-category-search"
+                      dropdownClassName="certain-category-search-dropdown"
+                      dropdownMatchSelectWidth={false}
+                      style={{ width: "230px" }}
+                      dataSource={newoptions}
+                      placeholder="队长姓名"
+                      value={info["adminName"] || undefined}
+                      onChange={this.followUp.bind(this)}
+                      filterOption={true}
+                      onSelect={this.selectF.bind(this)}
+                    >
+                      <Input />
+                    </AutoComplete>
+                  </FormItem>
+
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="等级"
+                  >
+                    <Select
+                      placeholder="选择等级"
+                      style={{ width: "230px" }}
+                      value={info["lvl"] ? info["lvl"] : undefined}
+                      onChange={(e) => {
+                        info["lvl"] = e;
+                        info["superId"] = null;
+                        this.setState({ info });
+                        this.salesTeam(e)
+                      }}
+                    >
+                      {[
+                        { key: "一级", value: 1 },
+                        { key: "二级", value: 2 },
+                        { key: "三级", value: 3 }].map(function (item) {
+                          return (
+                            <Select.Option key={item.value} value={item.value}>
+                              {item.key}
+                            </Select.Option>
+                          );
+                        })}
+                    </Select>
+                  </FormItem>
+
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="所属部门"
+                  >
+                    <Select
+                      placeholder="部门"
+                      style={{ width: 230 }}
+                      value={info["depId"]
+                        ? info["depId"]
+                        : undefined}
+                      onChange={e => {
+                        info["depId"] = e;
+                        this.setState({
+                          info,
+                        });
+                      }}
+                    >
+                      {departmentArr.map(function (item) {
+                        return (
+                          <Select.Option key={item.id}>{item.name}</Select.Option>
+                        );
+                      })}
+                    </Select>
+                  </FormItem>
+
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="上级团队"
+                  >
+                    <Select
+                      placeholder="上级团队"
+                      style={{ width: 230 }}
+                      value={info["superId"]
+                        ? info["superId"]
+                        : undefined}
+                      onChange={e => {
+                        info["superId"] = e;
+                        this.setState({
+                          info,
+                        });
+                      }}
+                    >
+                      {teamList.map(function (item) {
+                        return (
+                          <Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>
+                        );
+                      })}
+                    </Select>
+                  </FormItem>
+
+                  <FormItem
+                    className="half-middle"
+                    {...formItemLayout}
+                    label="状态"
+                  >
+                    <Select
+                      placeholder="选择状态"
+                      style={{ width: "230px" }}
+                      value={info["status"]}
+                      onChange={(e) => {
+                        info["status"] = e;
+                        this.setState({
+                          info,
+                        });
+                      }}
+                    >
+                      <Select.Option value={0}>正常</Select.Option>
+                      <Select.Option value={1}>解散</Select.Option>
+                    </Select>
+                  </FormItem>
+                </div>
+
+                <FormItem className="half-middle">
+                  <Button
+                    className="set-submit"
+                    type="primary"
+                    style={{ marginLeft: "150px" }}
+                    onClick={this.handleOk}
+                  >
+                    保存
+                  </Button>
+                  <Button
+                    className="set-submit"
+                    type="ghost"
+                    onClick={this.handleCancel}
+                  >
+                    取消
+                  </Button>
+                </FormItem>
+              </Spin>
+            </Form>
+          </Modal>
+
+        </div>
+      </div>
+    );
+  }
+}));
+
+export default Team;

+ 79 - 17
js/component/manageCenter/set/userManagementS/user.jsx

@@ -44,6 +44,7 @@ const User = Form.create()(React.createClass({
         ancestors: this.state.amb == 2 ? this.state.ambId : undefined,
         seniorStaff: this.state.seniorStaff,
         publicPurview: this.state.publicPurview,
+        teamId: this.state.teamId,
       },
       success: function (data) {
         let theArr = [];
@@ -79,6 +80,7 @@ const User = Form.create()(React.createClass({
               ancestorsNames: thisdata.ancestorsNames, //分巴
               ambName: thisdata.ambName,
               ambRole: thisdata.ambRole,
+              teamName: thisdata.teamName,
             });
           };
           this.state.pagination.current = data.data.pageNo ? data.data.pageNo : '0';
@@ -189,6 +191,7 @@ const User = Form.create()(React.createClass({
       departmentArr: [],
       loading: false,
       roleArr: [],
+      teamList: [],
       pagination: {
         defaultCurrent: 1,
         defaultPageSize: 10,
@@ -218,12 +221,14 @@ const User = Form.create()(React.createClass({
         dataIndex: 'userNo',
         key: 'userNo',
         isNoD: true,
-      }, {
+      },
+      {
         title: '登录用户名',
         dataIndex: 'mobile',
         key: 'mobile',
         width: "140px",
-      }, {
+      },
+      {
         title: '角色',
         dataIndex: 'rolesName',
         key: 'rolesName',
@@ -231,25 +236,34 @@ const User = Form.create()(React.createClass({
           <span>
             {text + (getRole(record.ambRole) ? ("(" + getRole(record.ambRole) + ")") : "")}
           </span>
-      }, {
+      },
+      {
         title: '用户姓名',
         dataIndex: 'name',
         key: 'name',
         width: "140px",
-      }, {
+      },
+      {
         title: '部门',
         dataIndex: 'departmentName',
         key: 'departmentName',
-      }, {
-        title: '分巴',
-        dataIndex: 'ancestorsNames',
-        key: 'ancestorsNames',
-        render: (text, record) =>
-          <span>
-            {!!text && text.replace(/,/g, "-")}
-            {!!record.ambName && "-" + record.ambName}
-          </span>
-      }, {
+      },
+      {
+        title: '团队',
+        dataIndex: 'teamName',
+        key: 'teamName',
+      },
+      // {
+      //   title: '分巴',
+      //   dataIndex: 'ancestorsNames',
+      //   key: 'ancestorsNames',
+      //   render: (text, record) =>
+      //     <span>
+      //       {!!text && text.replace(/,/g, "-")}
+      //       {!!record.ambName && "-" + record.ambName}
+      //     </span>
+      // },
+      {
         title: '职务',
         dataIndex: 'duty',
         key: 'duty',
@@ -406,6 +420,7 @@ const User = Form.create()(React.createClass({
     this.departmentList();
     this.rolesList();
     this.getList();
+    this.salesTeam();
   },
   tableRowClick(record, index) {
     this.rolesArrS(record)
@@ -700,7 +715,8 @@ const User = Form.create()(React.createClass({
     this.loadDatas();
   },
   reset() {
-    this.state.ambManage = undefined
+    this.state.teamId = undefined;
+    this.state.ambManage = undefined;
     this.state.ambId = undefined;
     this.state.amb = 1;
     this.state.userNameSearch = undefined;
@@ -836,6 +852,36 @@ const User = Form.create()(React.createClass({
       }.bind(this)
     );
   },
+  // 团队
+  salesTeam() {
+    this.setState({
+      loading: true
+    });
+    $.ajax({
+      method: "get",
+      dataType: "json",
+      crossDomain: false,
+      url: globalConfig.context + "/api/admin/salesTeam/lvlList",
+      data: {},
+      success: function (data) {
+        this.setState({
+          loading: false,
+        });
+        if (data.error && data.error.length === 0) {
+          let list = data.data
+          this.setState({
+            teamList: list ? this.handleTreeData(list) : []
+          });
+        } else {
+          message.warning(data.error[0].message);
+        }
+      }.bind(this),
+    }).always(function () {
+      this.setState({
+        loading: false
+      });
+    }.bind(this));
+  },
   // 树状默认数据处理
   handleTreeData(treeData) {
     let nodeDta = [];
@@ -1014,7 +1060,22 @@ const User = Form.create()(React.createClass({
                   <Input />
                 </AutoComplete>
                 <div style={{ marginTop: 10 }}>
-                  <Select
+
+                  <TreeSelect
+                    style={{ width: 200 }}
+                    value={this.state.teamId}
+                    dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
+                    treeData={this.state.teamList}
+                    placeholder="请选择团队"
+                    showSearch
+                    treeNodeFilterProp="title"
+                    onChange={(e) => {
+                      this.setState({
+                        teamId: e,
+                      });
+                    }}
+                  />
+                  {/* <Select
                     placeholder="巴主"
                     style={{ width: 180 }}
                     value={this.state.ambManage}
@@ -1052,7 +1113,7 @@ const User = Form.create()(React.createClass({
                       <Select.Option value={1}>本巴</Select.Option>
                       <Select.Option value={2}>全部</Select.Option>
                     </Select>
-                  }
+                  } */}
                   <Button style={{ marginRight: 10 }} type="primary" onClick={this.search}>搜索</Button>
                   <Button style={{ marginRight: 10 }} onClick={this.reset}>重置</Button>
                   <Button
@@ -1157,6 +1218,7 @@ const User = Form.create()(React.createClass({
               showDesc={this.state.showDesc}
               closeDesc={this.closeDesc}
               level1Data={this.state.level1Data}
+              teamList={this.state.teamList}
             />}
           <div className="patent-desc">
             <Modal

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "afanti",
-  "version": "1.3.31",
+  "version": "1.3.32",
   "description": "",
   "main": "index.js",
   "scripts": {