index.vue 16 KB

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