Quellcode durchsuchen

增加游戏异常率和微信授权信息功能

倚楼听风雨 vor 3 Jahren
Ursprung
Commit
455d21a947

+ 42 - 0
src/api/data_abnormal_rate.js

@@ -0,0 +1,42 @@
+/*
+ * @Author: 倚楼听风雨 18408246387@163.com
+ * @Date: 2023-02-02 13:47:20
+ * @LastEditors: 倚楼听风雨 18408246387@163.com
+ * @LastEditTime: 2023-02-08 11:51:59
+ * @FilePath: \log-server-web\src\api\data_abnormal_rate.js
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
+ */
+import service from "@/utils/request";
+
+//DataAbnormalRateRouter============================================================================
+export const queryAbnormalRate = (data) => {
+  return service({
+    url: "/dataStatistics/queryAbnormalRate",
+    method: "post",
+    data,
+  });
+};
+//WeChatScannerApiRouter============================================================================
+export const getWeChatScannerApiList = (data) => {
+  return service({
+    url: "/dataStatistics/getWeChatScannerApiList",
+    method: "post",
+    data,
+  });
+};
+//WeChatScannerDetailedRouter============================================================================
+export const getWeChatScannerDetailedList = (data) => {
+  return service({
+    url: "/dataStatistics/getWeChatScannerDetailedList",
+    method: "post",
+    data,
+  });
+};
+//WeChatScannerLedgerRouter=================================================================================
+export const getWeChatScannerLedgerList = (data) => {
+  return service({
+    url: "/dataStatistics/getWeChatScannerLedgerList",
+    method: "post",
+    data,
+  });
+};

+ 527 - 0
src/view/dataStatistics/data_abnormal_rate.vue

