index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. <template>
  2. <div class="Content">
  3. <el-breadcrumb separator-class="el-icon-arrow-right">
  4. <el-breadcrumb-item>新媒体</el-breadcrumb-item>
  5. <el-breadcrumb-item>应用分析</el-breadcrumb-item>
  6. <el-breadcrumb-item>直播分析</el-breadcrumb-item>
  7. </el-breadcrumb>
  8. <el-card class="box-card">
  9. <el-form
  10. ref="form"
  11. :model="form"
  12. size="small"
  13. :inline="true"
  14. label-width="120px"
  15. class="demo-form-inline"
  16. >
  17. <el-form-item label="日期">
  18. <el-date-picker
  19. v-if="form.date.length"
  20. v-model="form.date"
  21. type="daterange"
  22. :disabled-date="time => disabledDate(time)"
  23. range-separator="-"
  24. start-placeholder="开始日期"
  25. end-placeholder="结束日期"
  26. :clearable="false"
  27. >
  28. </el-date-picker>
  29. </el-form-item>
  30. <el-form-item label="应用">
  31. <el-select
  32. v-model="form.app"
  33. placeholder="请选择时段"
  34. @change="change"
  35. >
  36. <el-option
  37. v-for="item in cycle"
  38. :key="item.value"
  39. :label="item.label"
  40. :value="item.value"
  41. :disabled="item.disabled"
  42. >
  43. </el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item label="渠道">
  47. <el-select
  48. filterable
  49. multiple
  50. collapse-tags
  51. clearable
  52. v-model="form.channel"
  53. @change="changechannel"
  54. placeholder="请选择渠道"
  55. >
  56. <el-option
  57. v-for="item in channel"
  58. :key="item.value"
  59. :label="item.label"
  60. :value="item.value"
  61. :disabled="item.disabled"
  62. >
  63. </el-option>
  64. </el-select>
  65. </el-form-item>
  66. <el-form-item label="版本">
  67. <el-select
  68. filterable
  69. multiple
  70. collapse-tags
  71. clearable
  72. v-model="form.version"
  73. placeholder="请选择版本"
  74. @change="changeversion"
  75. >
  76. <el-option
  77. v-for="item in version"
  78. :key="item.value"
  79. :label="item.label"
  80. :value="item.value"
  81. :disabled="item.disabled"
  82. >
  83. </el-option>
  84. </el-select>
  85. </el-form-item>
  86. <el-form-item label="直播编号">
  87. <el-input
  88. v-model="form.liveId"
  89. placeholder="请输入直播编号"
  90. clearable
  91. />
  92. </el-form-item>
  93. <el-form-item label="直播标题">
  94. <el-input
  95. v-model="form.liveTitle"
  96. placeholder="请输入直播标题"
  97. clearable
  98. />
  99. </el-form-item>
  100. <!-- <el-form-item label="主播">
  101. <el-input
  102. v-model="form.publisherName"
  103. placeholder="请输入主播名称"
  104. clearable
  105. />
  106. </el-form-item> -->
  107. <el-form-item style="float: right">
  108. <el-button type="primary" @click="onSubmit">查询</el-button>
  109. </el-form-item>
  110. </el-form>
  111. </el-card>
  112. <br />
  113. <el-card class="box-card">
  114. <div style="text-align: right">
  115. <el-button
  116. size="small"
  117. style="margin-left: 0.5em"
  118. type="primary"
  119. @click="onExport"
  120. >
  121. 导出
  122. </el-button>
  123. </div>
  124. <br />
  125. <br />
  126. <el-table
  127. :data="table.records || []"
  128. style="width: 100%"
  129. :header-cell-style="{
  130. backgroundColor: '#f4f5f7',
  131. color: '#606266',
  132. }"
  133. >
  134. <el-table-column
  135. prop="liveId"
  136. header-align="center"
  137. align="center"
  138. label="直播编号"
  139. show-overflow-tooltip
  140. >
  141. <template #default="scope">
  142. <span v-text="scope.row.liveId || '-'"></span>
  143. </template>
  144. </el-table-column>
  145. <el-table-column
  146. prop="liveTitle"
  147. :width="320"
  148. header-align="center"
  149. align="center"
  150. label="直播标题"
  151. show-overflow-tooltip
  152. >
  153. <template #default="scope">
  154. <span v-text="scope.row.liveTitle || '-'"></span>
  155. </template>
  156. </el-table-column>
  157. <el-table-column
  158. show-overflow-tooltip
  159. label="应用名称"
  160. header-align="center"
  161. align="center"
  162. >
  163. <template #default>
  164. <span>{{ lastParams.app || "-" }}</span>
  165. </template>
  166. </el-table-column>
  167. <!-- <el-table-column
  168. prop="publisherName"
  169. header-align="center"
  170. align="center"
  171. label="主播"
  172. show-overflow-tooltip
  173. >
  174. <template #default="scope">
  175. <span>{{ scope.row.publisherName || "-" }}</span>
  176. </template>
  177. </el-table-column> -->
  178. <!-- <el-table-column
  179. label="关注用户数"
  180. header-align="center"
  181. align="center"
  182. prop="follow"
  183. >
  184. <template #default="scope">
  185. <countTo
  186. :startVal="scope.row.follow || 0"
  187. :endVal="scope.row.follow || 0"
  188. :duration="100"
  189. ></countTo>
  190. </template>
  191. </el-table-column> -->
  192. <el-table-column
  193. label="观看用户数"
  194. header-align="center"
  195. align="center"
  196. prop="userCount"
  197. >
  198. <template #default="scope">
  199. <countTo
  200. :startVal="scope.row.userCount || 0"
  201. :endVal="scope.row.userCount || 0"
  202. :duration="100"
  203. ></countTo>
  204. </template>
  205. </el-table-column>
  206. <el-table-column
  207. label="累计观看时长"
  208. header-align="center"
  209. align="center"
  210. prop="duration"
  211. >
  212. <template #default="scope">
  213. {{ timeFormat(scope.row.duration) }}
  214. </template>
  215. </el-table-column>
  216. <el-table-column
  217. label="累计观看次数"
  218. header-align="center"
  219. align="center"
  220. prop="pv"
  221. >
  222. <template #default="scope">
  223. <countTo
  224. :startVal="scope.row.pv || 0"
  225. :endVal="scope.row.pv || 0"
  226. :duration="100"
  227. ></countTo>
  228. </template>
  229. </el-table-column>
  230. <el-table-column
  231. label="评论数"
  232. header-align="center"
  233. align="center"
  234. prop="comments"
  235. >
  236. <template #default="scope">
  237. <countTo
  238. :startVal="scope.row.comments || 0"
  239. :endVal="scope.row.comments || 0"
  240. :duration="100"
  241. ></countTo>
  242. </template>
  243. </el-table-column>
  244. <el-table-column
  245. label="点赞数"
  246. header-align="center"
  247. align="center"
  248. prop="support"
  249. >
  250. <template #default="scope">
  251. <countTo
  252. :startVal="scope.row.support || 0"
  253. :endVal="scope.row.support || 0"
  254. :duration="100"
  255. ></countTo>
  256. </template>
  257. </el-table-column>
  258. <!-- <el-table-column
  259. label="礼物数"
  260. header-align="center"
  261. align="center"
  262. prop="giftCount"
  263. >
  264. <template #default="scope">
  265. <countTo
  266. :startVal="scope.row.giftCount || 0"
  267. :endVal="scope.row.giftCount || 0"
  268. :duration="100"
  269. ></countTo>
  270. </template>
  271. </el-table-column> -->
  272. </el-table>
  273. <br />
  274. <el-pagination
  275. layout="prev, pager, next"
  276. :page-size="form.size"
  277. :current-page="form.page"
  278. :total="table.total"
  279. background
  280. @current-change="changePage"
  281. />
  282. </el-card>
  283. </div>
  284. </template>
  285. <script>
  286. // @ is an alias to /src
  287. import { getRule, getAppList, getSearchData, getLivePage } from "@/api/index";
  288. import countTo from "@/components/counto/vue-countTo.vue";
  289. import config from "@/config/index";
  290. export default {
  291. name: "Version",
  292. data() {
  293. return {
  294. lastParams: {},
  295. table: {},
  296. numType: "newUser",
  297. form: {
  298. app: "",
  299. version: [],
  300. channel: [],
  301. date: [],
  302. liveId: "",
  303. liveTitle: "",
  304. publisherName: "",
  305. page: 1,
  306. size: 20,
  307. },
  308. cycle: [],
  309. showList: [],
  310. channel: [],
  311. version: [],
  312. };
  313. },
  314. async mounted() {
  315. const { source, appV, appC, appli, appVLi, appCLi } =
  316. await this.getAppListFunc();
  317. const keys = {
  318. value: "mname",
  319. label: "mname",
  320. };
  321. this.cycle = this.verifyList(appli, source, keys, false);
  322. this.channel = this.verifyList(appCLi, appC, keys, true);
  323. this.version = this.verifyList(appVLi, appV, keys, true);
  324. this.form = {
  325. // app: (this.cycle[0] || { value: "" }).value,
  326. app: "起点新闻",
  327. version: [(this.version[0] || { value: "" }).value],
  328. channel: [(this.channel[0] || { value: "" }).value],
  329. date: [new Date(Date.now() - 604800000), new Date(Date.now() - 86400000)],
  330. liveId: "",
  331. liveTitle: "",
  332. publisherName: "",
  333. };
  334. this.onSubmit();
  335. },
  336. computed: {},
  337. methods: {
  338. verifyList(list, verify, obj, more) {
  339. if (!obj) return;
  340. let li = list || [];
  341. const out = [];
  342. more && out.push({ value: -1, label: "不限" });
  343. for (let i = 0; i < li.length; i++) {
  344. const v = li[i];
  345. if (verify.length !== 0 && !verify[v.mcode]) continue;
  346. out.push({
  347. value: v[obj.value],
  348. label: v[obj.label],
  349. });
  350. }
  351. return out;
  352. },
  353. selectNumType(type) {
  354. this.numType = type;
  355. },
  356. changePage(e) {
  357. this.form.page = e;
  358. this.onSubmit();
  359. },
  360. onSubmit() {
  361. this.lastParams = {
  362. app: this.form.app,
  363. start: this.FormData(this.form.date[0]),
  364. end: this.FormData(this.form.date[1]),
  365. manufacturer: this.form.channel == -1 ? undefined : this.form.channel,
  366. version: this.form.version == -1 ? undefined : this.form.version,
  367. liveId: this.form.liveId,
  368. liveTitle: this.form.liveTitle,
  369. publisherName: this.form.publisherName,
  370. page: this.form.page,
  371. pageSize: this.form.size,
  372. };
  373. getLivePage(this.lastParams).then(r => (this.table = r || {}));
  374. },
  375. async getAppListFunc() {
  376. const { r, li, appVersion, channel } = await this.getAppListOri();
  377. let source = { length: 0 },
  378. appli = [];
  379. let appV = { length: 0 },
  380. appVLi = [];
  381. let appC = { length: 0 },
  382. appCLi = [];
  383. let prvList = r.output && r.output.data && r.output.data.prvRolectrl || [];
  384. for (let i = 0; i < prvList.length; i++) {
  385. const v = prvList[i];
  386. if (v.controlid == "RMT_SOURCE")
  387. (source[v.detid] = true), (source.length = source.length + 1);
  388. if (v.controlid == "APP_VERSION")
  389. (appV[v.detid] = true), (appV.length = appV.length + 1);
  390. if (v.controlid == "CHANNEL")
  391. (appC[v.detid] = true), (appC.length = appC.length + 1);
  392. }
  393. if (li.status === "0") appli = li.output.data || [];
  394. if (appVersion.length) appVLi = appVersion || [];
  395. if (channel.length) appCLi = channel || [];
  396. return {
  397. source,
  398. appV,
  399. appC,
  400. appli,
  401. appVLi,
  402. appCLi,
  403. };
  404. },
  405. async getAppListOri() {
  406. const roleid = JSON.parse(
  407. window.parent.localStorage.userinfo || "{}"
  408. ).roleid;
  409. const r = await getRule({
  410. db: "authplat",
  411. exportMark: "0",
  412. menuid: 399,
  413. roleid,
  414. });
  415. // 应用列表
  416. const li = await getAppList({
  417. exportMark: "0",
  418. gcode: "SOURCE",
  419. pageid: 1,
  420. pagesize: 1000,
  421. });
  422. const defaultAppName = "起点新闻";
  423. // 应用版本列表
  424. const appVersion = await getSearchData({
  425. gcode: "APP_VERSION",
  426. source: defaultAppName,
  427. });
  428. // 应用渠道列表
  429. const channel = await getSearchData({
  430. gcode: "CHANNEL",
  431. source: defaultAppName,
  432. });
  433. return { r, li, appVersion, channel };
  434. },
  435. disabledDate(time) {
  436. const first = new Date("2021-06-21 00:00:00");
  437. return (
  438. time.getTime() > Date.now() - 86400000 ||
  439. time.getTime() < first.getTime()
  440. );
  441. },
  442. FormData(date) {
  443. const d = new Date(date || Date.now() - 86400000);
  444. const year = d.getFullYear();
  445. const month =
  446. d.getMonth() <= 8 ? "0" + (d.getMonth() + 1) : d.getMonth() + 1;
  447. const day = d.getDate() <= 9 ? "0" + d.getDate() : d.getDate();
  448. return [year, month, day].join("-");
  449. },
  450. timeFormat(t) {
  451. const Time = t || 0;
  452. const mH = Time % 3600;
  453. let hour = (Time - mH) / 3600;
  454. let min = (mH - (mH % 60)) / 60;
  455. let son = Number(mH % 60).toFixed(0);
  456. hour = hour <= 9 ? "0" + hour : hour;
  457. min = min <= 9 ? "0" + min : min;
  458. son = son <= 9 ? "0" + son : son;
  459. let out = [];
  460. if (hour * 1 > 0) out.push(hour);
  461. out.push(...[min, son]);
  462. return out.join(":");
  463. },
  464. change() {
  465. const roleid = JSON.parse(
  466. window.parent.localStorage.userinfo || "{}"
  467. ).roleid;
  468. const appV = {
  469. length: 0,
  470. };
  471. getRule({
  472. db: "authplat",
  473. exportMark: "0",
  474. menuid: 399,
  475. roleid,
  476. }).then(rule => {
  477. let prvList = rule.output && rule.output.data && rule.output.data.prvRolectrl || [];
  478. for (let i = 0; i < prvList.length; i++) {
  479. const v = prvList[i];
  480. if (v.controlid == "APP_VERSION")
  481. (appV[v.detid] = true), (appV.length = appV.length + 1);
  482. }
  483. getSearchData({
  484. gcode: "APP_VERSION",
  485. source: this.form.app,
  486. }).then(r => {
  487. let version = [
  488. {
  489. label: "不限",
  490. value: -1,
  491. },
  492. ];
  493. r.map(v => {
  494. if ((appV.length && appV[v.mcode]) || appV.length === 0)
  495. version.push({
  496. value: v.mname,
  497. label: v.mname,
  498. });
  499. });
  500. this.version = version;
  501. this.form = {
  502. ...this.form,
  503. version: [-1],
  504. };
  505. });
  506. getSearchData({
  507. gcode: "CHANNEL",
  508. source: this.form.app,
  509. }).then(r => {
  510. let channel = [
  511. {
  512. label: "不限",
  513. value: -1,
  514. },
  515. ];
  516. r.map(v => {
  517. if ((appV.length && appV[v.mcode]) || appV.length === 0)
  518. channel.push({
  519. value: v.mname,
  520. label: v.mname,
  521. });
  522. });
  523. this.channel = channel;
  524. this.form = {
  525. ...this.form,
  526. channel: [-1],
  527. };
  528. });
  529. });
  530. },
  531. changeversion(v) {
  532. if (!v.length) return (this.form.version = [-1]);
  533. const last = v[v.length - 1];
  534. if (last == -1) return (this.form.version = [-1]);
  535. let ver = [];
  536. for (let i = 0; i < v.length; i++) {
  537. const element = v[i];
  538. if (element == -1) continue;
  539. ver.push(element);
  540. }
  541. this.form.version = ver;
  542. },
  543. changechannel(v) {
  544. if (!v.length) return (this.form.channel = [-1]);
  545. const last = v[v.length - 1];
  546. if (last == -1) return (this.form.channel = [-1]);
  547. let ver = [];
  548. for (let i = 0; i < v.length; i++) {
  549. const element = v[i];
  550. if (element == -1) continue;
  551. ver.push(element);
  552. }
  553. this.form.channel = ver;
  554. },
  555. onExport() {
  556. const S = this.form.date[0]
  557. ? this.FormData(this.form.date[0])
  558. : undefined;
  559. const E = this.form.date[1]
  560. ? this.FormData(this.form.date[1])
  561. : undefined;
  562. const app = this.lastParams.app || this.form.app;
  563. const version =
  564. this.form.version == -1 ? undefined : this.form.version.join(",");
  565. const manufacturer =
  566. this.lastParams.manufacturer || this.form.channel.join(",");
  567. let url =
  568. config.base.leverAudience +
  569. "/cxzx-program/new-media/live/export?start=" +
  570. S +
  571. "&end=" +
  572. E +
  573. "&app=" +
  574. app;
  575. version && (url += "&version=" + version);
  576. version && (url += "&version=" + version);
  577. this.lastParams.liveId && (url += "&liveId=" + this.lastParams.liveId);
  578. this.lastParams.liveTitle &&
  579. (url += "&liveTitle=" + this.lastParams.liveTitle);
  580. this.lastParams.publisherName &&
  581. (url += "&publisherName=" + this.lastParams.publisherName);
  582. manufacturer &&
  583. manufacturer !== -1 &&
  584. (url += "&manufacturer=" + manufacturer);
  585. window.open(url);
  586. },
  587. },
  588. components: {
  589. countTo,
  590. },
  591. };
  592. </script>
  593. <style>
  594. .Content {
  595. margin: 10px 15px;
  596. }
  597. .libTitle {
  598. color: tomato;
  599. font-weight: 700;
  600. font-size: 14px;
  601. }
  602. .btn-next i,
  603. .btn-prev i {
  604. margin: 0 auto;
  605. }
  606. .caret-wrapper .ascending {
  607. display: none;
  608. }
  609. </style>