he wei
2024-11-13 9862e1be04889c584540abdd3eeb80e1a2d9807b
src/views/test/index.vue
@@ -1,13 +1,923 @@
<script setup name="test">
import { ref } from "vue";
import { ref, onMounted, computed, watch, reactive } from "vue";
import ycCard from "@/components/ycCard.vue";
import bar from "@/components/echarts/bar2.vue";
import iconPower from "@/components/icons/iconPower.vue";
import useDevsRt from "@/hooks/useDevsRt.js";
import paramContent from "./paramContent.vue";
import battCountContent from "./battCountContent.vue";
import useWebSocket from "@/hooks/useWebSocket.js";
import { getA200Param } from "./api.js";
import formatSeconds from "@/assets/js/tools/formatSeconds.js";
import jhParamContent from "./jhParamContent.vue";
import ytjRtInfo from "./ytjRtInfo.vue";
import jhyRtInfo from "./jhyRtInfo.vue";
import { controllerActmParam, stopA200, pauseA200 } from "./api";
import useElement from "@/hooks/useElement.js";
const { $alert, $loading, $message, $confirm } = useElement();
const { list } = useDevsRt();
const devType = ref(1);
const keyWord = ref("");
// const infoTab = ref(0);
// const battVolChart = ref();
const testVisible = ref(false);
const currentDevId = ref(0);
const testGroupIdx = ref();
const jhyBattCountVisible = ref(false);
const isUpdateParam = ref(false);
// TODO  有几组
// const onlyOneGroup = ref(false);
const onlyOneGroup = computed(() => {
  if (!currentDev.value.state) {
    return false;
  }
  return currentDev.value.state[0].batteryCount == 1;
});
const resList = computed(() => {
  let _list = list.value[devType.value];
  return _list.filter((v) => ("" + v.devIdcode).indexOf(keyWord.value) > -1);
});
const currentDev = computed(() => {
  let _list = list.value[devType.value];
  return _list.filter((v) => v.devId == currentDevId.value)[0] || {};
});
// 是否可以修改均衡仪电池组数
const canChangeBattCount = computed(() => {
  // !currentDev.state[0].isTesting && !currentDev.state[1].isTesting
  if (1 == devType.value || !currentDev.value.state) {
    return false;
  }
  if (onlyOneGroup.value) {
    return !currentDev.value.state[0].isTesting;
  } else {
    return !currentDev.value.state[0].isTesting && !currentDev.value.state[1].isTesting;
  }
});
const testMode = computed(() => {
  if (1 == devType.value) {
    return ["--", "放电测试", "充电测试"][currentDev.value.state?.testType];
  } else {
    let states = ["充电", "放电", "均衡"];
    let [res1, res2] = [0, 1].map((v) =>
      currentDev.value.state
        ? states[currentDev.value.state[v].workMode] || "--"
        : "--"
    );
    return onlyOneGroup.value ? `组1:${res1}` : `组1:${res1}, 组2: ${res2}`;
  }
});
const testStates = computed(() => {
  if (1 == devType.value) {
    return currentDev.value.state?.isTesting
      ? currentDev.value.state?.testPause
        ? "暂停中"
        : "测试中"
      : "--";
  } else {
    let [res1, res2] = [0, 1].map((v) =>
      currentDev.value.state
        ? currentDev.value.state[v].moduleStatus || "--"
        : "--"
    );
    return onlyOneGroup.value ? `组1:${res1}` : `组1:${res1}, 组2: ${res2}`;
  }
});
function typeChange() {
  chooseDev(resList.value[0]);
}
function controlTest(groupIdx, ctrlType) {
  //  * 2暂停 * 3继续 * 4 停止
  let loading = $loading();
  controllerActmParam(currentDevId.value, groupIdx, ctrlType)
    .then((res) => {
      loading.close();
      let { code, data, msg } = res.data;
      if (200 == code) {
        $message.success("操作成功");
        console.log(data);
      } else {
        $message.error("操作失败:" + msg);
      }
    })
    .catch((err) => {
      loading.close();
      $message.error("操作失败:" + err);
      console.log(err);
    });
}
watch(list, (val, old) => {
  // console.log("list", val, old, "========??=====");
  if (!old[1].length && !old[2].length && val[1].length) {
    chooseDev(val[1][0]);
  }
});
function stopYtj() {
  let loading = $loading();
  stopA200(currentDevId.value)
    .then((res) => {
      loading.close();
      let { code, data, msg } = res.data;
      if (200 == code) {
        $message.success("操作成功");
        console.log(data);
      } else {
        $message.error("操作失败:" + msg);
      }
    })
    .catch((err) => {
      loading.close();
      $message.error("操作失败:" + err);
      console.log(err);
    });
}
function chooseDev(params) {
  // console.log('params', params, '=============');
  currentDevId.value = params.devId;
}
function setBattCount() {
  jhyBattCountVisible.value = true;
  // console.log("cur", currentDev, "=============");
}
/**
 * isUpdate 是否是更新参数弹窗
 */
