|
@@ -0,0 +1,779 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="Version">
|
|
|
|
+ <el-breadcrumb separator-class="el-icon-arrow-right">
|
|
|
|
+ <el-breadcrumb-item>新媒体</el-breadcrumb-item>
|
|
|
|
+ <el-breadcrumb-item>用户分析</el-breadcrumb-item>
|
|
|
|
+ <el-breadcrumb-item>用户活跃度</el-breadcrumb-item>
|
|
|
|
+ </el-breadcrumb>
|
|
|
|
+ <el-card class="box-card">
|
|
|
|
+ <el-form
|
|
|
|
+ ref="form"
|
|
|
|
+ :model="form"
|
|
|
|
+ size="small"
|
|
|
|
+ :inline="true"
|
|
|
|
+ label-width="120px"
|
|
|
|
+ class="demo-form-inline"
|
|
|
|
+ >
|
|
|
|
+ <el-form-item label="日期">
|
|
|
|
+ <el-date-picker
|
|
|
|
+ v-if="form.date.length"
|
|
|
|
+ v-model="form.date"
|
|
|
|
+ type="daterange"
|
|
|
|
+ :disabled-date="time => disabledDate(time)"
|
|
|
|
+ range-separator="-"
|
|
|
|
+ start-placeholder="开始日期"
|
|
|
|
+ end-placeholder="结束日期"
|
|
|
|
+ :clearable="false"
|
|
|
|
+ >
|
|
|
|
+ </el-date-picker>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="应用">
|
|
|
|
+ <el-select
|
|
|
|
+ v-model="form.app"
|
|
|
|
+ placeholder="请选择时段"
|
|
|
|
+ @change="change"
|
|
|
|
+ >
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="item in cycle"
|
|
|
|
+ :key="item.value"
|
|
|
|
+ :label="item.label"
|
|
|
|
+ :value="item.value"
|
|
|
|
+ :disabled="item.disabled"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="渠道">
|
|
|
|
+ <el-select
|
|
|
|
+ filterable
|
|
|
|
+ multiple
|
|
|
|
+ collapse-tags
|
|
|
|
+ clearable
|
|
|
|
+ v-model="form.channel"
|
|
|
|
+ @change="changechannel"
|
|
|
|
+ placeholder="请选择渠道"
|
|
|
|
+ >
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="item in channel"
|
|
|
|
+ :key="item.value"
|
|
|
|
+ :label="item.label"
|
|
|
|
+ :value="item.value"
|
|
|
|
+ :disabled="item.disabled"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="版本">
|
|
|
|
+ <el-select
|
|
|
|
+ filterable
|
|
|
|
+ multiple
|
|
|
|
+ collapse-tags
|
|
|
|
+ clearable
|
|
|
|
+ v-model="form.version"
|
|
|
|
+ placeholder="请选择版本"
|
|
|
|
+ @change="changeversion"
|
|
|
|
+ >
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="item in version"
|
|
|
|
+ :key="item.value"
|
|
|
|
+ :label="item.label"
|
|
|
|
+ :value="item.value"
|
|
|
|
+ :disabled="item.disabled"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="来源">
|
|
|
|
+ <el-select
|
|
|
|
+ collapse-tags
|
|
|
|
+ clearable
|
|
|
|
+ v-model="form.client"
|
|
|
|
+ placeholder="请选择来源"
|
|
|
|
+ >
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="item in client"
|
|
|
|
+ :key="item.value"
|
|
|
|
+ :label="item.label"
|
|
|
|
+ :value="item.value"
|
|
|
|
+ :disabled="item.disabled"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item style="float: right">
|
|
|
|
+ <el-button type="primary" @click="onSubmit">查询</el-button>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-form>
|
|
|
|
+ </el-card>
|
|
|
|
+ <br />
|
|
|
|
+ <el-card class="box-card">
|
|
|
|
+ <div style="text-align: right">
|
|
|
|
+ <el-button-group>
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ :type="numType === 'mau1' ? 'primary' : 'plain'"
|
|
|
|
+ @click="() => selectNumType('mau1')"
|
|
|
|
+ >
|
|
|
|
+ 日活跃用户数
|
|
|
|
+ </el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ :type="numType === 'mau7' ? 'primary' : 'plain'"
|
|
|
|
+ @click="() => selectNumType('mau7')"
|
|
|
|
+ >
|
|
|
|
+ 周活跃用户数
|
|
|
|
+ </el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ :type="numType === 'mau30' ? 'primary' : 'plain'"
|
|
|
|
+ @click="() => selectNumType('mau30')"
|
|
|
|
+ >
|
|
|
|
+ 月活跃用户数
|
|
|
|
+ </el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ :type="numType === 'total' ? 'primary' : 'plain'"
|
|
|
|
+ @click="() => selectNumType('total')"
|
|
|
|
+ >
|
|
|
|
+ 累积用户数
|
|
|
|
+ </el-button>
|
|
|
|
+ </el-button-group>
|
|
|
|
+ </div>
|
|
|
|
+ <br />
|
|
|
|
+ <div ref="regionChart" ></div>
|
|
|
|
+ <br />
|
|
|
|
+ <div style="text-align: right">
|
|
|
|
+ <el-button
|
|
|
|
+ size="small"
|
|
|
|
+ style="margin-left: 0.5em"
|
|
|
|
+ type="primary"
|
|
|
|
+ @click="onExport"
|
|
|
|
+ >
|
|
|
|
+ 导出
|
|
|
|
+ </el-button>
|
|
|
|
+ </div>
|
|
|
|
+ <br />
|
|
|
|
+ <br />
|
|
|
|
+ <el-table
|
|
|
|
+ :data="table || []"
|
|
|
|
+ style="width: 100%"
|
|
|
|
+ :header-cell-style="{
|
|
|
|
+ backgroundColor: '#f4f5f7',
|
|
|
|
+ color: '#606266',
|
|
|
|
+ }"
|
|
|
|
+ >
|
|
|
|
+ <el-table-column
|
|
|
|
+ prop="date"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ label="日期"
|
|
|
|
+ show-overflow-tooltip
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <span v-text="scope.row.date || '-'"></span>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ show-overflow-tooltip
|
|
|
|
+ label="应用名称"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ >
|
|
|
|
+ <template #default>
|
|
|
|
+ <span>{{ lastParams.app || "-" }}</span>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ prop="upgradeUser"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ label="日活跃用户数"
|
|
|
|
+ show-overflow-tooltip
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <countTo
|
|
|
|
+ :startVal="scope.row.mau1 || 0"
|
|
|
|
+ :endVal="scope.row.mau1 || 0"
|
|
|
|
+ :duration="100"
|
|
|
|
+ ></countTo>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="日活跃度"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="mau1"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ {{ (100 * scope.row.mau1 / scope.row.total).toFixed(2) }}%
|
|
|
|
+ </template>
|
|
|
|
+
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="日活/月活"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="mau1"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ {{ (100 * scope.row.mau1 / scope.row.mau30).toFixed(2) }}%
|
|
|
|
+ </template>
|
|
|
|
+
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="周活跃用户数"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="mau7"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <countTo
|
|
|
|
+ :startVal="scope.row.mau7 || 0"
|
|
|
|
+ :endVal="scope.row.mau7 || 0"
|
|
|
|
+ :duration="100"
|
|
|
|
+ ></countTo>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="周活跃度"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="startTimes"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ {{ (100 * scope.row.mau7 / scope.row.total).toFixed(2) }}%
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="月活跃用户数"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="mau30"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <countTo
|
|
|
|
+ :startVal="scope.row.mau30 || 0"
|
|
|
|
+ :endVal="scope.row.mau30 || 0"
|
|
|
|
+ :duration="100"
|
|
|
|
+ ></countTo>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="月活跃度"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="startTimes"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ {{ (100 * scope.row.mau30 / scope.row.total).toFixed(2) }}%
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="累计用户数"
|
|
|
|
+ header-align="center"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="total"
|
|
|
|
+ >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <countTo
|
|
|
|
+ :startVal="scope.row.total || 0"
|
|
|
|
+ :endVal="scope.row.total || 0"
|
|
|
|
+ :duration="100"
|
|
|
|
+ ></countTo>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ </el-table>
|
|
|
|
+ </el-card>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+<script>
|
|
|
|
+// @ is an alias to /src
|
|
|
|
+import {
|
|
|
|
+ getRule,
|
|
|
|
+ getAppList,
|
|
|
|
+ getSearchData,
|
|
|
|
+ getUserActivity
|
|
|
|
+} from "@/api/index";
|
|
|
|
+
|
|
|
|
+import countTo from "@/components/counto/vue-countTo.vue";
|
|
|
|
+import * as echarts from "echarts/core";
|
|
|
|
+import { LineChart } from "echarts/charts";
|
|
|
|
+import {
|
|
|
|
+ TitleComponent,
|
|
|
|
+ TooltipComponent,
|
|
|
|
+ GridComponent,
|
|
|
|
+ ToolboxComponent,
|
|
|
|
+ LegendComponent,
|
|
|
|
+} from "echarts/components";
|
|
|
|
+import { CanvasRenderer } from "echarts/renderers";
|
|
|
|
+echarts.use([
|
|
|
|
+ TitleComponent,
|
|
|
|
+ TooltipComponent,
|
|
|
|
+ GridComponent,
|
|
|
|
+ LineChart,
|
|
|
|
+ CanvasRenderer,
|
|
|
|
+ ToolboxComponent,
|
|
|
|
+ LegendComponent,
|
|
|
|
+]);
|
|
|
|
+
|
|
|
|
+// import config from "@/config/index";
|
|
|
|
+let chart = undefined;
|
|
|
|
+export default {
|
|
|
|
+ name: "Version",
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ lastParams: {},
|
|
|
|
+ table: [],
|
|
|
|
+ numType: "mau1",
|
|
|
|
+ form: {
|
|
|
|
+ app: "",
|
|
|
|
+ version: [],
|
|
|
|
+ channel: [],
|
|
|
|
+ date: [],
|
|
|
|
+ client: "",
|
|
|
|
+ },
|
|
|
|
+ cycle: [],
|
|
|
|
+ showList: [],
|
|
|
|
+ channel: [],
|
|
|
|
+ version: [],
|
|
|
|
+ client: [],
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ async mounted() {
|
|
|
|
+ if (chart && chart.dispose) chart.dispose();
|
|
|
|
+ const { source, appV, appC, appli, appVLi, appCLi, clentV, clentli } =
|
|
|
|
+ await this.getAppListFunc();
|
|
|
|
+ const keys = {
|
|
|
|
+ value: "mname",
|
|
|
|
+ label: "mname",
|
|
|
|
+ };
|
|
|
|
+ let client = clentli.find(r => r.mdefault).mcode.toString();
|
|
|
|
+ this.cycle = this.verifyList(appli, source, keys, false);
|
|
|
|
+ this.channel = this.verifyList(appCLi, appC, keys, true);
|
|
|
|
+ this.version = this.verifyList(appVLi, appV, keys, true);
|
|
|
|
+ this.client = this.verifyList(
|
|
|
|
+ clentli,
|
|
|
|
+ clentV,
|
|
|
|
+ {
|
|
|
|
+ value: "mcode",
|
|
|
|
+ label: "mname",
|
|
|
|
+ },
|
|
|
|
+ true
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ this.form = {
|
|
|
|
+ // app: (this.cycle[0] || { value: "" }).value,
|
|
|
|
+ app: "起点新闻",
|
|
|
|
+ version: [-1],
|
|
|
|
+ channel: [(this.channel[0] || { value: "" }).value],
|
|
|
|
+ date: [new Date(Date.now() - 604800000), new Date(Date.now() - 86400000)],
|
|
|
|
+ client
|
|
|
|
+ };
|
|
|
|
+ this.onSubmit();
|
|
|
|
+ },
|
|
|
|
+ computed: {},
|
|
|
|
+ methods: {
|
|
|
|
+ verifyList(list, verify, obj, more) {
|
|
|
|
+ if (!obj) return;
|
|
|
|
+ let li = list || [];
|
|
|
|
+ const out = [];
|
|
|
|
+ more && out.push({ value: -1, label: "不限" });
|
|
|
|
+ for (let i = 0; i < li.length; i++) {
|
|
|
|
+ const v = li[i];
|
|
|
|
+ if (verify.length !== 0 && !verify[v.mcode]) continue;
|
|
|
|
+ out.push({
|
|
|
|
+ value: v[obj.value],
|
|
|
|
+ label: v[obj.label],
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return out;
|
|
|
|
+ },
|
|
|
|
+ selectNumType(type) {
|
|
|
|
+ this.numType = type;
|
|
|
|
+ let resChart = this.table;
|
|
|
|
+ let keyList = [],
|
|
|
|
+ valueList = [];
|
|
|
|
+ if ((resChart || []).length && chart && chart.clear) chart.clear();
|
|
|
|
+ resChart.map(v => {
|
|
|
|
+ keyList.push(v.date);
|
|
|
|
+ valueList.push(v[this.numType]);
|
|
|
|
+ });
|
|
|
|
+ this.createImage(keyList, valueList, '');
|
|
|
|
+
|
|
|
|
+ },
|
|
|
|
+ onSubmit() {
|
|
|
|
+ this.lastParams = {
|
|
|
|
+ app: this.form.app,
|
|
|
|
+ start: this.FormData(this.form.date[0]),
|
|
|
|
+ end: this.FormData(this.form.date[1]),
|
|
|
|
+ manufacturer: this.form.channel == -1 ? undefined : this.form.channel,
|
|
|
|
+ version: this.form.version == -1 ? undefined : this.form.version,
|
|
|
|
+ lib: this.form.client == -1 ? undefined : this.form.client,
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ getUserActivity(this.lastParams).then(resChart => {
|
|
|
|
+ this.table = resChart
|
|
|
|
+
|
|
|
|
+ let keyList = [],
|
|
|
|
+ valueList = [];
|
|
|
|
+ if ((resChart || []).length && chart && chart.clear) chart.clear();
|
|
|
|
+
|
|
|
|
+ resChart.map(v => {
|
|
|
|
+ keyList.push(v.date);
|
|
|
|
+ valueList.push(v[this.numType]);
|
|
|
|
+ });
|
|
|
|
+ this.createImage(keyList, valueList, '');
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ createImage(keyList, valueList, title) {
|
|
|
|
+ console.log(keyList,valueList,title)
|
|
|
|
+ if (!chart) {
|
|
|
|
+ chart = echarts.init(this.$refs.regionChart);
|
|
|
|
+ window.onresize = chart.resize;
|
|
|
|
+ }
|
|
|
|
+ chart.resize({
|
|
|
|
+ height: (this.$refs.regionChart.offsetWidth * 4) / 16,
|
|
|
|
+ });
|
|
|
|
+ chart.clear();
|
|
|
|
+ chart.setOption({
|
|
|
|
+ tooltip: {
|
|
|
|
+ confine: true,
|
|
|
|
+ trigger: "axis",
|
|
|
|
+ },
|
|
|
|
+ toolbox: {
|
|
|
|
+ feature: {
|
|
|
|
+ saveAsImage: {
|
|
|
|
+ type: "jpg",
|
|
|
|
+ name: "用户活跃度-" + this.form.app,
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ legend: {
|
|
|
|
+ // data: title,
|
|
|
|
+ },
|
|
|
|
+ grid: {
|
|
|
|
+ left: "3%",
|
|
|
|
+ right: "4%",
|
|
|
|
+ bottom: "3%",
|
|
|
|
+ containLabel: true,
|
|
|
|
+ },
|
|
|
|
+ xAxis: {
|
|
|
|
+ type: "category",
|
|
|
|
+ boundaryGap: true,
|
|
|
|
+ data: keyList,
|
|
|
|
+ },
|
|
|
|
+ yAxis: {
|
|
|
|
+ type: "value",
|
|
|
|
+ scale: true,
|
|
|
|
+ minInterval: 1,
|
|
|
|
+ axisLabel: {
|
|
|
|
+ formatter(v) {
|
|
|
|
+ let val = v;
|
|
|
|
+ if (val >= 100000000) {
|
|
|
|
+ val = (val / 100000000).toFixed(2) + "亿";
|
|
|
|
+ } else if (val >= 10000) {
|
|
|
|
+ val = (val / 10000).toFixed(2) + "万";
|
|
|
|
+ }
|
|
|
|
+ return val;
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ series: [
|
|
|
|
+ {
|
|
|
|
+ name: title,
|
|
|
|
+ data: valueList,
|
|
|
|
+ symbolSize: 0,
|
|
|
|
+ lineStyle: {
|
|
|
|
+ width: 1,
|
|
|
|
+ },
|
|
|
|
+ type: "line",
|
|
|
|
+ smooth: true,
|
|
|
|
+ color: "rgba(58,132,255,.9)",
|
|
|
|
+ areaStyle: {
|
|
|
|
+ color: {
|
|
|
|
+ type: "linear",
|
|
|
|
+ x: 0,
|
|
|
|
+ y: 0,
|
|
|
|
+ x2: 0,
|
|
|
|
+ y2: 1,
|
|
|
|
+ colorStops: [
|
|
|
|
+ {
|
|
|
|
+ offset: 0,
|
|
|
|
+ color: "rgba(58,132,255, 0.8)", // 0% 处的颜色
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ offset: 1,
|
|
|
|
+ color: "rgba(58,132,255, 0.1)", // 100% 处的颜色
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ global: false, // 缺省为 false
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ ],
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ async getAppListFunc() {
|
|
|
|
+ const { r, li, appVersion, channel, clientList } = await this.getAppListOri();
|
|
|
|
+ let source = { length: 0 },
|
|
|
|
+ appli = [];
|
|
|
|
+ let appV = { length: 0 },
|
|
|
|
+ appVLi = [];
|
|
|
|
+ let appC = { length: 0 },
|
|
|
|
+ appCLi = [],
|
|
|
|
+ clentV = { length: 0 },
|
|
|
|
+ clentli = [];
|
|
|
|
+ let prvList = r.output.data.prvRolectrl || [];
|
|
|
|
+ for (let i = 0; i < prvList.length; i++) {
|
|
|
|
+ const v = prvList[i];
|
|
|
|
+ if (v.controlid == "RMT_SOURCE")
|
|
|
|
+ (source[v.detid] = true), (source.length = source.length + 1);
|
|
|
|
+ if (v.controlid == "APP_VERSION")
|
|
|
|
+ (appV[v.detid] = true), (appV.length = appV.length + 1);
|
|
|
|
+ if (v.controlid == "CHANNEL")
|
|
|
|
+ (appC[v.detid] = true), (appC.length = appC.length + 1);
|
|
|
|
+ if (v.controlid == "CLIENT_TYPE")
|
|
|
|
+ (clentV[v.detid] = true), (clentV.length = clentV.length + 1);
|
|
|
|
+ }
|
|
|
|
+ if (li.status === "0") appli = li.output.data || [];
|
|
|
|
+ if (appVersion.length) appVLi = appVersion || [];
|
|
|
|
+ if (channel.length) appCLi = channel || [];
|
|
|
|
+ if (clientList.length) clentli = clientList || [];
|
|
|
|
+ return {
|
|
|
|
+ source,
|
|
|
|
+ appV,
|
|
|
|
+ appC,
|
|
|
|
+ appli,
|
|
|
|
+ appVLi,
|
|
|
|
+ appCLi,
|
|
|
|
+ clentV,
|
|
|
|
+ clentli
|
|
|
|
+ };
|
|
|
|
+ },
|
|
|
|
+ async getAppListOri() {
|
|
|
|
+ const roleid = JSON.parse(
|
|
|
|
+ window.parent.localStorage.userinfo || "{}"
|
|
|
|
+ ).roleid;
|
|
|
|
+ const r = await getRule({
|
|
|
|
+ db: "authplat",
|
|
|
|
+ exportMark: "0",
|
|
|
|
+ menuid: 399,
|
|
|
|
+ roleid,
|
|
|
|
+ });
|
|
|
|
+ // 应用列表
|
|
|
|
+
|
|
|
|
+ const li = await getAppList({
|
|
|
|
+ exportMark: "0",
|
|
|
|
+ gcode: "SOURCE",
|
|
|
|
+ pageid: 1,
|
|
|
|
+ pagesize: 1000,
|
|
|
|
+ });
|
|
|
|
+ const defaultAppName = "起点新闻";
|
|
|
|
+ // 应用版本列表
|
|
|
|
+ const appVersion = await getSearchData({
|
|
|
|
+ gcode: "APP_VERSION",
|
|
|
|
+ source: defaultAppName,
|
|
|
|
+ });
|
|
|
|
+ // 应用渠道列表
|
|
|
|
+ const channel = await getSearchData({
|
|
|
|
+ gcode: "CHANNEL",
|
|
|
|
+ source: defaultAppName,
|
|
|
|
+ });
|
|
|
|
+ // 端列表
|
|
|
|
+ const clientList = await getSearchData({
|
|
|
|
+ gcode: "CLIENT_TYPE",
|
|
|
|
+ source: defaultAppName,
|
|
|
|
+ });
|
|
|
|
+ return { r, li, appVersion, channel, clientList };
|
|
|
|
+ },
|
|
|
|
+ disabledDate(time) {
|
|
|
|
+ const first = new Date("2021-06-21 00:00:00");
|
|
|
|
+ return (
|
|
|
|
+ time.getTime() > Date.now() - 86400000 ||
|
|
|
|
+ time.getTime() < first.getTime()
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ FormData(date) {
|
|
|
|
+ const d = new Date(date || Date.now() - 86400000);
|
|
|
|
+ const year = d.getFullYear();
|
|
|
|
+ const month =
|
|
|
|
+ d.getMonth() <= 8 ? "0" + (d.getMonth() + 1) : d.getMonth() + 1;
|
|
|
|
+ const day = d.getDate() <= 9 ? "0" + d.getDate() : d.getDate();
|
|
|
|
+ return [year, month, day].join("-");
|
|
|
|
+ },
|
|
|
|
+ timeFormat(t) {
|
|
|
|
+ const Time = t || 0;
|
|
|
|
+ const mH = Time % 3600;
|
|
|
|
+ let hour = (Time - mH) / 3600;
|
|
|
|
+ let min = (mH - (mH % 60)) / 60;
|
|
|
|
+ let son = Number(mH % 60).toFixed(0);
|
|
|
|
+ hour = hour <= 9 ? "0" + hour : hour;
|
|
|
|
+ min = min <= 9 ? "0" + min : min;
|
|
|
|
+ son = son <= 9 ? "0" + son : son;
|
|
|
|
+ let out = [];
|
|
|
|
+ if (hour * 1 > 0) out.push(hour);
|
|
|
|
+ out.push(...[min, son]);
|
|
|
|
+ return out.join(":");
|
|
|
|
+ },
|
|
|
|
+ change() {
|
|
|
|
+ const roleid = JSON.parse(
|
|
|
|
+ window.parent.localStorage.userinfo || "{}"
|
|
|
|
+ ).roleid;
|
|
|
|
+ const appV = {
|
|
|
|
+ length: 0,
|
|
|
|
+ };
|
|
|
|
+ getRule({
|
|
|
|
+ db: "authplat",
|
|
|
|
+ exportMark: "0",
|
|
|
|
+ menuid: 399,
|
|
|
|
+ roleid,
|
|
|
|
+ }).then(rule => {
|
|
|
|
+ let prvList = rule.output.data.prvRolectrl || [];
|
|
|
|
+ for (let i = 0; i < prvList.length; i++) {
|
|
|
|
+ const v = prvList[i];
|
|
|
|
+ if (v.controlid == "APP_VERSION")
|
|
|
|
+ (appV[v.detid] = true), (appV.length = appV.length + 1);
|
|
|
|
+ }
|
|
|
|
+ getSearchData({
|
|
|
|
+ gcode: "APP_VERSION",
|
|
|
|
+ source: this.form.app,
|
|
|
|
+ }).then(r => {
|
|
|
|
+ let version = [{ value: -1, label: "不限" }];
|
|
|
|
+ r.map(v => {
|
|
|
|
+ if ((appV.length && appV[v.mcode]) || appV.length === 0)
|
|
|
|
+ version.push({
|
|
|
|
+ value: v.mname,
|
|
|
|
+ label: v.mname,
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ this.version = version;
|
|
|
|
+
|
|
|
|
+ this.form = {
|
|
|
|
+ ...this.form,
|
|
|
|
+ version: [-1],
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+ getSearchData({
|
|
|
|
+ gcode: "CHANNEL",
|
|
|
|
+ source: this.form.app,
|
|
|
|
+ }).then(r => {
|
|
|
|
+ let channel = [
|
|
|
|
+ {
|
|
|
|
+ label: "不限",
|
|
|
|
+ value: -1,
|
|
|
|
+ },
|
|
|
|
+ ];
|
|
|
|
+ r.map(v => {
|
|
|
|
+ if ((appV.length && appV[v.mcode]) || appV.length === 0)
|
|
|
|
+ channel.push({
|
|
|
|
+ value: v.mname,
|
|
|
|
+ label: v.mname,
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ this.channel = channel;
|
|
|
|
+ this.form = {
|
|
|
|
+ ...this.form,
|
|
|
|
+ channel: [-1],
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ changeversion(v) {
|
|
|
|
+ if (!v.length)
|
|
|
|
+ return (this.form.version = [-1]);
|
|
|
|
+ const last = v[v.length - 1];
|
|
|
|
+ if (last == -1) return (this.form.version = [-1]);
|
|
|
|
+ let ver = [];
|
|
|
|
+ for (let i = 0; i < v.length; i++) {
|
|
|
|
+ const element = v[i];
|
|
|
|
+ if (element == -1) continue;
|
|
|
|
+ ver.push(element);
|
|
|
|
+ }
|
|
|
|
+ this.form.version = ver;
|
|
|
|
+ },
|
|
|
|
+ changechannel(v) {
|
|
|
|
+ if (!v.length) return (this.form.channel = [-1]);
|
|
|
|
+ const last = v[v.length - 1];
|
|
|
|
+ if (last == -1) return (this.form.channel = [-1]);
|
|
|
|
+ let ver = [];
|
|
|
|
+ for (let i = 0; i < v.length; i++) {
|
|
|
|
+ const element = v[i];
|
|
|
|
+ if (element == -1) continue;
|
|
|
|
+ ver.push(element);
|
|
|
|
+ }
|
|
|
|
+ this.form.channel = ver;
|
|
|
|
+ },
|
|
|
|
+ onExport() {
|
|
|
|
+ const S = this.form.date[0]
|
|
|
|
+ ? this.FormData(this.form.date[0])
|
|
|
|
+ : undefined;
|
|
|
|
+ const E = this.form.date[1]
|
|
|
|
+ ? this.FormData(this.form.date[1])
|
|
|
|
+ : undefined;
|
|
|
|
+ let p = this.lastParams.app
|
|
|
|
+ ? this.lastParams
|
|
|
|
+ : {
|
|
|
|
+ app: this.form.app,
|
|
|
|
+ start: S,
|
|
|
|
+ end: E,
|
|
|
|
+ manufacturer:
|
|
|
|
+ this.form.channel == -1 ? undefined : this.form.channel,
|
|
|
|
+ version: this.form.version == -1 ? undefined : this.form.version,
|
|
|
|
+ };
|
|
|
|
+ getUserActivity(p).then(r => {
|
|
|
|
+ // 生成数据
|
|
|
|
+ let strcsv =
|
|
|
|
+ "data:text/csv;charset=utf-8,\uFEFF日期,应用,日活跃用户数,日活跃度,日活/月活,周活跃用户数,周活跃度,月活跃用户数,月活跃度,累积用户数\r\n";
|
|
|
|
+ (r || []).map(v => {
|
|
|
|
+ strcsv += [
|
|
|
|
+ v.date,
|
|
|
|
+ p.app,
|
|
|
|
+ v.mau1,
|
|
|
|
+ (100 * v.mau1 / v.total).toFixed(2) + '%',
|
|
|
|
+ (100 * v.mau1 / v.mau30).toFixed(2) + '%',
|
|
|
|
+ v.mau7,
|
|
|
|
+ (100 * v.mau7 / v.total).toFixed(2) + '%',
|
|
|
|
+ v.mau30,
|
|
|
|
+ (100 * v.mau30 / v.total).toFixed(2) + '%',
|
|
|
|
+ v.total,
|
|
|
|
+ "\r\n",
|
|
|
|
+ ].join(",");
|
|
|
|
+ });
|
|
|
|
+ // 导出
|
|
|
|
+ let link = document.createElement("a");
|
|
|
|
+ link.id = "download-csv";
|
|
|
|
+ link.setAttribute("href", encodeURI(strcsv));
|
|
|
|
+ link.setAttribute(
|
|
|
|
+ "download",
|
|
|
|
+ p.app + "用户活跃度" + S + "_" + E + ".csv"
|
|
|
|
+ );
|
|
|
|
+ // document.body.appendChild(link);
|
|
|
|
+ link.click();
|
|
|
|
+ link = undefined;
|
|
|
|
+ });
|
|
|
|
+ },
|
|
|
|
+ },
|
|
|
|
+ components: {
|
|
|
|
+ countTo,
|
|
|
|
+ },
|
|
|
|
+};
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style>
|
|
|
|
+.Version {
|
|
|
|
+ margin: 10px 15px;
|
|
|
|
+}
|
|
|
|
+.libTitle {
|
|
|
|
+ color: tomato;
|
|
|
|
+ font-weight: 700;
|
|
|
|
+ font-size: 14px;
|
|
|
|
+}
|
|
|
|
+.btn-next i,
|
|
|
|
+.btn-prev i {
|
|
|
|
+ margin: 0 auto;
|
|
|
|
+}
|
|
|
|
+.caret-wrapper .ascending {
|
|
|
|
+ display: none;
|
|
|
|
+}
|
|
|
|
+</style>
|