duanshenglang 5 hari lalu
induk
melakukan
6517cd9639
2 mengubah file dengan 496 tambahan dan 12 penghapusan
  1. 118 12
      lottery/bigJxs.html
  2. 378 0
      lottery/js/hierarchyFilter.js

+ 118 - 12
lottery/bigJxs.html

@@ -21,6 +21,7 @@
   <script src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
   <script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script>
   <script src="js/select-date.js"></script>
+  <script src="js/hierarchyFilter.js"></script>
   <script
     src="https://wl-1306604067.cos.ap-guangzhou.myqcloud.com/production/ct/103548289110001/1758187289797/echarts.js"></script>
   <script src="js/echarts-wordcloud.js"></script>
@@ -152,7 +153,7 @@
     top: 44px;
     left: 0;
     width: 100%;
-    z-index: 2;
+    z-index: 1;
   }
 
   .top_data_bottom {
@@ -248,6 +249,7 @@
   .top_data_title {
     display: flex;
     align-items: center;
+    flex-shrink: 0;
   }
 
   .top_data_right {
@@ -278,7 +280,18 @@
     text-overflow: ellipsis;
     /* 显示省略号 */
   }
-
+  .top_data_title_branch2 {
+    font-weight: 400;
+    font-size: 12px;
+    color: #222222;
+    max-width: 180px;
+    white-space: nowrap;
+    /* 禁止换行 */
+    overflow: hidden;
+    /* 隐藏溢出内容 */
+    text-overflow: ellipsis;
+    /* 显示省略号 */
+  }
   .triangle {
     width: 0;
     height: 0;
@@ -373,7 +386,7 @@
   }
 
   .date_list {
-    width: 212px;
+    /* width: 212px; */
     box-sizing: border-box;
     display: flex;
     align-items: center;
@@ -624,6 +637,98 @@
     align-items: center;
     justify-content: center;
   }
+
+  /* 层级筛选样式 */
+  .hierarchy_title {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 13px 15px;
+    box-sizing: border-box;
+    font-weight: 500;
+    font-size: 14px;
+    color: #222222;
+    line-height: 20px;
+  }
+  .hierarchy_filter {
+    display: flex;
+    align-items: center;
+  }
+
+  .hierarchy_filter_trigger {
+    display: flex;
+    align-items: center;
+    cursor: pointer;
+    box-sizing: border-box;
+  }
+
+  .hierarchy_filter_trigger .top_data_title_branch {
+    font-weight: 400;
+    font-size: 12px;
+    color: #222222;
+    max-width: 90px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .hierarchy_filter_trigger .triangle {
+    width: 0;
+    height: 0;
+    border: 6px solid transparent;
+    border-top-color: #222222;
+    margin-top: 6px;
+    border-radius: 5px;
+    margin-left: 5px;
+  }
+
+  .hierarchy_panel {
+    display: flex;
+    padding: 12px 16px 8px;
+    box-sizing: border-box;
+    background: #fff;
+  }
+
+  .hierarchy_column {
+    flex: 1;
+    max-height: 320px;
+    overflow-y: auto;
+    padding-right: 8px;
+  }
+
+  .hierarchy_column + .hierarchy_column {
+    border-left: 1px solid #f0f2f5;
+    padding-left: 8px;
+  }
+
+  .hierarchy_item {
+    font-size: 14px;
+    color: #333;
+    padding: 8px 10px;
+    border-radius: 6px;
+    margin-bottom: 6px;
+    background: #f7f9fc;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .hierarchy_item--active {
+    background: #1677ff;
+    color: #fff;
+  }
+
+  .hierarchy_actions {
+    display: flex;
+    justify-content: flex-end;
+    padding: 8px 16px 12px;
+    background: #fff;
+    border-top: 1px solid #f0f2f5;
+  }
+
+  .hierarchy_actions .van-button + .van-button {
+    margin-left: 8px;
+  }
 </style>
 
 <body>
@@ -644,18 +749,14 @@
           <div class="top_data_title_text">{{pageTitle}}</div>
         </div>
         <div class="top_data_right" v-if="pageTitle === '客户资产'">
-          <div class="top_data_title item_gap" @click="showPicker = true">
-            <div class="top_data_title_branch">网点:{{outletName}}</div>
-            <div class="triangle"></div>
-          </div>
-          <div class="top_data_title" @click="showDeptPicker = true">
-            <div class="top_data_title_branch">部门:{{deptName}}</div>
-            <div class="triangle"></div>
-          </div>
+          <hierarchy-filter :tenancy-Id="tenancyId" :token="token" @on-change="handleHierarchyChange"></hierarchy-filter>
         </div>
         <select-date v-else :page-date="pageDate" @change-date="handleChangeDate"></select-date>
       </div>
-      <div class="top_data_bottom" v-show="pageTitle !== '客户资产'">
+      <div class="top_data_bottom" v-show="pageTitle === '聊天分析' || pageTitle === '运营任务'">
+        <hierarchy-filter :tenancy-Id="tenancyId" :token="token" @on-change="handleHierarchyChange"></hierarchy-filter>
+      </div>
+      <div class="top_data_bottom" v-show="pageTitle === '员工监测'">
         <div class="outlet_data item_gap" @click="showPicker = true">
           <div class="top_data_title_branch">网点:{{outletName}}</div>
           <div class="triangle"></div>
@@ -1320,6 +1421,11 @@
       this.getAdminList()
     },
     methods: {
+      handleHierarchyChange (departmentIds, outletIds, tenancyIds) {
+        console.log('departmentIds', departmentIds)
+        console.log('outletIds', outletIds)
+        console.log('tenancyIds', tenancyIds)
+      },
       // 初始化
       initialization() {
         this.clientIndicators = []

+ 378 - 0
lottery/js/hierarchyFilter.js

@@ -0,0 +1,378 @@
+var hierarchy_tpl = `
+  <div class="hierarchy_filter">
+    <div class="hierarchy_filter_trigger" @click="showPopup = true">
+      <div class="top_data_title_branch2">{{ label }}:{{ displayText || placeholder }}</div>
+      <div class="triangle"></div>
+    </div>
+    <van-popup v-model="showPopup"  duration="0.2" round position="bottom" :close-on-click-overlay="false" :style="{ width: '100%' }">
+      <div class="hierarchy_title">
+        <div class="close_icon"></div>
+        <div>层级筛选</div>
+        <img class="close_icon" src="./img/qw/close_icon.png" alt="" @click="showPopup = false">
+      </div>
+      <div class="hierarchy_panel">
+        <!-- 城市 -->
+        <div class="hierarchy_column">
+          <div
+            v-for="city in cityOptionsData"
+            :key="city.value"
+            :class="['hierarchy_item', { 'hierarchy_item--active': city.value === activeCityValue }]"
+            @click="selectCity(city)"
+          >
+            {{ city.label }}
+          </div>
+        </div>
+        <!-- 门店 -->
+        <div class="hierarchy_column" v-if="currentOutlets.length">
+          <div
+            v-for="outlet in currentOutlets"
+            :key="outlet.value"
+            :class="['hierarchy_item', { 'hierarchy_item--active': outlet.value === activeOutletValue }]"
+            @click="selectOutlet(outlet)"
+          >
+            {{ outlet.label }}
+          </div>
+        </div>
+        <!-- 部门 -->
+        <div class="hierarchy_column" v-if="currentDepartments.length">
+          <div
+            v-for="dept in currentDepartments"
+            :key="dept.value"
+            :class="['hierarchy_item', { 'hierarchy_item--active': dept.value === activeDeptValue }]"
+            @click="selectDepartment(dept)"
+          >
+            {{ dept.label }}
+          </div>
+        </div>
+      </div>
+      <div class="hierarchy_actions">
+        <van-button size="small" @click="handleClear">重置</van-button>
+        <van-button size="small" type="primary" @click="handleConfirm">确定</van-button>
+      </div>
+    </van-popup>
+  </div>
+`
+
+var hierarchyComponent = Vue.extend({
+  template: hierarchy_tpl,
+
+  props: {
+    tenancyId: {
+      type: [Number, String],
+      default: () => ''
+    },
+    token: {
+      type: String,
+      default: () => ''
+    },
+    // 绑定值(选中路径的 value 数组)
+    value: {
+      type: Array,
+      default: function () {
+        return []
+      },
+    },
+    // 外部可直接传入完整的层级数据(结构与原 aa.vue 一致)
+    options: {
+      type: Array,
+      default: function () {
+        return []
+      },
+    },
+    // 标签文本
+    label: {
+      type: String,
+      default: '筛选',
+    },
+    // 占位符
+    placeholder: {
+      type: String,
+      default: '全部',
+    },
+    // 是否显示连接符
+    showConnector: {
+      type: Boolean,
+      default: true,
+    },
+    // 连接符
+    connector: {
+      type: String,
+      default: '-',
+    },
+    // 是否展示城市层级(与原组件保持一致,预留)
+    showCityOptions: {
+      type: Boolean,
+      default: true,
+    },
+  },
+
+  data: function () {
+    return {
+      httpUrl: '',
+      env: '',
+      showPopup: false,
+      internalValue: [],
+      cityOptionsData: [],
+      activeCityValue: null,
+      activeOutletValue: null,
+      activeDeptValue: null,
+    }
+  },
+
+  computed: {
+    // 当前门店列表
+    currentOutlets: function () {
+      var city = this.cityOptionsData.find(function (item) {
+        return String(item.value) === String(this.activeCityValue)
+      }.bind(this))
+      return city && city.children ? city.children : []
+    },
+    // 当前部门列表
+    currentDepartments: function () {
+      var outlets = this.currentOutlets
+      var outlet = outlets.find(function (item) {
+        return String(item.value) === String(this.activeOutletValue)
+      }.bind(this))
+      return outlet && outlet.children ? outlet.children : []
+    },
+    // 展示文本
+    displayText: function () {
+      if (!this.internalValue.length) return ''
+      var labels = this.getLabelsByValues(this.internalValue)
+      if (!labels.length) return ''
+      if (labels[0] === '全部') return '全部'
+      var lastTwo = labels.slice(-2).map(function (l) {
+        return String(l).replace(/-/g, '')
+      })
+      return this.showConnector ? lastTwo.join(this.connector) : lastTwo.join('')
+    },
+  },
+
+  watch: {
+    value: {
+      immediate: true,
+      handler: function (val) {
+        this.internalValue = (val || []).slice()
+        this.syncActiveFromValue()
+      },
+    },
+    options: {
+      immediate: true,
+      handler: function (list) {
+        if (Array.isArray(list) && list.length) {
+          this.cityOptionsData = list
+        }
+      },
+    },
+  },
+
+  created: function () {
+    this.env = this.getQueryParam('env')
+
+    if (!this.env || this.env === 'prod') {
+      this.httpUrl = 'https://wlapi.wefanbot.com'
+    } else {
+      this.httpUrl = 'http://test.wefanbot.com:18993'
+    }
+    // 如果外部没有传 options,则可以在这里按需请求
+    // 由于 lottery 项目中未必有 $http,这里只保留占位逻辑,避免直接报错
+    if ((!this.options || !this.options.length) && typeof this.getCityOptions === 'function') {
+      this.getCityOptions()
+    }
+  },
+
+  methods: {
+    // 获取城市-门店-部门层级数据(与 aa.vue 保持同结构)
+    getCityOptions() {
+      var headers = new Headers()
+      headers.append('tenancyId', this.tenancyId)
+      headers.append('token', this.token)
+      fetch(this.httpUrl + '/scrm/v1/tenancy-city/city-outlet-depart-options', {
+        method: 'GET',
+        headers: headers,
+      })
+        .then(function (res) {
+          return res.json()
+        })
+        .then(function (result) {
+          var data = result.data
+          var code = result.code
+          var msg = result.msg
+          if (code === 1) {
+            var list = Array.isArray(data) ? data : (data && (data.records || data.list)) || []
+            this.cityOptionsData =
+              list && list.length
+                ? [
+                    {
+                      value: 'allCity',
+                      label: '全部城市',
+                    },
+                    ].concat(
+                      list.map(function (j) {
+                        return {
+                          value: j.cityAreaNo,
+                          label: j.cityName,
+                          children:
+                            j.outlets && j.outlets.length
+                              ? [
+                                  {
+                                    value: 'outlet_' + j.cityAreaNo,
+                                    label: '全部门店',
+                                  },
+                                ].concat(
+                                  j.outlets.map(function (k) {
+                                    return {
+                                      value: k.outletId,
+                                      label: k.outletName,
+                                      outletId: k.outletId,
+                                      children:
+                                        k.departments && k.departments.length
+                                          ? [
+                                              {
+                                                value: 'department_' + k.outletId,
+                                                label: '全部部门',
+                                              },
+                                            ].concat(
+                                              k.departments.map(function (p) {
+                                                return {
+                                                  value: p.departmentId,
+                                                  label: p.departmentName,
+                                                }
+                                              })
+                                            )
+                                          : [],
+                                    }
+                                  })
+                                )
+                              : [],
+                        }
+                      })
+                    )
+                : []
+          } else {
+            vant.Toast.fail(msg || '获取城市选项失败')
+          }
+        }.bind(this))
+        .catch(function () {
+          vant.Toast.fail('获取城市选项失败')
+        })
+    },
+    // 根据当前 internalValue 还原活动节点
+    syncActiveFromValue: function () {
+      var vals = this.internalValue
+      if (!vals || !vals.length) {
+        this.activeCityValue = null
+        this.activeOutletValue = null
+        this.activeDeptValue = null
+        return
+      }
+      this.activeCityValue = vals[0] != null ? vals[0] : null
+      this.activeOutletValue = vals[1] != null ? vals[1] : null
+      this.activeDeptValue = vals[2] != null ? vals[2] : null
+    },
+
+    // 根据 value 路径拿到 label 数组
+    getLabelsByValues: function (values) {
+      var labels = []
+      var level = this.cityOptionsData
+      for (var i = 0; i < values.length; i++) {
+        if (!level || !level.length) break
+        var val = values[i]
+        var node = null
+        for (var j = 0; j < level.length; j++) {
+          if (String(level[j].value) === String(val)) {
+            node = level[j]
+            break
+          }
+        }
+        if (!node) break
+        labels.push(node.label)
+        level = node.children || []
+      }
+      return labels
+    },
+
+    // 选择城市
+    selectCity: function (city) {
+      this.activeCityValue = city.value
+      this.activeOutletValue = null
+      this.activeDeptValue = null
+      this.internalValue = [city.value]
+    },
+
+    // 选择门店
+    selectOutlet: function (outlet) {
+      this.activeOutletValue = outlet.value
+      this.activeDeptValue = null
+      this.internalValue = [this.activeCityValue, outlet.value]
+    },
+
+    // 选择部门
+    selectDepartment: function (dept) {
+      this.activeDeptValue = dept.value
+      this.internalValue = [this.activeCityValue, this.activeOutletValue, dept.value]
+    },
+
+    // 清空选择
+    handleClear: function () {
+      this.activeCityValue = null
+      this.activeOutletValue = null
+      this.activeDeptValue = null
+      this.internalValue = []
+      this.$emit('input', [])
+      this.$emit('on-change', [], [], [])
+    },
+
+    // 确认选择,复用原 aa.vue 的 on-change 事件签名
+    handleConfirm: function () {
+      var values = this.internalValue.slice()
+      var departmentIds = []
+      var outletIds = []
+      var tenancyIds = []
+      if (values && values.length) {
+        var value = String(values[values.length - 1])
+        if (value !== 'allRegion' && value !== 'allCity' && value.indexOf('_') === -1) {
+          if (this.showCityOptions) {
+            departmentIds.push(Number(value))
+          } else {
+            tenancyIds.push(Number(value))
+          }
+        } else if (value.indexOf('department_') > -1) {
+          outletIds.push(Number(value.split('_')[1]))
+        } else if (value.indexOf('outlet_') > -1) {
+          var city = this.cityOptionsData.filter(function (item) {
+            return Number(item.value) === Number(value.split('_')[1])
+          })
+          if (city[0] && city[0].children) {
+            outletIds = city[0].children
+              .filter(function (item) {
+                return item.outletId
+              })
+              .map(function (item) {
+                return item.outletId
+              })
+          }
+        } else if (value.indexOf('city_') > -1) {
+          tenancyIds.push(Number(value.split('_')[1]))
+        } else if (value === 'allRegion' || value === 'allCity') {
+          departmentIds = []
+          outletIds = []
+          tenancyIds = []
+        }
+      }
+      this.$emit('input', values)
+      this.$emit('on-change', departmentIds, outletIds, tenancyIds)
+      this.showPopup = false
+    },
+    // 截取 url 中的 env(与 select-tag.js 保持一致)
+    getQueryParam: function (paramName) {
+      var queryString = window.location.search
+      var urlParams = new URLSearchParams(queryString)
+      return urlParams.get(paramName)
+    },
+  },
+})
+
+// 全局注册组件:<hierarchy-filter></hierarchy-filter>
+Vue.component('hierarchy-filter', hierarchyComponent)
+