function test(isUpdate, groupIdx) {
  testGroupIdx.value = groupIdx;
  isUpdateParam.value = !!isUpdate;
  testVisible.value = true;
}
function pauseYtj(type) {
  // console.log("currentDev", currentDev, "=============");
  if (!currentDev.value.devId) {
    return false;
  }
  let loading = $loading();
  pauseA200(currentDev.value.devId, type)
    .then((res) => {
      let { code, data } = res.data;
      if (code  == 200) {
        console.log(data);
        $message.success("操作成功");
      } else {
        $message.error("操作失败");
      }
      loading.close();
    })
    .catch((err) => {
      console.log(err);
      loading.close();
      $message.error("操作失败");
    });
}
onMounted(() => {});
</script>
<template>
test
  <div class="page">
    <div class="p-left">
      <div class="filter">
        <el-input
          v-model="keyWord"
          class="key-word"
          placeholder="请您输入您要查找的设备"
        >
          <template #suffix>
            <el-icon class="el-input__icon" color="#42f4b5"><search /></el-icon>
          </template>
        </el-input>
      </div>
      <div class="tabs">
        <el-radio-group
          v-model="devType"
          @change="typeChange"
          size="default"
          is-button
        >
          <el-radio-button :value="1">充放电测试仪</el-radio-button>
          <el-radio-button :value="2">均衡测试仪</el-radio-button>
        </el-radio-group>
      </div>
      <div class="list-wrap posR">
        <div class="list pos-full">
          <div
            :class="['item', { active: item.devId == currentDev.devId }]"
            v-for="item in resList"
            :key="item.devId"
            @click="chooseDev(item)"
          >
            {{ item.devIdcode }}
          </div>
        </div>
      </div>
    </div>
    <yc-card class="p-header" title="测试操作">
      <template #tools>
        <template v-if="1 == devType">
          <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start"
            v-if="!currentDev.state?.isTesting"
            @click="test(false)"
            >启动测试</el-button
          >
          <!-- <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start"
            @click="pauseYtj"
            >暂停测试</el-button
          > -->
          <template v-else>
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start"
              @click="test(true)"
              >修改参数</el-button
            >
            <!-- TODO 是否是暂停 -->
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              v-if="!currentDev.state.testPause"
              class="btn-start"
              @click="pauseYtj(1)"
              >暂停测试</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              v-if="currentDev.state.testPause"
              class="btn-start"
              @click="pauseYtj(2)"
              >继续测试</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start"
              @click="stopYtj"
              >停止测试</el-button
            >
          </template>
        </template>
        <template v-else-if="currentDev.state">
          <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start btn-grp1"
            v-if="canChangeBattCount"
            @click="setBattCount"
            >设置组数</el-button
          >
          <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start btn-grp1"
            v-if="!currentDev.state[0].isTesting"
            @click="test(false, 0)"
            >启动组1</el-button
          >
          <template v-else>
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start btn-grp1"
              @click="test(true, 0)"
              >修改组1参数</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start btn-grp1"
              v-if="!currentDev.state[0].isTestPause"
              @click="controlTest(0, 2)"
              >暂停组1</el-button
            >
          </template>
          <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start btn-grp1"
            v-if="currentDev.state[0].isTestPause"
            @click="controlTest(0, 3)"
            >继续组1</el-button
          >
          <el-button
            size="small"
            :disabled="!currentDev.devOnline"
            class="btn-start btn-grp1"
            v-if="
              currentDev.state[0].isTesting || currentDev.state[0].isTestPause
            "
            @click="controlTest(0, 4)"
            >停止组1</el-button
          >
          <!--  -->
          <template v-if="!onlyOneGroup">
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start btn-grp2"
              v-if="!currentDev.state[1].isTesting"
              @click="test(false, 1)"
              >启动组2</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              v-else-if="!currentDev.state[1].isTestPause"
              class="btn-start btn-grp2"
              @click="controlTest(1, 2)"
              >暂停组2</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              v-if="currentDev.state[1].isTestPause"
              class="btn-start btn-grp2"
              @click="controlTest(1, 3)"
              >继续组2</el-button
            >
            <el-button
              size="small"
              :disabled="!currentDev.devOnline"
              class="btn-start btn-grp2"
              v-if="
                currentDev.state[1].isTesting || currentDev.state[1].isTestPause
              "
              @click="controlTest(1, 4)"
              >停止组2</el-button
            >
          </template>
        </template>
      </template>
      <div class="card-content">
        <div class="label">设备型号</div>
        <div class="value">{{ currentDev.devModel }}</div>
        <div class="label">设备类型</div>
        <div class="value">
          {{ { 1: "充放电测试仪", 2: "均衡测试仪" }[currentDev.devType] }}
        </div>
        <div class="label">设备编号</div>
        <div class="value">{{ currentDev.devIdcode }}</div>
        <div class="label">通信状态</div>
        <div
          :class="['value', 'state', { offLine: 0 == currentDev.devOnline }]"
        >
          {{ ["离线", "正常"][currentDev.devOnline] }}
        </div>
        <div class="label">测试模式</div>
        <div class="value">
          {{ testMode }}
        </div>
        <div class="label">测试状态</div>
        <div class="value">
          {{ testStates }}
        </div>
      </div>
    </yc-card>
    <ytj-rt-info
      class="p-content"
      v-if="1 == devType"
      :devId="currentDevId"
    ></ytj-rt-info>
    <jhy-rt-info
      class="p-content"
      v-else
      :onlyOneGroup="onlyOneGroup"
      :devId="currentDevId"
    ></jhy-rt-info>
    <!-- 弹窗 -->
    <el-dialog
      title="设置测试参数"
      v-model="testVisible"
      :close-on-click-modal="false"
      class="dialog-center"
      width="700px"
      center
    >
      <template v-if="testVisible && 1 == devType">
        <param-content
          v-model="testVisible"
          v-if="testVisible"
          :isUpdate="isUpdateParam"
          :devs="currentDev"
        ></param-content>
      </template>
      <template v-if="testVisible && 2 == devType">
        <jh-param-content
          v-model="testVisible"
          v-if="testVisible"
          :isUpdate="isUpdateParam"
          :grpIdx="testGroupIdx"
          :devs="currentDev"
        ></jh-param-content>
      </template>
    </el-dialog>
    <!-- 设置均衡仪组数 -->
    <el-dialog
      title="设置均衡仪电池组数"
      v-model="jhyBattCountVisible"
      :close-on-click-modal="false"
      class="dialog-center"
      width="600px"
      center
    >
      <batt-count-content
        v-model="jhyBattCountVisible"
        v-if="jhyBattCountVisible"
        :devs="currentDev"
        :isOnlyOne="onlyOneGroup"
      ></batt-count-content>
    </el-dialog>
  </div>