@@ -0,0 +1,527 @@
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-form ref="searchForm" :inline="true" :model="searchInfo">
+          <el-form-item label="任务Id">
+            <el-input v-model="searchInfo.task_id" placeholder="任务ID" />
+          </el-form-item>
+          <el-form-item label="负责人">
+            <el-input v-model="searchInfo.director_name" placeholder="负责人" />
+          </el-form-item>
+          <el-form-item label="日期" prop="date">
+            <el-date-picker
+              v-model="searchInfo.date"
+              size="default"
+              type="daterange"
+              unlink-panels
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+            />
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              size="small"
+              type="primary"
+              icon="search"
+              @click="onSubmit"
+              >查询</el-button
+            >
+            <el-button size="small" icon="refresh" @click="onReset"
+              >重置</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="gva-table-box" style="padding: 0">
+      <el-table
+        :data="tableData"
+        border
+        style="width: 100%; cursor: pointer"
+        stripe
+        align="center"
+        header-align="center"
+        size="mini"
+        :default-sort="{ prop: 'task_id', order: 'ascending' }"
+        v-loading="loading"
+      >
+        <el-table-column type="index" label="#" min-width="10" fixed="left" />
+        <el-table-column
+          fixed="left"
+          prop="task_id"
+          label="任务ID"
+          min-width="80"
+          sortable
+        />
+        <el-table-column
+          fixed="left"
+          prop="task_name"
+          label="任务名称"
+          min-width="100"
+        />
+        <el-table-column
+          fixed="left"
+          prop="director_name"
+          label="负责人"
+          min-width="80"
+          sortable
+        />
+        <el-table-column label="留存账号" align="center">
+          <el-table-column prop="num_could_pay" align="center" label="能付费">
+            <template #default="scope">
+              {{ scope.row.num_account_lc }}
+              <!-- <br /> -->
+              <el-divider style="margin: 0" />
+              {{ scope.row.num_could_pay }}
+            </template>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column
+          prop="num_frozen"
+          label="封号数"
+          min-width="60"
+          align="center"
+        />
+        <el-table-column
+          prop="num_pull_account"
+          label="下发账号"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column
+          prop="num_start_script"
+          label="脚本启动"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column
+          prop="num_start_simulator"
+          label="模拟器启动"
+          min-width="80"
+          align="center"
+        />
+        <el-table-column
+          prop="num_ip"
+          label="查询IP"
+          min-width="60"
+          align="center"
+        />
+        <el-table-column
+          prop="num_start_game"
+          label="启动游戏"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column
+          prop="num_login_success"
+          label="账号登录"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column
+          prop="num_into_game"
+          label="进入游戏"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column label="活跃成功" align="center">
+          <el-table-column
+            prop="num_new_success"
+            label="新增成功"
+            min-width="70"
+            align="center"
+          />
+          <el-table-column
+            prop="num_lc_success"
+            label="留存成功"
+            min-width="70"
+            align="center"
+          />
+        </el-table-column>
+        <el-table-column
+          prop="num_pay_success"
+          label="付费成功"
+          min-width="70"
+          align="center"
+        />
+        <el-table-column label="订单数" align="center">
+          <el-table-column label="付费成功" align="center">
+            <el-table-column
+              prop="num_order_pay,num_pay"
+              align="center"
+              label="成功率"
+              sortable
+              :sort-method="sortBySuccess1"
+            >
+              <template #default="scope">
+                {{ scope.row.step6 }}
+                <el-divider style="margin: 0" />
+                {{ scope.row.rate_pay_success }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="下发账号" align="center">
+          <el-table-column label="脚本启动" align="center">
+            <el-table-column
+              prop="num_pull_account,num_start_script"
+              align="center"
+              label="成功率"
+              sortable
+              :sort-method="sortBySuccess2"
+            >
+              <template #default="scope">
+                {{ scope.row.step2 }}
+                <el-divider style="margin: 0" />
+                {{ Math.round(scope.row.rate2 * 10000) / 100 + "%" }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="脚本启动" align="center">
+          <el-table-column label="进入游戏" align="center">
+            <el-table-column
+              prop="num_into_game,num_start_game"
+              label="成功率"
+              align="center"
+              sortable
+              :sort-method="sortBySuccess3"
+            >
+              <template #default="scope">
+                {{ scope.row.num_start_script }}
+                <el-divider style="margin: 0 5px" direction="vertical" />{{
+                  scope.row.num_into_game
+                }}
+                <el-divider style="margin: 0" />
+                {{ Math.round(scope.row.rate3 * 10000) / 100 + "%" }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="脚本启动" align="center">
+          <el-table-column label="活跃成功" align="center">
+            <el-table-column
+              prop="num_start_script,num_active"
+              label="成功率"
+              align="center"
+              sortable
+              :sort-method="sortBySuccess4"
+            >
+              <template #default="scope">
+                {{ scope.row.num_start_script }}
+                <el-divider style="margin: 0 5px" direction="vertical" />{{
+                  scope.row.num_active
+                }}
+                <el-divider style="margin: 0" />
+                {{ Math.round(scope.row.rate4 * 10000) / 100 + "%" }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table-column>
+        <el-table-column label="下发付费" align="center">
+          <el-table-column label="付费成功" align="center">
+            <el-table-column
+              prop="num_start_script,num_new_success,num_lc_success"
+              label="成功率"
+              align="center"
+              sortable
+              :sort-method="sortBySuccess5"
+            >
+              <template #default="scope">
+                {{ scope.row.num_pull_pay }}
+                <el-divider style="margin: 0 5px" direction="vertical" />{{
+                  scope.row.num_pay_success
+                }}
+                <el-divider style="margin: 0" />
+                {{ Math.round(scope.row.rate5 * 10000) / 100 + "%" }}
+              </template>
+            </el-table-column>
+          </el-table-column>
+        </el-table-column>
+        <!-- <el-table-column
+          fixed="right"
+          label="操作"
+          width="60"
+          align="center"
+          header-align="center"
+        >
+          <template #default="scope">
+            <el-button
+              size="mini"
+              type="primary"
+              plain
+              @click="showSevenTab(scope.row)"
+              >7天</el-button
+            >
+          </template>
+        </el-table-column> -->
+      </el-table>
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "data_abnormal_rate",
+};
+</script>
+
+<script setup>
+import { queryAbnormalRate } from "@/api/data_abnormal_rate";
+import { useUserStore } from "@/pinia/modules/user";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import dayjs from "dayjs";
+import { ElMessage } from "element-plus";
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(100);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+const userStore = useUserStore();
+const loading = ref(false);
+
+const disabledDate = (time) => {
+  return time.getTime() > Date.now();
+};
+
+const shortcuts = [
+  {
+    text: "今日",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      return [start, end];
+    },
+  },
+  {
+    text: "最近一周",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+      return [start, end];
+    },
+  },
+  {
+    text: "最近一月",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+      return [start, end];
+    },
+  },
+];
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+const onReset = () => {
+  searchInfo.value = {};
+};
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 搜索
+const onSubmit = () => {
+  loading.value = true;
+  page.value = 1;
+  pageSize.value = 10;
+
+  if (typeof searchInfo.value.task_id != "undefined") {
+    searchInfo.value.task_id = Number(searchInfo.value.task_id);
+  }
+  if (typeof searchInfo.value.date != "undefined") {
+    searchInfo.value.date[0] = dayjs(searchInfo.value.date[0]).format(
+      "YYYY-MM-DD"
+    );
+    searchInfo.value.date[1] = dayjs(searchInfo.value.date[1]).format(
+      "YYYY-MM-DD"
+    );
+  }
+  if (
+    typeof searchInfo.value.date != "undefined" &&
+    searchInfo.value.date[0] != searchInfo.value.date[1] &&
+    searchInfo.value.date[1] == dayjs(new Date()).format("YYYY-MM-DD")
+  ) {
+    ElMessage({
+      message: "今日数据只可单独查询,已去掉今日数据",
+      type: "warning",
+      offset: 150,
+    });
+  }
+
+  // console.log(searchInfo.value);
+
+  getTableData();
+  loading.value = false;
+};
+
+// 查询
+const getTableData = async () => {
+  ElMessage({
+    message: "查询中,请稍等",
+    type: "success",
+    offset: 50,
+  });
+  const table = await queryAbnormalRate({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = [];
+    const data = table.data.list;
+    if (data) {
+      data.forEach((e) => {
+        let rate2 = 0;
+        let rate3 = 0;
+        let rate4 = 0;
+        let rate5 = 0;
+        if (e.num_pull_account != 0) {
+          rate2 = e.num_start_script / e.num_pull_account;
+        }
+        if (e.num_start_script != 0) {
+          rate3 = e.num_into_game / e.num_start_script;
+          rate4 = (e.num_new_success + e.num_lc_success) / e.num_start_script;
+        }
+        if (e.num_pull_pay != 0) {
+          rate5 = e.num_pay_success / e.num_pull_pay;
+        }
+        let obj1 = {
+          task_id: e.task_id,
+          task_name: e.task_name,
+          director_name: e.director_name,
+          new_date: e.new_date,
+          num_frozen: e.num_frozen,
+          num_pull_account: e.num_pull_account,
+          num_start_simulator: e.num_start_simulator,
+          num_ip: e.num_ip,
+          num_start_script: e.num_start_script,
+          num_start_game: e.num_start_game,
+          num_login_success: e.num_login_success,
+          num_into_game: e.num_into_game,
+          num_new_success: e.num_new_success,
+          num_lc_success: e.num_lc_success,
+          num_pay_success: e.num_pay_success,
+          rate_all_step: Math.round(e.rate_all_step * 10000) / 100 + "%",
+          step2: e.num_pull_account + " | " + e.num_start_script,
+          num_active: e.num_new_success + e.num_lc_success,
+          num_pull_pay: e.num_pull_pay,
+          num_account_lc: e.num_account_lc,
+          num_could_pay: e.num_could_pay,
+          num_order_pay: e.num_order_pay,
+          num_pay: e.num_pay,
+          step6: e.num_order_pay + " | " + e.num_pay,
+          rate_pay_success: e.rate_pay_success,
+          rate2: rate2,
+          rate3: rate3,
+          rate4: rate4,
+          rate5: rate5,
+        };
+        tableData.value.push(obj1);
+      });
+      getSpanArr(table.data.list);
+    }
+    // console.log(tableData);
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+  }
+};
+
+getTableData();
+
+function sortBySuccess1(obj1, obj2) {
+  let str1 = obj1.rate_pay_success;
+  let str2 = obj2.rate_pay_success;
+  // let arr1 = str1.split("/");
+  // let arr2 = str2.split("/");
+  return str1.replace("%", "") - str2.replace("%", "");
+}
+function sortBySuccess2(obj1, obj2) {
+  let num1 = obj1.rate2;
+  let num2 = obj2.rate2;
+  return num1 - num2;
+}
+function sortBySuccess3(obj1, obj2) {
+  let num1 = obj1.rate3;
+  let num2 = obj2.rate3;
+  return num1 - num2;
+}
+function sortBySuccess4(obj1, obj2) {
+  let num1 = obj1.rate4;
+  let num2 = obj2.rate4;
+  return num1 - num2;
+}
+function sortBySuccess5(obj1, obj2) {
+  let num1 = obj1.rate5;
+  let num2 = obj2.rate5;
+  return num1 - num2;
+}
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>

+ 215 - 0
src/view/dataStatistics/wechat_scanner_api.vue

@@ -0,0 +1,215 @@
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-form ref="searchForm" :inline="true" :model="searchInfo">
+          <el-form-item label="平台">
+            <el-select v-model="searchInfo.name" size="small">
+              <el-option label="浪潮" value="浪潮" />
+              <el-option label="海马" value="海马" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="日期" prop="new_date">
+            <el-date-picker
+              v-model="searchInfo.new_date"
+              popper-class="picker-popovers"
+              class="timefilter"
+              type="date"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+              placeholder="选择日期时间"
+              value-format="YYYY-MM-DD"
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              size="small"
+              type="primary"
+              icon="search"
+              @click="onSubmit"
+              >查询</el-button
+            >
+            <el-button size="small" icon="refresh" @click="onReset"
+              >重置</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="gva-table-box">
+      <!-- <el-scrollbar height="550px"> -->
+      <el-table
+        height="500px"
+        :data="tableData"
+        @sort-change="sortChange"
+        @selection-change="handleSelectionChange"
+        border
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column
+          align="left"
+          label="日期"
+          min-width="100"
+          prop="new_date"
+        />
+        <el-table-column
+          align="left"
+          label="更新时间"
+          min-width="150"
+          prop="update_time"
+        />
+        <el-table-column
+          align="left"
+          label="平台名"
+          min-width="100"
+          prop="name"
+        />
+        <el-table-column
+          align="left"
+          label="平台余额"
+          min-width="100"
+          prop="balance"
+        />
+      </el-table>
+      <!-- </el-scrollbar> -->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "wechat_scanner_api",
+};
+</script>
+
+<script setup>
+import { getWeChatScannerApiList } from "@/api/data_abnormal_rate";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { formatDate } from "@/utils/format";
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(20);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+const shortcuts = [
+  {
+    text: "今日",
+    value: new Date(),
+  },
+  {
+    text: "昨日",
+    value: () => {
+      const date = new Date();
+      date.setTime(date.getTime() - 3600 * 1000 * 24);
+      return date;
+    },
+  },
+];
+
+const disabledDate = (time) => {
+  return time.getTime() > Date.now();
+};
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  // console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+const onReset = () => {
+  searchInfo.value = {};
+};
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 搜索
+const onSubmit = () => {
+  page.value = 1;
+  pageSize.value = 10;
+
+  // if (typeof searchInfo.value.name != "undefined") {
+  //   searchInfo.value.name = Number(searchInfo.value.name);
+  // }
+  // searchInfo.value.new_date = String(searchInfo.value.new_date);
+
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await getWeChatScannerApiList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+  }
+};
+getTableData();
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>

