|
@@ -0,0 +1,447 @@
|
|
|
+<template>
|
|
|
+ <div class="Jugou">
|
|
|
+ <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"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="频道">
|
|
|
+ <el-select
|
|
|
+ v-model="select"
|
|
|
+ placeholder="请选择频道"
|
|
|
+ >
|
|
|
+ <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>
|
|
|
+ </el-card>
|
|
|
+ <br />
|
|
|
+ <el-card>
|
|
|
+ <div style="padding: 0 100px">
|
|
|
+ <video
|
|
|
+ controls
|
|
|
+ autoplay
|
|
|
+ ref="video"
|
|
|
+ @timeupdate="timeupdate"
|
|
|
+ :src="videoUrl"
|
|
|
+ ></video>
|
|
|
+ <div style="position: relative;">
|
|
|
+ <div
|
|
|
+ class="chart"
|
|
|
+ ref="chart"
|
|
|
+ style="width: 100%;min-height: 100px;"
|
|
|
+ ></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>
|
|
|
+ 收视率%
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <div style="padding: 5px 20px">
|
|
|
+ 当前时间:{{
|
|
|
+ nowItem.date ? nowItem.date.split(" ")[1] || "" : ""
|
|
|
+ }}
|
|
|
+ </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 { markRaw } from "vue";
|
|
|
+
|
|
|
+import * as echarts from "echarts";
|
|
|
+// import config from "@/config/index";
|
|
|
+
|
|
|
+let sec = 0,
|
|
|
+ timeout = undefined,
|
|
|
+ isplay = false,
|
|
|
+ isClick = false,
|
|
|
+ stepNum = 6.8,
|
|
|
+ page = 0;
|
|
|
+export default {
|
|
|
+ name: "Channel",
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ list: [
|
|
|
+ {
|
|
|
+ channelName: "陕西2套",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ select: -1,
|
|
|
+ channel: "陕西2套",
|
|
|
+ leftNum: 50,
|
|
|
+ videoUrl: "",
|
|
|
+ date: "",
|
|
|
+ myChart: undefined,
|
|
|
+ orgLi: [],
|
|
|
+ nowItem: {},
|
|
|
+ left: [],
|
|
|
+ right: [],
|
|
|
+ };
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ leverAudience().then(res => {
|
|
|
+ this.list = res || [];
|
|
|
+ this.select = this.list[0].channelId || "";
|
|
|
+ let d = new Date(new Date() - 86400000 * 2),
|
|
|
+ y = d.getFullYear(),
|
|
|
+ m = d.getMonth() + 1,
|
|
|
+ h = d.getHours() + 1,
|
|
|
+ day = d.getDate();
|
|
|
+ m > 9 ? "" : (m = "0" + m);
|
|
|
+ day > 9 ? "" : (day = "0" + day);
|
|
|
+ h > 9 ? "" : (h = "0" + h);
|
|
|
+ this.date = [y, m, day].join("-");
|
|
|
+ this.getData();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ computed: {},
|
|
|
+ methods: {
|
|
|
+ getData() {
|
|
|
+ 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 = videoUrl.replace("{yyyyMMddHH}", d+'16');
|
|
|
+ console.log(this.videoUrl);
|
|
|
+ defaultAjax({
|
|
|
+ url,
|
|
|
+ }).then(res => {
|
|
|
+ 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();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ selectChannel(item) {
|
|
|
+ if (this.channel === item.channelName) return;
|
|
|
+ this.channel = item.channelName;
|
|
|
+ },
|
|
|
+ chart() {
|
|
|
+ this.myChart = markRaw(echarts.init(this.$refs.chart));
|
|
|
+ this.myChart.resize({
|
|
|
+ height: 300,
|
|
|
+ });
|
|
|
+ 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: 10,
|
|
|
+ type: "slider",
|
|
|
+ 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,
|
|
|
+ emphasis: {
|
|
|
+ focus: "series",
|
|
|
+ },
|
|
|
+ itemStyle: {
|
|
|
+ color: "#df5a5a",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ name: "流出",
|
|
|
+ type: "bar",
|
|
|
+ yAxisIndex: 0,
|
|
|
+ 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",
|
|
|
+ },
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ });
|
|
|
+ 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);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ 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),
|
|
|
+ },
|
|
|
+ });
|
|
|
+ },
|
|
|
+ },
|
|
|
+ components: {},
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style>
|
|
|
+.Jugou {
|
|
|
+ min-width: 1149px;
|
|
|
+ padding: 10px 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.Jugou video {
|
|
|
+ width: 100%;
|
|
|
+ height: 500px;
|
|
|
+}
|
|
|
+.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;
|
|
|
+}
|
|
|
+</style>
|