liyongli 1 рік тому
батько
коміт
20722d1484
3 змінених файлів з 965 додано та 499 видалено
  1. 1 1
      src/config/index.js
  2. 436 498
      src/views/Jugou/Jugou.vue
  3. 528 0
      src/views/Jugou/Jugou_back01.vue

+ 1 - 1
src/config/index.js

@@ -44,7 +44,7 @@ export default {
     requestRetry: 4,
     requestRetryDelay: 800,
     token: '',
-    Intranet: 'http://172.16.101.20:8762',
+    Intranet: 'http://sxgd-media.oss-cn-xian-sxgd-d01-a.ops.cloud.sxtvs.com.cn',
   },
   order,
   tableCol,

+ 436 - 498
src/views/Jugou/Jugou.vue

@@ -1,527 +1,465 @@
 <template>
-  <div class="Jugou">
-    <el-loading></el-loading>
-    <el-card>
-      <el-form ref="form" size="small" :inline="true" label-width="120px">
-        <el-form-item label="日期">
-          <el-date-picker
-            style="width:100%;height: 58px"
-            v-model="date"
-            type="date"
-            placeholder="请选择日期"
-            value-format="YYYY-MM-DD"
-            :disabled-date="pickerOptions"
+  <el-card class="Jugou">
+    <el-form size="small" inline label-width="120px">
+      <el-form-item label="日期">
+        <el-date-picker
+          style="width: 100%; height: 58px"
+          v-model="date"
+          type="date"
+          placeholder="请选择日期"
+          value-format="YYYY-MM-DD"
+          :disabled-date="pickerOptions"
+        />
+      </el-form-item>
+      <el-form-item v-show="select != -1" label="频道">
+        <el-select
+          v-model="select"
+          placeholder="请选择频道"
+          @change="selectfun"
+        >
+          <el-option
+            v-for="item in list_channel"
+            :key="item.channelId || ''"
+            :label="item.channelName"
+            :value="item.channelId"
           />
-        </el-form-item>
-        <el-form-item v-show="select != -1" label="频道">
-          <el-select
-            v-model="select"
-            placeholder="请选择频道"
-            @change="selectfun"
-          >
-            <el-option
-              v-for="item in list"
-              :key="item.channelId || ''"
-              :label="item.channelName"
-              :value="item.channelId || ''"
-            />
-          </el-select>
-        </el-form-item>
-        <el-form-item style="float: right">
-          <el-button type="primary" @click="getData">查询</el-button>
-        </el-form-item>
-      </el-form>
-      <div style="padding: 0 100px">
-        <div style="position: relative;">
-          <video
-            controls
-            autoplay
-            ref="video"
-            @timeupdate="timeupdate"
-            @error="videoerror"
-            @canplay="videoload"
-            :src="videoUrl"
-          />
-          <img
-            v-show="videoerrorStart"
-            class="videoerror"
-            src="../../assets/img/videoerror.png"
-          />
-        </div>
-        <div style="position: relative;">
-          <div
-            class="chart"
-            ref="chart"
-            style="width: 100%;min-height: 300px;"
-          ></div>
-          <div class="lineinfobackground" :style="'left:' + leftNum + 'px'">
-            <div style="position: relative;width: 100%;height: 100%">
-              <div class="line"></div>
-              <el-row style="padding: 10px 0 0 20px">
-                <el-col :span="6">
-                  <span class="icon" style="background-color: #e05c5c"></span>
-                  流入
-                </el-col>
-                <el-col :span="6">
-                  <span class="icon" style="background-color: #6ab581"></span>
-                  流出
-                </el-col>
-                <el-col :span="12">
-                  <span class="iconLine"></span>
-                  收视率%
-                  <div style="float: right;padding: 0 5px 0 0">
-                    {{ tof(nowItem.audienceRating, 4) }}%
-                  </div>
-                </el-col>
-              </el-row>
-              <div style="padding: 5px 20px">
-                当前时间:{{
-                  nowItem.date ? nowItem.date.split(" ")[1] || "" : ""
-                }}
-                <div style="float: right">
-                  人数: {{ formateNum(nowItem.uv) }}
+        </el-select>
+      </el-form-item>
+      <el-form-item style="float: right">
+        <el-button type="primary" @click="getData">查询</el-button>
+      </el-form-item>
+    </el-form>
+    <div ref="bg">
+      <video
+        controls
+        autoplay
+        ref="video"
+        @timeupdate="timeupdate"
+        :src="vUrl"
+      />
+
+      <div style="position: relative">
+        <div ref="chartEle"></div>
+        <div class="lineinfobackground" :style="'left:' + leftNum + 'px'">
+          <div style="position: relative; width: 100%; height: 100%">
+            <div class="line"></div>
+            <el-row style="padding: 10px 0 0 10px">
+              <el-col :span="6">
+                <span class="icon" style="background-color: #e05c5c"></span>
+                流入
+              </el-col>
+              <el-col :span="6">
+                <span class="icon" style="background-color: #6ab581"></span>
+                流出
+              </el-col>
+              <el-col :span="12">
+                <span class="iconLine"></span>
+                收视率%
+                <div style="float: right; padding: 0 5px 0 0">
+                  {{ tof(jindu.audienceRating, 4) }}%
                 </div>
