tyler пре 2 година
родитељ
комит
456b66bd66

+ 10 - 8
.env.development

@@ -19,16 +19,18 @@ ENV='development'
 # VUE_APP_SYSTEM_JS='http://ng-upload.elken.com'
 
 # api请求地址
-VUE_APP_BASE_API=''
+VUE_APP_BASE_API='http://16.163.228.151:8042'
 # 文件下载地址
 VUE_APP_BASE_DO_API='http://16.163.228.151:8042'
 # CDN文件地址
-VUE_APP_CDN_API='http://172.17.133.86:9970'
-# 页面地址
-VUE_APP_BASE_WEBSITE='http://local.ng.backend.ele.com'
-# 会员端地址
-VUE_APP_FRONTEND_WEBSITE='http://local.ng.frontend.ele.com'
-# PayStack
+VUE_APP_CDN_API='http://16.163.228.151:8042'
+# 区域js文件地址
+VUE_APP_SYSTEM_JS='http://ng-upload.elken.com'
+# 结算页面地址
+VUE_APP_BASE_WEBSITE='http://16.163.228.151:8042'
+# 会员页面地址
+VUE_APP_FRONTEND_WEBSITE='http://16.163.228.151:8045'
+# PayStack支付key
 VUE_APP_BASE_PAY_STACK_PUBLIC_KEY='pk_test_2eed10135c4a958c5073795b22854ded9d1a6c55'
 # 请求token前缀
-VUE_APP_ACCESS_TOKEN_PREFIX='Bearer '
+VUE_APP_ACCESS_TOKEN_PREFIX='Bearer '

+ 2 - 2
package.json

@@ -19,10 +19,9 @@
     "axios": "0.18.1",
     "clipboard": "2.0.4",
     "codemirror": "5.45.0",
-    "core-js": "3.6.5",
+    "core-js": "^3.32.0",
     "driver.js": "0.9.5",
     "dropzone": "5.5.1",
-    "echarts": "4.2.1",
     "element-ui": "2.13.2",
     "file-saver": "2.0.1",
     "fuse.js": "3.4.4",
@@ -66,6 +65,7 @@
     "chalk": "2.4.2",
     "chokidar": "2.1.5",
     "connect": "3.6.6",
+    "echarts": "^5.4.3",
     "html-webpack-plugin": "3.2.0",
     "husky": "1.3.1",
     "lint-staged": "8.1.5",