+ 242 - 0
src/view/dataStatistics/wechat_scanner_detailed.vue

@@ -0,0 +1,242 @@
+<template>
+  <div>
+    <el-alert title="微信授权游戏专用" type="warning" :closable="false" />
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-form ref="searchForm" :inline="true" :model="searchInfo">
+          <el-form-item label="任务Id">
+            <el-input v-model="searchInfo.task_id" placeholder="任务ID" />
+          </el-form-item>
+          <el-form-item label="平台">
+            <el-input v-model="searchInfo.platform" placeholder="平台" />
+          </el-form-item>
+          <el-form-item label="日期" prop="new_date">
+            <el-date-picker
+              v-model="searchInfo.new_date"
+              popper-class="picker-popovers"
+              class="timefilter"
+              type="date"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+              placeholder="选择日期"
+              value-format="YYYY-MM-DD"
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="新留">
+            <el-select v-model="searchInfo.new_retained" size="small">
+              <el-option label="新增" value="1" />
+              <el-option label="留存" value="2" />
+              <!-- <el-option label="3留" value="3" />
+              <el-option label="4留" value="4" />
+              <el-option label="5留" value="5" />
+              <el-option label="6留" value="6" />
+              <el-option label="7留" value="7" />
+              <el-option label="8留" value="8" /> -->
+            </el-select>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              size="small"
+              type="primary"
+              icon="search"
+              @click="onSubmit"
+              >查询</el-button
+            >
+            <el-button size="small" icon="refresh" @click="onReset"
+              >重置</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="gva-table-box">
+      <!-- <el-scrollbar height="550px"> -->
+      <el-table
+        height="500px"
+        :data="tableData"
+        @sort-change="sortChange"
+        @selection-change="handleSelectionChange"
+        border
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column
+          align="left"
+          label="授权时间"
+          min-width="150"
+          prop="authorization_time"
+        />
+        <el-table-column
+          align="left"
+          label="订单号"
+          min-width="150"
+          prop="order_id"
+        />
+        <el-table-column
+          align="left"
+          label="平台"
+          min-width="150"
+          prop="platform"
+        />
+        <el-table-column
+          align="left"
+          label="任务ID"
+          min-width="100"
+          prop="task_id"
+        />
+        <el-table-column
+          align="left"
+          label="任务名称"
+          min-width="100"
+          prop="task_name"
+        />
+        <el-table-column
+          align="left"
+          label="留存天数(1:新增2:次留3:三留...)"
+          min-width="150"
+          prop="new_retained"
+        />
+      </el-table>
+      <!-- </el-scrollbar> -->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "wechat_scanner_detailed",
+};
+</script>
+
+<script setup>
+import { getWeChatScannerDetailedList } from "@/api/data_abnormal_rate";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { formatDate } from "@/utils/format";
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(20);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+const shortcuts = [
+  {
+    text: "今日",
+    value: new Date(),
+  },
+  {
+    text: "昨日",
+    value: () => {
+      const date = new Date();
+      date.setTime(date.getTime() - 3600 * 1000 * 24);
+      return date;
+    },
+  },
+];
+
+const disabledDate = (time) => {
+  return time.getTime() > Date.now();
+};
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  // console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+const onReset = () => {
+  searchInfo.value = {};
+};
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 搜索
+const onSubmit = () => {
+  page.value = 1;
+  pageSize.value = 10;
+
+  if (typeof searchInfo.value.new_retained != "undefined") {
+    searchInfo.value.new_retained = Number(searchInfo.value.new_retained);
+  }
+  if (typeof searchInfo.value.task_id != "undefined") {
+    searchInfo.value.task_id = Number(searchInfo.value.task_id);
+  }
+
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await getWeChatScannerDetailedList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+  }
+};
+getTableData();
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>

