企微助手 ,仓库名 短剧

playletData.vue 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. <template>
  2. <div v-loading="loading" class="playletData">
  3. <div class="screenBox flex">
  4. <div class="flex-align-center">
  5. <date-picker title="自定义" :quickFlag='true' :afferent_time="default_time" :clearFlag='false' @changeTime="changeTime"></date-picker>
  6. <self-channel title="剧集" type='dramaList' @channelDefine="(val)=>{playlet_id = val;init(1)}"></self-channel>
  7. </div>
  8. <el-button type="primary" size="mini" @click="init(1,'export')">导出Excel</el-button>
  9. </div>
  10. <div class="dataInfoBox">
  11. <div class="dataInfoItem">
  12. <div class="dataItemTitle">
  13. <img src="@/assets/img/iconNew/首日roi@2x.png" style="height:14px" class="titleIcon" alt="">
  14. <span>首日ROI</span>
  15. </div>
  16. <div class="dataItem-data">{{dataInfo&&(dataInfo.first_day_roi||dataInfo.first_day_roi==0)?$formatNum(dataInfo.first_day_roi):'-'}}</div>
  17. </div>
  18. <div class="dataInfoItem">
  19. <div class="dataItemTitle">
  20. <img src="@/assets/img/iconNew/当天总消耗@2x.png" style="height:14px" class="titleIcon" alt="">
  21. <span>当天总消耗</span>
  22. </div>
  23. <div class="dataItem-data">{{dataInfo&&(dataInfo.day_paid||dataInfo.day_paid==0)?$formatNum(dataInfo.day_paid):'-'}}</div>
  24. </div>
  25. <div class="dataInfoItem">
  26. <div class="dataItemTitle">
  27. <img src="@/assets/img/icon/累计充值@2x.png" style="height:20px" class="titleIcon" alt="">
  28. <span>当日新用户累计充值</span>
  29. </div>
  30. <div class="dataItem-data">{{dataInfo&&(dataInfo.charge_total||dataInfo.charge_total==0)?$formatNum(dataInfo.charge_total):'-'}}</div>
  31. </div>
  32. <div class="dataInfoItem">
  33. <div class="dataItemTitle">
  34. <img src="@/assets/img/iconNew/回本率@2x.png" style="height:14px" class="titleIcon" alt="">
  35. <span>回本率</span>
  36. </div>
  37. <div class="dataItem-data">{{dataInfo&&(dataInfo.cost_cover_rate||dataInfo.cost_cover_rate==0)?dataInfo.cost_cover_rate:'-'}}</div>
  38. </div>
  39. <div class="dataInfoItem">
  40. <div class="dataItemTitle">
  41. <img src="@/assets/img/icon/总关注人数@2x.png" style="height:18px" class="titleIcon" alt="">
  42. <span>新增粉丝数</span>
  43. </div>
  44. <div class="dataItem-data">{{dataInfo&&(dataInfo.fans_increase||dataInfo.fans_increase==0)?$formatNum(dataInfo.fans_increase):'-'}}</div>
  45. </div>
  46. <div class="dataInfoItem">
  47. <div class="dataItemTitle">
  48. <img src="@/assets/img/icon/平均关注人数成本@2x.png" style="height:14px" class="titleIcon" alt="">
  49. <span>新增粉丝成本</span>
  50. </div>
  51. <div class="dataItem-data">{{dataInfo&&(dataInfo.new_user_cost||dataInfo.new_user_cost==0)?$formatNum(dataInfo.new_user_cost):'-'}}</div>
  52. </div>
  53. <div class="dataInfoItem">
  54. <div class="dataItemTitle">
  55. <img src="@/assets/img/iconNew/充值人数@2x.png" style="height:14px" class="titleIcon" alt="">
  56. <span>充值人数</span>
  57. </div>
  58. <div class="dataItem-data">{{dataInfo&&(dataInfo.new_user_charge_uv||dataInfo.new_user_charge_uv==0)?$formatNum(dataInfo.new_user_charge_uv):'-'}}</div>
  59. </div>
  60. <div class="dataInfoItem">
  61. <div class="dataItemTitle">
  62. <img src="@/assets/img/iconNew/充值次数@2x.png" style="height:14px" class="titleIcon" alt="">
  63. <span>充值次数</span>
  64. </div>
  65. <div class="dataItem-data">{{dataInfo&&(dataInfo.new_user_charge_pv||dataInfo.new_user_charge_pv==0)?$formatNum(dataInfo.new_user_charge_pv):'-'}}</div>
  66. </div>
  67. <div class="dataInfoItem">
  68. <div class="dataItemTitle">
  69. <img src="@/assets/img/iconNew/充值用户成本@2x.png" class="titleIcon" alt="">
  70. <span>充值用户成本</span>
  71. </div>
  72. <div class="dataItem-data">{{dataInfo&&(dataInfo.charge_user_cost||dataInfo.charge_user_cost==0)?$formatNum(dataInfo.charge_user_cost):'-'}}</div>
  73. </div>
  74. </div>
  75. <ux-grid ref="plxTableDj" class="djtfqs" key="plxTableDj" :border="false" @row-click="()=>{return}" :header-cell-style="()=>{return { backgroundColor: '#FFFFFF !important', border: 'none!important',height: '50px !important' }}" :height="height+130" show-footer-overflow="tooltip" show-overflow="tooltip" size="mini">
  76. <ux-table-column v-for="item in desColDj" :key="item.prop" :resizable="true" :field="item.prop" :title="item.label" :min-width="item.min_width?item.min_width:120" :fixed="item.fixed?item.fixed:''" align="center">
  77. <template #header>
  78. <div :class="['flex-align-jus-center',item.sort?'pointer':'',sort_field==item.prop?'sortFieldStyle':'']" @click="item.sort?sortFieldEvent(item.prop):''">{{item.label}}<i class="el-icon-caret-bottom" v-if="item.sort"></i>
  79. <el-tooltip v-if="item.notes" :content="item.notes" placement="top">
  80. <div><i class="el-icon-question"></i></div>
  81. </el-tooltip>
  82. </div>
  83. </template>
  84. <template v-slot="{ row }">
  85. <span :class="sort_field==item.prop?'sortFieldStyle':''">{{row[item.prop]||row[item.prop]==0?$formatNum(row[item.prop]):'-' }}</span>
  86. </template>
  87. </ux-table-column>
  88. <ux-table-column title="统计" width="100" v-for="(item_extra,index_extra) in extra" :key="index_extra+'extra'">
  89. <template #header>
  90. <div class="flex-align-jus-center">{{item_extra}}
  91. <el-tooltip placement="top" v-if="index_extra==0">
  92. <div slot="content">充:当日回收<br />增:当日回收/当天消耗<br />回:累计充值/当天消耗<br />倍:回/增</div>
  93. <i class="el-icon-question"></i>
  94. </el-tooltip>
  95. </div>
  96. </template>
  97. <template v-slot="{ row }">
  98. <div>
  99. <span class="font" style="color:#2C9841">充:</span>
  100. <span>{{row.charge_data&&(row.charge_data[item_extra].day_charge||row.charge_data[item_extra].day_charge==0)?$formatNum(row.charge_data[item_extra].day_charge):'-'}}</span>
  101. </div>
  102. <div>
  103. <span class="font" style="color:#F28544">增:</span>
  104. <span>{{row.charge_data&&(row.charge_data[item_extra].day_add||row.charge_data[item_extra].day_add==0)?$formatNum(row.charge_data[item_extra].day_add):'-'}}</span>
  105. </div>
  106. <div>
  107. <span class="font" style="color:#EB4315">回:</span>
  108. <span>{{row.charge_data&&(row.charge_data[item_extra].day_cover||row.charge_data[item_extra].day_cover==0)?$formatNum(row.charge_data[item_extra].day_cover):'-'}}</span>
  109. </div>
  110. <div>
  111. <span class="font" style="color:#2983DF">倍:</span>
  112. <span>{{row.charge_data&&(row.charge_data[item_extra].day_times||row.charge_data[item_extra].day_times==0)?$formatNum(row.charge_data[item_extra].day_times):'-'}}</span>
  113. </div>
  114. </template>
  115. </ux-table-column>
  116. </ux-grid>
  117. <div class="pagination" v-show="total>0">
  118. <el-pagination background :current-page="page" @current-change="handleCurrentChange" layout="prev, pager, next" :page-count='Number(pages)'>
  119. </el-pagination>
  120. </div>
  121. </div>
  122. </template>
  123. <script>
  124. import datePicker from '@/components/assembly/screen/datePicker.vue'
  125. import selfChannel from '@/components/assembly/screen/channel.vue'
  126. export default {
  127. components: { selfChannel, datePicker },
  128. data () {
  129. return {
  130. loading: false,
  131. page: 1,
  132. pages: 0,
  133. total: 0,
  134. page_size: 10,
  135. tableData: [],
  136. sort_field: '',
  137. dataInfo: {},
  138. default_time: [this.$getDay(-30, false), this.$getDay(0, false)],
  139. time: [],
  140. playlet_id: '',
  141. height: '',
  142. desColDj: [
  143. { prop: "ref_date", label: "时间", fixed: 'left' },
  144. { prop: "playlet_name", label: "短剧", fixed: 'left' },
  145. { prop: "first_day_roi", label: "首日ROI" },
  146. { prop: "day_paid", label: "当天消耗" },
  147. { prop: "charge_total", min_width: "160", label: "当日新用户累计充值" },
  148. { prop: 'cost_cover_rate', label: "回本率(%)" },
  149. { prop: 'fans_increase', label: "新增粉丝数" },
  150. { prop: 'new_user_cost', label: "新增粉丝成本" },
  151. { prop: 'new_user_charge_uv_count', label: "充值总人数", },
  152. { prop: 'new_user_charge_uv', label: "当日首充人数", },
  153. { prop: 'new_user_charge_pv_count', label: "总充值次数", },
  154. { prop: 'new_user_charge_pv', label: "新用户首日充值次数", },
  155. { prop: 'charge_user_cost', label: "充值用户成本", notes: '充值用户成本=当天消耗/充值人数', min_width: "160" },
  156. ],
  157. extra: [],
  158. }
  159. },
  160. created () {
  161. this.height = document.documentElement.clientHeight - 300 > 400 ? document.documentElement.clientHeight - 400 : 400
  162. this.time = this.default_time
  163. this.init(1)
  164. },
  165. methods: {
  166. tableRowClassName ({ row, rowIndex }) {
  167. return row.self_class ? row.self_class : ''
  168. },
  169. //头部颜色
  170. headerColor ({ row, column, rowIndex, columnIndex }) {
  171. if (column.level == 2) {
  172. return 'display: none'
  173. }
  174. return { backgroundColor: "#EFEFEF !important", border: 'none!important', height: '50px !important' }
  175. },
  176. rowStyle ({ row, rowIndex }) {//行颜色控制
  177. if (row.self_class == 'warning-row') {
  178. return { background: '#f4f4f4' }
  179. }
  180. },
  181. changeTime (time) {//筛选时间变化
  182. if (!time || time && time.length == 0) {
  183. this.time = []
  184. } else {
  185. this.time = time
  186. }
  187. this.init(1)
  188. },
  189. init (page, type) {
  190. if (type != 'export') {
  191. this.page = page ? page : this.page;
  192. } else {
  193. if (this.total == 0) {
  194. this.$message({
  195. message: '暂无数据可导出',
  196. type: "warning"
  197. })
  198. return
  199. }
  200. }
  201. this.loading = true
  202. this.$axios.get(this.URL.BASEURL + this.URL.statistics_playletDataTrend, {
  203. params: {
  204. // sort_field: this.sort_field,
  205. playlet_id: this.playlet_id,
  206. start_date: this.time[0],
  207. end_date: this.time[1],
  208. page: type == 'export' ? 1 : this.page,
  209. page_size: type == 'export' ? this.$store.state.exportNumber : this.page_size,
  210. }
  211. }).then((res) => {
  212. var res = res.data
  213. this.loading = false
  214. if (res && res.errno == 0) {
  215. if (type == 'export') {
  216. this.exportEvent_playletData(res.rst.data.list)
  217. } else {
  218. this.dataInfo = res.rst.data.overview;
  219. this.extra = res.rst.data.extra;
  220. this.datas = res.rst.data.list // 知道为啥datas不在 data()方法里面定义吗?嘻嘻
  221. this.$nextTick(() => {
  222. this.$refs.plxTableDj.reloadData(this.datas)
  223. })
  224. this.total = res.rst.pageInfo.total;
  225. this.pages = res.rst.pageInfo.pages;
  226. }
  227. } else if (res.errno != 4002) {
  228. this.$message({
  229. message: res.err,
  230. type: "warning"
  231. })
  232. }
  233. }).catch((err) => {
  234. this.loading = false
  235. });
  236. },
  237. handleCurrentChange (val) {
  238. this.init(val)
  239. },
  240. // sortFieldEvent (type) {
  241. // this.sort_field = type;
  242. // this.init(1)
  243. // },
  244. exportEvent_playletData (data) {
  245. let list = data;
  246. let tHeader = this.desColDj.map((v) => {
  247. return v.label;
  248. })
  249. let self_extra = this.extra.map((v) => {
  250. return 'chargeData_' + v
  251. })
  252. tHeader = tHeader.concat(...this.extra)
  253. let filterVal = this.desColDj.map((v) => {
  254. return v.prop
  255. })
  256. filterVal = filterVal.concat(...self_extra)
  257. list.forEach((item) => {
  258. for (var i in item.charge_data) {
  259. self_extra.forEach((v) => {
  260. item[v] = `
  261. 充:${item.charge_data[i] && (item.charge_data[i].day_charge || item.charge_data[i].day_charge == 0) ? item.charge_data[i].day_charge : '-'}
  262. 增:${item.charge_data[i] && (item.charge_data[i].day_add || item.charge_data[i].day_add == 0) ? item.charge_data[i].day_add : '-'}
  263. 回:${item.charge_data[i] && (item.charge_data[i].day_cover || item.charge_data[i].day_cover == 0) ? item.charge_data[i].day_cover : '-'}
  264. 倍:${item.charge_data[i] && (item.charge_data[i].day_times || item.charge_data[i].day_times == 0) ? item.charge_data[i].day_times : '-'}`
  265. })
  266. }
  267. })
  268. let excelDatas = [
  269. {
  270. tHeader: tHeader, // sheet表一头部
  271. filterVal: filterVal, // 表一的数据字段
  272. tableDatas: list, // 表一的整体json数据
  273. sheetName: ''// 表一的sheet名字
  274. }
  275. ]
  276. this.$exportOrder({ excelDatas, name: `短剧数据(导出时间:${this.$getDay(0)})` })
  277. },
  278. }
  279. }
  280. </script>
  281. <style lang="scss" scoped>
  282. .screenBox {
  283. background: #fff;
  284. padding: 5px 20px;
  285. }
  286. .dataInfoBox {
  287. display: flex;
  288. margin-top: 10px;
  289. flex-wrap: wrap;
  290. .dataInfoItem {
  291. background: #ffffff;
  292. border-radius: 8px;
  293. margin-right: 10px;
  294. margin-bottom: 10px;
  295. padding: 0 16px;
  296. height: 70px;
  297. display: flex;
  298. flex-direction: column;
  299. justify-content: center;
  300. align-items: center;
  301. .dataItemTitle {
  302. display: flex;
  303. align-items: center;
  304. color: #6f6f6f;
  305. font-size: 13px;
  306. line-height: 17px;
  307. font-weight: bold;
  308. .titleIcon {
  309. height: 16px;
  310. margin-right: 4px;
  311. }
  312. }
  313. .dataItem-data {
  314. color: #000000;
  315. font-size: 19px;
  316. line-height: 28px;
  317. font-weight: bold;
  318. margin-top: 2px;
  319. }
  320. }
  321. }
  322. </style>
  323. <style lang="scss">
  324. .playletData .elx-table .elx-table--border-line {
  325. border: 1px solid #ebeef5 !important;
  326. }
  327. .playletData .djtfqs {
  328. .elx-table.elx-editable.size--mini .elx-body--column,
  329. .elx-table.size--mini .elx-body--column.col--ellipsis,
  330. .elx-table.size--mini .elx-footer--column.col--ellipsis,
  331. .elx-table.size--mini .elx-header--column.col--ellipsis {
  332. height: 110px !important;
  333. }
  334. .elx-table.size--mini .elx-body--column.col--ellipsis > .elx-cell,
  335. .elx-table.size--mini .elx-footer--column.col--ellipsis > .elx-cell,
  336. .elx-table.size--mini .elx-header--column.col--ellipsis > .elx-cell {
  337. max-height: initial !important;
  338. }
  339. }
  340. </style>