Parcourir la source

abtest 导出

hml il y a 2 ans
Parent
commit
2b9cfbe844

+ 0 - 7
admin/src/api/common.js

@@ -27,10 +27,3 @@ export const put = (url, data) => request({
   method: 'put',
   data
 })
-
-export const getExport = (url, data) => request({
-  url: url,
-  method: 'get',
-  params: data,
-  responseType: "blob"
-})

+ 0 - 1
admin/src/main.js

@@ -70,7 +70,6 @@ import Tinymce from '@/components/tinymce/index.vue'
 Vue.component('tinymce', Tinymce)
 import '@/icons'
 import request from "@/utils/request" // 实现 form generator 使用自己定义的 axios request 对象
-console.log(request)
 Vue.prototype.$axios = request
 import '@/styles/index.scss'
 

+ 38 - 0
admin/src/views/ABtest/index.js

@@ -0,0 +1,38 @@
+import request from '@/utils/request'
+
+// 获取ABtest列表
+export function abtestList (params) {
+  return request({
+    url: '/abtest/test-info/page',
+    method: 'get',
+    params
+  })
+}
+
+// 删除abtest数据
+export function removeAbtest (params) {
+  return request({
+    url: '/abtest/test-info/delete',
+    method: 'delete',
+    params
+  })
+}
+
+
+// 获取二级渠道
+export function secondChannel (params) {
+  return request({
+    url: '/channel/info/listChannels',
+    method: 'get',
+    params
+  })
+}
+
+// 获取abtest类型列表
+export function typeListApi (params) {
+  return request({
+    url: '/abtest/type-dict/page',
+    method: 'get',
+    params
+  })
+}

+ 285 - 210
admin/src/views/ABtest/index.vue

@@ -1,259 +1,334 @@
 <template>