</template>
<style scoped lang="less">
.custom-timeline :deep(.el-timeline-item__tail) {
  // left: auto;
  // right: 18px;
}
</style>
.custom-timeline :deep(.el-timeline-item__content) {
  margin-left: 0;
  margin-right: 30px;
}
.custom-timeline :deep(.el-timeline-item__timestamp) {
  position: absolute;
  left: 0;
  transform: translateX(-100%);
  padding-right: 20px;
  text-align: right;
  color: #fff;
}
.custom-timeline {
  .card {
    color: #fff;
    padding-top: 10px;
    .row {
      display: flex;
      height: 38px;
      align-items: center;
      background: rgba(0, 0, 0, 0.2);
      border-radius: 6px;
      margin-top: 6px;
      padding-left: 2em;
      .time {
        margin-right: 0.8em;
        color: #0ff;
        font-weight: bold;
      }
    }
  }
  &.time-left {
    padding-left: 160px;
  }
}
.page {
  height: 100%;
  padding: 8px;
  display: grid;
  grid-template-rows: 180px 1fr;
  grid-template-columns: 340px 1fr;
  gap: 12px;
  .p-left {
    grid-row-start: span 2;
    background: radial-gradient(#1a585d10, #1a585d80);
    display: flex;
    flex-direction: column;
    .filter {
      padding: 6px;
      .key-word {
        // margin: 6px;
      }
      :deep(.el-input__inner) {
        background: transparent;
        color: #fff;
        &::placeholder {
          color: #b0b7b4;
        }
      }
      :deep(.el-input__wrapper) {
        background-color: rgba(66, 244, 181, 0.1);
        box-shadow: 0 0 0 1px #42f4b5 inset;
      }
    }
    .tabs {
      display: flex;
      justify-content: center;
    }
    .list-wrap {
      flex: 1;
      margin: 6px;
      .list {
        border: 1px solid #0ff;
        overflow-y: auto;
        padding-left: 4em;
        padding-top: 6px;
        .item {
          height: 38px;
          display: flex;
          align-items: center;
          position: relative;
          color: #0ff;
          cursor: pointer;
          &.active {
            background: #007983;
          }
          &:hover {
            background: rgba(100, 216, 216, 0.3);
          }
          &::before {
            content: "";
            position: absolute;
            left: -2em;
            top: 50%;
            width: 1.8em;
            border-top: 1px solid #0ff;
          }
          &::after {
            content: "";
            position: absolute;
            top: 50%;
            left: -2em;
            height: 100%;
            border-left: 1px solid #0ff;
          }
          &:last-of-type {
            &::after {
              content: none;
            }
          }
        }
      }
    }
  }
  .p-header {
    .btn-start {
      cursor: pointer;
      padding: 2px 12px;
      margin-top: 8px;
      border-radius: 6px;
      background: #0ff;
      color: #333;
      font-size: 12px;
      border: 0 none;
      &.btn-grp0 {
        background: rgb(231, 181, 0);
      }
      &.btn-grp1 {
        background: rgb(0, 231, 231);
      }
      &.btn-grp2 {
        background: rgb(0, 231, 112);
      }
      &.is-disabled,
      &.is-disabled:hover {
        background: #ccc;
        cursor: not-allowed;
      }
    }
    .card-content {
      height: 100%;
      padding: 20px;
      display: grid;
      grid-template-columns: repeat(3, 6em 1fr);
      grid-template-rows: 1fr 1fr;
      place-items: center start;
      font-size: 18px;
      color: #0ff;
      gap: 8px;
      .label {
        justify-self: end;
        &::after {
          content: ":";
        }
      }
      .value {
        &.state {
          color: #0f0;
          font-weight: bold;
          &.offLine {
            color: #d9001b;
          }
        }
      }
    }
  }
  .p-content {
    .tab-chart {
      height: 100%;
      display: flex;
      flex-direction: column;
      .chart-info {
        display: grid;
        grid-template-columns: repeat(3, 4em 6em);
        place-content: center center;
        // place-items: center center;
        gap: 6px;
        .label {
          display: flex;
          justify-content: end;
          align-items: center;
          &::after {
            content: ":";
          }
        }
        .value {
          display: flex;
          justify-content: center;
          align-items: center;
          height: 36px;
          text-align: center;
          background: #02a7f0;
          &.max {
            background: #438D29;
          }
          &.min {
            background: #DBD608;
          }
        }
      }
      .chart-wrap {
        flex: 1;
        // background: #000;
      }
    }
    .tab-batt {
      display: flex;
      flex-direction: column;
      .info {
        display: grid;
        grid-template-columns: repeat(3, 4em 6em);
        place-content: center center;
        // place-items: center center;
        gap: 6px;
        .label {
          display: flex;
          justify-content: end;
          align-items: center;
          &::after {
            content: ":";
          }
        }
        .value {
          display: flex;
          justify-content: center;
          align-items: center;
          height: 36px;
          text-align: center;
          background: #02a7f0;
          &.max {
            background: #438D29;
          }
          &.min {
            background: #DBD608;
          }
        }
      }
      .list-wrap {
        margin-top: 8px;
        flex: 1;
        .scroll {
          // min-height: 0;
          display: grid;
          place-content: start center;
          grid-template-columns: repeat(auto-fill, 200px);
          overflow-y: auto;
          gap: 24px;
          .item {
            display: flex;
            border-radius: 6px;
            background: #1e6866;
            height: 36px;
            align-items: center;
            padding: 0 0.4em 0 1em;
            .label {
              margin-right: 1em;
              width: 3em;
              text-align: right;
            }
            .value {
              background: #02a7f0;
              flex: 1;
              padding: 2px 10px;
              border-radius: 6px;
              &.max {
                background: #438D29;
              }
              &.min {
                background: #DBD608;
              }
            }
          }
        }
      }
    }
    .test-content {
      // background: #000;
      display: flex;
      flex-direction: column;
      .state {
        display: flex;
        justify-content: center;
        align-items: flex-end;
        margin-bottom: 6px;
        .item {
          color: #ccc;
          border-bottom: 1px #81d3f8 solid;
          padding: 0 1em;
          &.active {
            border-bottom: 4px #fff solid;
            font-size: 22px;
            color: #fff;
          }
        }
      }
      .content {
        flex: 1;
        // background: #000;
        display: grid;
        grid-template-columns: 1fr 2.3fr 140px 2.3fr 1fr;
        grid-template-rows: repeat(5, 1fr);
        gap: 10px 20px;
        grid-auto-flow: column;
        place-items: center;
        padding: 30px;
        &::before {
          content: "";
          grid-area: 5 e("/") 1 e("/") 6 e("/") 2;
        }
        .item {
          place-self: center stretch;
          display: flex;
          border-radius: 6px;
          background: #1e6866;
          height: 36px;
          align-items: center;
          padding: 0 0.4em 0 1em;
          .label {
            margin-right: 1em;
            width: 3em;
            text-align: right;
          }
          .value {
            background: #02a7f0;
            flex: 1;
            padding: 2px 10px;
            border-radius: 6px;
          }
          &.item1 {
            grid-row: 2 e("/") 3;
          }
        }
        .item-big {
          grid-row: 1 e("/") 5;
          grid-column: 2 e("/") 3;
          place-self: stretch;
          display: flex;
          justify-content: center;
          align-items: center;
          font-size: 60px;
          font-weight: bold;
          position: relative;
          &::before {
            content: "";
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            background: url('data:image/svg+xml,%3csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 300"%3e%3cpath d="M200,4h-80l-80,130l80,130h70" stroke="%2302a7f0" fill="none" stroke-width="2" %3e%3c/path%3e%3cpath d="M60,66l-40,65l92,150h110" stroke="%230ff" fill="none" stroke-width="10" %3e%3c/path%3e%3c/svg%3e')
              center center / contain no-repeat;
          }
          .unit {
            color: #ccc;
            font-size: 16px;
            margin-left: 0.4em;
            margin-top: 2em;
          }
          &.curr {
            grid-column: 4 e("/") 5;
            &::before {
              transform: scaleX(-1);
            }
          }
        }
        .border {
          grid-column: 2 e("/") 3;
          border: 1px #0ff solid;
          display: flex;
          align-items: center;
          justify-content: space-between;
          padding: 0 0.4em;
          height: 40px;
          font-size: 24px;
          width: 8em;
          &.border2 {
            grid-column: 4 e("/") 5;
          }
          .i {
            margin-top: 0.2em;
          }
        }
        .center {
          display: flex;
          flex-direction: column;
          justify-content: center;
          align-items: center;
          place-self: stretch;
          grid-area: 1 e("/") 3 e("/") 6 e("/") 4;
          .i {
            height: 150px;
            width: 100%;
            background: url('data:image/svg+xml,%3csvg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"%3e%3cpath d="M630.997333 916.074667l57.728 0.021333h36.48l6.698667 0.021333h18.794667l5.802666 0.021334h15.893334l4.757333 0.021333h12.586667l3.562666 0.021333h6.250667l2.624 0.021334h4.245333l1.578667 0.021333 2.090667 0.021333c0.874667 0 0.768 0.021333-0.448 0.042667A65.066667 65.066667 0 0 1 744.576 981.333333H279.424a65.066667 65.066667 0 0 1-64.96-61.226666l-0.106667-3.84c-1.216 0-1.344 0-0.426666-0.021334h2.069333l1.578667-0.021333h4.245333l2.624-0.021333h6.229333l3.605334-0.021334h12.565333l4.757333-0.021333 15.893334-0.021333h24.597333l6.698667-0.021334h28.8l7.68-0.021333h57.728l8.746666-0.021333h229.248z m-100.245333-698.773334l37.269333 0.042667c133.12 0.149333 250.816 0.853333 242.197334 2.133333l-0.576 0.064v672.917334c12.992 1.28-99.050667 2.005333-229.418667 2.197333l-14.293333 0.021333h-7.168l-18.645334 0.021334H465.237333l-7.189333-0.021334h-14.293333c-128-0.213333-238.314667-0.917333-229.973334-2.133333l0.576-0.085333V219.541333c-13.397333-1.322667 106.133333-2.048 241.621334-2.197333l37.248-0.042667h37.546666zM640 348.288l-250.282667 190.570667 85.674667 23.402666L384 741.248l250.282667-190.570667-85.653334-23.402666L640 348.288z m104.576-218.304a65.066667 65.066667 0 0 1 65.066667 65.066667c1.216 0 1.322667 0 0.426666 0.021333h-2.069333l-1.578667 0.021333h-4.245333l-2.624 0.021334h-6.250667l-3.584 0.021333-12.586666 0.021333h-4.736l-15.893334 0.021334h-24.597333l-6.72 0.021333h-28.8l-7.658667 0.021333-57.728 0.021334H392.981333l-57.728-0.021334H298.816l-6.72-0.021333h-18.794667l-5.802666-0.021333h-15.893334l-4.757333-0.021334h-12.586667l-3.584-0.021333h-6.229333l-2.624-0.021333h-4.245333l-1.578667-0.021334-2.090667-0.021333c-0.896 0-0.768-0.021333 0.448-0.042667l0.106667-3.818666a65.066667 65.066667 0 0 1 64.96-61.226667zM554.453333 42.666667a21.333333 21.333333 0 0 1 21.333334 21.333333v43.946667c1.92 0.085333-9.130667 0.128-25.472 0.170666h-9.386667l-4.992 0.021334h-62.250667a843.136 843.136 0 0 1-25.472-0.213334V64a21.333333 21.333333 0 0 1 21.333334-21.333333z" fill="%231296db"%3e%3c/path%3e%3c/svg%3e')
              center center / auto 80% no-repeat;
          }
          .value {
            display: flex;
            align-items: center;
            font-size: 32px;
            font-weight: bold;
            .unit {
              color: #ccc;
              font-size: 14px;
              margin-left: 0.2em;
              margin-top: 1em;
            }
          }
        }
      }
    }
  }
}
.tab-container {
  height: 100%;
  position: relative;
  overflow: hidden;
  .tab-content {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    height: 100%;
    color: #fff;
    padding: 6px;
  }
  .slide-left-enter-active,
  .slide-left-leave-active,
  .slide-right-enter-active,
  .slide-right-leave-active {
    transition: all 0.3s;
  }
  .slide-left-enter-from {
    transform: translateX(100%);
  }
  .slide-left-leave-to {
    transform: translateX(-100%);
  }
  .slide-right-enter-from {
    transform: translateX(-100%);
  }
  .slide-right-leave-to {
    transform: translateX(100%);
  }
  .slide-left-enter-to,
  .slide-right-enter-to {
    transform: translateX(0);
  }
}
</style>