Browse Source

5.30提交

chen 2 years ago
parent
commit
8d09b70656

+ 152 - 0
admin/src/views/ABtest/ABclass/edit.vue

@@ -0,0 +1,152 @@
+<template>
+    <div>
+        <el-container>
+            <el-main>
+                <el-form :model="form" :rules="rules" ref="ruleForm" label-width="100px">
+                    <el-form-item label="类型名称" prop="typeName">
+                        <el-input style="width: 300px" v-model="form.typeName"/>
+                    </el-form-item>
+                    <el-form-item label="类型标识" prop="tagName">
+                        <el-input style="width: 300px" v-model="form.tagName"/>
+                    </el-form-item>
+                    <el-form-item label="类型描述" prop="content">
+                        <el-input type="textarea"
+                                  :autosize="{ minRows: 2, maxRows: 4}"
+                                  v-model="form.content"
+                        style="width: 50%"/>
+                    </el-form-item>
+                    <el-form-item label="状态">
+                        <el-switch style="width: 300px" v-model="form.state"
+                                   active-text="生效"
+                                   :active-value=1
+                                   inactive-text="无效"
+                                   :inactive-value=0 />
+                    </el-form-item>
+                </el-form>
+            </el-main>
+            <el-footer style="z-index: 9999">
+                <div class="bodyBox">
+                    <div style="display: flex;">
+                        <el-button type="primary" @click="onSubmit('ruleForm')">
+                            {{btn}}
+                        </el-button>
+                        <el-button @click="close">
+                            取消
+                        </el-button>
+                    </div>
+                </div>
+            </el-footer>
+        </el-container>
+    </div>
+</template>
+
+<script>
+    import {post, get} from '@/api/common'
+    export default {
+        name: 'ABclassEdit',
+        data() {
+            return {
+                //策略表单
+                form: {
+                    state: 1
+                },
+                oldform: {},
+                btn: '立即创建',
+
+                rules: {
+                    strategyName: [
+                        {required: true, message: '请输入活动名称', trigger: 'blur'},
+                    ],
+                    strategyType: [
+                        {required: true, message: '请选择策略类型', trigger: 'change'},
+                    ],
+                    templateId: [
+                        {required: true, message: '请选择模版', trigger: 'change'},
+                    ]
+                }
+            }
+        },
+        created() {
+            document.title = '编辑测试类型'
+        },
+        mounted() {
+            if (this.$route.query.id) {
+                get('/abtest/typedict/list', {'id': this.$route.query.id}).then(res => {
+                    res = res.data.list[0];
+                    console.log(res)
+                    this.oldform = JSON.parse(JSON.stringify(res))
+                    this.form = res;
+
+                });
+                this.btn = '编辑保存'
+            }
+        },
+        methods: {
+            // 提交按钮
+            onSubmit: function (formName) {
+                this.$confirm('您确定编辑该类型?当前操作会影响所有相关测试', '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    this.$refs[formName].validate((valid) => {
+                        if (valid) {
+                            if (this.$route.query.id) {
+                                post('/abtest/typedict/update/' + this.$route.query.id, this.form).then(res => {
+                                    this.$message({
+                                        message: res.message,
+                                        type: 'success',
+                                        duration: 3000,
+                                        offset: 360
+                                    })
+                                })
+                            } else {
+                                post('/abtest/typedict/create', this.form).then(res => {
+                                    this.$message({
+                                        message: res.message,
+                                        type: 'success',
+                                        duration: 3000,
+                                        offset: 360
+                                    })
+                                })
+                            }
+                        } else {
+                            console.log('error submit!!');
+                            return false;
+                        }
+                    });
+                }).catch(() => {
+                    this.$message({
+                        type: 'info',
+                        message: '已取消'
+                    });
+                });
+            },
+
+            // 取消按钮
+            close() {
+                this.$confirm('此操作不会保存已编辑数据, 是否继续?', '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    window.location.href = 'about:blank'
+                    window.close()
+                }).catch(() => {
+                    this.$message({
+                        type: 'info',
+                        message: '已取消'
+                    });
+                });
+            }
+        }
+
+    }
+</script>
+
+<style lang="scss">
+    .avatar {
+        width: 100%;
+        max-width: 500px;
+    }
+</style>