-              </div>
-              <el-row>
-                <el-col :span="12">
-                  <div style="padding: 0 20px">
-                    流入排行
-                    <div>
-                      <div
-                        style="font-size: 12px;line-height: 22px;"
-                        v-for="(item, i) in left"
-                        :key="i"
-                        v-text="item"
-                      ></div>
-                    </div>
+              </el-col>
+            </el-row>
+            <div style="padding: 5px 10px">
+              当前时间:{{ jindu.date ? jindu.date.split(' ')[1] || '' : '' }}
+              <div style="float: right">人数: {{ formateNum(jindu.uv) }}</div>
+            </div>
+            <el-row>
+              <el-col :span="12">
+                <div style="padding: 0 10px">
+                  流入排行
+                  <div>
+                    <div
+                      style="font-size: 12px; line-height: 22px"
+                      v-for="(item, i) in jindu.lrTop"
+                      :key="i"
+                      v-text="item"
+                    ></div>
                   </div>
-                </el-col>
-                <el-col :span="12">
-                  <div style="padding: 0 20px">
-                    流出排行
-                    <div>
-                      <div
-                        style="font-size: 12px;line-height: 22px;"
-                        v-for="(item, i) in right"
-                        :key="i"
-                        v-text="item"
-                      ></div>
-                    </div>
+                </div>
+              </el-col>
+              <el-col :span="12">
+                <div style="padding: 0 10px">
+                  流出排行
+                  <div>
+                    <div
+                      style="font-size: 12px; line-height: 22px"
+                      v-for="(item, i) in jindu.lcTop"
+                      :key="i"
+                      v-text="item"
+                    ></div>
                   </div>
-                </el-col>
-              </el-row>
-            </div>
+                </div>
+              </el-col>
+            </el-row>
           </div>
         </div>
       </div>
-    </el-card>
-  </div>
+    </div>
+  </el-card>
 </template>
 
-<script>
+<script setup>
 // @ is an alias to /src
-import { defaultAjax, leverAudience } from "@/api/index";
-import config from "@/config/index";
+import { leverAudience, defaultAjax } from '@/api/index';
+import * as echarts from 'echarts';
+import config from '@/config/index';
+import { ref, onMounted } from 'vue';
 
-import { markRaw } from "vue";
-const ElLoading = require("element-plus/lib/el-loading/index");
-import "element-plus/lib/theme-chalk/el-loading.css";
-
-import * as echarts from "echarts";
+let select_channel = {};
+const list_channel = ref([]);
+const select = ref('');
+const date = ref('');
+const vUrl = ref('');
 
+const video = ref(null);
+const bg = ref(null);
+const leftNum = ref(130);
+const chartEle = ref(null);
+const jindu = ref({});
+let chart = undefined;
+let timeout = undefined;
+let isClick = false;
+let list = [];
 let sec = 0,
