vDay.vue 19 KB

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