index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. <template>
  2. <div style="font-size: 0; background-color: #fff">
  3. <img
  4. :src="
  5. 'https://cxzx.smcic.net/zhoubao/assets/tv' + $route.query.date + '.jpg'
  6. "
  7. width="100%"
  8. class="content"
  9. style="margin-bottom: 1em; display: block"
  10. alt=""
  11. />
  12. <p
  13. class="content"
  14. :style="
  15. 'text-indent: 2em; font-weight: 700; padding: 0.5em 3px;font-size: ' +
  16. fontSize +
  17. 'px;'
  18. "
  19. v-html="title.desc"
  20. ></p>
  21. <div :style="'height: ' + fontSize + 'px;'"></div>
  22. <div class="tv-list" :style="'font-size:' + fontSize + 'px'">
  23. <div class="content">
  24. <!-- <div class="titleTop">
  25. <p v-text="title.company"></p>
  26. <p v-text="title.name"></p>
  27. <p v-text="title.title"></p>
  28. </div> -->
  29. <div class="itemHead">
  30. <van-row>
  31. <van-col span="4" class="td"> 省排名 </van-col>
  32. <van-col span="6" class="td"> 频道 </van-col>
  33. <van-col span="5">
  34. <van-popover
  35. v-model="fene"
  36. trigger="click"
  37. @select="fene = !fene"
  38. >
  39. <div style="padding: 5px">
  40. 市场份额=本频道收视率/所有频道收视率
  41. </div>
  42. <template #reference>
  43. <p class="td">市场份额</p>
  44. </template>
  45. </van-popover>
  46. </van-col>
  47. <!-- td2 :style="width > 667 ? 'line-height: 2.5em' : 'line-height: 1.5em'" -->
  48. <van-col span="7">
  49. <van-popover
  50. v-model="shichang"
  51. trigger="click"
  52. @select="shichang = !shichang"
  53. >
  54. <div style="padding: 5px">
  55. 市场份额=本频道收视率/所有频道收视率
  56. </div>
  57. <template #reference>
  58. <p class="td">周人均时长(分)</p>
  59. </template>
  60. </van-popover>
  61. </van-col>
  62. <van-col span="2" class="td">
  63. <img
  64. src="../../../assets/image/shou.gif"
  65. width="26px"
  66. alt=""
  67. style="vertical-align: middle;transform: rotate(45deg);"
  68. />
  69. </van-col>
  70. </van-row>
  71. </div>
  72. <div v-for="(v, o) in platfromData || []" :key="v.name">
  73. <div
  74. style="border-bottom: 1px dashed #eee; margin: 11px 0 0 0"
  75. v-if="o === 50"
  76. ></div>
  77. <van-row
  78. :style="v.shanxi_channel ? 'background: #F5DEB3' : ''"
  79. class="item"
  80. @click="() => showPopup(o)"
  81. >
  82. <van-col
  83. span="4"
  84. :class="{ td: true }"
  85. :style="{ color: color[o] || '#000', fontWeight: 600 }"
  86. >
  87. {{ v.rank }}
  88. </van-col>
  89. <van-col
  90. :style="v.shanxi_channel ? 'font-weight: 600' : ''"
  91. span="6"
  92. :class="{ td: true }"
  93. >
  94. {{ v.channelname }}
  95. </van-col>
  96. <van-col span="5" :class="{ td: true }">
  97. {{ formatNum(v.occrate, 2) }}%
  98. <van-icon
  99. v-if="v.occrate_change !== '相等'"
  100. name="down"
  101. :color="v.occrate_change === '上升' ? '#f00' : '#0f0'"
  102. :class="{ rise: v.occrate_change === '上升' }"
  103. />
  104. </van-col>
  105. <van-col span="7" :class="{ td: true }">
  106. {{ timeFormat(v.user_duration) }}
  107. <van-icon
  108. v-if="v.user_duration_change !== '相等'"
  109. name="down"
  110. :color="v.user_duration_change === '上升' ? '#f00' : '#0f0'"
  111. :class="{ rise: v.user_duration_change === '上升' }"
  112. />
  113. </van-col>
  114. <van-col span="2" class="td" style="cursor: pointer">
  115. <van-icon name="arrow" />
  116. </van-col>
  117. </van-row>
  118. </div>
  119. <van-popup
  120. :style="{ height: '100%', width: '100%' }"
  121. position="right"
  122. v-model="show"
  123. >
  124. <div class="main">
  125. <van-cell
  126. title-style="flex: 3"
  127. :title="ratios.schedulename"
  128. :label="ratios.channelname"
  129. >
  130. <div
  131. @click="show = false"
  132. style="color: #5470c6; cursor: pointer"
  133. >
  134. <van-icon name="revoke" />
  135. {{ ratios.channelname }}
  136. </div>
  137. </van-cell>
  138. <van-cell-group title="视听收视新指标">
  139. <van-row>
  140. <van-col span="10" class="td" style="text-align: right">
  141. 收视总时长:
  142. </van-col>
  143. <van-col span="14" class="td">
  144. <counto
  145. :startVal="0"
  146. :endVal="ratios.timecount || 0"
  147. :duration="1000"
  148. ></counto>
  149. <span v-if="ratios.timecountP">.</span>
  150. {{
  151. (ratios.timecountP > 0 ? ratios.timecountP : "") +
  152. ratios.timecountWei
  153. }}
  154. </van-col>
  155. <van-col span="10" class="td" style="text-align: right">
  156. 收视总次数:
  157. </van-col>
  158. <van-col span="14" class="td">
  159. <counto
  160. :startVal="0"
  161. :endVal="ratios.hitcount || 0"
  162. :duration="1000"
  163. ></counto>
  164. <span v-if="ratios.hitcountP">.</span>
  165. {{
  166. (ratios.hitcountP > 0 ? ratios.hitcountP : "") +
  167. ratios.hitcountWei
  168. }}
  169. </van-col>
  170. <van-col span="10" class="td" style="text-align: right">
  171. 周活跃户数:
  172. </van-col>
  173. <van-col span="14" class="td">
  174. <counto
  175. :startVal="0"
  176. :endVal="ratios.usrcount || 0"
  177. :duration="1000"
  178. ></counto>
  179. <span v-if="ratios.usrcountP">.</span>
  180. {{
  181. (ratios.usrcountP > 0 ? ratios.usrcountP : "") +
  182. ratios.usrcountWei
  183. }}
  184. </van-col>
  185. <van-col span="10" class="td" style="text-align: right">
  186. 接触频次:
  187. </van-col>
  188. <van-col span="14" class="td">
  189. {{ formatType1(ratios.touchfreq, 0) }}%
  190. </van-col>
  191. </van-row>
  192. </van-cell-group>
  193. <van-cell-group title="传统指标">
  194. <van-row>
  195. <van-col span="5" class="td"> 到达率: </van-col>
  196. <van-col span="5" class="td"
  197. >{{ formatNum(ratios.reachrate, 2) }}%
  198. </van-col>
  199. <van-col span="7" class="td"> 周人均时长: </van-col>
  200. <van-col span="7" class="td"
  201. >{{ timeFormat(ratios.user_duration, 0) }}分钟
  202. </van-col>
  203. <van-col span="5" class="td"> 收视率: </van-col>
  204. <van-col span="5" class="td">
  205. {{ formatNum(ratios.watchrate, 2) }}%
  206. </van-col>
  207. <van-col span="7" class="td"> 市场占有率: </van-col>
  208. <van-col span="7" class="td"
  209. >{{ formatNum(ratios.occrate, 2) }}%
  210. </van-col>
  211. <van-col span="5" class="td"> 忠诚度: </van-col>
  212. <van-col span="5" class="td"
  213. >{{ formatNum(ratios.loyalty, 2) }}%
  214. </van-col>
  215. <van-col span="7" class="td"> 接触度: </van-col>
  216. <van-col span="7" class="td"
  217. >{{ formatType1(ratios.hitcount, 0) }}次
  218. </van-col>
  219. </van-row>
  220. </van-cell-group>
  221. <div ref="pie"></div>
  222. <div ref="day"></div>
  223. </div>
  224. <div class="bottom content">
  225. 本数据由“陕西广电融媒体集团大数据平台”提供。
  226. <p>
  227. 技术支持 <span style="white-space: nowrap">白帆13325452244;</span
  228. ><span style="white-space: nowrap">陈科18629350958。</span>
  229. </p>
  230. </div>
  231. </van-popup>
  232. </div>
  233. <div class="bottom content">
  234. 本数据由“陕西广电融媒体集团大数据平台”提供。
  235. <p>
  236. 技术支持 <span style="white-space: nowrap">白帆13325452244;</span
  237. ><span style="white-space: nowrap">陈科18629350958。</span>
  238. </p>
  239. </div>
  240. </div>
  241. </div>
  242. </template>
  243. <script>
  244. // @ is an alias to /src
  245. import counto from "@/components/counto/vue-countTo.vue";
  246. import watermark from "watermark-package";
  247. import {
  248. Col as vanCol,
  249. Row as vanRow,
  250. Icon as vanIcon,
  251. Popup as vanPopup,
  252. cellGroup as vanCellGroup,
  253. Cell as vanCell,
  254. Popover as vanPopover,
  255. } from "vant";
  256. import "vant/lib/popover/style/index";
  257. import "vant/lib/cell-group/style/index";
  258. import "vant/lib/cell/style/index";
  259. import "vant/lib/popup/style/index";
  260. import "vant/lib/icon/style/index";
  261. import "vant/lib/col/style/index";
  262. import "vant/lib/row/style/index";
  263. // import {} from "../utils/tool";
  264. import Dayjs from "dayjs";
  265. import { jsonZhou } from "../../../api/index";
  266. import echarts from "../../../utils/echarts";
  267. export default {
  268. name: "tv-list",
  269. data() {
  270. return {
  271. shichang: false,
  272. fene: false,
  273. fontSize: 17,
  274. show: false,
  275. charts: undefined,
  276. ratios: {},
  277. platfromData: [],
  278. color: ["#ff0036", "#ff9b00", "#ffcc00"],
  279. echarts: undefined,
  280. dayEcharts: undefined,
  281. title: {},
  282. width: document.body.offsetWidth || 0,
  283. };
  284. },
  285. watch: {},
  286. mounted() {
  287. if (
  288. this.$route.query.auto !==
  289. "06fd56cdf5a6cfc3a2139cc8514d05aa0439ee8c1fb4d81145bc9647"
  290. )
  291. return;
  292. this.fontSize = (document.body.offsetWidth / 24).toFixed(2) - 0;
  293. if (document.body.offsetWidth > 677) this.fontSize = 22;
  294. watermark.setWaterMark({
  295. w_texts: ["陕西视听大数据"],
  296. w_options: {
  297. w_opacity: "0.1",
  298. },
  299. });
  300. const time = new Date(this.$route.query.date);
  301. let D = new Date(time);
  302. const lasetDay = new Dayjs(D.getTime() - D.getDay() * 86400000);
  303. const firstDay = new Dayjs(lasetDay - 6 * 86400000);
  304. jsonZhou({
  305. start: firstDay.format("YYYYMMDD"),
  306. end: lasetDay.format("YYYYMMDD"),
  307. time: Date.now(),
  308. })
  309. .then(res => {
  310. const title = {
  311. company: res.company || "",
  312. name: res.name || "",
  313. title: res.title || "",
  314. desc: res.desc || "",
  315. };
  316. this.title = title;
  317. this.platfromData = res.list || [];
  318. this.$emit("start", {
  319. status: 200,
  320. });
  321. })
  322. .catch(err => {
  323. this.$emit("start", {
  324. status: err,
  325. });
  326. });
  327. window.onresize = () => {
  328. const doc = document.body;
  329. const width = doc.offsetWidth - 32;
  330. let height = (width / 4) * 3;
  331. this.width = document.body.offsetWidth || 0;
  332. this.dayEcharts &&
  333. this.dayEcharts.resize({
  334. width,
  335. height: width,
  336. });
  337. this.echarts &&
  338. this.echarts.resize({
  339. width,
  340. height,
  341. });
  342. };
  343. },
  344. computed: {},
  345. methods: {
  346. formatType1(num, W) {
  347. let N = this.formatNum(num, 2);
  348. if (N >= 100000000) {
  349. N = (N / 100000000).toFixed(W || 2) + "亿";
  350. } else if (N >= 10000) {
  351. N = (N / 10000).toFixed(W || 2) + "万";
  352. }
  353. return N;
  354. },
  355. formatNum(num, w) {
  356. if (isNaN(num)) return 0;
  357. return Number(num).toFixed(w || 4) - 0;
  358. },
  359. formatType(num, W) {
  360. let N = this.formatNum(num, 2);
  361. let wei = "";
  362. if (N >= 100000000) {
  363. N = (N / 100000000).toFixed(W || 2);
  364. wei = "亿";
  365. } else if (N >= 10000) {
  366. N = (N / 10000).toFixed(W || 2);
  367. wei = "万";
  368. }
  369. N = N.toString().split(".");
  370. return {
  371. N: (N[0] || 0) * 1,
  372. P: N[1] || 0,
  373. wei,
  374. };
  375. },
  376. timeFormat(t, w) {
  377. const Time = t || 0;
  378. let out = Time.toFixed(w || 0) - 0;
  379. return out;
  380. },
  381. showPopup(i) {
  382. this.show = true;
  383. const reaios = JSON.parse(JSON.stringify(this.platfromData[i] || {}));
  384. let hitcount = this.formatType(reaios.hitcount, 1);
  385. reaios.hitcount = hitcount.N;
  386. reaios.hitcountP = hitcount.P;
  387. reaios.hitcountWei = hitcount.wei;
  388. let usrcount = this.formatType(reaios.usrcount, 1);
  389. reaios.usrcount = usrcount.N;
  390. reaios.usrcountP = usrcount.P;
  391. reaios.usrcountWei = usrcount.wei;
  392. let timecount = this.formatType(reaios.timecount / 60, 1);
  393. reaios.timecount = timecount.N;
  394. reaios.timecountP = timecount.P;
  395. reaios.timecountWei = timecount.wei + "小时";
  396. this.ratios = reaios;
  397. this.$nextTick(() => {
  398. this.upEcharts();
  399. this.dayEchartsFun();
  400. });
  401. },
  402. dayEchartsFun() {
  403. this.dayEcharts && this.dayEcharts.clear && this.dayEcharts.clear();
  404. if (!this.dayEcharts) {
  405. const doc = document.body;
  406. const width = doc.offsetWidth - 32;
  407. let height = (width / 4) * 3;
  408. if (height > 400) height = 400;
  409. this.dayEcharts = echarts.init(
  410. this.$refs.day,
  411. {},
  412. {
  413. width,
  414. height,
  415. }
  416. );
  417. }
  418. const key = [],
  419. value = [];
  420. this.ratios.detail_list.map(v => {
  421. let val = v.usrcount;
  422. key.push(v.dt);
  423. value.push(val);
  424. });
  425. this.dayEcharts.setOption({
  426. title: {
  427. text: "家庭户收视规模",
  428. subtext: this.ratios.usrcount_compare
  429. ? this.ratios.usrcount_compare + " 单位:户"
  430. : "单位:户",
  431. textStyle: {
  432. fontSize: 14,
  433. },
  434. },
  435. tooltip: {
  436. show: true,
  437. trigger: "axis",
  438. },
  439. xAxis: {
  440. type: "category",
  441. boundaryGap: false,
  442. data: key,
  443. },
  444. grid: {
  445. right: "25px",
  446. left: "40px",
  447. },
  448. yAxis: {
  449. type: "value",
  450. axisLabel: {
  451. formatter: e => {
  452. const T = this.formatType(e);
  453. let out = T.N;
  454. if (T.P > 0) out += "." + (T.P - 0);
  455. out += T.wei;
  456. return out;
  457. },
  458. },
  459. },
  460. series: [
  461. {
  462. type: "line",
  463. data: value,
  464. },
  465. ],
  466. });
  467. },
  468. upEcharts() {
  469. this.echarts && this.echarts.clear && this.echarts.clear();
  470. if (!this.echarts) {
  471. const doc = document.body;
  472. const width = doc.offsetWidth - 32;
  473. let height = width;
  474. if (height > 667) height = 667;
  475. this.echarts = echarts.init(
  476. this.$refs.pie,
  477. {},
  478. {
  479. width,
  480. height,
  481. }
  482. );
  483. }
  484. this.echarts.setOption({
  485. title: {
  486. text: "观看时长用户分布",
  487. subtext: "单位:%",
  488. textStyle: {
  489. fontSize: 14,
  490. },
  491. },
  492. color: [
  493. "#87cefa",
  494. "#00bfff",
  495. "#1e90ff",
  496. "#0000ff",
  497. "#00008b",
  498. "#191970",
  499. "#000080",
  500. "#0000cd",
  501. "#4169e1",
  502. "#6495ed",
  503. ],
  504. series: [
  505. {
  506. name: "Nightingale Chart",
  507. type: "pie",
  508. radius: [30, 70],
  509. center: ["50%", "50%"],
  510. data: this.ratios.duration_list.map(v => {
  511. let bfb = (v.value * 100).toFixed(0) - 0;
  512. return {
  513. value: bfb,
  514. name: v.range + "\n 占比" + bfb + "%",
  515. };
  516. }),
  517. },
  518. ],
  519. });
  520. },
  521. },
  522. beforeUnmount() {},
  523. components: {
  524. counto,
  525. vanCol,
  526. vanRow,
  527. vanIcon,
  528. vanPopup,
  529. vanCell,
  530. vanCellGroup,
  531. vanPopover,
  532. },
  533. };
  534. </script>
  535. <style scoped>
  536. .tv-list {
  537. background-color: #fff;
  538. padding: 5px;
  539. height: 100%;
  540. overflow-y: auto;
  541. box-sizing: border-box;
  542. }
  543. .bottom {
  544. border: 4px solid #0983a8;
  545. margin-top: 1em;
  546. padding: 10px;
  547. font-size: 0.9rem;
  548. padding-left: 5px;
  549. font-weight: 600;
  550. overflow: hidden;
  551. }
  552. .td {
  553. text-align: center;
  554. line-height: 2.5em;
  555. overflow: hidden;
  556. white-space: nowrap;
  557. text-overflow: ellipsis;
  558. }
  559. .td2 {
  560. line-height: 1.5em;
  561. white-space: initial;
  562. }
  563. .item {
  564. overflow: hidden;
  565. border-radius: 3px;
  566. margin-top: 11px;
  567. background-color: #f5f6f8;
  568. }
  569. .itemHead {
  570. margin-top: 0;
  571. background-color: #f5f6f8;
  572. }
  573. .main {
  574. padding: 0.5em;
  575. }
  576. .content {
  577. margin: 0 auto;
  578. max-width: 667px;
  579. }
  580. .rise {
  581. /* 上升 */
  582. transform: rotate(180deg);
  583. }
  584. .titleTop {
  585. padding: 1em 0;
  586. font-weight: 600;
  587. background-image: linear-gradient(to right, #014392, #008fc4, #00428c);
  588. color: #fff;
  589. text-align: center;
  590. }
  591. </style>
  592. <style>
  593. .van-cell-group__title {
  594. font-size: 1.1rem;
  595. padding-left: 8px;
  596. color: #000;
  597. font-weight: 600;
  598. }
  599. </style>