+ 236 - 0
admin/src/views/ABtest/ABclass/list.vue

@@ -0,0 +1,236 @@
+<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.typeName" name="searchForm.strategyName" 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="typeName"
+                            title="名称"
+                    />
+                    <vxe-table-column
+                            field="tagName"
+                            title="标识"
+                    />
+                    <vxe-table-column
+                            field="content"
+                            title="描述"
+                            width="300"
+                    />
+                    <vxe-table-column
+                            field="state"
+                            title="状态"
+                            :edit-render="{name: '$select', options: strategyStatus}"
+                            width="80"
+                    />
+                    <vxe-table-column
+                            field="createTime"
+                            title="开始时间"
+                            width="160"
+                    />
+                    <vxe-table-column
+                            field="createTime"
+                            title="结束时间"
+                            width="160"
+                    />
+                    <vxe-table-column title="操作" width="150">
+                        <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="toAdd(row)">编辑</vxe-button>
+                                <vxe-button @click="del(row)">删除</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>
+</template>
+
+<script>
+    import {post, get} from '@/api/common'
+
+    export default {
+        name: 'Index',
+        data() {
+            return {
+                //  搜索相关内容
+                searchForm: {
+                    typeName: '',
+                    state: 1,
+                    pageNum: 1,
+                    pageSize: 10,
+                    totalResult: 0
+                },
+                // 表格数据
+                loading: false,
+                tableData: [],
+                strategyStatus: [
+                    {label: '生效', value: 1},
+                    {label: '无效', value: 0}
+                ],
+
+                schemelog: [],
+                schemelogList: [],
+                filterName1: '',
+                schemelogParam: {
+                    pageNum: 1,
+                    pageSize: 10,
+                    totalResult: 0
+                },
+            }
+        },
+        mounted() {
+            this.init()
+        },
+        methods: {
+            init() {
+                get('/abtest/typedict/list', this.searchForm).then(res => {
+                    this.tableData = res.data.list
+                    console.log(this.tableData)
+                    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/typedict/update/' + row.id, row).then(res => {
+                            this.$message({
+                                message: res.message,
+                                type: 'success'
+                            });
+                        })
+                        // 局部更新单元格为已保存状态
+                        $table.reloadRow(row, null, field)
+                    }, 300)
+                }
+            },
+            reset(formName) { // 重置
+                this.searchForm = {
+                    typeName: '',
+                    state: 1,
+                    pageNum: 1,
+                    pageSize: 10,
+                    totalResult: 0
+                },
+                this.init()
+            },
+            toAdd(e) {
+                const routeUrl = this.$router.resolve({path: '/ABtest/ABclass/edit', query: {id: e.id}})
+                window.open(routeUrl.href, '_blank')
+            },
+            toCopy(e) {
+                const routeUrl = this.$router.resolve({path: '/ABtest/ABclass/edit', query: {copyId: e.id}})
+                window.open(routeUrl.href, '_blank')
+            },
+            del(row) {
+                this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
+                    confirmButtonText: '确定',
+                    cancelButtonText: '取消',
+                    type: 'warning'
+                }).then(() => {
+                    const $table = this.$refs.xTable
+                    $table.remove(row)
+                    post('/abtest/typedict/delete', {'ids': [row.id]}).then(res => {
+                    })
+                }).catch(() => {
+                    this.$message({
+                        type: 'info',
+                        message: '已取消删除'
+                    });
+                });
+            },
+            handlePageChange({currentPage, pageSize}) {
+                this.searchForm.pageNum = currentPage
+                this.searchForm.pageSize = pageSize
+                this.init()
+            }
+        }
+    }
+</script>
+
+<style lang="scss">
+    .searchBox {
+        background-color: #fff;
+        border-radius: 4px;
+        box-shadow: #bfbfbf 0 0 2px;
+        height: unset !important;
+        padding: 10px 10px;
+
+        form {
+            margin: auto;
+
+            .el-form-item {
+                margin: 5px 5px;
+            }
+        }
+    }
+
+    .tableBox {
+        margin-top: 10px;
+        background-color: #fff;
+        border-radius: 4px;
+        box-shadow: #bfbfbf 0 0 2px;
+
+        .block {
+            .el-pagination {
+                margin-top: 30px;
+                float: right;
+            }
+        }
+    }
+</style>

