mediaReport.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. <template>
  2. <div class="mediaReport">
  3. <div class="mediaReport_header">
  4. <div class="option-top">
  5. <span class="item">
  6. <span class="title">
  7. 公司
  8. <a-tooltip class="tipinfo">
  9. <template slot="title">
  10. 不选时,默认查询全部公司(包括渠道)。
  11. </template>
  12. <a-icon type="question-circle" />
  13. </a-tooltip>
  14. </span>
  15. <span>:</span>
  16. <a-select placeholder="请选择公司" style="width: 120px" v-model="company" @change="companyChange">
  17. <a-select-option value="">全部</a-select-option>
  18. <a-select-option v-for="item in companyArr" :key="item.companyId" :value='item.companyId'>
  19. {{item.area}}
  20. </a-select-option>
  21. </a-select>
  22. </span>
  23. <span class="item">
  24. <span class="title">
  25. 广告主
  26. <a-tooltip class="tipinfo">
  27. <template slot="title">
  28. 不选时,默认查询全部广告主。不选择公司时,不可选择广告主。
  29. </template>
  30. <a-icon type="question-circle" />
  31. </a-tooltip>
  32. </span>
  33. <span>:</span>
  34. <a-select
  35. show-search
  36. placeholder='请选择或搜索广告主'
  37. option-filter-prop="children"
  38. style="width: 300px"
  39. :filter-option="filterOption"
  40. @focus="handleFocus"
  41. @blur="handleBlur"
  42. @change="advertisersChange"
  43. v-model="advertiser"
  44. >
  45. <a-select-option value="">全部</a-select-option>
  46. <a-select-option v-for="item in advertisersArr" :key="item.id" :value='item.id'>
  47. {{item.name}}
  48. </a-select-option>
  49. </a-select>
  50. </span>
  51. <span class="item">
  52. <span class="title">
  53. 项目
  54. <a-tooltip class="tipinfo">
  55. <template slot="title">
  56. 不选时,默认查询全部项目。不选广告主时,不可选择项目
  57. </template>
  58. <a-icon type="question-circle" />
  59. </a-tooltip>
  60. </span>
  61. <span>:</span>
  62. <a-select
  63. show-search
  64. option-filter-prop="children"
  65. :filter-option="filterOption"
  66. @focus="handleFocus"
  67. @blur="handleBlur"
  68. placeholder='请选择或搜索项目'
  69. style="width: 200px"
  70. @change="projectChange"
  71. v-model="project"
  72. >
  73. <a-select-option value="">全部</a-select-option>
  74. <a-select-option v-for="item in projectArr" :key="item.id" :value='item.id'>
  75. {{item.project_name}}
  76. </a-select-option>
  77. </a-select>
  78. </span>
  79. </div>
  80. <div class="option-bot">
  81. <span class="item">
  82. <span class="title">
  83. 媒体
  84. <a-tooltip class="tipinfo">
  85. <template slot="title">
  86. 不选时,默认查询全部媒体。
  87. </template>
  88. <a-icon type="question-circle" />
  89. </a-tooltip>
  90. </span>
  91. <span>:</span>
  92. <a-select placeholder="请选择媒体" style="width: 120px" v-model="mediaType" >
  93. <a-select-option value="">全部</a-select-option>
  94. <a-select-option :value='1'>头条</a-select-option>
  95. <a-select-option :value='2'>快手</a-select-option>
  96. <a-select-option :value='3'>头条内广</a-select-option>
  97. <a-select-option :value='4'>快手内广</a-select-option>
  98. </a-select>
  99. </span>
  100. <span class="item">
  101. <span class="title">
  102. 日期
  103. <a-tooltip class="tipinfo">
  104. <template slot="title">
  105. 将以选择的日期为准,消耗差值=当天-前一天;
  106. </template>
  107. <a-icon type="question-circle" />
  108. </a-tooltip>
  109. </span>
  110. <span>:</span>
  111. <a-date-picker @change="onChange" v-model="dateValue" placeholder='请选择日期' :disabled-date="disabledDate" />
  112. </span>
  113. </div>
  114. <a-button type='primary' class="option-btn" @click="searchHandle">搜索</a-button>
  115. </div>
  116. <div class="tableBox">
  117. <div class="tableOption">
  118. <a-button type='primary' class="export" @click="exportExcel">导出报表</a-button>
  119. </div>
  120. <div class="tableBody">
  121. <a-table
  122. size="middle"
  123. :columns="columns"
  124. :dataSource="tableData"
  125. bordered
  126. id="tableBody"
  127. :pagination="ipagination"
  128. :loading="loading"
  129. @change="tableChange"
  130. style="word-break: break-all;font-size:16px;font-weight:600"
  131. >
  132. <span slot="mediaType" slot-scope="text">
  133. <span v-if="text==1">头条</span>
  134. <span v-if="text==2">快手</span>
  135. <span v-if="text==3">头条内广</span>
  136. <span v-if="text==4">快手内广</span>
  137. <span v-if="text=='-'">-</span>
  138. </span>
  139. <span slot="yesterdayCost" slot-scope="yesterdayCost">{{yesterdayCost | decimalsHandle}}</span>
  140. <span slot="todayCost" slot-scope="todayCost">{{todayCost | decimalsHandle}}</span>
  141. <span slot="diffCost" slot-scope="diffCost">{{diffCost | decimalsHandle}}</span>
  142. <span slot="operatorManger" slot-scope="operatorManger">{{ operatorManger | blankHandle}}</span>
  143. <span slot="operator" slot-scope="operator">{{ operator | blankHandle}}</span>
  144. <span slot="sale" slot-scope="sale">{{ sale | blankHandle}}</span>
  145. <span slot="plan" slot-scope="plan">{{ plan | blankHandle}}</span>
  146. <span slot="shot" slot-scope="shot">{{ shot | blankHandle}}</span>
  147. <span slot="clip" slot-scope="clip">{{ clip | blankHandle}}</span>
  148. </a-table>
  149. </div>
  150. </div>
  151. </div>
  152. </template>
  153. <script>
  154. import moment from 'moment';
  155. import { getAction, postAction, downFile, downFilePost } from '@/api/manage';
  156. import { JeecgListMixin } from '@/mixins/ipagination'
  157. export default {
  158. mixins:[JeecgListMixin],
  159. data() {
  160. return {
  161. moment,
  162. company:undefined,//公司的默认值
  163. mediaType:undefined,// 媒体类型
  164. advertiser:undefined,//广告主
  165. project:undefined,//项目
  166. dateValue:moment(),//
  167. advertisersArr:[],//广告主数组
  168. projectArr:[],//项目数组
  169. companyArr:[],//公司数组
  170. mediaTypeArr:[],
  171. tableData:[],
  172. loading:false,
  173. dateString1:moment().subtract(1,'days').format('YYYY-MM-DD'),
  174. dateString2:moment().format('YYYY-MM-DD'),
  175. columns:[
  176. {
  177. title: '媒体',
  178. dataIndex: 'mediaType',
  179. align: 'center',
  180. scopedSlots: { customRender: 'mediaType' },
  181. width:50
  182. },
  183. {
  184. title: '广告主',
  185. dataIndex: 'advertiserName',
  186. align: 'center',
  187. scopedSlots: { customRender: 'advertiserName' }
  188. },
  189. {
  190. title: '项目',
  191. dataIndex: 'projectName',
  192. align: 'center',
  193. scopedSlots: { customRender: 'projectName' },
  194. width:80
  195. },
  196. {
  197. title:moment().subtract(1,'days').format('YYYY-MM-DD'),
  198. dataIndex: 'yesterdayCost',
  199. align: 'center',
  200. scopedSlots: { customRender: 'yesterdayCost' }
  201. },
  202. {
  203. title:moment().format('YYYY-MM-DD'),
  204. dataIndex: 'todayCost',
  205. align: 'center',
  206. scopedSlots: { customRender: 'todayCost' }
  207. },
  208. {
  209. title: '消耗差值',
  210. dataIndex: 'diffCost',
  211. align: 'center',
  212. scopedSlots: { customRender: 'diffCost' }
  213. },
  214. {
  215. title: '运营经理',
  216. dataIndex: 'operatorManger',
  217. align: 'center',
  218. scopedSlots: { customRender: 'operatorManger' },
  219. width:80
  220. },
  221. {
  222. title: '运营',
  223. dataIndex: 'operator',
  224. align: 'center',
  225. scopedSlots: { customRender: 'operator' },
  226. width:120
  227. },
  228. {
  229. title: '销售',
  230. dataIndex: 'sale',
  231. align: 'center',
  232. scopedSlots: { customRender: 'sale' },
  233. width:80
  234. },
  235. {
  236. title: '策划',
  237. dataIndex: 'plan',
  238. align: 'center',
  239. scopedSlots: { customRender: 'plan' },
  240. width:120
  241. },
  242. {
  243. title: '拍摄',
  244. dataIndex: 'shot',
  245. align: 'center',
  246. scopedSlots: { customRender: 'shot' },
  247. width:120
  248. },
  249. {
  250. title: '剪辑',
  251. dataIndex: 'clip',
  252. align: 'center',
  253. scopedSlots: { customRender: 'clip' },
  254. width:120
  255. },
  256. ]
  257. }
  258. },
  259. methods: {
  260. companyChange(value){
  261. if(this.company=='' || this.company==undefined){
  262. this.advertisersArr=[];
  263. this.projectArr=[];
  264. this.advertiser=undefined;
  265. this.project=undefined;
  266. }else{
  267. //网络请求获取广告主数据
  268. this.advertisersArr=[];
  269. this.projectArr=[];
  270. this.advertiser=undefined;
  271. this.project=undefined;
  272. getAction('/ctop/media/report/getAdvertiser', {
  273. companyId:this.company
  274. }).then(res => {
  275. if(res.success){
  276. console.log(res)
  277. this.advertisersArr=res.result
  278. }
  279. })
  280. }
  281. },
  282. //广告主改变
  283. advertisersChange(value){
  284. console.log(`selected ${value}`);
  285. if(this.advertiser=='' || this.advertiser==undefined){
  286. this.project=undefined;
  287. this.projectArr=[];
  288. }else{
  289. this.project=undefined;
  290. this.projectArr=[];
  291. getAction('/ctop/media/report/getProject', {
  292. companyId:this.company,
  293. advertiserId:this.advertiser
  294. }).then(res => {
  295. if(res.success){
  296. console.log(res)
  297. this.projectArr=res.result
  298. }
  299. })
  300. }
  301. },
  302. projectChange(value){
  303. console.log(`selected ${value}`);
  304. if(this.project==''){
  305. // this.project=undefined
  306. }
  307. },
  308. //日期改变
  309. onChange(date, dateString) {
  310. // console.log(date, dateString,this.dateValue);
  311. let addCol=[
  312. {
  313. title:moment(date).subtract(1,'days').format('YYYY-MM-DD'),
  314. dataIndex: 'yesterdayCost',
  315. align: 'center',
  316. scopedSlots: { customRender: 'accountId' }
  317. },
  318. {
  319. title:dateString,
  320. dataIndex: 'todayCost',
  321. align: 'center',
  322. scopedSlots: { customRender: 'accountId' }
  323. },
  324. ];
  325. this.columns.splice(3,2,addCol[0],addCol[1]);
  326. this.searchHandle();
  327. },
  328. //搜索
  329. searchHandle(){
  330. let company='';
  331. let advertiser='';
  332. let project='';
  333. let mediaType=''
  334. if(this.company==undefined){
  335. company=''
  336. }else{
  337. company=this.company
  338. }
  339. if(this.advertiser==undefined){
  340. advertiser=''
  341. }else{
  342. advertiser=this.advertiser
  343. }
  344. if(this.project==undefined){
  345. project=''
  346. }else{
  347. project=this.project
  348. }
  349. if(this.mediaType==undefined){
  350. mediaType=''
  351. }else{
  352. mediaType=this.mediaType
  353. }
  354. this.tableHttp({
  355. companyId:company,
  356. advertiserId:advertiser,
  357. projectId:project,
  358. mediaType,
  359. todayDate:this.dateValue.format('YYYY-MM-DD'),
  360. yesterdayDate:moment(this.dateValue).subtract(1,"days").format('YYYY-MM-DD'),
  361. })
  362. },
  363. //table的改变(页码改变请求数据,也可以写排序)
  364. tableChange(pagination, filters, sorter, { currentDataSource }){
  365. this.searchHandle();
  366. },
  367. //table的网络请求
  368. tableHttp(params){
  369. this.loading=true;
  370. this.tableData=[]
  371. postAction(`/ctop/media/report/${this.ipagination.current}/${this.ipagination.pageSize}`, params).then(res => {
  372. if(res.success){
  373. // console.log(res)
  374. this.loading=false;
  375. this.ipagination.total = res.result.total
  376. if(res.success){
  377. res.result.list.map((item,index)=>{
  378. item.key=index
  379. })
  380. this.tableData=res.result.list
  381. }
  382. }
  383. })
  384. },
  385. //导出报表
  386. exportExcel() {
  387. let company='';
  388. let advertiser='';
  389. let project='';
  390. let mediaType=''
  391. if(this.company==undefined){
  392. company=''
  393. }else{
  394. company=this.company
  395. }
  396. if(this.advertiser==undefined){
  397. advertiser=''
  398. }else{
  399. advertiser=this.advertiser
  400. }
  401. if(this.project==undefined){
  402. project=''
  403. }else{
  404. project=this.project
  405. }
  406. if(this.mediaType==undefined){
  407. mediaType=''
  408. }else{
  409. mediaType=this.mediaType
  410. }
  411. downFilePost('/ctop/media/report/excel', {
  412. companyId:company,
  413. advertiserId:advertiser,
  414. projectId:project,
  415. mediaType,
  416. todayDate:this.dateValue.format('YYYY-MM-DD'),
  417. yesterdayDate:moment(this.dateValue).subtract(1,"days").format('YYYY-MM-DD'),
  418. }).then(res => {
  419. let blob = new Blob([res], {
  420. type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
  421. })
  422. let downloadElement = document.createElement('a')
  423. let href = window.URL.createObjectURL(blob) //创建下载的链接
  424. downloadElement.href = href
  425. downloadElement.download = moment().format('YYYY-MM-DD') + '媒介报表.xlsx' //下载后文件名
  426. document.body.appendChild(downloadElement)
  427. downloadElement.click() //点击下载
  428. document.body.removeChild(downloadElement) //下载完成移除元素
  429. window.URL.revokeObjectURL(href) //释放掉blob对象
  430. })
  431. },
  432. handleBlur() {
  433. // console.log('blur');
  434. },
  435. handleFocus() {
  436. // console.log('focus');
  437. },
  438. filterOption(input, option) {
  439. return (
  440. option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
  441. );
  442. },
  443. disabledDate(current) {
  444. // console.log(current)
  445. return current &&current > moment()
  446. },
  447. },
  448. mounted() {
  449. getAction('/ctop/media/report/getCompany', {
  450. }).then(res => {
  451. if(res.success){
  452. this.companyArr=res.result
  453. }
  454. });
  455. this.tableHttp({
  456. companyId:'',
  457. advertiserId:'',
  458. projectId:'',
  459. mediaType:'',
  460. todayDate:this.dateValue.format('YYYY-MM-DD'),
  461. yesterdayDate:moment(this.dateValue).subtract(1,'days').format('YYYY-MM-DD'),
  462. })
  463. },
  464. filters: {
  465. toPercentage(val) {
  466. if(val){
  467. if(typeof val != 'string'){
  468. return (val * 100).toFixed(2) + '%'
  469. }else{
  470. return val
  471. }
  472. }else if(typeof val =='string'){
  473. return val
  474. }
  475. else{
  476. return 0
  477. }
  478. },
  479. //保留两位小数并且变成货币格式
  480. decimalsHandle(val){
  481. if(val && typeof val !='string'){
  482. if(val>=0){
  483. val=parseFloat(val).toFixed(2);
  484. let numberStr = val.toString()
  485. let str = numberStr.split('.')
  486. let str0=str[0].split('').reverse();
  487. for (let i = 0; i < str0.length; i++) {
  488. if ((i + 1) % 4 === 0) {
  489. str0.splice(i, 0, ',')
  490. }
  491. }
  492. str0.reverse()
  493. let handleResult = ''
  494. for (let j = 0; j < str0.length; j++) {
  495. handleResult += str0[j]
  496. }
  497. return handleResult+'.'+str[1]
  498. }else{
  499. val=parseFloat(val).toFixed(2);
  500. let numberStr = val.toString()
  501. let str = numberStr.split('.')
  502. let str0=str[0].substr(1).split('').reverse();
  503. for (let i = 0; i < str0.length; i++) {
  504. if ((i + 1) % 4 === 0) {
  505. str0.splice(i, 0, ',')
  506. }
  507. }
  508. str0.reverse()
  509. let handleResult = ''
  510. for (let j = 0; j < str0.length; j++) {
  511. handleResult += str0[j]
  512. }
  513. return '-'+handleResult+'.'+str[1]
  514. }
  515. }else if(typeof val =='string'){
  516. return val
  517. }
  518. else{
  519. return 0
  520. }
  521. },
  522. //变成货币格式
  523. formatCurrency(val){
  524. if((val||val==0)&& typeof val !='string'){
  525. let numberStr = val.toString()
  526. let str = numberStr.split('').reverse()
  527. for (let i = 0; i < str.length; i++) {
  528. if ((i + 1) % 4 === 0) {
  529. str.splice(i, 0, ',')
  530. }
  531. }
  532. str.reverse()
  533. let handleResult = ''
  534. for (let j = 0; j < str.length; j++) {
  535. handleResult += str[j]
  536. }
  537. return handleResult
  538. }else if(typeof val =='string'){
  539. return val
  540. }
  541. else{
  542. return '-'
  543. }
  544. },
  545. //处理空白为 --
  546. blankHandle(val){
  547. if(val){
  548. return val
  549. }else{
  550. return '-'
  551. }
  552. }
  553. }
  554. }
  555. </script>
  556. <style lang="scss" scoped>
  557. .mediaReport{
  558. padding: 0 10px;
  559. .mediaReport_header{
  560. padding: 15px 10px;
  561. background: #fff;
  562. position: relative;
  563. .option-top,.option-bot{
  564. .item{
  565. margin-right: 20px;
  566. display: inline-block;
  567. .title{
  568. display: inline-block;
  569. position: relative;
  570. padding-right: 15px;
  571. margin-right: 5px;
  572. }
  573. .tipinfo{
  574. position: absolute;
  575. font-size: 12px;
  576. right: 0px;
  577. top: 0;
  578. }
  579. }
  580. }
  581. .option-top{
  582. margin-bottom: 15px;
  583. }
  584. .option-btn{
  585. position: absolute;
  586. top: 15px;
  587. right: 10px;
  588. }
  589. }
  590. .mediaReport_header:hover{
  591. border-radius: 5px;
  592. box-shadow: 0 0 15px rgba(0,0,0,.2);
  593. }
  594. .tableBox{
  595. margin-top: 30px;
  596. background: #fff;
  597. padding: 10px 10px;
  598. .tableOption{
  599. margin-bottom: 10px;
  600. text-align: right;
  601. }
  602. }
  603. }
  604. </style>
  605. <style lang="scss">
  606. .ant-tooltip-inner,.ant-tooltip,.ant-tooltip-arrow::before{
  607. background-color: #fff;
  608. color: #666;
  609. font-size: 12px;
  610. }
  611. </style>