+ 226 - 0
src/view/dataStatistics/wechat_scanner_ledger.vue

@@ -0,0 +1,226 @@
+<template>
+  <div>
+    <div class="gva-search-box">
+      <div class="gva-btn-list">
+        <el-form ref="searchForm" :inline="true" :model="searchInfo">
+          <el-form-item label="平台">
+            <el-input v-model="searchInfo.platform" placeholder="平台" />
+          </el-form-item>
+          <el-form-item label="日期" prop="new_date">
+            <el-date-picker
+              v-model="searchInfo.new_date"
+              popper-class="picker-popovers"
+              class="timefilter"
+              type="date"
+              :disabled-date="disabledDate"
+              :shortcuts="shortcuts"
+              placeholder="选择日期时间"
+              value-format="YYYY-MM-DD"
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <el-button
+              size="small"
+              type="primary"
+              icon="search"
+              @click="onSubmit"
+              >查询</el-button
+            >
+            <el-button size="small" icon="refresh" @click="onReset"
+              >重置</el-button
+            >
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+    <div class="gva-table-box">
+      <!-- <el-scrollbar height="550px"> -->
+      <el-table
+        height="500px"
+        :data="tableData"
+        @sort-change="sortChange"
+        @selection-change="handleSelectionChange"
+        border
+        show-summary
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column
+          align="left"
+          label="日期"
+          min-width="50"
+          prop="new_date"
+        />
+        <el-table-column
+          align="left"
+          label="任务ID"
+          min-width="50"
+          prop="task_id"
+        />
+        <el-table-column
+          align="left"
+          label="任务名称"
+          min-width="100"
+          prop="task_name"
+        />
+        <el-table-column
+          align="left"
+          label="平台"
+          min-width="100"
+          prop="platform"
+        />
+        <el-table-column
+          align="left"
+          label="消耗"
+          min-width="100"
+          prop="ledger"
+        />
+        <el-table-column
+          align="left"
+          label="新增消耗"
+          min-width="100"
+          prop="ledger_new"
+        />
+        <el-table-column
+          align="left"
+          label="留存消耗"
+          min-width="100"
+          prop="ledger_retained"
+        />
+      </el-table>
+      <!-- </el-scrollbar> -->
+      <div class="gva-pagination">
+        <el-pagination
+          :current-page="page"
+          :page-size="pageSize"
+          :page-sizes="[10, 20, 30, 50, 100]"
+          :total="total"
+          layout="total, sizes, prev, pager, next, jumper"
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "wechat_scanner_ledger",
+};
+</script>
+
+<script setup>
+import { getWeChatScannerLedgerList } from "@/api/data_abnormal_rate";
+import { toSQLLine } from "@/utils/stringFun";
+import { ref } from "vue";
+import { ElMessage, ElMessageBox } from "element-plus";
+import { formatDate } from "@/utils/format";
+
+const page = ref(1);
+const total = ref(0);
+const pageSize = ref(50);
+const tableData = ref([]);
+let spanArr = [];
+const searchInfo = ref({});
+const shortcuts = [
+  {
+    text: "今日",
+    value: new Date(),
+  },
+  {
+    text: "昨日",
+    value: () => {
+      const date = new Date();
+      date.setTime(date.getTime() - 3600 * 1000 * 24);
+      return date;
+    },
+  },
+];
+
+const disabledDate = (time) => {
+  return time.getTime() > Date.now();
+};
+
+const getSpanArr = (data) => {
+  spanArr = [];
+  var pos = 0;
+  for (var i = 0; i < data.length; i++) {
+    if (i === 0) {
+      spanArr.push(1);
+      pos = 0;
+    } else {
+      if (data[i].pc_code === data[i - 1].pc_code) {
+        spanArr[pos] += 1;
+        spanArr.push(0);
+      } else {
+        spanArr.push(1);
+        pos = i;
+      }
+    }
+  }
+  // console.log(spanArr);
+};
+
+// 分页
+const handleSizeChange = (val) => {
+  pageSize.value = val;
+  getTableData();
+};
+const onReset = () => {
+  searchInfo.value = {};
+};
+const handleCurrentChange = (val) => {
+  page.value = val;
+  getTableData();
+};
+
+// 排序
+const sortChange = ({ prop, order }) => {
+  if (prop) {
+    if (prop === "id") {
+      prop = "id";
+    }
+    searchInfo.value.orderKey = toSQLLine(prop);
+    searchInfo.value.desc = order === "descending";
+  }
+  getTableData();
+};
+
+// 搜索
+const onSubmit = () => {
+  page.value = 1;
+  pageSize.value = 50;
+
+  getTableData();
+};
+
+// 查询
+const getTableData = async () => {
+  const table = await getWeChatScannerLedgerList({
+    page: page.value,
+    pageSize: pageSize.value,
+    ...searchInfo.value,
+  });
+  if (table.code === 0) {
+    tableData.value = table.data.list;
+    total.value = table.data.total;
+    page.value = table.data.page;
+    pageSize.value = table.data.pageSize;
+    getSpanArr(table.data.list);
+  }
+};
+getTableData();
+</script>
+
+<style scoped lang="scss">
+.button-box {
+  padding: 10px 20px;
+  .el-button {
+    float: right;
+  }
+}
+.warning {
+  color: #dc143c;
+}
+</style>