+ 1 - 1
src/components/Charts/Keyboard.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
 
 export default {

+ 1 - 1
src/components/Charts/LineMarker.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
 
 export default {

+ 1 - 1
src/components/Charts/MixChart.vue

@@ -3,7 +3,7 @@
 </template>
 
 <script>
-import echarts from 'echarts'
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
 
 export default {

+ 269 - 0
src/components/TreeChart/index.vue

@@ -0,0 +1,269 @@
+<template>
+  <div class="echarts-container" />
+</template>
+<script>
+import { TreeChart } from 'echarts/charts'
+import { TooltipComponent } from 'echarts/components'
+import * as echarts from 'echarts/core'
+import { CanvasRenderer } from 'echarts/renderers'
+
+echarts.use([TooltipComponent, TreeChart, CanvasRenderer])
+let myChart
+let option
+export default {
+  name: 'TreeChart',
+  props: {
+    treeData: {
+      type: Object,
+      default: () => {
+        return {}
+      }
+    },
+    topDeep: Number,
+    type: String,
+    clickNodeList: Array
+  },
+  watch: {
+    clickNodeList:{
+      handler(newValue, old){
+        console.log(newValue,old)
+        this.init()
+      }
+    }
+  },
+  mounted() {
+    this.init()
+    // 监听树图节点的点击事件
+    myChart.on('click', (e) => {
+      console.log('e:', e)
+      this.$emit('clickNode', e)
+    })
+  },
+  methods: {
+    init() {
+      const that = this
+      // console.log('$el:', this.$el)
+      myChart = echarts.init(this.$el)
+      option = {
+        tooltip: {
+          // 提示框浮层设置
+          trigger: 'item',
+          triggerOn: 'mousemove', // 提示框触发条件
+          enterable: true, // 鼠标是否可进入提示框浮层中,默认false
+          confine: true, // 是否将tooltip框限制在图表的区域内
+          padding: [5, 10],
+          formatter: function(params) {
+            // 提示框浮层内容格式器,支持字符串模板和回调函数两种形式
+            // console.log('params:', params)
+            return "<div style='display: flex;flex-direction: column;'>" +
+              '<span>' +
+              (that.type == 'placement' ? (params.data.TOP_NETWORK_DEEP - that.topDeep) : '') +
+              '</span>' +
+              '<span>' +
+              params.data.USER_NAME +
+              '</span>' +
+              '<span>' +
+              params.data.REAL_NAME +
+              '</span>' +
+              '<span>' +
+              that.$t('atlas.location') +
+              ': ' +
+              (params.data.RELATIVE_LOCATION || '') +
+              '</span>' +
+              '<span>' +
+              params.data.DEC_LV_NAME +
+              '</span>' +
+              '<span>' +
+              that.$t('atlas.highest') +
+              ': ' +
+              params.data.EMP_LV_NAME + ',' + params.data.CROWN_LV_NAME +
+              '</span>' +
+              '<span>' +
+              params.data.PERIOD_AT +
+              '</span>' +
+              '</div>'
+          },
+          // valueFormatter: function (value) { // tooltip 中数值显示部分的格式化回调函数
+          //   return '$' + value.toFixed(2)
+          // },
+          backgroundColor: 'rgba(250,250,250,0.99)', // 提示框浮层的背景颜色
+          borderColor: '#1890FF', // 提示框浮层的边框颜色
+          borderWidth: 0.5, // 提示框浮层的边框宽
+          borderRadius: 8, // 提示框浮层圆角
+          textStyle: {
+            // 提示框浮层的文本样式
+            color: '#333', // 文字颜色
+            fontWeight: 400, // 字体粗细
+            fontSize: 14, // 字体大小
+            lineHeight: 20, // 行高
+            width: 60, // 文本显示宽度
+            // 文字超出宽度是否截断或者换行;只有配置width时有效
+            overflow: 'breakAll', // truncate截断,并在末尾显示ellipsis配置的文本,默认为...;break换行;breakAll换行,并强制单词内换行
+            ellipsis: '...'
+          },
+          extraCssText:
+            'min-height:100px;box-shadow: 0 0 9px rgba(0, 0, 0, 0.3);text-align: left;', // 额外添加到浮层的css样式
+          axisPointer: {
+            type: 'shadow',
+            shadowStyle: {
+              color: new echarts.graphic.LinearGradient(
+                0, 0, 0, 1,
+                [
+                  { offset: 0, color: 'rgba(255, 255, 255, 0)' },
+                  { offset: 1, color: 'rgba(37, 107, 230, 0.18)' }
+                ]
+              )
+            }
+          }
+        },
+        series: [
+          {
+            width: '100%',
+            height: '100%',
+            type: 'tree',
+            data: [this.treeData],
+            name: '树图',
+            top: '10%', // 组件离容器上侧的距离,像素值20,或相对容器的百分比20%
+            left: '5%', // 组件离容器左侧的距离
+            bottom: '1%', // 组件离容器下侧的距离
+            right: '2%', // 组件离容器右侧的距离
+            layout: 'orthogonal', // 树图的布局,正交orthogonal和径向radial两种
+            orient: 'TB', // 树图中正交布局的方向,'LR','RL','TB','BT',只有布局是正交时才生效
+            edgeShape: 'polyline', // 树图边的形状,有曲线curve和折线polyline两种,只有正交布局下生效
+            roam: true, // 是否开启鼠标缩放或平移,默认false
+            zoom: 1,
+            scaleLimit: {
+              min: 0.5,
+              max: 10
+            },
+            initialTreeDepth: -1, // 树图初始的展开层级(深度),根节点是0,不设置时全部展开
+            // symbol: 'emptyCircle', // 标记的图形,默认是emptyCircle;circle,rect,roundRect,triangle,diamond,pin,arrow,none
+            symbol: function(value, params) {
+                  // params.data节点的所有数据
+                if (params.data.leaf == true) {
+                    return 'emptyCircle'
+                  } else if (params.data.leaf == false) {
+                    return 'circle'
+                }
+            },
+            // symbolRotate: 270, // 配合arrow图形使用效果较好
+            symbolSize: 10, // 大于0时是圆圈,等于0时不展示,标记的大小
+            itemStyle: {
+              // 树图中每个节点的样式
+              color: '#1890FF', // 节点未展开时的填充色
+              borderColor: 'rgba(255, 144, 0, 1)', // 图形的描边颜色
+              borderWidth: 0.5, // 描边线宽,为0时无描边
+              borderType: 'dotted', // 描边类型
+              borderCap: 'square', // 指定线段末端的绘制方式butt方形结束,round圆形结束,square
+              shadowColor: 'rgba(0,121,221,0.3)', // 阴影颜色
+              shadowBlur: 16, // 图形阴影的模糊大小
+              opacity: 1 // 图形透明度
+            },
+            label: {
+              // 每个节点对应的文本标签样式
+              show: true, // 是否显示标签
+              distance: 15, // 文本距离图形元素的距离
+              position: 'bottom', // 标签位置
+              verticalAlign: 'middle', // 文字垂直对齐方式,默认自动,top,middle,bottom
+              align: 'center', // 文字水平对齐方式,默认自动,left,right,center
+              fontSize: 14, // 字体大小
+              color: '#333', // 字体颜色
+              backgroundColor: '#F0F5FA', // 文字块的背景颜色
+              borderColor: '#1890FF', // 文字块边框颜色
+              borderWidth: 0.5, // 文字块边框宽度
+              borderType: 'solid', // 文字块边框描边类型 solid dashed dotted
+              borderRadius: 6, // 文字块的圆角
+              padding: [9, 6], // 文字块内边距
+              shadowColor: 'rgba(0,121,221,0.6)', // 文字块的背景阴影颜色
+              shadowBlur: 6, // 文字块的背景阴影长度
+              // width: 60,
+              // 文字超出宽度是否截断或者换行;只有配置width时有效
+              overflow: 'truncate', // truncate截断,并在末尾显示ellipsis配置的文本,默认为...;break换行;breakAll换行,并强制单词内换行
+              ellipsis: '...',
+              formatter: function(params) {
+                // return params.data.USER_NAME + '\n' + '\n' + params.data.REAL_NAME
+                return params.data.REAL_NAME
+              }
+            },
+            lineStyle: {
+              // 树图边的样式
+              color: 'rgba(0,0,0,.35)', // 树图边的颜色
+              width: 2, // 树图边的宽度
+              curveness: 0.5, // 树图边的曲度
+              shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
+              shadowBlur: 10 // 图形阴影的模糊大小
+            },
+            emphasis: {
+              // 树图中图形和标签高亮的样式
+              disabled: false, // 是否关闭高亮状态,默认false
+              // 在高亮图形时,是否淡出其它数据的图形已达到聚焦的效果
+              focus: 'relative', // none不淡出其他图形(默认);self只聚焦当前高亮的数据图形;series聚焦当前高亮的数据所在系列的所有图形;ancestor聚焦所有祖先节点;descendant聚焦所有子孙节点;relative聚焦所有子孙和祖先节点
+              blurScope: 'coordinateSystem', // 开启focus时,配置淡出的范围,coordinateSystem淡出范围为坐标系(默认);series淡出范围为系列;global淡出范围为全局
+              itemStyle: {
+                // 该节点的样式
+                color: '#1890FF', // 图形的颜色
+                // borderColor: 'rgba(255, 144, 0, 1)', // 图形的描边颜色
+                borderWidth: 1, // 描边线宽,为0时无描边
+                borderType: 'solid', // 描边类型 solid dashed dotted
+                borderCap: 'square', // 指定线段末端的绘制方式butt方形结束,round圆形结束,square
+                shadowColor: 'rgba(0,121,221,0.3)', // 阴影颜色
+                shadowBlur: 12, // 图形阴影的模糊大小
+                opacity: 1 // 图形透明度
+              },
+              lineStyle: {
+                // 树图边的样式
+                color: 'rgba(0,0,0,.45)', // 树图边的颜色
+                width: 2, // 树图边的宽度
+                curveness: 0.5, // 树图边的曲度
+                shadowColor: 'rgba(0, 0, 0, 0.5)', // 阴影颜色
+                shadowBlur: 6 // 图形阴影的模糊大小
+              },
+              label: {
+                // 高亮标签的文本样式
+                color: '#333',
+                fontWeight: 600
+              }
+            },
+            blur: {
+              // 淡出状态的相关配置,开启emphasis.focus后有效
+              itemStyle: {}, // 节点的样式
+              lineStyle: {}, // 树图边的样式
+              label: {} // 淡出标签的文本样式
+            },
+            leaves: {
+              // 叶子节点的特殊配置
+              label: {
+                // 叶子节点的文本标签样式
+                distance: 8,
+                // color: '#1890FF',
+                position: 'bottom',
+                verticalAlign: 'middle',
+                align: 'center'
+              },
+              itemStyle: {}, // 叶子节点的样式
+              emphasis: {}, // 叶子节点高亮状态的配置
+              blur: {}, // 叶子节点淡出状态的配置
+              select: {} // 叶子节点选中状态的配置
+            },
+            animation: true, // 是否开启动画
+            expandAndCollapse: true, // 子树折叠和展开的交互,默认打开
+            animationDuration: 500, // 初始动画的时长
+            animationEasing: 'linear', // 初始动画的缓动效果
+            animationDelay: 0, // 初始动画的延迟
+            animationDurationUpdate: 500, // 数据更新动画的时长
+            animationEasingUpdate: 'cubicInOut', // 数据更新动画的缓动效果
+            animationDelayUpdate: 0 // 数据更新动画的延迟
+          }
+        ]
+      }
+      myChart.setOption(option)
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.echarts-container {
+  width: 100%;
+  height: calc(100vh - 105px);
+}
+</style>

+ 5 - 1
src/lang/en.js

@@ -81,6 +81,8 @@ export default {
     financeWithdraw:'Withdrawal management',
     atlasRelationOpt:'Sponsor network',
     atlasNetworkOpt:'Placement network',
+    sponsorNetworkEx:'Sponsor network Ex',
+    placementNetworkEx:'Placement network Ex',
     shopIndex:'Products list',
     shopGoodsAdd:'Add Product',
     shopOrderDecList:'External mall entry list',
@@ -640,7 +642,9 @@ export default {
   // Network
   network: {
     placementNetwork: 'Placement Network',
-    sponsorNetwork: 'Sponsor Network'
+    sponsorNetwork: 'Sponsor Network',
+    placementNetworkEx: 'Placement Network Ex',
+    sponsorNetworkEx: 'Sponsor Network Ex'
   },
 
   // Configuration

+ 4 - 0
src/lang/zh.js

@@ -81,6 +81,8 @@ export default {
     financeWithdraw:'提现管理',
     atlasRelationOpt:'开拓网络',
     atlasNetworkOpt:'安置网络',
+    sponsorNetworkEx:'安置网络 Ex',
+    placementNetworkEx:'开拓网络 Ex',
     shopIndex:'商品列表',
     shopGoodsAdd:'商品添加',
     shopOrderDecList:'外部商城报单列表',
@@ -477,6 +479,8 @@ export default {
     // 二级菜单/接口-networkChart
     placementNetwork: '安置网络',
     sponsorNetwork: '推荐网路',
+    placementNetworkEx: '推荐网络 Ex',
+    sponsorNetworkEx: '安置网路 Ex',
     // 二级菜单/接口-bonusManagement
     closurePeriod: '封期管理',
     memberBonusBalance: '会员账户余额',

+ 13 - 1
src/router/index.js

@@ -7,8 +7,8 @@ Vue.use(Router)
 import Layout from '@/layout'
 
 /* Router Modules */
-import memberRouter from '@/router/modules/member'
 import configRouter from '@/router/modules/config'
+import memberRouter from '@/router/modules/member'
 
 /**
  * Note: sub-menu only appear when route children.length >= 1
@@ -165,6 +165,18 @@ export const constantRoutes = [
         name: 'atlas_network-opt',
         meta: {title: 'atlasNetworkOpt',},
       },
+      {
+        path: '/atlas/relation-list', // 开拓网络Ex
+        component: () => import('@/views/atlas/relation-ex'),
+        name: 'atlas_relation-ex',
+        meta: {title: 'placementNetworkEx',},
+      },
+      {
+        path: '/atlas/network-list', // 安置网络Ex
+        component: () => import('@/views/atlas/network-ex'),
+        name: 'atlas_network-ex',
+        meta: {title: 'sponsorNetworkEx',},
+      },
     ]
   },
   {

+ 347 - 0
src/views/atlas/network-ex.vue

@@ -0,0 +1,347 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <el-tabs v-model="tabActiveName">
+          <el-tab-pane :label="$t('atlas.resettlementNetworkDiagram')" name="first" v-if="permission.hasPermission(`atlas/network`)"><!-- 安置网络图 -->
+            <div class="filter-user" @keyup.enter="enterToGetData()">
+              <el-input v-model="mainUserName" size="small" style="width:300px;">
+                <template slot="prepend">{{ $t('atlas.topMember') }}<!-- 顶级会员 --></template>
+              </el-input>
+              <el-input v-model="expandDeep" size="small" style="width:200px;">
+                <template slot="prepend">{{ $t('atlas.spreadDepth') }}<!-- 展开深度 --></template>
+              </el-input>
+              <el-input v-model="periodNum" size="small" style="width:150px;" v-show="false">
+                <template slot="prepend">{{ $t('atlas.numberOfPeriods') }}<!-- 期数 --></template>
+              </el-input>
+              <el-button type="primary" size="small" @click="getMainData()">{{ $t('common.confirm') }}<!-- 确定 --></el-button>
+            </div>
+            <el-tree :props="props" :data="treeData" node-key="USER_ID" @node-click="getChildData" ref="tree" :indent="0"
+                     default-expand-all :height="tool.getTableHeight(true)">
+              <span :id="'node_'+data.USER_ID" :class="'custom-tree-node '+data.className"
+                    slot-scope="{ node, data }">
+                <span :class="'el-icon-loading '+ data.displayNone"></span>
+                <span :class="data.icon"></span>
+                <span>
+                  <el-tag type="danger">{{ $t('atlas.numberOfLayers') }} :{{countTopDeep(data.TOP_NETWORK_DEEP,topDeep)}}</el-tag>
+                  <el-tag><!-- 会员编号 -->{{ $t('atlas.memberCode') }}:{{ node.label }}</el-tag>
+                  <el-tag>{{ $t('atlas.name') }}<!-- 姓名 -->:{{data.REAL_NAME}}</el-tag>
+                  <el-tag type="danger"><!-- 区位 -->{{ $t('atlas.location') }}:{{data.RELATIVE_LOCATION}}</el-tag>
+                  <el-tag type="success"><!-- 级别 -->{{ $t('atlas.level') }}:{{data.DEC_LV_NAME}}</el-tag>
+                  <el-tag type="warning"><!-- 聘级 -->{{ $t('atlas.highest') }}:{{data.EMP_LV_NAME}}, {{data.CROWN_LV_NAME}}</el-tag>
+                  <el-tag><!-- 加入期数 -->{{ $t('atlas.joiningPeriod') }}:{{data.PERIOD_AT}}</el-tag>
+                </span>
+              </span>
+            </el-tree>
+          </el-tab-pane>
+          <el-tab-pane :label="$t('atlas.placementNetworkList')" name="two" v-if="permission.hasPermission(`atlas/network-list`)"><!-- 安置网络列表 -->
+            <div class="filter-user">
+              <el-input v-model="filterForm.userName" size="small" style="width:300px;">
+                <template slot="prepend"><!-- 会员编号 -->{{ $t('atlas.memberCode') }}</template>
+              </el-input>
+              <el-input v-model="filterForm.deep" size="small" style="width:150px;">
+                <template slot="prepend"><!-- 深度 -->{{ $t('atlas.depth') }}</template>
+              </el-input>
+              <el-input v-model="filterForm.periodNum" size="small" style="width:150px;" v-show="false">
+                <template slot="prepend"><!-- 期数 -->{{ $t('atlas.numberOfPeriods') }}</template>
+              </el-input>
+              <el-button type="primary" size="small" @click="handleFilter">{{ $t('common.confirm') }}<!-- 确定 --></el-button>
+            </div>
+
+            <el-table :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight(true)">
+              <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''">
+                <template slot-scope="scope">
+                  <template v-if="scope.row[tableHeader.index].other.tag" >
+                    <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+                  </template>
+                  <template v-else-if="scope.row[tableHeader.index].other.progress" >
+                    <el-progress type="circle" :percentage="Number.parseInt(percentList['MOVE_PERCENT'][scope.row.ID])"
+                                 :width="50"
+                                 :stroke-width="3"></el-progress>
+                  </template>
+                  <template v-else>
+                    <template v-if="tableHeader.index === 'USER_NAME'">
+                      <el-tooltip class="item" effect="dark" :content="$t('atlas.subordinatesMember')" placement="top"><!-- 查看该会员的下级 -->
+                      <el-button @click.native="handleShow(scope.row)" size="small" type="primary">
+                        {{scope.row[tableHeader.index].value}}
+                      </el-button>
+                      </el-tooltip>
+                    </template>
+                    <template v-else>
+                    <div v-html="scope.row[tableHeader.index].value"></div>
+                    </template>
+                  </template>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div class="white-box-footer">
+              <el-button type="success" size="small" @click="handleExport"
+                         v-show="permission.hasPermission(`atlas/network-list-export`)">{{ $t('common.exportExcel') }}<!-- 导出Excel -->
+              </el-button>
+              <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+    </div>
+  </template>
+
+  <script>
+  import { getNetwork, mainUserInfo, networkList, networkListExport } from '@/api/atlas'
+import Pagination from '@/components/Pagination'
+import baseInfo from '@/utils/baseInfo'
+import permission from '@/utils/permission'
+import tool from '@/utils/tool'
+import store from '@/utils/vuexStore'
+
+  export default {
+    name: 'atlas_network-ex',
+    components: {Pagination},
+    mounted() {
+      this.getData()
+      store.state.socket.onMessageCallback = this.onMessageCallback
+    },
+    data() {
+      return {
+        loading: true,
+        tabActiveName: 'first',
+        permission: permission,
+        //relation
+        props: {
+          label: 'USER_NAME',
+          children: 'children',
+          //isLeaf: 'leaf',
+          icon: 'icon',
+        },
+        treeData: null,
+        expandDeep: 2,
+        topDeep: 0,
+        mainUserName: '',
+        periodNum: null,
+        listPeriodNum: null,
+        allData: null,
+        tableHeaders: null,
+        tableData: null,
+        currentPage: 1,
+        totalPages: 1,
+        totalCount: 1,
+        pageSize: 20,
+        tool: tool,
+        filterForm: {
+          userName: null,
+          deep: 2,
+          periodNum: null,
+        },
+        listTopDeep: 0,
+      }
+    },
+    methods: {
+      getData() {
+        this.$message({
+          message: this.$t('atlas.getDataWait'), // 正在获取数据,请稍后
+        })
+        this.periodNum = baseInfo.nowPeriodNum()
+        this.filterForm.periodNum = baseInfo.nowPeriodNum()
+        if (permission.hasPermission(`atlas/network-list`) && !permission.hasPermission(`atlas/network`)) {
+          this.tabActiveName = 'two'
+          this.getListData()
+        }
+        if (permission.hasPermission(`atlas/network`)) {
+          this.tabActiveName = 'first'
+          if(permission.hasPermission(`atlas/network-list`)){
+            this.getMainData(null,true)
+          }else{
+            this.getMainData()
+          }
+        }
+      },
+      getMainData (userName = null, getList = false) {
+        this.$message.closeAll()
+        this.$message({
+          message: this.$t('atlas.getDataWait'),//正在获取数据,请稍后
+        })
+        let thisObj = this
+        let requestData = {
+          periodNum: this.periodNum
+        }
+        if (this.mainUserName !== null) {
+          requestData = {userName: this.mainUserName,periodNum: this.periodNum}
+        }
+
+        mainUserInfo(requestData).then(response=>{
+            thisObj.treeData = response.data
+            thisObj.topDeep = Number(response.data[0].TOP_NETWORK_DEEP)
+            thisObj.listPeriodNum = response.data[0].listPeriodNum
+            if(getList) thisObj.getListData()
+            thisObj.loading = false
+        }).catch(err => {
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+            thisObj.loading = false
+        })
+      },
+      getChildData (data, node) {
+        let thisObj = this
+        let userId = data.USER_ID
+        let thisData = data
+        if (thisData.leaf) {
+          return ''
+        }
+        if (thisData.isExpanded) {
+          return ''
+        }
+        if (thisData.children !== null && thisData.children.length > 0) {
+          return ''
+        }
+        thisData.displayNone = ''
+        getNetwork({
+          id: userId,
+          deep: thisObj.expandDeep,
+          periodNum: this.periodNum
+        }).then(response => {
+            thisObj.$refs.tree.updateKeyChildren(userId, response.data.allData)
+            thisObj.listPeriodNum = response.data.periodNum
+            thisData.displayNone = 'display-none'
+            thisData.isExpanded = true
+        }).catch(err => {
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+        })
+      },
+      countTopDeep(deep,topDeep){
+        return Number(deep)-Number(topDeep)
+      },
+      handleCurrentChange (page) {
+        this.getListData(page, this.pageSize)
+      },
+      handleSizeChange (pageSize) {
+        this.getListData(this.currentPage, pageSize)
+      },
+      handleFilter () {
+        this.getListData(1, this.pageSize)
+        this.tabActiveName = 'two'
+      },
+      handleShow(row) {
+        this.loading = true
+        this.filterForm.userName = row.SEE_USER_NAME
+        this.getListData(1, this.pageSize)
+        this.tabActiveName = 'two'
+      },
+      getListData (page, pageSize) {
+        let obj = this
+        let filterData = this.filterForm
+        const paramsData = Object.assign({
+            page: (page === null || page == undefined) ? 1 : page,
+            pageSize: (pageSize === null || pageSize == undefined) ? obj.pageSize : pageSize
+          }, filterData)
+        networkList(paramsData).then(response => {
+            obj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            obj.tableData = response.data.list
+            obj.filterTypes = response.data.filterTypes
+            obj.allData = response.data.list
+            obj.listTopDeep = response.data.listTopDeep
+            obj.periodNum = response.data.periodNum
+            obj.currentPage = page
+            obj.totalPages = parseInt(response.data.totalPages)
+            obj.totalCount = parseInt(response.data.totalCount)
+            obj.pageSize = pageSize
+            obj.loading = false
+        }).catch(err => {
+            obj.loading = false
+            this.$message({
+              message: err,
+              type: 'error'
+            })
+        })
+      },
+      onMessageCallback(data) {
+        //this.getData(this.currentPage, this.pageSize, false)
+      },
+      handleExport(){
+        this.$confirm(this.$t('atlas.exportNotice'), this.$t('common.hint'), {//`确定要导出当前数据吗?`, '提示'
+          confirmButtonText: this.$t('common.confirm'), // 确定
+          cancelButtonText: this.$t('common.cancel'), // 取消
+          type: 'warning'
+        }).then(() => {
+            networkListExport(this.filterForm).then(response => {
+                this.$message({
+                    message: response.data,
+                    type: 'success'
+                })
+            }).catch(err => {
+                this.$message({
+                message: err,
+                type: 'error'
+                })
+            })
+        })
+      },
+      enterToGetData (ev) {
+        this.getMainData()
+      },
+    }
+  }
+  </script>
+
+  <style>
+    .filter-user{font-size: 14px;margin-bottom: 20px;}
+    .filter-user:after{content: '';display: table;
+      clear: both;}
+    .filter-user .el-input-group{float: left;margin-right: 15px;}
+    .el-tree {
+      padding-bottom: 20px;
+      font-size: 14px;
+      overflow-x: auto;
+    }
+
+    .el-tree .el-tag {
+      height: 20px;
+      line-height: 18px;vertical-align: middle;
+    }
+    .el-tree-node{position: relative;}
+
+    .el-tree-node__content {
+      height: 30px;
+      line-height: 30px;
+    }
+
+    .el-tree-node__children {
+      position: relative;
+      padding: 0 0 0 16px;
+    }
+
+    .el-tree-node:before {
+      position: absolute;
+      content: '';
+      top: 0px;
+      left: -4px;
+      height: 100%;
+      border-left: 1px solid #ccc;
+    }
+    .el-tree-node:last-child:before{height: 15px;}
+
+    .custom-tree-node {
+      position: relative;
+      padding-left: 5px;
+    }
+
+    .first-node:before {
+      display: none;
+    }
+
+    .custom-tree-node:before {
+      position: absolute;
+      width: 8px;
+      content: '';
+      top: 15px;
+      left: -4px;
+      border-bottom: 1px solid #ccc;
+    }
+
+    .el-tree-node__expand-icon {
+      display: none !important;
+    }
+  </style>

+ 374 - 0
src/views/atlas/relation-ex.vue

@@ -0,0 +1,374 @@
+<template>
+    <div v-loading="loading">
+      <div class="white-box">
+        <el-tabs v-model="tabActiveName">
+          <el-tab-pane :label="$t('atlas.sponsorNetworkDiagram')" name="first" v-if="permission.hasPermission(`atlas/relation`)"><!-- 开拓网络图 -->
+            <div class="filter-user">
+              <el-input v-model="mainUserName" size="small" style="width:300px;">
+                <template slot="prepend">{{ $t('atlas.topMember') }}<!-- 顶级会员 --></template>
+              </el-input>
+              <el-input v-model="expandDeep" size="small" style="width:200px;">
+                <template slot="prepend">{{ $t('atlas.spreadDepth') }}<!-- 展开深度 --></template>
+              </el-input>
+              <el-input v-model="periodNum" size="small" style="width:150px;" v-show="false">
+                <template slot="prepend">{{ $t('atlas.numberOfPeriods') }}<!-- 期数 --></template>
+              </el-input>
+              <el-button type="primary" size="small" @click="getMainData()">{{ $t('common.confirm') }}<!-- 确定 --></el-button>
+            </div>
+            <el-tree :props="props" :data="treeData" node-key="USER_ID" @node-click="getChildData" ref="tree" :indent="0"
+                     default-expand-all>
+                  <span :id="'node_'+data.USER_ID" :class="'custom-tree-node '+data.className"
+                        slot-scope="{ node, data }">
+                      <span :class="'el-icon-loading '+ data.displayNone"></span>
+                      <span :class="data.icon"></span>
+                      <span>
+                        <el-tag type="danger"><!-- 代数 -->{{ $t('atlas.algebra') }}:  {{countTopDeep(data.TOP_RELATION_DEEP,topDeep)}}</el-tag>
+                        <el-tag><!-- 会员编号 -->{{ $t('atlas.memberCode') }}:{{ node.label }}</el-tag>
+                        <el-tag type="success">{{ $t('atlas.name') }}<!-- 姓名 -->:{{data.REAL_NAME}}</el-tag>
+                        <el-tag type="warning">{{ $t('atlas.level') }}<!-- 级别 -->:{{data.DEC_LV_NAME}}</el-tag>
+                        <el-tag type="warning">{{ $t('atlas.highest') }}:<!-- 聘级 -->{{data.EMP_LV_NAME}}, {{data.CROWN_LV_NAME}}</el-tag>
+  <!--                      <el-tag type="warning">Star:&lt;!&ndash; 星级 &ndash;&gt;{{data.CROWN_LV_NAME}}</el-tag>-->
+                      </span>
+                  </span>
+            </el-tree>
+            <div v-if="treeChartShow" class="tree-chart">
+              <tree-chart :tree-data="treeData" :top-deep="topDeep" type="placement" @clickNode="getNodeData" :clickNodeList="clickNodeList" />
+            </div>
+          </el-tab-pane>
+          <el-tab-pane :label="$t('atlas.sponsorNetworkList')" name="two" v-if="permission.hasPermission(`atlas/relation-list`)"><!-- 开拓网络列表 -->
+            <div class="filter-user">
+              <el-input v-model="filterForm.userName" size="small" style="width:300px;">
+                <template slot="prepend"><!-- 会员编号 -->{{ $t('atlas.memberCode') }}</template>
+              </el-input>
+              <el-input v-model="filterForm.deep" size="small" style="width:150px;">
+                <template slot="prepend"><!-- 深度 -->{{ $t('atlas.depth') }}</template>
+              </el-input>
+              <el-input v-model="filterForm.periodNum" size="small" style="width:150px;" v-show="false">
+                <template slot="prepend"><!-- 期数 -->{{ $t('atlas.numberOfPeriods') }}</template>
+              </el-input>
+              <el-button type="primary" size="small" @click="handleFilter">{{ $t('common.confirm') }}<!-- 确定 --></el-button>
+            </div>
+
+            <el-table :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight(true)">
+              <!--<el-table-column type="selection" width="55" v-if="tableHeaders"></el-table-column>-->
+              <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''">
+                <template slot-scope="scope">
+                  <template v-if="scope.row[tableHeader.index].other.tag" >
+                    <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null" >{{scope.row[tableHeader.index].value}}</el-tag>
+                  </template>
+                  <template v-else-if="scope.row[tableHeader.index].other.progress" >
+                    <el-progress type="circle" :percentage="Number.parseInt(percentList['MOVE_PERCENT'][scope.row.ID])"
+                                 :width="50"
+                                 :stroke-width="3"></el-progress>
+                  </template>
+                  <template v-else>
+                    <template v-if="tableHeader.index === 'USER_NAME'">
+                      <el-tooltip class="item" effect="dark" :content="$t('atlas.subordinatesMember')" placement="top"><!-- 查看该会员的下级 -->
+                        <el-button @click.native="handleShow(scope.row)" size="small" type="primary">
+                          {{scope.row[tableHeader.index].value}}
+                        </el-button>
+                      </el-tooltip>
+                    </template>
+                    <template v-else>
+                      <div v-html="scope.row[tableHeader.index].value"></div>
+                    </template>
+                  </template>
+                </template>
+              </el-table-column>
+            </el-table>
+            <div class="white-box-footer">
+              <el-button type="success" size="small" @click="handleExport"
+                         v-show="permission.hasPermission(`atlas/relation-list-export`)">{{ $t('common.exportExcel') }}<!-- 导出Excel -->
+              </el-button>
+              <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </div>
+    </div>
+  </template>
+
+  <script>
+    import { getRelation, mainUserInfo, relationList, relationListExport } from '@/api/atlas'
+import Pagination from '@/components/Pagination'
+import treeChart from '@/components/TreeChart/index.vue'
+import baseInfo from '@/utils/baseInfo'
+import permission from '@/utils/permission'
+import tool from '@/utils/tool'
+import store from '@/utils/vuexStore'
+
+    export default {
+      name: 'atlas_relation-ex',
+      components: {Pagination,treeChart},
+      mounted() {
+        this.getData()
+        store.state.socket.onMessageCallback = this.onMessageCallback
+      },
+      data() {
+        return {
+          loading: true,
+          tabActiveName: 'first',
+          permission: permission,
+          //relation
+          props: {
+            label: 'USER_NAME',
+            children: 'children',
+            //isLeaf: 'leaf',
+            icon: 'icon',
+          },
+          // treeData: null,
+          expandDeep: 2,
+          topDeep: 0,
+          mainUserName: '',
+          periodNum: null,
+          listPeriodNum: null,
+          allData: null,
+          tableHeaders: null,
+          tableData: null,
+          currentPage: 1,
+          totalPages: 1,
+          totalCount: 1,
+          pageSize: 20,
+          tool: tool,
+          filterForm: {
+            userName: null,
+            deep: 2,
+            periodNum: null,
+          },
+          listTopDeep: 0,
+
+          //tree
+          treeChartShow: false,
+          treeData: {
+            name: null,
+            children: null
+          },
+          clickNodeList:[],
+          clickNodeUserId:null
+        }
+      },
+      methods: {
+        //tree
+        getNodeData(e) {
+          // console.log(e)
+          if (e.collapsed === false && e.data.children == null) {
+            console.log(e.name + '---节点展开')
+          }
+          if (e.data.children == null) {
+            this.clickNodeUserId = e.data.USER_ID
+            this.getChildData(e.data, 'clickNode')
+
+          }
+
+        },
+        getData() {
+          this.$message({
+            message: this.$t('atlas.getDataWait'),//正在获取数据,请稍后
+            duration: 0
+          })
+          this.periodNum = baseInfo.nowPeriodNum()
+          this.filterForm.periodNum = baseInfo.nowPeriodNum()
+          if (permission.hasPermission(`atlas/relation-list`) && !permission.hasPermission(`atlas/relation`)) {
+            this.tabActiveName = 'two'
+            this.getListData()
+          }
+          if (permission.hasPermission(`atlas/relation`)) {
+            this.tabActiveName = 'first'
+            if (permission.hasPermission(`atlas/relation-list`)) {
+              this.getMainData(null, true)
+            } else {
+              this.getMainData()
+            }
+          }
+        },
+        getMainData (userName = null, getList = false) {
+          this.$message.closeAll()
+          this.$message({
+            message: this.$t('atlas.getDataWait'),//正在获取数据,请稍后
+          })
+          let thisObj = this
+          let requestData = {
+            periodNum: this.periodNum
+          }
+          if (this.mainUserName !== null) {
+            requestData = {userName: this.mainUserName,periodNum: this.periodNum}
+          }
+          mainUserInfo(requestData).then(response=>{
+            thisObj.treeData = response.data
+            thisObj.topDeep = Number(response.data[0].TOP_RELATION_DEEP)
+            thisObj.listPeriodNum = response.data[0].listPeriodNum
+            if(getList) thisObj.getListData()
+            thisObj.loading = false
+          }).catch(err => {
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+            thisObj.loading = false
+          })
+        },
+        getChildData (data, node) {
+          let thisObj = this
+          let userId = data.USER_ID
+          let thisData = data
+          if (thisData.leaf) {
+            return ''
+          }
+          if (thisData.isExpanded) {
+            return ''
+          }
+          if (thisData.children !== null && thisData.children.length > 0) {
+            return ''
+          }
+          this.$message({
+            message: this.$t('atlas.getDataWait'),//正在获取数据,请稍后
+          })
+          thisData.displayNone = ''
+          getRelation({
+            id: userId,
+            deep: thisObj.expandDeep,
+            periodNum: this.periodNum
+          }).then(response => {
+            thisObj.$refs.tree.updateKeyChildren(userId, response.data.allData)
+            thisData.listPeriodNum = response.data.periodNum
+            thisData.displayNone = 'display-none'
+            thisData.isExpanded = true
+          }).catch(err => {
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+          })
+        },
+        countTopDeep(deep,topDeep){
+          return Number(deep)-Number(topDeep)
+        },
+        getListData(page, pageSize) {
+          let obj = this
+          let filterData = this.filterForm
+          const paramsData = Object.assign({
+            page: (page === null || page == undefined) ? 1 : page,
+            pageSize: (pageSize === null || pageSize == undefined) ? obj.pageSize : pageSize
+          }, filterData)
+          relationList(paramsData).then(response => {
+            obj.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+            obj.tableData = response.data.list
+            obj.filterTypes = response.data.filterTypes
+            obj.allData = response.data.list
+            obj.listTopDeep = response.data.listTopDeep
+            obj.periodNum = response.data.periodNum
+            obj.currentPage = page
+            obj.totalPages = parseInt(response.data.totalPages)
+            obj.totalCount = parseInt(response.data.totalCount)
+            obj.pageSize = pageSize
+            obj.loading = false
+          }).catch(err => {
+            obj.loading = false
+            this.$message({
+                message: err,
+                type: 'error'
+            })
+          })
+        },
+        handleCurrentChange(page) {
+          this.getListData(page, this.pageSize)
+        },
+        handleSizeChange(pageSize) {
+          this.getListData(this.currentPage, pageSize)
+        },
+        handleFilter() {
+          this.getListData(1, this.pageSize)
+          this.tabActiveName = 'two'
+        },
+        handleShow(row) {
+          this.loading = true
+          this.filterForm.userName = row.SEE_USER_NAME
+          this.filterForm.deep = 1
+          this.getListData(1, this.pageSize)
+          this.tabActiveName = 'two'
+        },
+        onMessageCallback(data) {
+          //this.getData(this.currentPage, this.pageSize, false)
+        },
+        handleExport(){
+          this.$confirm(this.$t('atlas.exportNotice'), this.$t('common.hint'), {
+            confirmButtonText: this.$t('common.confirm'), // 确定
+            cancelButtonText: this.$t('common.cancel'), // 取消
+            type: 'warning'
+          }).then(() => {
+            relationListExport(this.filterForm).then(response => {
+                this.$message({
+                   message: response.data,
+                   type: 'success'
+                })
+            }).catch(err => {
+                this.$message({
+                   message: err,
+                   type: 'error'
+                })
+            })
+          })
+        },
+      }
+    }
+  </script>
+
+  <style>
+    .filter-user{font-size: 14px;margin-bottom: 20px;}
+    .filter-user:after{content: '';display: table;
+      clear: both;}
+    .filter-user .el-input-group{float: left;margin-right: 15px;}
+    .el-tree {
+      padding-bottom: 20px;
+      font-size: 14px;
+      overflow-x: auto;
+    }
+
+    .el-tree .el-tag {
+      height: 20px;
+      line-height: 18px;vertical-align: middle;
+    }
+    .el-tree-node{position: relative;}
+
+    .el-tree-node__content {
+      height: 30px;
+      line-height: 30px;
+    }
+
+    .el-tree-node__children {
+      position: relative;
+      padding: 0 0 0 16px;
+    }
+
+    .el-tree-node:before {
+      position: absolute;
+      content: '';
+      top: 0px;
+      left: -4px;
+      height: 100%;
+      border-left: 1px solid #ccc;
+    }
+    .el-tree-node:last-child:before{height: 15px;}
+
+    .custom-tree-node {
+      position: relative;
+      padding-left: 5px;
+    }
+
+    .first-node:before {
+      display: none;
+    }
+
+    .custom-tree-node:before {
+      position: absolute;
+      width: 8px;
+      content: '';
+      top: 15px;
+      left: -4px;
+      border-bottom: 1px solid #ccc;
+    }
+
+    .el-tree-node__expand-icon {
+      display: none !important;
+    }
+  </style>

+ 2 - 2
src/views/dashboard/admin/components/BarChart.vue

@@ -3,9 +3,9 @@
 </template>
 
 <script>
-import echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
+require('echarts/theme/macarons') // echarts theme
 
 const animationDuration = 6000
 

+ 2 - 2
src/views/dashboard/admin/components/LineChart.vue

@@ -3,9 +3,9 @@
 </template>
 
 <script>
-import echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
+require('echarts/theme/macarons') // echarts theme
 
 export default {
   mixins: [resize],

+ 2 - 2
src/views/dashboard/admin/components/PieChart.vue

@@ -3,9 +3,9 @@
 </template>
 
 <script>
-import echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
+require('echarts/theme/macarons') // echarts theme
 
 export default {
   mixins: [resize],

+ 2 - 2
src/views/dashboard/admin/components/RaddarChart.vue

@@ -3,9 +3,9 @@
 </template>
 
 <script>
-import echarts from 'echarts'
-require('echarts/theme/macarons') // echarts theme
+import * as echarts from 'echarts'
 import resize from './mixins/resize'
+require('echarts/theme/macarons') // echarts theme
 
 const animationDuration = 3000