+ 543 - 0
admin/src/views/ABtest/edit.vue

@@ -0,0 +1,543 @@
+<template>
+  <div>
+    <el-container>
+      <el-main>
+        <el-form
+          :model="form"
+          :rules="rules"
+          ref="ruleForm"
+          label-width="100px"
+        >
+          <el-form-item label="测试名称" prop="name">
+            <el-input style="width: 40%" v-model="form.name" />
+          </el-form-item>
+          <el-form-item label="测试描述" prop="content">
+            <el-input
+              type="textarea"
+              :autosize="{ minRows: 2, maxRows: 4 }"
+              v-model="form.content"
+              style="width: 40%"
+            />
+          </el-form-item>
+          <el-form-item label="生效时间" prop="timeBox">
+            <el-date-picker
+              v-model="timeBox"
+              type="datetimerange"
+              value-format="timestamp"
+              range-separator="至"
+              start-placeholder="开始日期"
+              end-placeholder="结束日期"
+              @change="handleChangeTime"
+            >
+            </el-date-picker>
+          </el-form-item>
+          <el-form-item label="渠道选择" prop="channelKey">
+            <el-select
+              v-model="channelBox"
+              style="width: 40%"
+              multiple
+              clearable
+              filterable
+              placeholder="请选择"
+              @change="handleChangeChannel"
+            >
+              <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="form.typeDictId"
+              pr
+              style="width: 40%"
+              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="状态">
+            <el-switch
+              style="width: 300px"
+              v-model="form.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"
+              @click="addTab(editableTabsValue)"
+              >新增分组</el-button
+            >
+          </div>
+          <el-tabs
+            v-model="editableTabsValue"
+            type="card"
+            closable
+            @tab-remove="removeTab"
+            @tab-click="clickTab"
+          >
+            <el-tab-pane
+              v-for="(item, index) in form.groupData"
+              :key="item.groupName"
+              :label="item.groupName"
+              :name="item.groupName"
+            >
+              <div>
+                <el-form-item label="组别名称" prop="name">
+                  <el-input style="width: 40%" 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"
+                    style="width: 40%"
+                  />
+                </el-form-item>
+
+                <el-form-item label="选择策略">
+                  <el-select
+                    v-model="item.strategyId"
+                    style="width: 40%"
+                    clearable
+                    filterable
+                    placeholder="请选择"
+                  >
+                    <el-option
+                      v-for="item in strategyList"
+                      :key="item.id"
+                      :label="item.strategyName"
+                      :value="item.id"
+                    >
+                    </el-option>
+                  </el-select>
+                  <span style="margin-left: 20px">
+                    <vxe-button
+                      @click="refresh"
+                      icon="el-icon-refresh"
+                      size="mini"
+                      content="刷新"
+                    ></vxe-button>
+                  </span>
+                  <span style="margin-left: 20px">
+                    <vxe-button
+                      @click="toAdd"
+                      icon="el-icon-plus"
+                      size="mini"
+                      content="新建"
+                    ></vxe-button>
+                  </span>
+                  <span style="margin-left: 20px">
+                    <vxe-button
+                      @click="toEdit(item.strategyId)"
+                      icon="el-icon-edit"
+                      size="mini"
+                      content="编辑"
+                    ></vxe-button>
+                  </span>
+                </el-form-item>
+
+                <el-form-item label="分流占比" prop="flowPercent">
+                  <el-input
+                    style="width: 40%"
+                    v-model="item.flowPercent"
+                    placeholder="请输入小数"
+                  />
+                  <div style="color: red">请输入小数如0.5,各组占比之和为1</div>
+                </el-form-item>
+              </div>
+            </el-tab-pane>
+          </el-tabs>
+        </el-form>
+      </el-main>
+      <el-footer style="z-index: 9999">
+        <div v-if="isEdit === true" class="bodyBox">
+          <div style="display: flex; justify-content: flex-end">
+            <el-button type="primary" @click="onSubmit('ruleForm')">
+              {{ btn }}
+            </el-button>
+            <el-button @click="close"> 取消 </el-button>
+          </div>
+        </div>
+        <div v-else class="bodyBox">
+          <div style="display: flex; justify-content: flex-end">
+            <el-button
+              style="width: 200px; margin-right: 100px"
+              type="primary"
+              @click="closeTwo"
+            >
+              关闭
+            </el-button>
+          </div>
+        </div>
+      </el-footer>
+    </el-container>
+  </div>
+</template>
+
+<script>
+import { post, get, put, del } from "@/api/common";
+
+export default {
+  name: "ABclassEdit",
+  data() {
+    return {
+      //类型列表
+      typeList: {},
+      //渠道列表
+      channelList: {},
+      //策略列表
+      strategyList: {},
+      //编辑表单
+      form: {
+        state: 1,
+        typeDictId: 2,
+        endTime: null,
+        begintime: null,
+        groupData: [
+          {
+            content: "",
+            flowPercent: null,
+            groupName: "对照组",
+            name: "对照组",
+            state: 1,
+            strategyId: 1,
+            // strategyId: null,
+            type: 0,
+          },
+          {
+            content: "",
+            flowPercent: null,
+            groupName: "控制组1",
+            name: "控制组1",
+            state: 1,
+            strategyId: 1,
+            type: 1,
+          },
+        ],
+      },
+      timeBox: [],
+      channelBox: [],
+      btn: "立即创建",
+      // 表单验证
+      rules: {
+        channelKey: [
+          { required: true, message: "请绑定渠道", trigger: "blur" },
+        ],
+        name: [{ required: true, message: "请填写测试名称", trigger: "blur" }],
+        typeDictId: [
+          { required: true, message: "请选择测试类型", trigger: "blur" },
+        ],
+      },
+      // 标签页
+      editableTabsValue: "对照组",
+      tabIndex: 1,
+      thisIndex: 0,
+      isEdit: true,
+    };
+  },
+  created() {
+    document.title = "编辑测试";
+    put("/abtest/test-info/update", { pageNum: 1, pageSize: 100 }).then(
+      (res) => {
+        this.typeList = res.data.list;
+      }
+    );
+    get("/channel/info/page", { pageSize: 100, pageNum: 1 }).then((res) => {
+      this.channelList = res.data.list;
+    });
+    get("/strategy/strategy-info/page", {
+      pageSize: 100,
+      pageNum: 1,
+      strategyType: 2,
+    }).then((res) => {
+      this.strategyList = res.data.list;
+    });
+  },
+  mounted() {
+    if (this.$route.query.id) {
+      get("/abtest/info/list", { id: this.$route.query.id }).then((res) => {
+        let nres = JSON.parse(JSON.stringify(res.data.list[0]));
+        this.timeBox = [nres.begintime, nres.endtime];
+        this.channelBox = nres.channelKey.split(",");
+        let now = Date.parse(new Date());
+        let begintime = Date.parse(nres.begintime);
+        let endtime = Date.parse(nres.endtime);
+        this.form = nres;
+        if (now > endtime) {
+          this.form.state = 0;
+          post("/abtest/info/update/" + this.$route.query.id, this.form);
+        }
+        if (now > begintime) {
+          this.isEdit = false;
+        }
+      });
+      this.btn = "编辑保存";
+    }
+
+    if (this.$route.query.copyId) {
+      get("/abtest/info/list", { id: this.$route.query.copyId }).then((res) => {
+        let nres = JSON.parse(JSON.stringify(res.data.list[0]));
+        this.timeBox = [nres.begintime, nres.endtime];
+        this.channelBox = nres.channelKey.split(",");
+        this.form = nres;
+        this.form.name = nres.name + " 副本";
+        console.log(this.form);
+      });
+    }
+  },
+  methods: {
+    // 提交按钮
+    onSubmit(formName) {
+      this.$confirm("您确定编辑该类型?当前操作会影响所有相关测试", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          //   this.form.begintime = date.getTime();
+          //   this.form.endTime = date.getTime();
+          console.log(this.timeBox, 11);
+          this.$refs[formName].validate((valid) => {
+            console.log(valid);
+            if (valid) {
+              if (this.form.groupData.length < 2) {
+                this.$message({
+                  message: "至少保留一组控制组",
+                  type: "warning",
+                  duration: 3000,
+                  offset: 360,
+                });
+                return false;
+              }
+              let sum = 0;
+              let havestag = true;
+              this.form.groupData.forEach((item, index) => {
+                sum = item.flowPercent * 1 + sum;
+                if (!item.strategyId) {
+                  this.$message({
+                    message: "请选择策略",
+                    type: "warning",
+                    duration: 3000,
+                    offset: 360,
+                  });
+                  havestag = false;
+                }
+              });
+
+              //   if (sum !== 1) {
+              //     this.$message({
+              //       message: "分流之和需要等于1",
+              //       type: "warning",
+              //       duration: 3000,
+              //       offset: 360,
+              //     });
+              //     return false;
+              //   }
+              if (havestag === false) return false;
+
+              if (this.$route.query.id) {
+                console.log(this.form);
+                post(
+                  "/abtest/info/update/" + this.$route.query.id,
+                  this.form
+                ).then((res) => {
+                  this.$message({
+                    message: res.message,
+                    type: "success",
+                    duration: 3000,
+                    offset: 360,
+                  });
+
+                  //   setTimeout(() => {
+                  //     window.close();
+                  //   }, 1500);
+                });
+              } else {
+                this.form.begintime = this.timeBox[0];
+                this.form.endTime = this.timeBox[1];
+                post("/abtest/test-info/create", this.form).then((res) => {
+                  console.log(this.form);
+                  this.$message({
+                    message: res.message,
+                    type: "success",
+                    duration: 3000,
+                    offset: 360,
+                  });
+                  setTimeout(() => {
+                    window.close();
+                  }, 1500);
+                });
+              }
+            } else {
+              console.log("error submit!!");
+              return false;
+            }
+          });
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+
+    // 取消按钮
+    close() {
+      this.$confirm("此操作不会保存已编辑数据, 是否继续?", "提示", {
+        confirmButtonText: "确定",
+        cancelButtonText: "取消",
+        type: "warning",
+      })
+        .then(() => {
+          window.location.href = "about:blank";
+          window.close();
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消",
+          });
+        });
+    },
+    closeTwo() {
+      window.location.href = "about:blank";
+      window.close();
+    },
+
+    // 表填格式转换
+    handleChangeTime(value) {
+      this.form.begintime = value[0];
+      this.form.endtime = value[1];
+    },
+    handleChangeChannel(value) {
+      let text = "";
+      for (var i = 0; i < value.length; i++) {
+        if (i === 0) {
+          text = value[i];
+        } else {
+          text = text + "," + value[i];
+        }
+      }
+      this.form.channelKey = text;
+      // console.log(this.channelBox)
+    },
+
+    // 标签页
+    addTab(targetName) {
+      if (this.form.groupData.length <= 4) {
+        this.tabIndex++;
+        this.form.groupData.push({
+          content: "",
+          flowPercent: null,
+          groupName: "控制组" + this.tabIndex,
+          name: "控制组" + this.tabIndex,
+          state: 1,
+          strategyId: null,
+          type: 1,
+        });
+        this.editableTabsValue = "控制组" + this.tabIndex;
+      } else {
+        this.$message({
+          message: "对照组最多4组",
+          type: "warning",
+          duration: 3000,
+          offset: 360,
+        });
+      }
+      console.log(this.form.groupData);
+    },
+    removeTab(targetName) {
+      if (targetName !== "对照组") {
+        let tabs = this.form.groupData;
+        let newTabs = [];
+        tabs.forEach((tab, index) => {
+          if (tab.groupName !== targetName) {
+            newTabs.push(tab);
+          }
+        });
+        this.editableTabsValue = "对照组";
+        this.form.groupData = newTabs;
+      } else {
+        this.$message({
+          message: "对照组不可删除",
+          type: "warning",
+          duration: 3000,
+          offset: 360,
+        });
+      }
+      console.log(this.form.groupData);
+    },
+    clickTab(tab) {
+      console.log(this.form.groupData[tab.index]);
+    },
+    toAdd(e) {
+      const routeUrl = this.$router.resolve({
+        path: "/schemeV2/schemeAdd",
+        query: { id: e.id },
+      });
+      window.open(routeUrl.href, "_blank");
+    },
+    toEdit(e) {
+      if (e === null) {
+        this.$message({
+          message: "请先选择一个策略",
+          type: "warning",
+          duration: 3000,
+          offset: 360,
+        });
+      } else {
+        const routeUrl = this.$router.resolve({
+          path: "/schemeV2/schemeAdd",
+          query: { id: e.id },
+        });
+        window.open(routeUrl.href + "?id=" + e, "_blank");
+      }
+    },
+    refresh() {
+      get("/strategyInfoNew/page", { pageSize: 9999, pageNum: 1 }).then(
+        (res) => {
+          this.strategyList = res.data.list;
+        }
+      );
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.el-date-editor--datetimerange.el-input,
+.el-date-editor--datetimerange.el-input__inner {
+  width: 40%;
+}
+
+.el-footer {
+  position: fixed;
+  bottom: 0;
+  right: 0;
+}
+
+.avatar {
+  width: 100%;
+  max-width: 500px;
+}
+</style>

+ 243 - 0
admin/src/views/ABtest/index.vue

@@ -0,0 +1,243 @@
+<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)">复制</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>
+</template>
+
+<script>
+import { post, get,del } from "@/api/common";
+
+export default {
+  name: "Index",
+  data() {
+    return {
+      //  搜索相关内容
+      searchForm: {
+        name: "",
+        state: 1,
+        pageNo: 1,
+        pageSize: 10,
+        totalResult: 0,
+      },
+      // 表格数据
+      loading: false,
+      tableData: [],
+      strategyStatus: [
+        { label: "生效", value: 1 },
+        { label: "失效", value: 0 },
+      ],
+    };
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    init() {
+      get("/abtest/test-info/page", this.searchForm).then((res) => {
+        this.tableData = res.data.list;
+        console.log(this.tableData);
+        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);
+      }
+    },
+    reset(formName) {
+      // 重置
+      (this.searchForm = {
+        name: "",
+        state: 1,
+        pageNum: 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");
+    },
+    toEdit(id) {
+      this.$router.push("/ABtest/edit?ids="+id);
+    },
+    toCopy(e) {
+      const routeUrl = this.$router.resolve({
+        path: "/ABtest/edit",
+        query: { copyId: e.id },
+      });
+      window.open(routeUrl.href, "_blank");
+    },
+    del(id) {
+      // this.$confirm("此操作将永久删除该文件, 是否继续?", "提示", {
+      //   confirmButtonText: "确定",
+      //   cancelButtonText: "取消",
+      //   type: "warning",
+      // })
+      //   .then(() => {
+      //     const $table = this.$refs.xTable;
+      //     $table.remove(row);
+          
+      //   })
+      //   .catch(() => {
+      //     this.$message({
+      //       type: "info",
+      //       message: "已取消删除",
+      //     });
+        // });
+        del("/abtest/test-info/delete", { id }).then((res) => {
+            console.log(res);
+          });
+    },
+    handlePageChange({ currentPage, pageSize }) {
+      this.searchForm.pageNum = currentPage;
+      this.searchForm.pageSize = pageSize;
+      this.init();
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.searchBox {
+  background-color: #fff;
+  border-radius: 4px;
+  box-shadow: #bfbfbf 0 0 2px;
+  height: unset !important;
+  padding: 10px 10px;
+
+  form {
+    margin: auto;
+
+    .el-form-item {
+      margin: 5px 5px;
+    }
+  }
+}
+
+.tableBox {
+  margin-top: 10px;
+  background-color: #fff;
+  border-radius: 4px;
+  box-shadow: #bfbfbf 0 0 2px;
+
+  .block {
+    .el-pagination {
+      margin-top: 30px;
+      float: right;
+    }
+  }
+}
+</style>

+ 179 - 0
admin/src/views/ABtest/testData.vue

@@ -0,0 +1,179 @@
+<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.name" name="searchForm.name" placeholder="请输入关键字"/>
+                    </el-form-item>
+
+                    <el-form-item style="float: right">
+                        <el-button type="primary" @click="init">搜索</el-button>
+                        <el-button @click="reset">重置</el-button>
+                    </el-form-item>
+                </el-form>
+            </el-header>
+            <!--表格-->
+            <el-main class="tableBox">
+                <vxe-toolbar>
+                    <template #buttons>
+                        <vxe-button @click="init()">刷新</vxe-button>
+                    </template>
+                </vxe-toolbar>
+                <vxe-table
+                        border
+                        resizable
+                        keep-source
+                        show-overflow
+                        highlight-hover-row
+                        stripe
+                        ref="xTable"
+                        :data="tableData"
+                        :span-method="mergeRowMethod"
+                >
+                    <vxe-table-column
+                            field="infoName"
+                            title="测试名称"
+                            width="180"
+                    />
+                    <vxe-table-column
+                            field="orderInfo"
+                            title="测试订购"
+                            width="100"
+                    />
+                    <vxe-table-column
+                            field="name"
+                            title="分组名称"
+                            width="180"
+                    />
+                    <vxe-table-column
+                            field="content"
+                            title="分组描述"
+                    />
+                    <vxe-table-column
+                            field="flowPercent"
+                            title="分流比例"
+                            width="100"
+                    />
+                    <vxe-table-column
+                            field="orderGroup"
+                            title="分组订购"
+                            width="100"
+                    />
+                </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>
+</template>
+
+<script>
+    import {post, get} from '@/api/common'
+
+    export default {
+        name: 'Index',
+        data() {
+            return {
+                //  搜索相关内容
+                searchForm: {
+                    name: '',
+                    // id: '1463041030558453760',
+                    pageNum: 1,
+                    pageSize: 10,
+                    totalResult: 0
+                },
+                // 表格数据
+                loading: false,
+                tableData: [],
+            }
+        },
+        mounted() {
+            this.init()
+        },
+        methods: {
+            init() {
+                get('/abtest/info/orderdata', this.searchForm).then(res => {
+                    this.tableData = res.data.list
+                    this.searchForm.totalResult = res.data.total
+                })
+            },
+            // 重置
+            reset() {
+                this.searchForm = {
+                    name: '',
+                    state: 1,
+                    pageNum: 1,
+                    pageSize: 10,
+                    totalResult: 0
+                }
+                this.init()
+            },
+            // 翻页
+            handlePageChange({currentPage, pageSize}) {
+                this.searchForm.pageNum = currentPage
+                this.searchForm.pageSize = pageSize
+                this.init()
+            },
+            // 合并函数
+            mergeRowMethod({row, _rowIndex, column, visibleData}) {
+                const fields = ['infoName', 'orderInfo']
+                const cellValue = row[column.property]
+                if (cellValue && fields.includes(column.property)) {
+                    const prevRow = visibleData[_rowIndex - 1]
+                    let nextRow = visibleData[_rowIndex + 1]
+                    if (prevRow && prevRow[column.property] === cellValue) {
+                        return {rowspan: 0, colspan: 0}
+                    } else {
+                        let countRowspan = 1
+                        while (nextRow && nextRow[column.property] === cellValue) {
+                            nextRow = visibleData[++countRowspan + _rowIndex]
+                        }
+                        if (countRowspan > 1) {
+                            return {rowspan: countRowspan, colspan: 1}
+                        }
+                    }
+                }
+            }
+        }
+    }
+</script>
+
+<style lang="scss">
+    .searchBox {
+        background-color: #fff;
+        border-radius: 4px;
+        box-shadow: #bfbfbf 0 0 2px;
+        height: unset !important;
+        padding: 10px 10px;
+
+        form {
+            margin: auto;
+
+            .el-form-item {
+                margin: 5px 5px;
+            }
+        }
+    }
+
+    .tableBox {
+        margin-top: 10px;
+        background-color: #fff;
+        border-radius: 4px;
+        box-shadow: #bfbfbf 0 0 2px;
+
+        .block {
+            .el-pagination {
+                margin-top: 30px;
+                float: right;
+            }
+        }
+    }
+</style>