dayStatistics.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. <style lang="scss" scoped>
  2. .search-bar {
  3. display: flex;
  4. align-items: center;
  5. }
  6. .search-box p {
  7. display: inline-block;
  8. border: 1px solid #f2f2f2;
  9. border-radius: 5px;
  10. margin-right: 10px;
  11. padding: 5px 10px;
  12. cursor: pointer;
  13. }
  14. </style>
  15. <style>
  16. /* .data-display-statistics .ant-card-body {
  17. padding: 0 15px;
  18. } */
  19. .data-display-statistics .ant-col-6 {
  20. margin: 10px 0;
  21. }
  22. .data-display-statistics .ant-col-6 .ant-card-body {
  23. display: flex;
  24. justify-content: center;
  25. }
  26. .data-display-statistics .ant-col-6 p,
  27. .data-display-statistics .ant-col-6 span {
  28. text-align: center;
  29. line-height: 40px;
  30. font-size: 30px;
  31. font-weight: 600;
  32. color: red;
  33. margin: 0;
  34. }
  35. .search-box .ant-card-body {
  36. padding: 5px 15px;
  37. }
  38. .data-display-statistics .ant-col-6 .ant-card-body .styleElse {
  39. line-height: 60px;
  40. height: 40px;
  41. font-size: 16px;
  42. font-weight: 400;
  43. margin-left: 10px;
  44. }
  45. .ant-modal-wrap .yincang .ant-modal-content .ant-modal-footer {
  46. display: none !important;
  47. }
  48. .yincang .ant-col-6 p {
  49. text-align: left;
  50. color: red;
  51. font-size: 16px;
  52. font-weight: 500;
  53. }
  54. .ant-table-thead div {
  55. font-weight: 700;
  56. }
  57. .tool-tip {
  58. position: absolute;
  59. top: 65px;
  60. right: 10px;
  61. }
  62. th div {
  63. white-space: nowrap;
  64. }
  65. </style>
  66. <template>
  67. <div class="data-statistics">
  68. <a-row class="image-list-heading vm-panel">
  69. <a-row type="flex" align="middle" justify="space-between" class="panel-body">
  70. <div class="search-bar" style="width:100%">
  71. <span>账户选择:</span>
  72. <a-select
  73. v-model="projectId"
  74. style="width:500px"
  75. showSearch
  76. optionFilterProp="children"
  77. :filterOption="filterOption"
  78. >
  79. <a-select-option :value="item.projectId" v-for="item of dataElse" :key="item.id">
  80. {{ item.projectName }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{
  81. item.mediaId == "1" ? '头条' :item.mediaId == "2"? '快手':item.mediaId == "3"?'头条内广':'快手内广'
  82. }}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{{ item.advertiserName }}
  83. </a-select-option>
  84. </a-select>
  85. <span style="margin-left:10px">日期选择:</span>
  86. <a-date-picker v-model="statDate" format="YYYY-MM-DD" :defaultValue="moment().subtract(1, 'days')" />
  87. <span style="margin-left:10px">返点比例:</span>
  88. <a-input-number
  89. :min="1"
  90. :max="10"
  91. :step="0.01"
  92. v-model="discount"
  93. placeholder="请输入折扣"
  94. style="width:100px"
  95. />
  96. <a-button type="primary" style="margin:10px" @click="addUser">搜索</a-button>
  97. <a-button
  98. type="primary"
  99. icon="reload"
  100. @click="getDataReset"
  101. style="background-color:#67c23a;border-color:#67c23a"
  102. >刷新</a-button
  103. >
  104. </div>
  105. </a-row>
  106. </a-row>
  107. <a-row :gutter="10" style="margin-top:10px">
  108. <a-col :span="24">
  109. <a-card
  110. style="width:100%"
  111. :tabList="tabListNoTitle"
  112. :activeTabKey="noTitleKey"
  113. @tabChange="key => onTabChange(key, 'noTitleKey')"
  114. >
  115. <div style="display:flex;margin-bottom:15px">
  116. <!-- <a-select style="width: 120px" v-model="statHour" @change="getElseData" allowClear>
  117. <a-select-option v-for="item of 24" :key="item - 1" :value="item - 1">{{ item - 1 }}</a-select-option>
  118. </a-select> -->
  119. <a-button type="primary" @click="exportExcel">导出</a-button>
  120. </div>
  121. <a-table
  122. size="middle"
  123. :columns="columns"
  124. :dataSource="data"
  125. bordered
  126. id="outTable"
  127. :pagination="ipagination"
  128. :scroll="{ x: 2000 }"
  129. :loading="loading"
  130. >
  131. </a-table>
  132. </a-card>
  133. </a-col>
  134. </a-row>
  135. </div>
  136. </template>
  137. <script>
  138. import ARow from 'ant-design-vue/es/grid/Row'
  139. import ACol from 'ant-design-vue/es/grid/Col'
  140. import countTo from 'vue-count-to'
  141. import moment from 'moment'
  142. import { getDailyReport } from '@api/statistics'
  143. import { getAction, postAction, downFile, downFilePost } from '@/api/manage'
  144. import axios from 'axios'
  145. import lifting from '../components/lifting'
  146. import timeCheck from '../components/timeCheck'
  147. import Treeselect from '../components/Treeselect.vue'
  148. import { mapGetters } from 'vuex'
  149. import { JeecgListMixin } from '@/mixins/ipagination'
  150. var length = 0
  151. var active = 1
  152. const columns = [
  153. {
  154. title: '代理商',
  155. dataIndex: 'agent',
  156. scopedSlots: { customRender: 'agent' },
  157. align: 'center'
  158. },
  159. {
  160. title: '媒体',
  161. dataIndex: 'media',
  162. scopedSlots: { customRender: 'media' },
  163. align: 'center'
  164. },
  165. {
  166. title: '设备',
  167. dataIndex: 'systemType',
  168. align: 'center'
  169. },
  170. {
  171. title: '日期',
  172. dataIndex: 'statDate',
  173. align: 'center'
  174. },
  175. {
  176. title: '渠道包',
  177. dataIndex: 'campaignName',
  178. align: 'center'
  179. },
  180. {
  181. title: '账面花费',
  182. dataIndex: 'charge',
  183. align: 'center',
  184. scopedSlots: { customRender: 'charge' }
  185. },
  186. {
  187. title: '现金花费',
  188. dataIndex: 'cashCost',
  189. align: 'center',
  190. scopedSlots: { customRender: 'cashCost' }
  191. },
  192. {
  193. title: '曝光',
  194. dataIndex: 'photoShow',
  195. align: 'center',
  196. scopedSlots: { customRender: 'photoShow' }
  197. },
  198. {
  199. title: '点击',
  200. dataIndex: 'photoClick',
  201. align: 'center',
  202. scopedSlots: { customRender: 'photoClick' }
  203. },
  204. {
  205. title: '点击率',
  206. dataIndex: 'clickRate',
  207. align: 'center',
  208. scopedSlots: { customRender: 'clickRate' }
  209. },
  210. {
  211. title: '千次嚗光花费',
  212. dataIndex: 'impression1kCost',
  213. align: 'center',
  214. scopedSlots: { customRender: 'impression1kCost' }
  215. },
  216. {
  217. title: '行为量',
  218. dataIndex: 'bclick',
  219. align: 'center',
  220. scopedSlots: { customRender: 'bclick' }
  221. },
  222. {
  223. title: '下载完成数',
  224. dataIndex: 'eventJinJianApp',
  225. align: 'center',
  226. scopedSlots: { customRender: 'eventJinJianApp' }
  227. },
  228. {
  229. title: '账户激活量',
  230. dataIndex: 'activation',
  231. align: 'center',
  232. scopedSlots: { customRender: 'activation' }
  233. },
  234. {
  235. title: '友盟激活量',
  236. dataIndex: 'youMengactivation',
  237. align: 'center',
  238. scopedSlots: { customRender: 'youMengactivation' }
  239. },
  240. {
  241. title: 'TD激活量',
  242. dataIndex: 'tdActivation',
  243. align: 'center',
  244. scopedSlots: { customRender: 'tdActivation' }
  245. },
  246. {
  247. title: '账户激活成本',
  248. dataIndex: 'activationCost',
  249. align: 'center',
  250. scopedSlots: { customRender: 'activationCost' }
  251. },
  252. {
  253. title: '友盟激活成本',
  254. dataIndex: 'youMengactivationCost',
  255. align: 'center',
  256. scopedSlots: { customRender: 'youMengactivationCost' }
  257. },
  258. {
  259. title: 'TD激活成本',
  260. dataIndex: 'tdActivationCost',
  261. align: 'center',
  262. scopedSlots: { customRender: 'tdActivationCost' }
  263. },
  264. {
  265. title: '平均行为单价',
  266. dataIndex: 'actionCost',
  267. align: 'center',
  268. scopedSlots: { customRender: 'actionCost' }
  269. },
  270. {
  271. title: '平均点击单价',
  272. dataIndex: 'clickCost',
  273. align: 'center',
  274. scopedSlots: { customRender: 'clickCost' }
  275. },
  276. {
  277. title: '行为率',
  278. dataIndex: 'actionRatio',
  279. align: 'center',
  280. scopedSlots: { customRender: 'actionRatio' }
  281. },
  282. {
  283. title: '下载完成行为率',
  284. dataIndex: 'eventJinJianAppRatio',
  285. align: 'center',
  286. scopedSlots: { customRender: 'eventJinJianAppRatio' }
  287. },
  288. {
  289. title: '下载完成激活率',
  290. dataIndex: 'activationRatio',
  291. align: 'center',
  292. scopedSlots: { customRender: 'activationRatio' }
  293. }
  294. ]
  295. const columnsThree = [
  296. {
  297. title: '代理商',
  298. dataIndex: 'agent',
  299. scopedSlots: { customRender: 'agent' },
  300. align: 'center'
  301. },
  302. {
  303. title: '媒体',
  304. dataIndex: 'media',
  305. scopedSlots: { customRender: 'media' },
  306. align: 'center'
  307. },
  308. {
  309. title: '设备',
  310. dataIndex: 'systemType',
  311. align: 'center'
  312. },
  313. {
  314. title: '日期',
  315. dataIndex: 'statDate',
  316. align: 'center'
  317. },
  318. {
  319. title: '账面花费',
  320. dataIndex: 'charge',
  321. align: 'center',
  322. scopedSlots: { customRender: 'charge' }
  323. },
  324. {
  325. title: '现金花费',
  326. dataIndex: 'cashCost',
  327. align: 'center',
  328. scopedSlots: { customRender: 'cashCost' }
  329. },
  330. {
  331. title: '曝光',
  332. dataIndex: 'photoShow',
  333. align: 'center',
  334. scopedSlots: { customRender: 'photoShow' }
  335. },
  336. {
  337. title: '点击',
  338. dataIndex: 'photoClick',
  339. align: 'center',
  340. scopedSlots: { customRender: 'photoClick' }
  341. },
  342. {
  343. title: '点击率',
  344. dataIndex: 'clickRate',
  345. align: 'center',
  346. scopedSlots: { customRender: 'clickRate' }
  347. },
  348. {
  349. title: '千次嚗光花费',
  350. dataIndex: 'impression1kCost',
  351. align: 'center',
  352. scopedSlots: { customRender: 'impression1kCost' }
  353. },
  354. {
  355. title: '行为量',
  356. dataIndex: 'bclick',
  357. align: 'center',
  358. scopedSlots: { customRender: 'bclick' }
  359. },
  360. {
  361. title: '下载完成数',
  362. dataIndex: 'eventJinJianApp',
  363. align: 'center',
  364. scopedSlots: { customRender: 'eventJinJianApp' }
  365. },
  366. {
  367. title: '账户激活量',
  368. dataIndex: 'activation',
  369. align: 'center',
  370. scopedSlots: { customRender: 'activation' }
  371. },
  372. {
  373. title: '友盟激活量',
  374. dataIndex: 'youMengactivation',
  375. align: 'center',
  376. scopedSlots: { customRender: 'youMengactivation' }
  377. },
  378. {
  379. title: 'TD激活量',
  380. dataIndex: 'tdActivation',
  381. align: 'center',
  382. scopedSlots: { customRender: 'tdActivation' }
  383. },
  384. {
  385. title: '账户激活成本',
  386. dataIndex: 'activationCost',
  387. align: 'center',
  388. scopedSlots: { customRender: 'activationCost' }
  389. },
  390. {
  391. title: '友盟激活成本',
  392. dataIndex: 'youMengactivationCost',
  393. align: 'center',
  394. scopedSlots: { customRender: 'youMengactivationCost' }
  395. },
  396. {
  397. title: 'TD激活成本',
  398. dataIndex: 'tdActivationCost',
  399. align: 'center',
  400. scopedSlots: { customRender: 'tdActivationCost' }
  401. },
  402. {
  403. title: '平均行为单价',
  404. dataIndex: 'actionCost',
  405. align: 'center',
  406. scopedSlots: { customRender: 'actionCost' }
  407. },
  408. {
  409. title: '平均点击单价',
  410. dataIndex: 'clickCost',
  411. align: 'center',
  412. scopedSlots: { customRender: 'clickCost' }
  413. },
  414. {
  415. title: '行为率',
  416. dataIndex: 'actionRatio',
  417. align: 'center',
  418. scopedSlots: { customRender: 'actionRatio' }
  419. },
  420. {
  421. title: '下载完成行为率',
  422. dataIndex: 'eventJinJianAppRatio',
  423. align: 'center',
  424. scopedSlots: { customRender: 'eventJinJianAppRatio' }
  425. },
  426. {
  427. title: '下载完成激活率',
  428. dataIndex: 'activationRatio',
  429. align: 'center',
  430. scopedSlots: { customRender: 'activationRatio' }
  431. }
  432. ]
  433. const columnsGroup = columns
  434. export default {
  435. name: 'data-display-statistics',
  436. components: {
  437. ACol,
  438. ARow,
  439. countTo,
  440. lifting,
  441. timeCheck,
  442. Treeselect
  443. },
  444. mixins: [JeecgListMixin],
  445. data: function() {
  446. return {
  447. // this.timeRange[1] = moment().add(1, 'months')
  448. statDate: moment().subtract(1, 'day'),
  449. title: '账户数据展示',
  450. show: true,
  451. data: [],
  452. dataAll: null,
  453. columns: columnsThree,
  454. options: [],
  455. list: [],
  456. appId: [],
  457. tabListNoTitle: [
  458. {
  459. key: 'day',
  460. tab: '安卓汇总'
  461. },
  462. {
  463. key: 'group',
  464. tab: 'ios汇总'
  465. },
  466. {
  467. key: 'application',
  468. tab: '应用直达'
  469. },
  470. {
  471. key: 'channel',
  472. tab: '渠道包分析'
  473. }
  474. ],
  475. noTitleKey: 'day',
  476. discount: 1.06,
  477. date: '',
  478. loading: false,
  479. dataElse: [],
  480. projectId: 50
  481. }
  482. },
  483. filters: {
  484. formatDate: function(value) {
  485. let date = new Date(value)
  486. let y = date.getFullYear()
  487. let MM = date.getMonth() + 1
  488. MM = MM < 10 ? '0' + MM : MM
  489. let d = date.getDate()
  490. d = d < 10 ? '0' + d : d
  491. let h = date.getHours()
  492. h = h < 10 ? '0' + h : h
  493. let m = date.getMinutes()
  494. m = m < 10 ? '0' + m : m
  495. let s = date.getSeconds()
  496. s = s < 10 ? '0' + s : s
  497. return y + '-' + MM + '-' + d
  498. },
  499. toFixtwo: function(value) {
  500. if (value) {
  501. return value.toFixed(2)
  502. } else {
  503. return 0.0
  504. }
  505. },
  506. getBo: function(value) {
  507. if (value) {
  508. return (value * 100).toFixed(2) + '%'
  509. } else {
  510. return '0.00%'
  511. }
  512. }
  513. },
  514. methods: {
  515. moment,
  516. filterOption(input, option) {
  517. return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  518. },
  519. ...mapGetters(['nickname', 'avatar', 'userInfo']),
  520. getParticipateList() {
  521. getAction('/ctop/projectMember/participateList', {
  522. userId: this.userInfo().id
  523. }).then(res => {
  524. if (res.code == 0) {
  525. this.dataElse = res.result
  526. }
  527. })
  528. },
  529. onTabChange(key, type) {
  530. console.log(key, type)
  531. this[type] = key
  532. this.data = []
  533. if (this.noTitleKey == 'day') {
  534. this.columns = columnsThree
  535. this.data.push(this.dataAll.android)
  536. } else if (this.noTitleKey == 'group') {
  537. this.columns = columnsThree
  538. this.data.push(this.dataAll.ios)
  539. } else if (this.noTitleKey == 'application') {
  540. this.columns = columnsThree
  541. this.data.push(this.dataAll.directApplication)
  542. } else if (this.noTitleKey == 'channel') {
  543. this.columns = columns
  544. this.data = this.dataAll.channelSubcontracting.map((item, index) => {
  545. return {
  546. ...item,
  547. key: index
  548. }
  549. })
  550. }
  551. this.ipagination.total = this.data.length
  552. this.ipagination.current = 1
  553. },
  554. disabledDate(current) {
  555. return current && current > moment().subtract(1, 'day')
  556. },
  557. getDataReset() {
  558. this.addUser()
  559. },
  560. addUser() {
  561. var that = this
  562. // if (this.appId.length > 0 && this.date != '') {
  563. that.getDailyReport()
  564. // } else {
  565. // this.$message.error('请选择账户及时间')
  566. // }
  567. },
  568. getDailyReport() {
  569. var params = {}
  570. params.projectId = this.projectId
  571. params.disCount = this.discount
  572. params.statDate = this.statDate.format('YYYY-MM-DD')
  573. this.data = []
  574. this.loading = true
  575. postAction('/ctop/yiche/report/dailyReport', params).then(res => {
  576. if (res.success) {
  577. this.loading = false
  578. this.dataAll = res.result
  579. console.log(res)
  580. if (this.noTitleKey == 'day') {
  581. this.columns = columnsThree
  582. this.data.push({ ...res.result.android, key: 1 })
  583. } else if (this.noTitleKey == 'group') {
  584. this.columns = columnsThree
  585. this.data.push({ ...res.result.ios, key: 1 })
  586. } else if (this.noTitleKey == 'application') {
  587. this.columns = columnsThree
  588. this.data.push({ ...res.result.directApplication, key: 1 })
  589. } else if (this.noTitleKey == 'channel') {
  590. this.columns = columns
  591. this.data = res.result.channelSubcontracting.map((item, index) => {
  592. return {
  593. ...item,
  594. key: index
  595. }
  596. })
  597. }
  598. this.ipagination.total = this.data.length
  599. }
  600. })
  601. },
  602. getDate(value) {
  603. if (value) {
  604. let date = new Date(value)
  605. let y = date.getFullYear()
  606. let MM = date.getMonth() + 1
  607. MM = MM < 10 ? '0' + MM : MM
  608. let d = date.getDate()
  609. d = d < 10 ? '0' + d : d
  610. this.date = y + '-' + MM + '-' + d
  611. } else {
  612. let date = new Date()
  613. let y = date.getFullYear()
  614. let MM = date.getMonth() + 1
  615. MM = MM < 10 ? '0' + MM : MM
  616. let d = date.getDate()
  617. d = d < 10 ? '0' + d : d
  618. this.date = y + '-' + MM + '-' + d
  619. }
  620. },
  621. exportExcel() {
  622. var params = {}
  623. params.projectId = this.projectId
  624. params.disCount = this.discount
  625. params.statDate = this.statDate.format('YYYY-MM-DD')
  626. var name = this.dataElse.filter(item => {
  627. return item.projectId == this.projectId
  628. })[0].projectName
  629. downFilePost('/ctop/yiche/report/exportDailyReport', params).then(res => {
  630. let blob = new Blob([res], {
  631. type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  632. })
  633. let downloadElement = document.createElement('a')
  634. let href = window.URL.createObjectURL(blob) //创建下载的链接
  635. downloadElement.href = href
  636. downloadElement.download = name + '-' + this.statDate.format('YYYY-MM-DD') + '-日报' //下载后文件名
  637. document.body.appendChild(downloadElement)
  638. downloadElement.click() //点击下载
  639. document.body.removeChild(downloadElement) //下载完成移除元素
  640. window.URL.revokeObjectURL(href) //释放掉blob对象
  641. })
  642. }
  643. },
  644. watch: {},
  645. distoryed() {},
  646. mounted: function() {
  647. this.getParticipateList()
  648. this.statDate = moment().subtract(1, 'day')
  649. // moment().format('YYYY-MM-DD_HH:mm')
  650. }
  651. }
  652. </script>