vDay.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. <template>
  2. <div class="vsummary">
  3. <div class="timeDiv">
  4. <div>
  5. <span>时间范围:</span>
  6. <a-button type="default" @click="yesterdayHandle">昨日</a-button>
  7. <a-date-picker
  8. :disabled-date="disabledDate"
  9. format="YYYY-MM-DD"
  10. style="width: 200px;"
  11. @change="dateChange"
  12. v-model="dateRange"
  13. />
  14. </div>
  15. <div>
  16. <span>消耗:</span>
  17. <a-input-number id="inputNumber" v-model="consumeValue" :min="0" @change="consumeOnChange" />
  18. <span>视频ID:</span>
  19. <a-input class="myinput" v-model="videoID" />
  20. </div>
  21. <a-button type="primary" @click="searchRes">查询</a-button>
  22. </div>
  23. <div style="display:flex;margin-bottom:15px" class="btndiv">
  24. <a-button type="primary" @click="customColumns">自定义列</a-button>
  25. </div>
  26. <a-modal v-model="visible" title="自定义列" on-ok="handleOk" width="65%">
  27. <template slot="footer">
  28. <a-button key="back" @click="handleCancel">取消</a-button>
  29. <a-button key="submit" type="primary" :loading="loading" @click="handleOk">应用</a-button>
  30. </template>
  31. <!-- <a-input-search placeholder="输入要添加的列的名称" style="width: 40%" enter-button @search="onSearch" /> -->
  32. <div class="zhuti">
  33. <div class="addlist">
  34. <p>可添加的列</p>
  35. <div class="selectionList">
  36. <!-- v-for="(item,index) in addColumns" :key="index" -->
  37. <selectComponent :showCol="listNum" @getshowlist="getshowlist" :fixedColLength='columnsFixd.length' />
  38. </div>
  39. </div>
  40. <div class="listNum">
  41. <p>已选{{listNum.length}}列</p>
  42. <a-button id="btn" type="link" @click="clearAllList">清空全部</a-button>
  43. <ul class="selectlist">
  44. <li v-for="(item,index) in listNum" :key="index">
  45. <span v-if=" index <5">
  46. <a-icon type="lock" />
  47. <span class="listText">{{item.title}}</span>
  48. </span>
  49. <span v-else-if=" index >4">
  50. <a-icon type="menu" style="color:#ccc" />
  51. <span class="listText">{{item.title}}</span>
  52. <a-icon
  53. type="close"
  54. @click="deleteCol(item,index)"
  55. id="closeStyle"
  56. style="fontSize:12px;"
  57. />
  58. </span>
  59. </li>
  60. </ul>
  61. </div>
  62. </div>
  63. </a-modal>
  64. <a-table
  65. size="middle"
  66. :columns="columns"
  67. :dataSource="data"
  68. bordered
  69. id="outTable"
  70. :pagination="ipagination"
  71. :scroll="{ x: scrollX }"
  72. :loading="loading"
  73. ref="vSummaryTable"
  74. height='100'
  75. :width='tableWidth'
  76. >
  77. <div slot="videoU" slot-scope="test,records">
  78. <img :src="records.url+'?x-oss-process=video/snapshot,t_0,m_fast'" alt="" style="width:140px" @click="openVideo(records.url)">
  79. </div>
  80. <span slot="ctr" slot-scope="ctr">{{ ctr | toPercentage }}</span>
  81. <span
  82. slot="play25FeedBreakRate"
  83. slot-scope="play25FeedBreakRate"
  84. >{{ play25FeedBreakRate | toPercentage }}</span>
  85. <span slot="playOverRate" slot-scope="playOverRate">{{ playOverRate | toPercentage }}</span>
  86. <span slot="convertRate" slot-scope="convertRate">{{ convertRate | toPercentage }}</span>
  87. <span
  88. slot="downloadStartRate"
  89. slot-scope="downloadStartRate"
  90. >{{ downloadStartRate | toPercentage }}</span>
  91. <span
  92. slot="downloadFinishRate"
  93. slot-scope="downloadFinishRate"
  94. >{{ downloadFinishRate | toPercentage }}</span>
  95. <span slot="activeRate" slot-scope="activeRate">{{ activeRate | toPercentage }}</span>
  96. <span
  97. slot="activeRegisterRate"
  98. slot-scope="activeRegisterRate"
  99. >{{ activeRegisterRate | toPercentage }}</span>
  100. <span
  101. slot="gameAddictionRate"
  102. slot-scope="gameAddictionRate"
  103. >{{ gameAddictionRate | toPercentage }}</span>
  104. <span slot="nextDayOpenRate" slot-scope="nextDayOpenRate">{{ nextDayOpenRate | toPercentage }}</span>
  105. <span slot="convertRate" slot-scope="convertRate">{{ convertRate | toPercentage }}</span>
  106. <span slot="nextDayOpenRate" slot-scope="nextDayOpenRate">{{ nextDayOpenRate | toPercentage }}</span>
  107. <span slot="ctr" slot-scope="ctr">{{ ctr | toPercentage }}</span>
  108. <span slot="cpc" slot-scope="cpm">{{ cpm | tofixed }}</span>
  109. <span slot="cpm" slot-scope="cpm">{{ cpm | tofixed }}</span>
  110. <span slot="activeRate" slot-scope="activeRate">{{ activeRate | toPercentage }}</span>
  111. <span slot="installFinishRate" slot-scope="installFinishRate">{{ installFinishRate | toPercentage }}</span>
  112. <span slot="validPlayRate" slot-scope="validPlayRate">{{ validPlayRate | tofixed }}</span>
  113. <span slot="activePayCost" slot-scope="activePayCost">{{ activePayCost | tofixed }}</span>
  114. <span slot="nextDayOpenCost" slot-scope="nextDayOpenCost">{{ nextDayOpenCost | tofixed }}</span>
  115. <span slot="validPlayCost" slot-scope="validPlayCost">{{ validPlayCost | tofixed }}</span>
  116. <span slot="activeCost" slot-scope="activeCost">{{ activeCost | tofixed }}</span>
  117. <span slot="gameAddictionCost" slot-scope="gameAddictionCost">{{ gameAddictionCost | tofixed }}</span>
  118. <span slot="downloadFinishCost" slot-scope="downloadFinishCost">{{ downloadFinishCost | tofixed }}</span>
  119. <span slot="downloadStartCost" slot-scope="downloadStartCost">{{ downloadStartCost | tofixed }}</span>
  120. <span slot="installFinishCost" slot-scope="installFinishCost">{{ installFinishCost | tofixed }}</span>
  121. <span slot="convertCost" slot-scope="convertCost">{{ convertCost | tofixed }}</span>
  122. </a-table>
  123. <a-modal v-model="Videovisible" title="视频详情" @ok="videoOk" :footer="null" width='50%'>
  124. <video
  125. @click.stop
  126. class="video"
  127. :src="videoUrl"
  128. controls="controls"
  129. style="height:600px;width:100%"
  130. >您的浏览器不支持 video 标签。</video>
  131. </a-modal>
  132. </div>
  133. </template>
  134. <script>
  135. import moment from 'moment'
  136. import { JeecgListMixin } from '@/mixins/ipagination'
  137. import { getAction, postAction, downFile, downFilePost } from '@/api/manage'
  138. import selectComponent from './selectComponent'
  139. const columnsFixd = [
  140. {
  141. title: '时间',
  142. dataIndex: 'statDatetime',
  143. align: 'center',
  144. width: 100,
  145. fixed: 'left'
  146. },
  147. {
  148. title: '视频',
  149. dataIndex: 'videoU',
  150. align: 'center',
  151. width: 150,
  152. fixed: 'left',
  153. key: 'videoU',
  154. scopedSlots: { customRender: 'videoU' }
  155. },
  156. {
  157. title: '视频ID',
  158. dataIndex: 'signature',
  159. align: 'center',
  160. width: 100,
  161. fixed: 'left'
  162. },
  163. {
  164. title: '视频链接',
  165. dataIndex: 'url',
  166. align: 'center',
  167. width: 150,
  168. fixed: 'left'
  169. },
  170. {
  171. title: '视频描述',
  172. dataIndex: 'materialDesc',
  173. align: 'center',
  174. width: 100,
  175. fixed: 'left'
  176. }
  177. ]
  178. let variableCol = [
  179. {
  180. title: '消耗',
  181. dataIndex: 'cost',
  182. scopedSlots: { customRender: 'cost' },
  183. align: 'center',
  184. sorter: (a, b) => a.cost - b.cost
  185. },
  186. {
  187. title: '点击数',
  188. dataIndex: 'clickMaterial',
  189. align: 'center',
  190. scopedSlots: { customRender: 'clickMaterial' },
  191. sorter: (a, b) => a.clickMaterial - b.clickMaterial
  192. },
  193. {
  194. title: '点击率',
  195. dataIndex: 'ctr',
  196. align: 'center',
  197. scopedSlots: { customRender: 'ctr' },
  198. sorter: (a, b) => a.ctr - b.ctr
  199. },
  200. {
  201. title: '展示数',
  202. dataIndex: 'showMaterial',
  203. align: 'center',
  204. scopedSlots: { customRender: 'showMaterial' },
  205. sorter: (a, b) => a.showMaterial - b.showMaterial
  206. },
  207. {
  208. title: '25%进度播放率',
  209. dataIndex: 'play25FeedBreakRate',
  210. align: 'center',
  211. scopedSlots: { customRender: 'play25FeedBreakRate' },
  212. sorter: (a, b) => a.play25FeedBreakRate - b.play25FeedBreakRate
  213. },
  214. {
  215. title: '播完率',
  216. dataIndex: 'playOverRate',
  217. align: 'center',
  218. tip: '表示广告在投放期内的预估花费金额。当天数据可能会有波动,次日稳定',
  219. scopedSlots: { customRender: 'playOverRate' },
  220. sorter: (a, b) => a.playOverRate - b.playOverRate
  221. },
  222. {
  223. title: '转化数',
  224. dataIndex: 'convertMaterial',
  225. align: 'center',
  226. scopedSlots: { customRender: 'convertMaterial' },
  227. sorter: (a, b) => a.convertMaterial - b.convertMaterial
  228. },
  229. {
  230. title: '转化率',
  231. dataIndex: 'convertRate',
  232. align: 'center',
  233. scopedSlots: { customRender: 'convertRate' },
  234. sorter: (a, b) => a.convertRate - b.convertRate
  235. }
  236. ]
  237. export default {
  238. data() {
  239. return {
  240. //gudinglie
  241. columnsFixd:columnsFixd,
  242. //设置表格的列宽
  243. tableWidth:'',
  244. columnsFixd,
  245. //是否打开视频
  246. Videovisible:false,
  247. videoUrl:'',
  248. //消耗的值
  249. consumeValue: 1000,
  250. //视频ID
  251. videoID: '',
  252. columns: [...columnsFixd, ...variableCol],
  253. addColumns: [],
  254. data: [],
  255. //右侧显示供选择几天
  256. totalSelect: 0,
  257. //是否显示共选几天的提示
  258. daysFlag: false,
  259. //日期选择器显示的日期范围
  260. dateRange: null,
  261. dataElse: [],
  262. loading: false,
  263. visible: false,
  264. //自定义列的搜索框
  265. searchInput: '',
  266. //弹出框中现实的选中列数
  267. scrollX: 0,
  268. listNum: [],
  269. //
  270. timedata: []
  271. //
  272. }
  273. },
  274. components: {
  275. selectComponent
  276. },
  277. mixins: [JeecgListMixin],
  278. methods: {
  279. moment,
  280. //打开视频
  281. openVideo(val){
  282. this.Videovisible=true;
  283. this.videoUrl=val
  284. },
  285. videoOk(){
  286. this.Videovisible=false
  287. },
  288. disabledDate(current) {
  289. // console.log(current)
  290. return current && current > moment().subtract(1, 'day')
  291. },
  292. consumeOnChange() {},
  293. //点击时间的 昨日 按钮
  294. yesterdayHandle() {
  295. let yesterday = moment()
  296. .subtract(1, 'days')
  297. .format('YYYY-MM-DD')
  298. this.dateRange=moment(yesterday)
  299. console.log(this.dateRange);
  300. this.timedata=this.dateRange
  301. // this.totalSelect = 1
  302. // this.daysFlag = true
  303. postAction('/toutiao/videoReportDaily/bytedanceVideoInfoListDaily', {
  304. date: this.timedata,
  305. cost: this.consumeValue,
  306. signature:this.videoID
  307. }).then(res => {
  308. let resArr = []
  309. this.loading = false
  310. console.log(res)
  311. if (res.success) {
  312. let result = res.result
  313. this.data.push({ ...result, key: 1 })
  314. result.map((item, index) => {
  315. item.key = index
  316. })
  317. this.data = result
  318. }
  319. })
  320. },
  321. //查询按钮
  322. searchRes() {
  323. console.log(this.timedata[0])
  324. this.date = []
  325. this.loading = true
  326. postAction('/toutiao/videoReportDaily/bytedanceVideoInfoListDaily', {
  327. date: this.timedata,
  328. cost: this.consumeValue,
  329. signature:this.videoID
  330. }).then(res => {
  331. let resArr = []
  332. this.loading = false
  333. console.log(res)
  334. if (res.success) {
  335. let result = res.result
  336. this.data.push({ ...result, key: 1 })
  337. result.map((item, index) => {
  338. item.key = index
  339. })
  340. this.data = result
  341. }
  342. })
  343. },
  344. //日期选择回调
  345. dateChange(data, dataString) {
  346. this.timedata = dataString
  347. },
  348. //弹出框打开,自定义列
  349. customColumns() {
  350. this.visible = true
  351. this.listNum = [...this.columns]
  352. },
  353. tableHandle(){
  354. // this.listNum = [...this.columns]
  355. console.log(this.listNum.length,this.columns)
  356. this.scrollX=0;
  357. if(this.listNum.length >= 12|| this.columns.length>=12){
  358. this.tableWidth=120;
  359. this.scrollX=this.columns.length*120
  360. console.log(this.scrollX)
  361. }else{
  362. this.scrollX = 0
  363. }
  364. },
  365. //弹出框确定
  366. handleOk(e) {
  367. this.loading = false
  368. this.visible = false
  369. this.tableHandle()
  370. if(this.listNum.length>=10){
  371. let newlist=this.listNum.slice(columnsFixd.length)
  372. console.log(newlist)
  373. this.columns = [...columnsFixd,...newlist]
  374. }else{
  375. this.columns = [...this.listNum]
  376. }
  377. // console.log(this.columns.length)
  378. if (this.columns.length == 4) {
  379. // console.log(this.listNum.length)
  380. this.columns.map((item, index) => {
  381. item.width = 500
  382. })
  383. // console.log(1)
  384. } else {
  385. this.columns.map((item, index) => {
  386. if (index == 1||index==3) {
  387. item.width = 150
  388. } else if (index >= 2 && index < 5 || index == 0) {
  389. item.width = 100
  390. }
  391. })
  392. // console.log(2)
  393. }
  394. },
  395. //弹出框取消按钮
  396. handleCancel(e) {
  397. this.visible = false
  398. },
  399. //弹出框里的搜索框
  400. onSearch(value) {
  401. console.log(value)
  402. },
  403. //清空全部按钮的事件
  404. clearAllList() {
  405. this.listNum = [...columnsFixd]
  406. console.log(this.listNum)
  407. console.log(this.$refs.vSummaryTable)
  408. },
  409. //li展示里的关闭按钮 删除当前被选中的这一个列
  410. deleteCol(item, index) {
  411. this.listNum = this.listNum.filter((item1, num) => {
  412. return num != index
  413. })
  414. },
  415. //从自定义列拿选择的项
  416. getshowlist(val) {
  417. console.log(val)
  418. if (val.length) {
  419. console.log(val);
  420. this.listNum = [...this.listNum,...val]
  421. } else {
  422. var arr
  423. arr = this.listNum.filter((item, index) => {
  424. return item.dataIndex == val.dataIndex
  425. })
  426. }
  427. if (arr.length > 0) {
  428. var index
  429. this.listNum.map((item,ind) => {
  430. if(item.dataIndex == val.dataIndex){
  431. index=ind
  432. }
  433. })
  434. console.log(index)
  435. this.listNum.splice(index, 1)
  436. } else {
  437. this.listNum.push(val)
  438. }
  439. }
  440. },
  441. activated() {
  442. console.log('activated')
  443. // this.getParticipateList()
  444. this.statDate = moment().subtract(1, 'day')
  445. moment().format('YYYY-MM-DD_HH:mm')
  446. postAction('/toutiao/videoReportDaily/getColumnJson', {
  447. columnType:2,
  448. }).then((res)=>{
  449. // console.log(res)
  450. if(res.success){
  451. // console.log(JSON.parse(res.result))
  452. let columns=JSON.parse(res.result)
  453. if(columns.length){
  454. if(columns.length>=columnsFixd.length){
  455. columns.map((item,index)=>{
  456. if(index>columnsFixd.length-1){
  457. item.sorter=function(a,b){ return a[item.dataIndex]-b[item.dataIndex]}
  458. }})
  459. columns=columns.slice(columnsFixd.length);
  460. this.columns=[...columnsFixd,...columns]
  461. this.tableHandle()
  462. }
  463. // console.log(this.columns)
  464. }
  465. }
  466. })
  467. },
  468. deactivated() {
  469. let arr = JSON.stringify(this.columns)
  470. // console.log(arr)
  471. postAction('/toutiao/videoReportDaily/saveOrUpdateColumnJson', {
  472. json: arr,
  473. columnType: 2
  474. }).then(res => {
  475. // console.log(res)
  476. })
  477. },
  478. filters: {
  479. toPercentage(val) {
  480. return (val * 100).toFixed(2) + '%'
  481. // return val
  482. },
  483. tofixed(val){
  484. return Number(val).toFixed(2)
  485. }
  486. },
  487. }
  488. </script>
  489. <style lang="less">
  490. .ant-table .ant-table-fixed-left .ant-table-thead {
  491. height: 108px !important ;
  492. }
  493. .ant-table .ant-table-thead .ant-table-header-column .ant-table-column-title{
  494. // display:block;
  495. white-space:normal;
  496. word-break: break-all;
  497. }
  498. </style>
  499. <style lang="scss" scoped>
  500. .vsummary {
  501. width: 100%;
  502. height: 100%;
  503. }
  504. .timeDiv {
  505. display: flex;
  506. justify-content: space-between;
  507. }
  508. span {
  509. margin-left: 5px;
  510. }
  511. .myinput {
  512. width: 40%;
  513. }
  514. .addlist {
  515. float: left;
  516. width: 70%;
  517. border: 1px solid #eee;
  518. .selectionList {
  519. padding: 10px 15px;
  520. height: 450px;
  521. overflow: auto;
  522. .leibie {
  523. .leiName {
  524. font-size: 26px;
  525. text-align: left;
  526. }
  527. }
  528. .jutixiang {
  529. display: inline-block;
  530. width: 32%;
  531. box-sizing: border-box;
  532. padding: 10px 3px;
  533. }
  534. }
  535. }
  536. .listNum {
  537. float: right;
  538. width: 28%;
  539. border: 1px solid #eee;
  540. position: relative;
  541. }
  542. .zhuti {
  543. margin-top: 15px;
  544. overflow: hidden;
  545. p {
  546. height: 40px;
  547. line-height: 20px;
  548. padding: 10px 15px;
  549. background: rgb(249, 250, 253);
  550. border-bottom: 1px solid #eee;
  551. }
  552. #btn {
  553. position: absolute;
  554. right: 0;
  555. top: 5px;
  556. }
  557. .selectlist {
  558. width:100%;
  559. list-style: none;
  560. margin: 0;
  561. height: 450px;
  562. padding: 0 15px 10px;
  563. overflow: auto;
  564. li {
  565. width: 100%;
  566. padding: 5px 8px;
  567. margin: 6px 0;
  568. border-radius: 10px;
  569. background: rgb(248, 248, 248);
  570. height: 32px;
  571. position: relative;
  572. span {
  573. width: 80%;
  574. height: 100%;
  575. display: inline-block;
  576. margin: 0 10px;
  577. // overflow:hidden;
  578. // text-overflow:ellipsis;
  579. // white-space: nowrap;
  580. }
  581. .listText{
  582. position: absolute;
  583. top: 2;
  584. left: 10;
  585. width: 40%;
  586. overflow: hidden;
  587. white-space: nowrap;
  588. text-overflow: ellipsis;
  589. }
  590. #closeStyle {
  591. position: absolute;
  592. top: 9px;
  593. right: 7px;
  594. }
  595. }
  596. }
  597. }
  598. </style>