index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597
  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. 'font-weight: 700;word-break: normal;text-align: justify; 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' : '#04c15f'"
  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' : '#04c15f'"
  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="
  133. 'float:left;color: #5470c6;word-break: normal;text-align: justify;cursor:pointer;font-size:' +
  134. fontSize +
  135. 'px'
  136. "
  137. >
  138. <van-icon name="revoke" />
  139. 返回
  140. </div>
  141. <div
  142. :style="
  143. 'width: 100%; text-align: center;font-size:' + fontSize + 'px'
  144. "
  145. >
  146. {{ ratios.channelname }}
  147. </div>
  148. </van-cell>
  149. <van-cell-group title="视听收视新指标">
  150. <van-row>
  151. <van-col span="7" class="td" style="text-align: right">
  152. 收视总时长:
  153. </van-col>
  154. <van-col span="5" class="td">
  155. {{ ratios.timecount }}小时
  156. </van-col>
  157. <van-col span="7" class="td" style="text-align: right">
  158. 收视总次数:
  159. </van-col>
  160. <van-col span="5" class="td">
  161. {{ ratios.hitcount }}
  162. </van-col>
  163. <van-col span="7" class="td" style="text-align: right">
  164. 周活跃户数:
  165. </van-col>
  166. <van-col span="5" class="td">
  167. {{ ratios.usrcount }}
  168. </van-col>
  169. <van-col span="7" class="td" style="text-align: right">
  170. 周接触频次:
  171. </van-col>
  172. <van-col span="5" class="td">
  173. {{ formatType1(ratios.touchfreq, 1) }}次
  174. </van-col>
  175. </van-row>
  176. </van-cell-group>
  177. <van-cell-group title="传统指标">
  178. <van-row>
  179. <van-col span="5" class="td"> 到达率: </van-col>
  180. <van-col span="5" class="td"
  181. >{{ formatNum(ratios.reachrate, 2) }}%
  182. </van-col>
  183. <van-col span="7" class="td"> 周人均时长: </van-col>
  184. <van-col span="7" class="td"
  185. >{{ timeFormat(ratios.user_duration, 0) }}分钟
  186. </van-col>
  187. <van-col span="5" class="td"> 收视率: </van-col>
  188. <van-col span="5" class="td">
  189. {{ formatNum(ratios.watchrate, 2) }}%
  190. </van-col>
  191. <van-col span="7" class="td"> 市场占有率: </van-col>
  192. <van-col span="7" class="td"
  193. >{{ formatNum(ratios.occrate, 2) }}%
  194. </van-col>
  195. <van-col span="5" class="td"> 忠诚度: </van-col>
  196. <van-col span="5" class="td"
  197. >{{ formatNum(ratios.loyalty, 2) }}%
  198. </van-col>
  199. </van-row>
  200. </van-cell-group>
  201. <div ref="pie"></div>
  202. <div ref="day"></div>
  203. </div>
  204. <div class="bottom content">
  205. 本数据由<span style="color: red"
  206. >“陕西广电融媒体集团大数据平台”</span
  207. >提供。
  208. <p>
  209. 技术支持:
  210. <span style="white-space: nowrap">白帆13325452244 </span>
  211. <span style="white-space: nowrap">陈科18629350958。</span>
  212. </p>
  213. </div>
  214. </van-popup>
  215. </div>
  216. <div class="bottom content">
  217. 本数据由<span style="color: red">“陕西广电融媒体集团大数据平台”</span
  218. >提供。
  219. <p>
  220. 技术支持:
  221. <span style="white-space: nowrap">白帆13325452244 </span>
  222. <span style="white-space: nowrap">陈科18629350958。</span>
  223. </p>
  224. </div>
  225. </div>
  226. </div>
  227. </template>
  228. <script>
  229. // @ is an alias to /src
  230. import watermark from "watermark-package";
  231. import {
  232. Col as vanCol,
  233. Row as vanRow,
  234. Icon as vanIcon,
  235. Popup as vanPopup,
  236. cellGroup as vanCellGroup,
  237. Cell as vanCell,
  238. Popover as vanPopover,
  239. } from "vant";
  240. import "vant/lib/popover/style/index";
  241. import "vant/lib/cell-group/style/index";
  242. import "vant/lib/cell/style/index";
  243. import "vant/lib/popup/style/index";
  244. import "vant/lib/icon/style/index";
  245. import "vant/lib/col/style/index";
  246. import "vant/lib/row/style/index";
  247. // import {} from "../utils/tool";
  248. import Dayjs from "dayjs";
  249. import { jsonZhou } from "../../../api/index";
  250. import echarts from "../../../utils/echarts";
  251. export default {
  252. name: "tv-list",
  253. data() {
  254. return {
  255. shichang: false,
  256. fene: false,
  257. fontSize: 17,
  258. show: false,
  259. charts: undefined,
  260. ratios: {},
  261. platfromData: [],
  262. color: ["#ff0036", "#ff9b00", "#ffcc00"],
  263. echarts: undefined,
  264. dayEcharts: undefined,
  265. title: {},
  266. width: document.body.offsetWidth || 0,
  267. };
  268. },
  269. watch: {},
  270. mounted() {
  271. if (
  272. this.$route.query.auto !==
  273. "06fd56cdf5a6cfc3a2139cc8514d05aa0439ee8c1fb4d81145bc9647"
  274. )
  275. return;
  276. this.fontSize = (document.body.offsetWidth / 24).toFixed(2) - 0;
  277. if (document.body.offsetWidth > 677) this.fontSize = 22;
  278. watermark.setWaterMark({
  279. w_texts: ["陕西视听大数据"],
  280. w_options: {
  281. w_opacity: "0.1",
  282. },
  283. });
  284. const time = new Date(this.$route.query.date);
  285. let D = new Date(time);
  286. const lasetDay = new Dayjs(D.getTime() - D.getDay() * 86400000);
  287. const firstDay = new Dayjs(lasetDay - 6 * 86400000);
  288. jsonZhou({
  289. start: firstDay.format("YYYYMMDD"),
  290. end: lasetDay.format("YYYYMMDD"),
  291. time: Date.now(),
  292. })
  293. .then(res => {
  294. const title = {
  295. company: res.company || "",
  296. name: res.name || "",
  297. title: res.title || "",
  298. desc: res.desc || "",
  299. };
  300. this.title = title;
  301. this.platfromData = res.list || [];
  302. this.$emit("start", {
  303. status: 200,
  304. });
  305. })
  306. .catch(err => {
  307. this.$emit("start", {
  308. status: err,
  309. });
  310. });
  311. window.onresize = () => {
  312. const doc = document.body;
  313. const width = doc.offsetWidth - 32;
  314. let height = (width / 4) * 3;
  315. this.width = document.body.offsetWidth || 0;
  316. this.dayEcharts &&
  317. this.dayEcharts.resize({
  318. width,
  319. height: width,
  320. });
  321. this.echarts &&
  322. this.echarts.resize({
  323. width,
  324. height,
  325. });
  326. };
  327. },
  328. computed: {},
  329. methods: {
  330. formatType1(num, W) {
  331. let N = this.formatNum(num, W || 0);
  332. if (N >= 100000000) {
  333. N = (N / 100000000).toFixed(W || 0) - 0 + "亿";
  334. } else if (N >= 10000) {
  335. N = (N / 10000).toFixed(W || 0) - 0 + "万";
  336. } else {
  337. N = Number(N).toFixed(W || 0) - 0;
  338. }
  339. return N;
  340. },
  341. formatNum(num, w) {
  342. if (isNaN(num)) return 0;
  343. return Number(num).toFixed(w || 4) - 0;
  344. },
  345. formatType(num, W) {
  346. let N = this.formatNum(num, 2);
  347. let wei = "";
  348. if (N >= 100000000) {
  349. N = (N / 100000000).toFixed(W || 2);
  350. wei = "亿";
  351. } else if (N >= 10000) {
  352. N = (N / 10000).toFixed(W || 2);
  353. wei = "万";
  354. }
  355. N = N.toString().split(".");
  356. return {
  357. N: (N[0] || 0) * 1,
  358. P: N[1] || 0,
  359. wei,
  360. };
  361. },
  362. timeFormat(t, w) {
  363. const Time = t || 0;
  364. let out = Time.toFixed(w || 0) - 0;
  365. return out;
  366. },
  367. showPopup(i) {
  368. this.show = true;
  369. const reaios = JSON.parse(JSON.stringify(this.platfromData[i] || {}));
  370. reaios.hitcount = this.formatType1(reaios.hitcount, 1);
  371. reaios.usrcount = this.formatType1(reaios.usrcount, 1);
  372. reaios.timecount = this.formatType1(reaios.timecount / 60, 0);
  373. this.ratios = reaios;
  374. this.$nextTick(() => {
  375. this.upEcharts();
  376. this.dayEchartsFun();
  377. });
  378. },
  379. dayEchartsFun() {
  380. this.dayEcharts && this.dayEcharts.clear && this.dayEcharts.clear();
  381. if (!this.dayEcharts) {
  382. const doc = document.body;
  383. const width = doc.offsetWidth - 32;
  384. let height = (width / 4) * 3;
  385. if (height > 400) height = 400;
  386. this.dayEcharts = echarts.init(
  387. this.$refs.day,
  388. {},
  389. {
  390. width,
  391. height,
  392. }
  393. );
  394. }
  395. const key = [],
  396. value = [];
  397. this.ratios.detail_list.map(v => {
  398. let val = v.usrcount;
  399. key.push(v.dt);
  400. value.push(val);
  401. });
  402. this.dayEcharts.setOption({
  403. title: {
  404. text: "家庭户收视规模",
  405. subtext: this.ratios.usrcount_compare
  406. ? this.ratios.usrcount_compare + " 单位:户"
  407. : "单位:户",
  408. textStyle: {
  409. fontSize: this.fontSize * 1.05,
  410. },
  411. subtextStyle: {
  412. fontSize: this.fontSize,
  413. },
  414. },
  415. tooltip: {
  416. show: true,
  417. trigger: "axis",
  418. },
  419. xAxis: {
  420. type: "category",
  421. boundaryGap: false,
  422. data: key,
  423. axisLabel: {
  424. interval: 0,
  425. rotate: 60,
  426. },
  427. },
  428. grid: {
  429. right: "5px",
  430. left: "40px",
  431. },
  432. yAxis: {
  433. type: "value",
  434. axisLabel: {
  435. formatter: e => {
  436. const T = this.formatType(e);
  437. let out = T.N;
  438. if (T.P > 0) out += "." + (T.P - 0);
  439. out += T.wei;
  440. return out;
  441. },
  442. },
  443. },
  444. series: [
  445. {
  446. type: "line",
  447. data: value,
  448. },
  449. ],
  450. });
  451. },
  452. upEcharts() {
  453. this.echarts && this.echarts.clear && this.echarts.clear();
  454. if (!this.echarts) {
  455. const doc = document.body;
  456. const width = doc.offsetWidth - 32;
  457. let height = width;
  458. if (height > 667) height = 667;
  459. this.echarts = echarts.init(
  460. this.$refs.pie,
  461. {},
  462. {
  463. width,
  464. height,
  465. }
  466. );
  467. }
  468. this.echarts.setOption({
  469. title: {
  470. text: "观看时长用户分布",
  471. subtext: "单位:%",
  472. textStyle: {
  473. fontSize: this.fontSize * 1.05,
  474. },
  475. },
  476. color: [
  477. "#87cefa",
  478. "#00bfff",
  479. "#1e90ff",
  480. "#0000ff",
  481. "#00008b",
  482. "#191970",
  483. "#000080",
  484. "#0000cd",
  485. "#4169e1",
  486. "#6495ed",
  487. ],
  488. series: [
  489. {
  490. name: "Nightingale Chart",
  491. type: "pie",
  492. radius: [30, 70],
  493. center: ["50%", "50%"],
  494. emphasis: {
  495. //使用emphasis
  496. disable: false,
  497. scale: false, //不缩放
  498. scaleSize: 0, //为了防止失效直接设置未0
  499. },
  500. data: this.ratios.duration_list.map(v => {
  501. let bfb = (v.value * 100).toFixed(0) - 0;
  502. return {
  503. value: bfb,
  504. name: v.range + "\n 占比" + bfb + "%",
  505. };
  506. }),
  507. },
  508. ],
  509. });
  510. },
  511. },
  512. beforeUnmount() {},
  513. components: {
  514. vanCol,
  515. vanRow,
  516. vanIcon,
  517. vanPopup,
  518. vanCell,
  519. vanCellGroup,
  520. vanPopover,
  521. },
  522. };
  523. </script>
  524. <style scoped>
  525. .tv-list {
  526. background-color: #fff;
  527. padding: 5px;
  528. height: 100%;
  529. overflow-y: auto;
  530. box-sizing: border-box;
  531. }
  532. .bottom {
  533. border: 4px solid #0983a8;
  534. background-color: #cdcdcd;
  535. margin-top: 1em;
  536. padding: 10px;
  537. font-size: 0.85rem;
  538. padding-left: 5px;
  539. font-weight: 600;
  540. overflow: hidden;
  541. }
  542. .td {
  543. text-align: center;
  544. line-height: 2.5em;
  545. overflow: hidden;
  546. white-space: nowrap;
  547. text-overflow: ellipsis;
  548. }
  549. .td2 {
  550. line-height: 1.5em;
  551. white-space: initial;
  552. }
  553. .item {
  554. overflow: hidden;
  555. border-radius: 3px;
  556. margin-top: 11px;
  557. background-color: #f5f6f8;
  558. }
  559. .itemHead {
  560. margin-top: 0;
  561. background-color: #f5f6f8;
  562. }
  563. .main {
  564. padding: 0.5em;
  565. }
  566. .content {
  567. margin: 0 auto;
  568. max-width: 667px;
  569. }
  570. .rise {
  571. /* 上升 */
  572. transform: rotate(180deg);
  573. }
  574. .titleTop {
  575. padding: 1em 0;
  576. font-weight: 600;
  577. background-image: linear-gradient(to right, #014392, #008fc4, #00428c);
  578. color: #fff;
  579. text-align: center;
  580. }
  581. </style>
  582. <style>
  583. .van-cell-group__title {
  584. font-size: 1.1rem;
  585. padding-left: 8px;
  586. color: #000;
  587. font-weight: 600;
  588. }
  589. </style>