-  timeout = undefined,
-  isplay = false,
-  isClick = false,
-  stepNum = 6.8,
-  page = 0;
-export default {
-  name: "Channel",
-  data() {
-    return {
-      videoerrorStart: false,
-      list: [],
-      select: -1,
-      channel: "",
-      leftNum: 50,
-      videoUrl: "",
-      date: "",
-      myChart: undefined,
-      orgLi: [],
-      nowItem: {},
-      left: [],
-      right: [],
-      load: undefined,
-    };
-  },
-  mounted() {
-    this.load = ElLoading.default.service();
-    leverAudience().then(res => {
-      this.list = res || [];
-      for (let i = 0; i < this.list.length; i++) {
-        const v = this.list[i];
-        if (v.isDefault == 0) continue;
-        this.select = v.channelId || "";
-        this.date = v.dt || "";
-        break
-      }
-      this.getData();
+  stepNum = 0;
+
+onMounted(() => {
+  chart = echarts.init(chartEle.value);
+  chart.resize({
+    height: 300,
+    width: bg.value.offsetWidth,
+  });
+
+  chart.on('datazoom', () => {
+    if (isClick) return;
+    isClick = true;
+    if (timeout) clearTimeout(timeout), (timeout = undefined);
+    video.value.pause();
+    timeout = setTimeout(() => {
+      clearTimeout(timeout);
+      timeout = undefined;
+      isClick = false;
+      //  拖拽后的事件
+      video.value.currentTime = chart.getOption().dataZoom[0].startValue;
+      stepNum =
+        chart.getOption().dataZoom[0].endValue -
+        chart.getOption().dataZoom[0].startValue;
+      video.value.play();
+    }, 200);
+  });
+});
+
+// 获取频道列表
+leverAudience().then(res => {
+  let li = res || [];
+  for (let i = 0; i < li.length; i++) {
+    const v = li[i];
+    li[i].dataUrl = li[i].dataUrl.replace('{$channel_id}', v.channelId);
+    li[i].videoUrl =
+      config.base.Intranet +
+      li[i].videoUrl.replace('{$channel_id}', v.channelId);
+    if (v.isDefault == 0) continue;
+    select_channel = v;
+  }
+  list_channel.value = li;
+  select.value = select_channel.channelId || '';
+  date.value = select_channel.dt || '';
+  getData();
+});
+
+function pickerOptions(d) {
+  let startDate = new Date('2022/04/11').getTime(),
+    nowDate = d.getTime();
+  startDate = startDate - (startDate % 86400000);
+  nowDate = nowDate - (nowDate % 86400000);
+  let out = nowDate < startDate || nowDate >= Date.now() - 172800000;
+  return out;
+}
+
+function selectfun(par) {
+  select_channel =
+    list_channel.value.find(v => v.channelId == par) || undefined;
+  if (!select_channel) return;
+  select.value = select_channel.channelId || '';
+  date.value = select_channel.dt || '';
+}
+
+function getData() {
+  const date_time = date.value.replace(/-/g, '');
+  let video = select_channel.videoUrl.split('{yyyyMMdd}');
+  vUrl.value = video[0] + date_time + video[1];
+
+  const data_url = select_channel.dataUrl.split('{yyyyMMdd}');
+  defaultAjax({
+    url: data_url[0] + date_time + data_url[1],
+  }).then(r => {
+    const li = r || {};
+    const Ir = [],
+      Ic = [],
+      ad = [],
+      keys = [];
+
+    for (const key in li) {
+      if (!Object.hasOwnProperty.call(li, key)) continue;
+      const v = li[key];
+      keys.push(key);
+      Ic.push(-1 * v.lc);
+      Ir.push(v.lr);
+      ad.push(v.audienceRating * 100);
+      v.date = key;
+      list.push(v);
+    }
+
+    stepNum = list.length;
+    draw(keys, Ir, Ic, ad);
+    jindu.value = list[0];
+  });
+}
+
+function timeupdate(v) {
+  // 播放中
+  if (sec === Math.floor(v.srcElement.currentTime)) return;
+  sec = Math.floor(v.srcElement.currentTime);
+  let s = chart.getOption().dataZoom[0].startValue,
+    e = chart.getOption().dataZoom[0].endValue;
+  let item = list[sec] || {};
+  jindu.value = item;
+  if (sec >= e) {
+    // 切页
+    chart.setOption({
+      dataZoom: {
+        startValue: e + 1,
+        endValue: e + 1 + e - s,
+      },
     });
-  },
-  computed: {},
-  methods: {
-    pickerOptions(d) {
-      let startDate = new Date("2022/04/11").getTime(),
-        nowDate = d.getTime();
-      startDate = startDate - (startDate % 86400000);
-      nowDate = nowDate - (nowDate % 86400000);
-      let out = nowDate < startDate || nowDate >= Date.now() - 172800000
-      return out;
-    },
-    getData() {
-      if (!this.load) this.load = ElLoading.default.service();
-      let item = {},
-        d = this.date.replace(/-/g, "");
-      for (let i = 0; i < this.list.length; i++) {
-        const v = this.list[i];
-        if (v.channelId !== this.select) continue;
-        item = v;
-        break;
-      }
-      let url = item.dataUrl
-        .replace("/{yyyyMMdd}/", "/" + d + "/")
-        .replace(/^https?:/, location.protocol)
-        .replace("{$channel_id}", this.select);
-      let videoUrl = item.videoUrl;
-      videoUrl = videoUrl
-        .replace("/{yyyyMMdd}/", "/" + d + "/")
-        .replace(/^https?:/, location.protocol);
-      this.videoUrl = config.base.Intranet + "/minio" + videoUrl.replace("{$channel_id}", this.select);
-      defaultAjax({
-        url,
-      })
-        .then(res => {
-          this.load.close();
-          let org = res || {},
-            li = [];
-          Object.keys(org).map(v => {
-            org[v].date = v;
-            li.push(org[v]);
-          });
-          if (!li.length) return;
-          this.orgLi = li;
-          this.nowItem = li[0];
-          this.left = li[0].lrTop || [];
-          this.right = li[0].lcTop || [];
-          return this.chart();
-        })
-        .catch(() => {
-          this.load.close();
-        });
-    },
-    tof(num, t) {
-      return Number(num * 100).toFixed(t || 2);
-    },
-    selectChannel(item) {
-      if (this.channel === item.channelName) return;
-      this.channel = item.channelName;
-    },
-    chart() {
-      if (!this.myChart) {
-        this.myChart = markRaw(echarts.init(this.$refs.chart));
-        this.myChart.resize({
-          height: 300,
-        });
-        this.myChart.on("datazoom", () => {
-          if (isClick) return;
-          isClick = true;
-          let funisplay = !this.$refs.video.paused;
-          if (timeout) clearTimeout(timeout), (timeout = undefined);
-          this.$refs.video.pause();
-          this.leftNum = 50;
-          timeout = setTimeout(() => {
-            clearTimeout(timeout);
-            timeout = undefined;
-            isClick = false;
-            //  拖拽后的事件
-            isplay = funisplay;
-            this.leftNum = 50;
-            this.$refs.video.currentTime = this.myChart.getOption().dataZoom[0].startValue;
-            if (isplay) this.$refs.video.play();
-            else this.$refs.video.pause();
-          }, 200);
-        });
-      }
-      let timeAll = [],
-        Irdata = [],
-        Icdata = [],
-        audienceRating = [];
-      this.orgLi.map(v => {
-        v.date && timeAll.push(v.date.split(" ")[1] || "");
-        Icdata.push(-1 * v.lc);
-        Irdata.push(v.lr);
-        audienceRating.push(v.audienceRating * 100);
-      });
-      this.myChart.setOption({
-        dataZoom: [
-          {
-            maxSpan: 10,
-            minSpan: 5,
-            type: "slider",
-            brushSelect: false,
-            // zoomLock: false,
-            show: true,
-            realtime: true,
-            start: stepNum * page,
-            end: stepNum * (page + 1),
-            zoomOnMouseWheel: false,
-            height: "30",
-            top: "85%",
-            handleIcon:
-              "path://M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z",
-            handleSize: 15,
-            textStyle: {
-              color: "#c5c6cc",
-            },
-            dataBackground: {
-              lineStyle: {
-                color: "#fff",
-              },
-              areaStyle: {
-                color: "#8b51a8",
-              },
-            },
-          },
-        ],
-        xAxis: {
-          data: timeAll,
-          position: "top",
-          silent: false,
-          axisLabel: {
-            interval: "auto",
-            color: "#000",
-            rotate: "-90",
-          },
+    leftNum.value = 130;
+    return;
+  }
+  let width = bg.value.offsetWidth - 260;
+  let cValue = sec - s;
+  let iWdith = width / (e - s);
+  leftNum.value = cValue * iWdith + 130;
+}
+
+function formateNum(n) {
+  let num = n;
+  if (isNaN(n)) num = '0';
+  else if (n >= 100000000)
+    num =
+      ((n / 100000000).toFixed(2) - 0 + '').replace(
+        /\B(?=(?:\d{3})+\b)/g,
+        ','
+      ) + '亿';
+  else if (n >= 10000)
+    num =
+      ((n / 10000).toFixed(2) - 0 + '').replace(/\B(?=(?:\d{3})+\b)/g, ',') +
+      '万';
+  else num = (num + '').replace(/\B(?=(?:\d{3})+\b)/g, ',');
+  return num;
+}
+
+function tof(num, t) {
+  return Number(num * 100).toFixed(t || 2);
+}
+
+function draw(key, Ir, Ic, ad) {
+  // 绘图
+  let option = {
+    dataZoom: [
+      {
+        maxSpan: 100,
+        minSpan: 1,
+        type: 'slider',
+        brushSelect: false,
+        // zoomLock: false,
+        show: true,
+        realtime: true,
+        startValue: 0,
+        endValue: stepNum,
+        zoomOnMouseWheel: false,
+        height: '30',
+        top: '85%',
+        handleIcon:
+          'path://M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
+        handleSize: 15,
+        textStyle: {
+          color: '#c5c6cc',
         },
-        yAxis: [
-          {
-            scale: false,
-            nameGap: 6,
-            inverse: false,
-            name: "流入流出",
-            nameLocation: "start",
-            splitArea: {
-              show: false,
-            },
-            splitLine: {
-              show: false,
-            },
-            axisLabel: {
-              color: "#000",
-              formatter: function(value) {
-                let v = value;
-                if (v < 0) v *= -1;
-                return v;
-              },
-            },
-            axisTick: {
-              show: false,
-            },
-            axisLine: {
-              show: false,
-            },
-            nameTextStyle: {
-              color: "#000",
-            },
+        dataBackground: {
+          lineStyle: {
+            color: '#fff',
           },
-          {
-            scale: true,
-            nameGap: 6,
-            type: "value",
-            name: "收视率%",
-            nameLocation: "start",
-            splitLine: {
-              show: false,
-            },
-            axisTick: {
-              show: false,
-            },
-            axisLine: {
-              show: false,
-            },
-            axisLabel: {
-              color: "#000",
-            },
-            nameTextStyle: {
-              color: "#000",
-            },
+          areaStyle: {
+            color: '#8b51a8',
           },
-        ],
-        grid: {
-          left: 50,
-          right: 50,
         },
-        series: [
-          {
-            name: "流入",
-            type: "bar",
-            yAxisIndex: 0,
-            stack: "one",
-            data: Irdata,
-            sampling: "lttb",
-            emphasis: {
-              focus: "series",
-            },
-            itemStyle: {
-              color: "#df5a5a",
-            },
-          },
-          {
-            name: "流出",
-            type: "bar",
-            yAxisIndex: 0,
-            sampling: "lttb",
-            stack: "one",
-            data: Icdata,
-            emphasis: {
-              focus: "series",
-            },
-            itemStyle: {
-              color: "#6ab581",
-            },
-          },
-          {
-            name: "收视率%",
-            type: "line",
-            yAxisIndex: 1,
-            smooth: true,
-            showSymbol: false,
-            data: audienceRating,
-            lineStyle: {
-              width: 1,
-              color: "#50abfd",
-            },
-          },
-        ],
-      });
+      },
+    ],
+    xAxis: {
+      data: key,
+      position: 'top',
+      silent: false,
+      axisLabel: {
+        interval: 'auto',
+        color: '#000',
+        rotate: '-90',
+      },
     },
-    timeupdate(v) {
-      if (sec === Math.floor(v.srcElement.currentTime)) return;
-      sec = Math.floor(v.srcElement.currentTime);
-      let width = this.$refs.chart.offsetWidth - 100;
-      let item = this.orgLi[sec] || {};
-      let s = this.myChart.getOption().dataZoom[0].startValue,
-        e = this.myChart.getOption().dataZoom[0].endValue;
-      let iW = width / (e - s),
-        cheng = sec - s < 0 ? 0 : sec - s;
-      let step = iW * cheng > width ? 0 : iW * cheng;
-      if (!item.lrTop) return;
-      this.nowItem = item;
-      this.left = item.lrTop || [];
-      this.right = item.lcTop || [];
-      this.leftNum = 50 + step;
-      if (iW * cheng <= width) return;
-      page++;
-      this.myChart.setOption({
-        dataZoom: {
-          start: stepNum * page,
-          end: stepNum * (page + 1),
+    yAxis: [
+      {
+        scale: false,
+        nameGap: 6,
+        inverse: false,
+        name: '流入流出',
+        nameLocation: 'start',
+        splitArea: {
+          show: false,
         },
-      });
-    },
-    selectfun() {
-      let nowDate = new Date(this.date),
-        newDate = undefined;
-      for (let i = 0; i < this.list.length; i++) {
-        const v = this.list[i];
-        if (v.channelId !== this.select) continue;
-        newDate = v.dt;
-        break;
-      }
-      nowDate - new Date(newDate) > 0 ? (this.date = newDate) : "";
-    },
-    videoerror() {
-      this.videoerrorStart = true;
-    },
-    videoload() {
-      this.videoerrorStart = false;
-    },
-    formateNum(n) {
-      let num = n;
-      if (isNaN(n)) num = "0";
-      else if (n >= 100000000)
-        num =
-          ((n / 100000000).toFixed(2) - 0 + "").replace(
-            /\B(?=(?:\d{3})+\b)/g,
-            ","
-          ) + "亿";
-      else if (n >= 10000)
-        num =
-          ((n / 10000).toFixed(2) - 0 + "").replace(
-            /\B(?=(?:\d{3})+\b)/g,
-            ","
-          ) + "万";
-      else num = (num + "").replace(/\B(?=(?:\d{3})+\b)/g, ",");
-      return num;
+        splitLine: {
+          show: false,
+        },
+        axisLabel: {
+          color: '#000',
+          formatter: function (value) {
+            let v = value;
+            if (v < 0) v *= -1;
+            return v;
+          },
+        },
+        axisTick: {
+          show: false,
+        },
+        axisLine: {
+          show: false,
+        },
+        nameTextStyle: {
+          color: '#000',
+        },
+      },
+      {
+        scale: true,
+        nameGap: 6,
+        type: 'value',
+        name: '收视率%',
+        nameLocation: 'start',
+        splitLine: {
+          show: false,
+        },
+        axisTick: {
+          show: false,
+        },
+        axisLine: {
+          show: false,
+        },
+        axisLabel: {
+          color: '#000',
+        },
+        nameTextStyle: {
+          color: '#000',
+        },
+      },
+    ],
+    grid: {
+      left: 130,
+      right: 130,
     },
-  },
-  components: {},
-};
+    series: [
+      {
+        name: '收视率%',
+        type: 'line',
+        yAxisIndex: 1,
+        smooth: true,
+        showSymbol: false,
+        data: ad,
+        lineStyle: {
+          width: 1,
+          color: '#50abfd',
+        },
+      },
+      {
+        name: '流入',
+        type: 'bar',
+        yAxisIndex: 0,
+        stack: 'one',
+        data: Ir,
+        sampling: 'lttb',
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: {
+          color: '#df5a5a',
+        },
+      },
+      {
+        name: '流出',
+        type: 'bar',
+        yAxisIndex: 0,
+        sampling: 'lttb',
+        stack: 'one',
+        data: Ic,
+        emphasis: {
+          focus: 'series',
+        },
+        itemStyle: {
+          color: '#6ab581',
+        },
+      },
+    ],
+  };
+  option && chart.setOption(option);
+}
 </script>
 
-<style>
+<style lang="scss">
 .Jugou {
-  min-width: 1149px;
   padding: 10px 12px;
-}
 
-.Jugou video {
-  width: 100%;
-  height: 500px;
-  background-color: #000;
-}
-.Jugou .lineinfobackground {
-  font-size: 12px;
-  border-radius: 9px;
-  position: absolute;
-  width: 345px;
-  height: 200px;
-  top: 30px;
-  left: 50px;
-  background: rgba(0, 0, 0, 0.5);
-  transform: translateX(-50%);
-  color: #fff;
-  /* opacity: 0.5; */
-}
-.Jugou .lineinfobackground .line {
-  position: absolute;
-  width: 2px;
-  height: 120%;
-  margin-top: -5%;
-  margin-left: 50%;
-  background-color: #888;
-}
-.Jugou .lineinfobackground .icon {
-  display: inline-block;
-  width: 30px;
-  height: 10px;
-  border-radius: 10px;
-}
-.Jugou .lineinfobackground .iconLine {
-  background-color: #50abfd;
-  display: inline-block;
-  width: 30px;
-  height: 2px;
-  vertical-align: middle;
-  border-radius: 10px;
-}
-.Jugou .videoerror {
-  position: absolute;
-  top: 50%;
-  left: 50%;
-  transform: translate(-50%, -50%);
-}
-video::-webkit-media-controls-timeline {
-  display: none;
+  video {
+    width: 100%;
+    height: 500px;
+    background-color: #000;
+    &::-webkit-media-controls-timeline {
+      display: none;
+    }
+  }
+
+  .lineinfobackground {
+    font-size: 12px;
+    border-radius: 9px;
+    position: absolute;
+    width: 305px;
+    height: 200px;
+    top: 30px;
+    left: 50px;
+    background: rgba(0, 0, 0, 0.5);
+    transform: translateX(-50%);
+    color: #fff;
+
+    .line {
+      position: absolute;
+      width: 2px;
+      height: 110%;
+      margin-top: -5%;
+      margin-left: 50%;
+      background-color: #888;
+    }
+
+    .icon {
+      display: inline-block;
+      width: 30px;
+      height: 10px;
+      border-radius: 10px;
+    }
+
+    .iconLine {
+      background-color: #50abfd;
+      display: inline-block;
+      width: 30px;
+      height: 2px;
+      vertical-align: middle;
+      border-radius: 10px;
+    }
+  }
 }
 </style>

+ 528 - 0
src/views/Jugou/Jugou_back01.vue

@@ -0,0 +1,528 @@
+<template>
+  <div class="Jugou">
+    <el-loading></el-loading>
+    <el-card>
+      <el-form ref="form" size="small" :inline="true" label-width="120px">
+        <el-form-item label="日期">
+          <el-date-picker
+            style="width:100%;height: 58px"
+            v-model="date"
+            type="date"
+            placeholder="请选择日期"
+            value-format="YYYY-MM-DD"
+            :disabled-date="pickerOptions"
+          />
+        </el-form-item>
+        <el-form-item v-show="select != -1" label="频道">
+          <el-select
+            v-model="select"
+            placeholder="请选择频道"
+            @change="selectfun"
+          >
+            <el-option
+              v-for="item in list"
+              :key="item.channelId || ''"
+              :label="item.channelName"
+              :value="item.channelId || ''"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item style="float: right">
+          <el-button type="primary" @click="getData">查询</el-button>
+        </el-form-item>
+      </el-form>
+      <div style="padding: 0 100px">
+        <div style="position: relative;">
+          <video
+            controls
+            autoplay
+            ref="video"
+            @timeupdate="timeupdate"
+            @error="videoerror"
+            @canplay="videoload"
+            :src="videoUrl"
+          />
+          <img
+            v-show="videoerrorStart"
+            class="videoerror"
+            src="../../assets/img/videoerror.png"
+          />
+        </div>
+        <div style="position: relative;">
+          <div
+            class="chart"
+            ref="chart"
+            style="width: 100%;min-height: 300px;"
+          ></div>
+          <div class="lineinfobackground" :style="'left:' + leftNum + 'px'">
+            <div style="position: relative;width: 100%;height: 100%">
+              <div class="line"></div>
+              <el-row style="padding: 10px 0 0 20px">
+                <el-col :span="6">
+                  <span class="icon" style="background-color: #e05c5c"></span>
+                  流入
+                </el-col>
+                <el-col :span="6">
+                  <span class="icon" style="background-color: #6ab581"></span>
+                  流出
+                </el-col>
+                <el-col :span="12">
+                  <span class="iconLine"></span>
+                  收视率%
+                  <div style="float: right;padding: 0 5px 0 0">
+                    {{ tof(nowItem.audienceRating, 4) }}%
+                  </div>
+                </el-col>
+              </el-row>
+              <div style="padding: 5px 20px">
+                当前时间:{{
+                  nowItem.date ? nowItem.date.split(" ")[1] || "" : ""
+                }}
+                <div style="float: right">
+                  人数: {{ formateNum(nowItem.uv) }}
+                </div>
+              </div>
+              <el-row>
+                <el-col :span="12">
+                  <div style="padding: 0 20px">
+                    流入排行
+                    <div>
+                      <div
+                        style="font-size: 12px;line-height: 22px;"
+                        v-for="(item, i) in left"
+                        :key="i"
+                        v-text="item"
+                      ></div>
+                    </div>
+                  </div>
+                </el-col>
+                <el-col :span="12">
+                  <div style="padding: 0 20px">
+                    流出排行
+                    <div>
+                      <div
+                        style="font-size: 12px;line-height: 22px;"
+                        v-for="(item, i) in right"
+                        :key="i"
+                        v-text="item"
+                      ></div>
+                    </div>
+                  </div>
+                </el-col>
+              </el-row>
+            </div>
+          </div>
+        </div>
+      </div>
+    </el-card>
+  </div>
+</template>
+
+<script>
+// @ is an alias to /src
+import { defaultAjax, leverAudience } from "@/api/index";
+import config from "@/config/index";
+
+import { markRaw } from "vue";
+const ElLoading = require("element-plus/lib/el-loading/index");
+import "element-plus/lib/theme-chalk/el-loading.css";
+
+import * as echarts from "echarts";
+
+let sec = 0,
+  timeout = undefined,
+  isplay = false,
+  isClick = false,
+  stepNum = 6.8,
+  page = 0;
+export default {
+  name: "Channel",
+  data() {
+    return {
+      videoerrorStart: false,
+      list: [],
+      select: -1,
+      channel: "",
+      leftNum: 50,
+      videoUrl: "",
+      date: "",
+      myChart: undefined,
+      orgLi: [],
+      nowItem: {},
+      left: [],
+      right: [],
+      load: undefined,
+    };
+  },
+  mounted() {
+    this.load = ElLoading.default.service();
+    leverAudience().then(res => {
+      this.list = res || [];
+      for (let i = 0; i < this.list.length; i++) {
+        const v = this.list[i];
+        if (v.isDefault == 0) continue;
+        this.select = v.channelId || "";
+        this.date = v.dt || "";
+        break
+      }
+      this.getData();
+    });
+  },
+  computed: {},
+  methods: {
+    pickerOptions(d) {
+      let startDate = new Date("2022/04/11").getTime(),
+        nowDate = d.getTime();
+      startDate = startDate - (startDate % 86400000);
+      nowDate = nowDate - (nowDate % 86400000);
+      let out = nowDate < startDate || nowDate >= Date.now() - 172800000
+      return out;
+    },
+    getData() {
+      if (!this.load) this.load = ElLoading.default.service();
+      let item = {},
+        d = this.date.replace(/-/g, "");
+      for (let i = 0; i < this.list.length; i++) {
+        const v = this.list[i];
+        if (v.channelId !== this.select) continue;
+        item = v;
+        break;
+      }
+      let url = item.dataUrl
+        .replace("/{yyyyMMdd}/", "/" + d + "/")
+        .replace(/^https?:/, location.protocol)
+        .replace("{$channel_id}", this.select);
+      let videoUrl = item.videoUrl;
+      videoUrl = videoUrl
+        .replace("/{yyyyMMdd}/", "/" + d + "/")
+        .replace(/^https?:/, location.protocol);
+      this.videoUrl = config.base.Intranet + videoUrl.replace("{$channel_id}", this.select);
+
+      defaultAjax({
+        url,
+      })
+        .then(res => {
+          this.load.close();
+          let org = res || {},
+            li = [];
+          Object.keys(org).map(v => {
+            org[v].date = v;
+            li.push(org[v]);
+          });
+          if (!li.length) return;
+          this.orgLi = li;
+          this.nowItem = li[0];
+          this.left = li[0].lrTop || [];
+          this.right = li[0].lcTop || [];
+          return this.chart();
+        })
+        .catch(() => {
+          this.load.close();
+        });
+    },
+    tof(num, t) {
+      return Number(num * 100).toFixed(t || 2);
+    },
+    selectChannel(item) {
+      if (this.channel === item.channelName) return;
+      this.channel = item.channelName;
+    },
+    chart() {
+      if (!this.myChart) {
+        this.myChart = markRaw(echarts.init(this.$refs.chart));
+        this.myChart.resize({
+          height: 300,
+        });
+        this.myChart.on("datazoom", () => {
+          if (isClick) return;
+          isClick = true;
+          let funisplay = !this.$refs.video.paused;
+          if (timeout) clearTimeout(timeout), (timeout = undefined);
+          this.$refs.video.pause();
+          this.leftNum = 50;
+          timeout = setTimeout(() => {
+            clearTimeout(timeout);
+            timeout = undefined;
+            isClick = false;
+            //  拖拽后的事件
+            isplay = funisplay;
+            this.leftNum = 50;
+            this.$refs.video.currentTime = this.myChart.getOption().dataZoom[0].startValue;
+            if (isplay) this.$refs.video.play();
+            else this.$refs.video.pause();
+          }, 200);
+        });
+      }
+      let timeAll = [],
+        Irdata = [],
+        Icdata = [],
+        audienceRating = [];
+      this.orgLi.map(v => {
+        v.date && timeAll.push(v.date.split(" ")[1] || "");
+        Icdata.push(-1 * v.lc);
+        Irdata.push(v.lr);
+        audienceRating.push(v.audienceRating * 100);
+      });
+      this.myChart.setOption({
+        dataZoom: [
+          {
+            maxSpan: 10,
+            minSpan: 5,
+            type: "slider",
+            brushSelect: false,
+            // zoomLock: false,
+            show: true,
+            realtime: true,
+            start: stepNum * page,
+            end: stepNum * (page + 1),
+            zoomOnMouseWheel: false,
+            height: "30",
+            top: "85%",
+            handleIcon:
+              "path://M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z",
+            handleSize: 15,
+            textStyle: {
+              color: "#c5c6cc",
+            },
+            dataBackground: {
+              lineStyle: {
+                color: "#fff",
+              },
+              areaStyle: {
+                color: "#8b51a8",
+              },
+            },
+          },
+        ],
+        xAxis: {
+          data: timeAll,
+          position: "top",
+          silent: false,
+          axisLabel: {
+            interval: "auto",
+            color: "#000",
+            rotate: "-90",
+          },
+        },
+        yAxis: [
+          {
+            scale: false,
+            nameGap: 6,
+            inverse: false,
+            name: "流入流出",
+            nameLocation: "start",
+            splitArea: {
+              show: false,
+            },
+            splitLine: {
+              show: false,
+            },
+            axisLabel: {
+              color: "#000",
+              formatter: function(value) {
+                let v = value;
+                if (v < 0) v *= -1;
+                return v;
+              },
+            },
+            axisTick: {
+              show: false,
+            },
+            axisLine: {
+              show: false,
+            },
+            nameTextStyle: {
+              color: "#000",
+            },
+          },
+          {
+            scale: true,
+            nameGap: 6,
+            type: "value",
+            name: "收视率%",
+            nameLocation: "start",
+            splitLine: {
+              show: false,
+            },
+            axisTick: {
+              show: false,
+            },
+            axisLine: {
+              show: false,
+            },
+            axisLabel: {
+              color: "#000",
+            },
+            nameTextStyle: {
+              color: "#000",
+            },
+          },
+        ],
+        grid: {
+          left: 50,
+          right: 50,
+        },
+        series: [
+          {
+            name: "流入",
+            type: "bar",
+            yAxisIndex: 0,
+            stack: "one",
+            data: Irdata,
+            sampling: "lttb",
+            emphasis: {
+              focus: "series",
+            },
+            itemStyle: {
+              color: "#df5a5a",
+            },
+          },
+          {
+            name: "流出",
+            type: "bar",
+            yAxisIndex: 0,
+            sampling: "lttb",
+            stack: "one",
+            data: Icdata,
+            emphasis: {
+              focus: "series",
+            },
+            itemStyle: {
+              color: "#6ab581",
+            },
+          },
+          {
+            name: "收视率%",
+            type: "line",
+            yAxisIndex: 1,
+            smooth: true,
+            showSymbol: false,
+            data: audienceRating,
+            lineStyle: {
+              width: 1,
+              color: "#50abfd",
+            },
+          },
+        ],
+      });
+    },
+    timeupdate(v) {
+      if (sec === Math.floor(v.srcElement.currentTime)) return;
+      sec = Math.floor(v.srcElement.currentTime);
+      let width = this.$refs.chart.offsetWidth - 100;
+      let item = this.orgLi[sec] || {};
+      let s = this.myChart.getOption().dataZoom[0].startValue,
+        e = this.myChart.getOption().dataZoom[0].endValue;
+      let iW = width / (e - s),
+        cheng = sec - s < 0 ? 0 : sec - s;
+      let step = iW * cheng > width ? 0 : iW * cheng;
+      if (!item.lrTop) return;
+      this.nowItem = item;
+      this.left = item.lrTop || [];
+      this.right = item.lcTop || [];
+      this.leftNum = 50 + step;
+      if (iW * cheng <= width) return;
+      page++;
+      this.myChart.setOption({
+        dataZoom: {
+          start: stepNum * page,
+          end: stepNum * (page + 1),
+        },
+      });
+    },
+    selectfun() {
+      let nowDate = new Date(this.date),
+        newDate = undefined;
+      for (let i = 0; i < this.list.length; i++) {
+        const v = this.list[i];
+        if (v.channelId !== this.select) continue;
+        newDate = v.dt;
+        break;
+      }
+      nowDate - new Date(newDate) > 0 ? (this.date = newDate) : "";
+    },
+    videoerror() {
+      this.videoerrorStart = true;
+    },
+    videoload() {
+      this.videoerrorStart = false;
+    },
+    formateNum(n) {
+      let num = n;
+      if (isNaN(n)) num = "0";
+      else if (n >= 100000000)
+        num =
+          ((n / 100000000).toFixed(2) - 0 + "").replace(
+            /\B(?=(?:\d{3})+\b)/g,
+            ","
+          ) + "亿";
+      else if (n >= 10000)
+        num =
+          ((n / 10000).toFixed(2) - 0 + "").replace(
+            /\B(?=(?:\d{3})+\b)/g,
+            ","
+          ) + "万";
+      else num = (num + "").replace(/\B(?=(?:\d{3})+\b)/g, ",");
+      return num;
+    },
+  },
+  components: {},
+};
+</script>
+
+<style>
+.Jugou {
+  min-width: 1149px;
+  padding: 10px 12px;
+}
+
+.Jugou video {
+  width: 100%;
+  height: 500px;
+  background-color: #000;
+}
+.Jugou .lineinfobackground {
+  font-size: 12px;
+  border-radius: 9px;
+  position: absolute;
+  width: 345px;
+  height: 200px;
+  top: 30px;
+  left: 50px;
+  background: rgba(0, 0, 0, 0.5);
+  transform: translateX(-50%);
+  color: #fff;
+  /* opacity: 0.5; */
+}
+.Jugou .lineinfobackground .line {
+  position: absolute;
+  width: 2px;
+  height: 120%;
+  margin-top: -5%;
+  margin-left: 50%;
+  background-color: #888;
+}
+.Jugou .lineinfobackground .icon {
+  display: inline-block;
+  width: 30px;
+  height: 10px;
+  border-radius: 10px;
+}
+.Jugou .lineinfobackground .iconLine {
+  background-color: #50abfd;
+  display: inline-block;
+  width: 30px;
+  height: 2px;
+  vertical-align: middle;
+  border-radius: 10px;
+}
+.Jugou .videoerror {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
+video::-webkit-media-controls-timeline {
+  display: none;
+}
+</style>