-  <div>
-    <el-container>
-      <!--搜索-->
-      <el-header class="searchBox">
-        <el-form
-          :inline="true"
-          :model="searchForm"
-          ref="searchForm"
-          class="demo-form-inline"
-        >
-          <el-form-item label="测试名称">
-            <el-input
-              v-model="searchForm.strategyName"
-              name="searchForm.name"
-              placeholder="请输入关键字"
-            />
-          </el-form-item>
-          <el-form-item label="状态">
-            <el-select
-              v-model="searchForm.state"
-              filterable
-              placeholder="请选择"
-            >
-              <el-option label="生效" :value="1" />
-              <el-option label="失效" :value="0" />
-            </el-select>
-          </el-form-item>
-
-          <el-form-item style="float: right">
-            <el-button type="primary" @click="init()">搜索</el-button>
-            <el-button @click="reset('searchForm')">重置</el-button>
-          </el-form-item>
-        </el-form>
-      </el-header>
-      <!--表格-->
-      <el-main class="tableBox">
-        <vxe-toolbar>
-          <template #buttons>
-            <vxe-button icon="fa fa-plus" @click="toAdd">新增</vxe-button>
-            <vxe-button @click="init()">刷新</vxe-button>
-            <!--                        <vxe-button status="primary" style="float: right" icon="fa fa-plus" @click="value5 = true">历史记录</vxe-button>-->
-          </template>
-        </vxe-toolbar>
-        <vxe-table
-          border
-          resizable
-          keep-source
-          show-overflow
-          highlight-hover-row
-          ref="xTable"
-          :data="tableData"
-          :edit-config="{ trigger: 'click', mode: 'cell', showStatus: true }"
-          @edit-closed="editClosedEvent"
-        >
-          <vxe-table-column field="name" title="名称" />
-          <vxe-table-column field="content" title="描述" width="300" />
-          <!-- <a href="../ABtest/edit.vue"></a> -->
-          <!-- <a href="../ABtest/ABclass/"></a> -->
-          <vxe-table-column
-            field="state"
-            title="状态"
-            :edit-render="{ name: '$select', options: strategyStatus }"
-            width="80"
-          />
-          <vxe-table-column field="beginTime" title="开始时间" />
-          <vxe-table-column field="endTime" title="结束时间" />
-          <vxe-table-column title="操作" width="220">
-            <template #default="{ row }">
-              <template v-if="$refs.xTable.isActiveByRow(row)">
-                <vxe-button @click="saveRowEvent(row)">保存</vxe-button>
-                <vxe-button @click="cancelRowEvent(row)">取消</vxe-button>
-              </template>
-              <template v-else>
-                <vxe-button @click="toEdit(row.id)">编辑</vxe-button>
-                <vxe-button @click="toCopy(row.id)">复制</vxe-button>
-                <vxe-button @click="del(row.id)">删除</vxe-button>
-              </template>
-            </template>
-          </vxe-table-column>
-        </vxe-table>
-        <vxe-pager
-          :loading="loading"
-          :current-page="searchForm.pageNum"
-          :page-size="searchForm.pageSize"
-          :total="searchForm.totalResult"
-          :layouts="[
-            'PrevPage',
-            'JumpNumber',
-            'NextPage',
-            'FullJump',
-            'Sizes',
-            'Total',
-          ]"
-          @page-change="handlePageChange"
-        />
-      </el-main>
-    </el-container>
+  <div class="abtestIndex">
+    <el-form :inline="true" :model="searchForm" size="small" ref="searchForm" class="demo-form-inline">
+      <el-form-item label="测试名称">
+        <el-input v-model="searchForm.name" name="searchForm.name" placeholder="请输入测试名称" />
+      </el-form-item>
+      <el-form-item label="状态">
+        <el-select v-model="searchForm.state" filterable placeholder="请选择状态" clearable>
+          <el-option label="生效" :value="1" />
+          <el-option label="失效" :value="0" />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" @click="init()">搜索</el-button>
+        <el-button icon="el-icon-refresh" @click="reset()">重置</el-button>
+      </el-form-item>
+    </el-form>
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button type="primary" plain icon="el-icon-plus" size="mini" @click="toAdd">新增</el-button>
+      </el-col>
+    </el-row>
+    <el-table v-loading="loading" :data="tableData">
+      <el-table-column label="名称" prop="name" align="center"></el-table-column>
+      <el-table-column label="描述" prop="content" align="center"></el-table-column>
+      <el-table-column label="状态" align="center">
+        <template slot-scope="scope">
+          <el-switch :value="scope.row.state" :active-value="1" :inactive-value="0"></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="开始时间" align="center">
+        <template slot-scope="scope">
+          <span>{{getTimeStr(scope.row.beginTime)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="结束时间" align="center">
+        <template slot-scope="scope">
+          <span>{{getTimeStr(scope.row.endTime)}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center">
+        <template slot-scope="scope">
+          <el-button size="mini" type="text" icon="el-icon-edit">编辑</el-button>
+          <el-button size="mini" type="text" icon="el-icon-set-up">复制</el-button>
+          <el-button size="mini" type="text" icon="el-icon-delete" @click="removeInfo(scope.row.id)">删除</el-button>
+        </template>
+      </el-table-column>
+      <pagination v-show="total>0" background layout="total, sizes, prev, pager, next, jumper" :total="total" :current-page="searchForm.pageNo" :page-size="searchForm.pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+    </el-table>
+    <!-- 新增编辑弹窗 -->
+    <el-dialog title="新建测试" :visible.sync="infoShow" append-to-body>
+      <el-form :model="infoForm" :rules="rules" style="width:60%" ref="ruleForm" label-width="100px">
+        <el-form-item label="测试名称" prop="name">
+          <el-input v-model="infoForm.name" />
+        </el-form-item>
+        <el-form-item label="测试描述" prop="content">
+          <el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" v-model="infoForm.content" />
+        </el-form-item>
+        <el-form-item label="生效时间" prop="timeBox">
+          <el-date-picker v-model="channelDateTime" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期">
+          </el-date-picker>
+        </el-form-item>
+        <el-form-item label="渠道选择" prop="channelKey">
+          <el-select v-model="channelVal" multiple clearable filterable placeholder="请选择">
+            <el-option v-for="item in channelList" :key="item.channelKey" :label="item.channelName" :value="item.channelKey">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="类型选择" prop="typeDictId">
+          <el-select v-model="infoForm.typeDictId" clearable filterable placeholder="请选择">
+            <el-option v-for="item in typeList" :key="item.id" :label="item.typeName" :value="item.id">
+            </el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="状态" prop="state">
+          <el-switch v-model="infoForm.state" active-text="生效" :active-value="1" inactive-text="无效" :inactive-value="0" />
+        </el-form-item>
+        <div v-if="isEdit === true" style="margin-bottom: 20px">
+          <el-button type="primary" size="small" icon="el-icon-plus" @click="addTab">新增对照组</el-button>
+        </div>
+        <el-tabs v-model="editableTabsValue" type="card" closable @tab-remove="removeTab">
+          <el-tab-pane v-for="(item, index) in infoForm.groupData" :key="item.groupName" :label="item.groupName" :name="item.groupName">
+            <div>
+              <el-form-item label="组别名称" prop="name">
+                <el-input v-model="item.name" />
+              </el-form-item>
+              <el-form-item label="组别描述" prop="content">
+                <el-input type="textarea" :autosize="{ minRows: 2, maxRows: 4 }" v-model="item.content" />
+              </el-form-item>
+              <el-form-item label="分流占比" prop="flowPercent">
+                <el-input v-model="item.flowPercent" placeholder="请输入小数" />
+                <div style="color: red">请输入小数如0.5,各组占比之和为1</div>
+              </el-form-item>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="infoShow = false">取 消</el-button>
+        <el-button type="primary" @click="createTest">确 定</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
 
 <script>
-import { post, get, del } from "@/api/common";
-import getTime from "@/utils/getTime.js";
+import { secondChannel, abtestList, removeAbtest, typeListApi } from './index'
 export default {
-  name: "Index",
-  data() {
+  name: "abtestIndex",
+  data () {
     return {
       //  搜索相关内容
       searchForm: {
-        strategyName: null,
-        state: 1,
+        name: null,
+        state: null,
         pageNo: 1,
         pageSize: 10,
-        totalResult: 0,
       },
       // 表格数据
-      loading: false,
+      loading: true,
       tableData: [],
-      strategyStatus: [
-        { label: "生效", value: 1 },
-        { label: "失效", value: 0 },
-      ],
+      total: 0,
+      infoShow: true,
+      infoForm: {
+        name: "",
+        content: "",
+        beginTime: "",
+        endTime: "",
+        channelKey: "",
+        typeDictId: "",
+        state: 0,
+        groupData: [
+          {
+            "content": "",
+            "flowPercent": null,
+            "groupName": "对照组",
+            "name": "对照组",
+            "state": 1,
+            "strategyId": null,
+            "type": 0
+          },
+          {
+            "content": "",
+            "flowPercent": null,
+            "groupName": "控制组1",
+            "name": "控制组1",
+            "state": 1,
+            "strategyId": null,
+            "type": 1
+          }
+        ]
+      },
+      channelDateTime: [], //新增编辑选择时间
+      channelList: [],   //渠道列表
+      channelVal: null,  //渠道key
+      typeList: [],  // 类型列表
+      // 表单规则
+      rules: {
+        name: [{ required: true, message: "请填写名称", trigger: "blur" }],
+        content: [{ required: true, message: "请填写描述", trigger: "blur" }],
+        timeBox: [{ type: 'date', required: true, message: '请选择生效时间', trigger: 'change' }],
+        channelKey: [{ required: true, message: "请绑定渠道", trigger: "change" }],
+        typeDictId: [{ required: true, message: "请选择测试类型", trigger: "change" }],
+        state: [{ required: true, message: "请选择状态", trigger: "change" }],
+        flowPercent: [{ required: true, message: "请输入占比", trigger: "blur" }],
+      },
+      // 标签页
+      editableTabsValue: "对照组",
+      tabIndex: 1,
+      thisIndex: 0,
+      isEdit: true,
     };
   },
-  mounted() {
-    this.init();
+  mounted () {
+    this.init();  // 获取abtest数据
+    this.getSecondChannel() // 获取二级渠道列表数据
+    this.getTypeList()    //获取类型选择
   },
   methods: {
-    getTimeStr(timeStamp) {
+    // 时间格式转换
+    getTimeStr (timeStamp) {
       var now = new Date(timeStamp),
         y = now.getFullYear(),
         m = ("0" + (now.getMonth() + 1)).slice(-2),
         d = ("0" + now.getDate()).slice(-2);
       return y + "-" + m + "-" + d + " " + now.toTimeString().substr(0, 8);
     },
-
-    init() {
-      get("/abtest/test-info/page", this.searchForm).then((res) => {
+    // 获取列表
+    init () {
+      this.loading = true
+      abtestList(this.searchForm).then(res => {
         this.tableData = res.data.list;
-        console.log(this.tableData);
-        this.tableData.forEach((item) => {
-          item.beginTime = getTime(item.beginTime);
-          item.endTime = getTime(item.endTime);
-        });
-        console.log(this.tableData[0].beginTime, 11111111111111);
-
-        this.searchForm.totalResult = res.data.total;
-      });
-    },
-
-    editClosedEvent({ row, column }) {
-      const $table = this.$refs.xTable;
-      const field = column.property;
-      const cellValue = row[field];
-      // 判断单元格值是否被修改
-      if ($table.isUpdateByRow(row, field)) {
-        setTimeout(() => {
-          let param = {};
-          param[field] = cellValue;
-          post("/abtest/info/update/" + row.id, row).then((res) => {
-            this.$message({
-              message: res.message,
-              type: "success",
-            });
-          });
-          // 局部更新单元格为已保存状态
-          $table.reloadRow(row, null, field);
-        }, 300);
-      }
+        this.total = res.data.total;
+        this.loading = false
+      })
     },
-    reset(formName) {
-      // 重置
-      (this.searchForm = {
-        name: "",
-        state: 1,
-        pageNum: 1,
+    // 重置
+    reset () {
+      this.searchForm = {
+        name: null,
+        state: null,
+        pageNo: 1,
         pageSize: 10,
-        totalResult: 0,
-      }),
+      },
         this.init();
     },
-    toAdd(e) {
-      // const routeUrl = this.$router.resolve({path: '/ABtest/edit', query: {id: e.id}})
-      // window.open(routeUrl.href, '_blank')
-      this.$router.push("/ABtest/edit");
+    // 新增数据
+    toAdd () {
+      this.infoShow = true
     },
-    toEdit(id) {
-      this.$router.push("/ABtest/edit?ids=" + id);
-    },
-    toCopy(id) {
-      // const routeUrl = this.$router.resolve({
-      //   path: "/ABtest/edit",
-      //   query: { copyId: e.id },
-      // });
-      // window.open(routeUrl.href, "_blank");
-      this.$router.push("/ABtest/edit?copyId=" + id);
-    },
-    del(id) {
+    // 删除数据
+    removeInfo (id) {
       this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning",
-      })
-        .then(() => {
-          // const $table = this.$refs.xTable;
-          // $table.remove(row);
-          del("/abtest/test-info/delete", { id }).then((res) => {
-            // console.log(res);
-            this.init();
-          });
+      }).then(() => {
+        removeAbtest({ ids: id }).then(res => {
+          this.init()
         })
-        .catch(() => {
-          this.$message({
-            type: "info",
-            message: "已取消删除",
-          });
-        });
+      })
     },
-    handlePageChange({ currentPage, pageSize }) {
-      this.searchForm.pageNum = currentPage;
-      this.searchForm.pageSize = pageSize;
+    // 列表选择每页数量
+    handleSizeChange (val) {
+      this.searchForm.pageNo = 1
+      this.searchForm.pageSize = val
       this.init();
     },
+    // 列表选择当前页
+    handleCurrentChange (val) {
+      this.searchForm.pageNo = val
+      this.init();
+    },
+    //获取二级渠道列表
+    getSecondChannel () {
+      secondChannel({ pageNo: 1, pageSize: 99 }).then(res => {
+        this.channelList = res.data.list
+      })
+    },
+    // 获取类型列表
+    getTypeList () {
+      typeListApi({ pageNo: 1, pageSize: 99 }).then(res => {
+        this.typeList = res.data.list
+      })
+    },
+    // 新增控制组
+    addTab () {
+      if (this.infoForm.groupData.length <= 4) {
+        let num = this.infoForm.groupData.length;
+        let name = "控制组" + num
+        this.infoForm.groupData.push({
+          "content": "",
+          "flowPercent": null,
+          "groupName": name,
+          "name": name,
+          "state": 1,
+          "strategyId": null,
+          "type": 1
+        });
+        this.editableTabsValue = name;
+      } else {
+        this.$message({
+          message: '对照组最多4组',
+          type: 'warning',
+          duration: 3000,
+          offset: 360
+        })
+      }
+    },
+    // 删除对照组
+    removeTab (targetName) {
+      if (targetName !== "对照组") {
+        let tabs = this.infoForm.groupData;
+        let item = tabs.find(val => {
+          return val.groupName === targetName
+        })
+        tabs.splice(tabs.indexOf(item), 1)
+      } else {
+        this.$message({
+          message: "对照组不可删除",
+          type: "warning",
+          duration: 3000,
+          offset: 360,
+        });
+      }
+      this.editableTabsValue = '对照组'
+    },
+    // 新建abtest
+    createTest () {
+      this.$refs['ruleForm'].validate((valid) => {
+        if (valid) {
+          alert(123)
+        }
+      });
+    }
   },
 };
 </script>
 
 <style lang="scss">
-.searchBox {
-  background-color: #fff;
-  border-radius: 4px;
-  box-shadow: #bfbfbf 0 0 2px;
-  height: unset !important;
-  padding: 10px 10px;
+.abtestIndex {
+  padding: 20px;
+  box-sizing: border-box;
+  // .searchBox {
+  //   background-color: #fff;
+  //   border-radius: 4px;
+  //   box-shadow: #bfbfbf 0 0 2px;
+  //   height: unset !important;
+  //   padding: 10px 10px;
 
-  form {
-    margin: auto;
+  //   form {
+  //     margin: auto;
 
-    .el-form-item {
-      margin: 5px 5px;
-    }
-  }
-}
+  //     .el-form-item {
+  //       margin: 5px 5px;
+  //     }
+  //   }
+  // }
 
-.tableBox {
-  margin-top: 10px;
-  background-color: #fff;
-  border-radius: 4px;
-  box-shadow: #bfbfbf 0 0 2px;
+  // .tableBox {
+  //   margin-top: 10px;
+  //   background-color: #fff;
+  //   border-radius: 4px;
+  //   box-shadow: #bfbfbf 0 0 2px;
 
-  .block {
-    .el-pagination {
-      margin-top: 30px;
-      float: right;
-    }
-  }
+  //   .block {
+  //     .el-pagination {
+  //       margin-top: 30px;
+  //       float: right;
+  //     }
+  //   }
+  // }
 }
 </style>

+ 11 - 0
admin/src/views/channel/api.js

@@ -0,0 +1,11 @@
+import request from '@/utils/request'
+
+// 导出角色
+export function exportChannel(query) {
+  return request({
+    url: '/channel/info/export-excel',
+    method: 'get',
+    params: query,
+    responseType: 'blob'
+  })
+}