Эх сурвалжийг харах

refactor: use setup refactor

xiaoxian521 3 жил өмнө
parent
commit
85f4917f26

+ 14 - 0
.eslintrc.js

@@ -11,6 +11,20 @@ module.exports = {
     $shallowRef: "readonly",
     $computed: "readonly",
 
+    // index.d.ts
+    // global.d.ts
+    Fn: "readonly",
+    PromiseFn: "readonly",
+    RefType: "readonly",
+    LabelValueOptions: "readonly",
+    EmitType: "readonly",
+    TargetContext: "readonly",
+    ComponentElRef: "readonly",
+    ComponentRef: "readonly",
+    ElRef: "readonly",
+    global: "readonly",
+    ForDataType: "readonly",
+
     // script setup
     defineProps: "readonly",
     defineEmits: "readonly",

+ 5 - 5
package.json

@@ -8,7 +8,7 @@
     "build": "rimraf dist && cross-env vite build",
     "preview": "vite preview",
     "preview:build": "yarn build && vite preview",
-    "clean:cache": "rm -rf node_modules && rm -rf .eslintcache && yarn cache clean && yarn install",
+    "clean:cache": "rm -rf node_modules && rm -rf .eslintcache && yarn cache clean && yarn",
     "lint:eslint": "eslint --cache --max-warnings 0  \"{src,mock}/**/*.{vue,ts,tsx}\" --fix",
     "lint:prettier": "prettier --write  \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
     "lint:stylelint": "stylelint --cache --fix \"**/*.{vue,css,scss,postcss,less}\" --cache --cache-location node_modules/.cache/stylelint/",
@@ -21,7 +21,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@logicflow/core": "^0.4.6",
     "@logicflow/extension": "^0.4.6",
-    "@vueuse/core": "^6.0.0",
+    "@vueuse/core": "^6.4.1",
     "animate.css": "^4.1.1",
     "await-to-js": "^3.0.0",
     "axios": "^0.21.1",
@@ -43,11 +43,11 @@
     "responsive-storage": "^1.0.9",
     "sortablejs": "1.13.0",
     "v-contextmenu": "^3.0.0",
-    "vue": "^3.2.11",
+    "vue": "^3.2.12",
     "vue-i18n": "^9.2.0-beta.3",
     "vue-json-pretty": "^2.0.2",
     "vue-router": "^4.0.11",
-    "vue-types": "^4.0.3",
+    "vue-types": "^4.1.0",
     "vuedraggable": "^4.1.0",
     "vxe-table": "^4.0.27",
     "wangeditor": "^4.7.7",
@@ -66,7 +66,7 @@
     "@typescript-eslint/parser": "^4.31.0",
     "@vitejs/plugin-vue": "^1.6.0",
     "@vitejs/plugin-vue-jsx": "^1.1.7",
-    "@vue/compiler-sfc": "^3.2.11",
+    "@vue/compiler-sfc": "^3.2.12",
     "@vue/eslint-config-prettier": "^6.0.0",
     "@vue/eslint-config-typescript": "^7.0.0",
     "autoprefixer": "^10.2.4",

+ 49 - 56
src/components/ReBreadCrumb/src/index.vue

@@ -1,3 +1,52 @@
+<script setup lang="ts">
+import { ref, watch, Ref } from "vue";
+import { useRoute, useRouter, RouteLocationMatched } from "vue-router";
+
+const levelList: Ref<RouteLocationMatched[]> = ref([]);
+const route = useRoute();
+const router = useRouter();
+
+const isDashboard = (route: RouteLocationMatched): boolean | string => {
+  const name = route && (route.name as string);
+  if (!name) {
+    return false;
+  }
+  return name.trim().toLocaleLowerCase() === "welcome".toLocaleLowerCase();
+};
+
+const getBreadcrumb = (): void => {
+  let matched = route.matched.filter(item => item.meta && item.meta.title);
+  const first = matched[0];
+  if (!isDashboard(first)) {
+    matched = [
+      {
+        path: "/welcome",
+        meta: { title: "message.hshome" }
+      } as unknown as RouteLocationMatched
+    ].concat(matched);
+  }
+  levelList.value = matched.filter(
+    item => item.meta && item.meta.title && item.meta.breadcrumb !== false
+  );
+};
+
+getBreadcrumb();
+
+watch(
+  () => route.path,
+  () => getBreadcrumb()
+);
+
+const handleLink = (item: RouteLocationMatched): any => {
+  const { redirect, path } = item;
+  if (redirect) {
+    router.push(redirect.toString());
+    return;
+  }
+  router.push(path);
+};
+</script>
+
 <template>
   <el-breadcrumb class="app-breadcrumb" separator="/">
     <transition-group appear name="breadcrumb">
@@ -15,62 +64,6 @@
   </el-breadcrumb>
 </template>
 
-<script lang="ts">
-import { ref, defineComponent, watch, Ref } from "vue";
-import { useRoute, useRouter, RouteLocationMatched } from "vue-router";
-
-export default defineComponent({
-  name: "ReBreadCrumb",
-  setup() {
-    const levelList: Ref<RouteLocationMatched[]> = ref([]);
-    const route = useRoute();
-    const router = useRouter();
-
-    const isDashboard = (route: RouteLocationMatched): boolean | string => {
-      const name = route && (route.name as string);
-      if (!name) {
-        return false;
-      }
-      return name.trim().toLocaleLowerCase() === "welcome".toLocaleLowerCase();
-    };
-
-    const getBreadcrumb = (): void => {
-      let matched = route.matched.filter(item => item.meta && item.meta.title);
-      const first = matched[0];
-      if (!isDashboard(first)) {
-        matched = [
-          {
-            path: "/welcome",
-            meta: { title: "message.hshome" }
-          } as unknown as RouteLocationMatched
-        ].concat(matched);
-      }
-      levelList.value = matched.filter(
-        item => item.meta && item.meta.title && item.meta.breadcrumb !== false
-      );
-    };
-
-    getBreadcrumb();
-
-    watch(
-      () => route.path,
-      () => getBreadcrumb()
-    );
-
-    const handleLink = (item: RouteLocationMatched): any => {
-      const { redirect, path } = item;
-      if (redirect) {
-        router.push(redirect.toString());
-        return;
-      }
-      router.push(path);
-    };
-
-    return { levelList, handleLink };
-  }
-});
-</script>
-
 <style lang="scss" scoped>
 .app-breadcrumb.el-breadcrumb {
   display: inline-block;

+ 101 - 136
src/components/ReFlop/src/index.vue

@@ -1,157 +1,122 @@
-<template>
-  <div class="flip-clock">
-    <flippers ref="flipperHour1" />
-    <flippers ref="flipperHour2" />
-    <em>:</em>
-    <flippers ref="flipperMinute1" />
-    <flippers ref="flipperMinute2" />
-    <em>:</em>
-    <flippers ref="flipperSecond1" />
-    <flippers ref="flipperSecond2" />
-  </div>
-</template>
-
-<script lang="ts">
+<script setup lang="ts">
 import { ref, unref, nextTick, onUnmounted } from "vue";
+import { templateRef } from "@vueuse/core";
 import flippers from "./Filpper";
 
-import { templateRef } from "@vueuse/core";
-export default {
-  name: "Flop",
-  components: {
-    flippers
-  },
-  setup() {
-    let timer = ref(null);
-    let flipObjs = ref([]);
+let timer = ref(null);
+let flipObjs = ref([]);
 
-    const flipperHour1 = templateRef<HTMLElement | null>("flipperHour1", null);
-    const flipperHour2 = templateRef<HTMLElement | null>("flipperHour2", null);
-    const flipperMinute1 = templateRef<HTMLElement | null>(
-      "flipperMinute1",
-      null
-    );
-    const flipperMinute2 = templateRef<HTMLElement | null>(
-      "flipperMinute2",
-      null
-    );
-    const flipperSecond1 = templateRef<HTMLElement | null>(
-      "flipperSecond1",
-      null
-    );
-    const flipperSecond2 = templateRef<HTMLElement | null>(
-      "flipperSecond2",
-      null
-    );
+const flipperHour1 = templateRef<HTMLElement | null>("flipperHour1", null);
+const flipperHour2 = templateRef<HTMLElement | null>("flipperHour2", null);
+const flipperMinute1 = templateRef<HTMLElement | null>("flipperMinute1", null);
+const flipperMinute2 = templateRef<HTMLElement | null>("flipperMinute2", null);
+const flipperSecond1 = templateRef<HTMLElement | null>("flipperSecond1", null);
+const flipperSecond2 = templateRef<HTMLElement | null>("flipperSecond2", null);
 
-    // 初始化数字
-    const init = () => {
-      let now = new Date();
-      let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
-      for (let i = 0; i < flipObjs.value.length; i++) {
-        flipObjs?.value[i]?.setFront(nowTimeStr[i]);
-      }
-    };
+// 初始化数字
+const init = () => {
+  let now = new Date();
+  let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
+  for (let i = 0; i < flipObjs.value.length; i++) {
+    flipObjs?.value[i]?.setFront(nowTimeStr[i]);
+  }
+};
 
-    // 开始计时
-    const run = () => {
-      timer.value = setInterval(() => {
-        // 获取当前时间
-        let now = new Date();
-        let nowTimeStr = formatDate(new Date(now.getTime() - 1000), "hhiiss");
-        let nextTimeStr = formatDate(now, "hhiiss");
-        for (let i = 0; i < flipObjs.value.length; i++) {
-          if (nowTimeStr[i] === nextTimeStr[i]) {
-            continue;
-          }
-          flipObjs?.value[i]?.flipDown(nowTimeStr[i], nextTimeStr[i]);
-        }
-      }, 1000);
-    };
+// 开始计时
+const run = () => {
+  timer.value = setInterval(() => {
+    // 获取当前时间
+    let now = new Date();
+    let nowTimeStr = formatDate(new Date(now.getTime() - 1000), "hhiiss");
+    let nextTimeStr = formatDate(now, "hhiiss");
+    for (let i = 0; i < flipObjs.value.length; i++) {
+      if (nowTimeStr[i] === nextTimeStr[i]) {
+        continue;
+      }
+      flipObjs?.value[i]?.flipDown(nowTimeStr[i], nextTimeStr[i]);
+    }
+  }, 1000);
+};
 
-    // 正则格式化日期
-    const formatDate = (date: Date, dateFormat: string) => {
-      /* 单独格式化年份,根据y的字符数量输出年份
+// 正则格式化日期
+const formatDate = (date: Date, dateFormat: string) => {
+  /* 单独格式化年份,根据y的字符数量输出年份
      * 例如:yyyy => 2019
             yy => 19
             y => 9
      */
-      if (/(y+)/.test(dateFormat)) {
-        dateFormat = dateFormat.replace(
-          RegExp.$1,
-          (date.getFullYear() + "").substr(4 - RegExp.$1.length)
-        );
-      }
-      // 格式化月、日、时、分、秒
-      let o = {
-        "m+": date.getMonth() + 1,
-        "d+": date.getDate(),
-        "h+": date.getHours(),
-        "i+": date.getMinutes(),
-        "s+": date.getSeconds()
-      };
-      for (let k in o) {
-        if (new RegExp(`(${k})`).test(dateFormat)) {
-          // 取出对应的值
-          let str = o[k] + "";
-          /* 根据设置的格式,输出对应的字符
-           * 例如: 早上8时,hh => 08,h => 8
-           * 但是,当数字>=10时,无论格式为一位还是多位,不做截取,这是与年份格式化不一致的地方
-           * 例如: 下午15时,hh => 15, h => 15
-           */
-          dateFormat = dateFormat.replace(
-            RegExp.$1,
-            RegExp.$1.length === 1 ? str : padLeftZero(str)
-          );
-        }
-      }
-      return dateFormat;
-    };
-
-    // 日期时间补零
-    const padLeftZero = (str: string | any[]) => {
-      return ("00" + str).substr(str.length);
-    };
+  if (/(y+)/.test(dateFormat)) {
+    dateFormat = dateFormat.replace(
+      RegExp.$1,
+      (date.getFullYear() + "").substr(4 - RegExp.$1.length)
+    );
+  }
+  // 格式化月、日、时、分、秒
+  let o = {
+    "m+": date.getMonth() + 1,
+    "d+": date.getDate(),
+    "h+": date.getHours(),
+    "i+": date.getMinutes(),
+    "s+": date.getSeconds()
+  };
+  for (let k in o) {
+    if (new RegExp(`(${k})`).test(dateFormat)) {
+      // 取出对应的值
+      let str = o[k] + "";
+      /* 根据设置的格式,输出对应的字符
+       * 例如: 早上8时,hh => 08,h => 8
+       * 但是,当数字>=10时,无论格式为一位还是多位,不做截取,这是与年份格式化不一致的地方
+       * 例如: 下午15时,hh => 15, h => 15
+       */
+      dateFormat = dateFormat.replace(
+        RegExp.$1,
+        RegExp.$1.length === 1 ? str : padLeftZero(str)
+      );
+    }
+  }
+  return dateFormat;
+};
 
-    nextTick(() => {
-      flipObjs.value = [
-        unref(flipperHour1),
-        unref(flipperHour2),
-        unref(flipperMinute1),
-        unref(flipperMinute2),
-        unref(flipperSecond1),
-        unref(flipperSecond2)
-      ];
+// 日期时间补零
+const padLeftZero = (str: string | any[]) => {
+  return ("00" + str).substr(str.length);
+};
 
-      init();
-      run();
-    });
+nextTick(() => {
+  flipObjs.value = [
+    unref(flipperHour1),
+    unref(flipperHour2),
+    unref(flipperMinute1),
+    unref(flipperMinute2),
+    unref(flipperSecond1),
+    unref(flipperSecond2)
+  ];
 
-    onUnmounted(() => {
-      if (timer.value) {
-        clearInterval(timer.value);
-        timer.value = null;
-      }
-    });
+  init();
+  run();
+});
 
-    return {
-      timer,
-      flipObjs,
-      init,
-      run,
-      formatDate,
-      padLeftZero,
-      flipperHour1,
-      flipperHour2,
-      flipperMinute1,
-      flipperMinute2,
-      flipperSecond1,
-      flipperSecond2
-    };
+onUnmounted(() => {
+  if (timer.value) {
+    clearInterval(timer.value);
+    timer.value = null;
   }
-};
+});
 </script>
 
+<template>
+  <div class="flip-clock">
+    <flippers ref="flipperHour1" />
+    <flippers ref="flipperHour2" />
+    <em>:</em>
+    <flippers ref="flipperMinute1" />
+    <flippers ref="flipperMinute2" />
+    <em>:</em>
+    <flippers ref="flipperSecond1" />
+    <flippers ref="flipperSecond2" />
+  </div>
+</template>
+
 <style>
 .flip-clock .m-flipper {
   margin: 0 3px;

+ 89 - 100
src/components/ReFlowChart/src/Control.vue

@@ -1,3 +1,92 @@
+<script setup lang="ts">
+import { ref, unref, onMounted } from "vue";
+import { templateRef } from "@vueuse/core";
+import { LogicFlow } from "@logicflow/core";
+
+interface Props {
+  lf: LogicFlow;
+  catTurboData?: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  lf: null
+});
+
+const emit = defineEmits<{
+  (e: "catData"): void;
+}>();
+
+const controlButton3 = templateRef<HTMLElement | any>("controlButton3", null);
+const controlButton4 = templateRef<HTMLElement | any>("controlButton4", null);
+
+let focusIndex = ref<Number>(-1);
+let titleLists = ref([
+  {
+    icon: "icon-zoom-out-hs",
+    text: "缩小",
+    disabled: false
+  },
+  {
+    icon: "icon-enlarge-hs",
+    text: "放大",
+    disabled: false
+  },
+  {
+    icon: "icon-full-screen-hs",
+    text: "适应",
+    disabled: false
+  },
+  {
+    icon: "icon-previous-hs",
+    text: "上一步",
+    disabled: true
+  },
+  {
+    icon: "icon-next-step-hs",
+    text: "下一步",
+    disabled: true
+  },
+  {
+    icon: "icon-download-hs",
+    text: "下载图片",
+    disabled: false
+  },
+  {
+    icon: "icon-watch-hs",
+    text: "查看数据",
+    disabled: false
+  }
+]);
+
+const onControl = (item, key) => {
+  ["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach(
+    (v, i) => {
+      let domControl = props.lf;
+      if (key === 1) {
+        domControl.zoom(true);
+      }
+      if (key === 6) {
+        emit("catData");
+      }
+      if (key === i) {
+        domControl[v]();
+      }
+    }
+  );
+};
+
+const onEnter = key => {
+  focusIndex.value = key;
+};
+
+onMounted(() => {
+  props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
+    unref(titleLists)[3].disabled = unref(controlButton3).disabled = !undoAble;
+    unref(titleLists)[4].disabled = unref(controlButton4).disabled = !redoAble;
+  });
+});
+</script>
+
 <template>
   <div class="control-container">
     <!-- 功能按钮 -->
@@ -26,106 +115,6 @@
   </div>
 </template>
 
-<script lang="ts">
-import { defineComponent, ref, unref, onMounted } from "vue";
-import { templateRef } from "@vueuse/core";
-
-export default defineComponent({
-  name: "Control",
-  props: {
-    lf: null,
-    catTurboData: Boolean
-  },
-  emits: ["catData"],
-  setup(props, { emit }) {
-    const controlButton3 = templateRef<HTMLElement | any>(
-      "controlButton3",
-      null
-    );
-    const controlButton4 = templateRef<HTMLElement | any>(
-      "controlButton4",
-      null
-    );
-
-    let focusIndex = ref(-1);
-    let titleLists = ref([
-      {
-        icon: "icon-zoom-out-hs",
-        text: "缩小",
-        disabled: false
-      },
-      {
-        icon: "icon-enlarge-hs",
-        text: "放大",
-        disabled: false
-      },
-      {
-        icon: "icon-full-screen-hs",
-        text: "适应",
-        disabled: false
-      },
-      {
-        icon: "icon-previous-hs",
-        text: "上一步",
-        disabled: true
-      },
-      {
-        icon: "icon-next-step-hs",
-        text: "下一步",
-        disabled: true
-      },
-      {
-        icon: "icon-download-hs",
-        text: "下载图片",
-        disabled: false
-      },
-      {
-        icon: "icon-watch-hs",
-        text: "查看数据",
-        disabled: false
-      }
-    ]);
-
-    const onControl = (item, key) => {
-      ["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach(
-        (v, i) => {
-          let domControl = props.lf;
-          if (key === 1) {
-            domControl.zoom(true);
-          }
-          if (key === 6) {
-            emit("catData");
-          }
-          if (key === i) {
-            domControl[v]();
-          }
-        }
-      );
-    };
-
-    const onEnter = key => {
-      focusIndex.value = key;
-    };
-
-    onMounted(() => {
-      props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
-        unref(titleLists)[3].disabled = unref(controlButton3).disabled =
-          !undoAble;
-        unref(titleLists)[4].disabled = unref(controlButton4).disabled =
-          !redoAble;
-      });
-    });
-
-    return {
-      focusIndex,
-      titleLists,
-      onControl,
-      onEnter
-    };
-  }
-});
-</script>
-
 <style scoped>
 @import "./assets/iconfont/iconfont.css";
 

+ 10 - 16
src/components/ReFlowChart/src/DataDialog.vue

@@ -1,23 +1,17 @@
+<script setup lang="ts">
+import VueJsonPretty from "vue-json-pretty";
+import "vue-json-pretty/lib/styles.css";
+
+const props = defineProps({
+  graphData: Object
+});
+</script>
+
 <template>
   <vue-json-pretty
     :path="'res'"
     :deep="3"
     :showLength="true"
-    :data="graphData"
+    :data="props.graphData"
   ></vue-json-pretty>
 </template>
-
-<script lang="ts">
-import VueJsonPretty from "vue-json-pretty";
-import "vue-json-pretty/lib/styles.css";
-import { defineComponent } from "vue";
-export default defineComponent({
-  name: "DataDialog",
-  props: {
-    graphData: Object
-  },
-  components: {
-    VueJsonPretty
-  }
-});
-</script>

+ 28 - 38
src/components/ReFlowChart/src/NodePanel.vue

@@ -1,9 +1,36 @@
+<script setup lang="ts">
+import { ref, unref } from "vue";
+import { LogicFlow } from "@logicflow/core";
+
+interface Props {
+  lf: LogicFlow;
+  nodeList: ForDataType<undefined>;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  lf: null,
+  nodeList: null
+});
+
+let properties = ref({
+  a: "efrwe",
+  b: "wewe"
+});
+
+const nodeDragNode = item => {
+  props.lf.dnd.startDrag({
+    type: item.type,
+    properties: unref(properties)
+  });
+};
+</script>
+
 <template>
   <!-- 左侧bpmn元素选择器 -->
   <div class="node-panel">
     <div
       class="node-item"
-      v-for="item in nodeList"
+      v-for="item in props.nodeList"
       :key="item.text"
       @mousedown="nodeDragNode(item)"
     >
@@ -18,43 +45,6 @@
   </div>
 </template>
 
-<script lang="ts">
-import { defineComponent, ref, unref } from "vue";
-export default defineComponent({
-  name: "NodePanel",
-  props: {
-    lf: Object,
-    nodeList: Array
-  },
-  setup(props) {
-    let node = ref({
-      type: "rect",
-      property: {
-        a: "efrwe",
-        b: "wewe"
-      }
-    });
-    let properties = ref({
-      a: "efrwe",
-      b: "wewe"
-    });
-
-    const nodeDragNode = item => {
-      props.lf.dnd.startDrag({
-        type: item.type,
-        properties: unref(properties)
-      });
-    };
-
-    return {
-      node,
-      properties,
-      nodeDragNode
-    };
-  }
-});
-</script>
-
 <style scoped>
 .node-panel {
   position: absolute;

+ 26 - 23
src/components/ReHamBurger/src/index.vue

@@ -1,8 +1,26 @@
+<script setup lang="ts">
+export interface Props {
+  isActive: boolean;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  isActive: false
+});
+
+const emit = defineEmits<{
+  (e: "toggleClick"): void;
+}>();
+
+const toggleClick = () => {
+  emit("toggleClick");
+};
+</script>
+
 <template>
-  <div style="padding: 0 15px" @click="toggleClick">
+  <div :class="classes.container" @click="toggleClick">
     <svg
-      :class="{ 'is-active': isActive }"
       class="hamburger"
+      :class="props.isActive ? 'is-active' : ''"
       viewBox="0 0 1024 1024"
       xmlns="http://www.w3.org/2000/svg"
       width="64"
@@ -15,26 +33,11 @@
   </div>
 </template>
 
-<script>
-import { defineComponent } from "vue";
-export default defineComponent({
-  name: "HamBurger",
-  props: {
-    isActive: {
-      type: Boolean,
-      default: false
-    }
-  },
-  emits: ["toggleClick"],
-  setup(props, ctx) {
-    const toggleClick = () => {
-      ctx.emit("toggleClick");
-    };
-
-    return { toggleClick };
-  }
-});
-</script>
+<style module="classes" scoped>
+.container {
+  padding: 0 15px;
+}
+</style>
 
 <style scoped>
 .hamburger {
@@ -44,7 +47,7 @@ export default defineComponent({
   height: 20px;
 }
 
-.hamburger.is-active {
+.is-active {
   transform: rotate(180deg);
 }
 </style>

+ 94 - 117
src/components/ReInfo/index.vue

@@ -1,3 +1,97 @@
+<script setup lang="ts">
+import { ref, PropType, getCurrentInstance, watch, nextTick, toRef } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { initRouter } from "/@/router";
+import { storageSession } from "/@/utils/storage";
+
+export interface ContextProps {
+  userName: string;
+  passWord: string;
+  verify: number | null;
+  svg: any;
+  telephone?: number;
+  dynamicText?: string;
+}
+
+const props = defineProps({
+  ruleForm: {
+    type: Object as PropType<ContextProps>
+  }
+});
+
+const emit = defineEmits<{
+  (e: "onBehavior", evt: Object): void;
+  (e: "refreshVerify"): void;
+}>();
+
+const instance = getCurrentInstance();
+
+const model = toRef(props, "ruleForm");
+let tips = ref<string>("注册");
+let tipsFalse = ref<string>("登录");
+
+const route = useRoute();
+const router = useRouter();
+
+watch(
+  route,
+  async ({ path }): Promise<void> => {
+    await nextTick();
+    path.includes("register")
+      ? (tips.value = "登录") && (tipsFalse.value = "注册")
+      : (tips.value = "注册") && (tipsFalse.value = "登录");
+  },
+  { immediate: true }
+);
+
+const rules: Object = ref({
+  userName: [{ required: true, message: "请输入用户名", trigger: "blur" }],
+  passWord: [
+    { required: true, message: "请输入密码", trigger: "blur" },
+    { min: 6, message: "密码长度必须不小于6位", trigger: "blur" }
+  ],
+  verify: [
+    { required: true, message: "请输入验证码", trigger: "blur" },
+    { type: "number", message: "验证码必须是数字类型", trigger: "blur" }
+  ]
+});
+
+// 点击登录或注册
+const onBehavior = (evt: Object): void => {
+  instance.refs.ruleForm.validate((valid: boolean) => {
+    if (valid) {
+      emit("onBehavior", evt);
+    } else {
+      return false;
+    }
+  });
+};
+
+// 刷新验证码
+const refreshVerify = (): void => {
+  emit("refreshVerify");
+};
+
+// 表单重置
+const resetForm = (): void => {
+  instance.refs.ruleForm.resetFields();
+};
+
+// 登录、注册页面切换
+const changPage = (): void => {
+  tips.value === "注册" ? router.push("/register") : router.push("/login");
+};
+
+const noSecret = (): void => {
+  storageSession.setItem("info", {
+    username: "admin",
+    accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
+  });
+  initRouter("admin").then(() => {});
+  router.push("/");
+};
+</script>
+
 <template>
   <div class="info">
     <el-form :model="model" :rules="rules" ref="ruleForm" class="rule-form">
@@ -47,123 +141,6 @@
   </div>
 </template>
 
-<script lang="ts">
-import {
-  ref,
-  defineComponent,
-  PropType,
-  getCurrentInstance,
-  watch,
-  nextTick,
-  toRef
-} from "vue";
-import { storageSession } from "/@/utils/storage";
-
-export interface ContextProps {
-  userName: string;
-  passWord: string;
-  verify: number | null;
-  svg: any;
-  telephone?: number;
-  dynamicText?: string;
-}
-
-import { useRouter, useRoute } from "vue-router";
-
-import { initRouter } from "/@/router";
-
-export default defineComponent({
-  name: "Info",
-  props: {
-    ruleForm: {
-      type: Object as PropType<ContextProps>,
-      require: true
-    }
-  },
-  emits: ["onBehavior", "refreshVerify"],
-  setup(props, ctx) {
-    const instance = getCurrentInstance();
-
-    const model = toRef(props, "ruleForm");
-    let tips = ref("注册");
-    let tipsFalse = ref("登录");
-
-    const route = useRoute();
-    const router = useRouter();
-
-    watch(
-      route,
-      async ({ path }): Promise<void> => {
-        await nextTick();
-        path.includes("register")
-          ? (tips.value = "登录") && (tipsFalse.value = "注册")
-          : (tips.value = "注册") && (tipsFalse.value = "登录");
-      },
-      { immediate: true }
-    );
-
-    const rules: Object = ref({
-      userName: [{ required: true, message: "请输入用户名", trigger: "blur" }],
-      passWord: [
-        { required: true, message: "请输入密码", trigger: "blur" },
-        { min: 6, message: "密码长度必须不小于6位", trigger: "blur" }
-      ],
-      verify: [
-        { required: true, message: "请输入验证码", trigger: "blur" },
-        { type: "number", message: "验证码必须是数字类型", trigger: "blur" }
-      ]
-    });
-
-    // 点击登录或注册
-    const onBehavior = (evt: Object): void => {
-      instance.refs.ruleForm.validate((valid: boolean) => {
-        if (valid) {
-          ctx.emit("onBehavior", evt);
-        } else {
-          return false;
-        }
-      });
-    };
-
-    // 刷新验证码
-    const refreshVerify = (): void => {
-      ctx.emit("refreshVerify");
-    };
-
-    // 表单重置
-    const resetForm = (): void => {
-      instance.refs.ruleForm.resetFields();
-    };
-
-    // 登录、注册页面切换
-    const changPage = (): void => {
-      tips.value === "注册" ? router.push("/register") : router.push("/login");
-    };
-
-    const noSecret = (): void => {
-      storageSession.setItem("info", {
-        username: "admin",
-        accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
-      });
-      initRouter("admin").then(() => {});
-      router.push("/");
-    };
-
-    return {
-      model,
-      rules,
-      tips,
-      tipsFalse,
-      resetForm,
-      onBehavior,
-      refreshVerify,
-      changPage,
-      noSecret
-    };
-  }
-});
-</script>
-
 <style lang="scss" scoped>
 .info {
   width: 30vw;

+ 1 - 9
src/components/ReMap/index.ts

@@ -1,6 +1,5 @@
 import { App } from "vue";
 import amap from "./src/Amap.vue";
-import baiduMap from "./src/BaiduMap.vue";
 
 export const Amap = Object.assign(amap, {
   install(app: App) {
@@ -8,13 +7,6 @@ export const Amap = Object.assign(amap, {
   }
 });
 
-export const BaiduMap = Object.assign(baiduMap, {
-  install(app: App) {
-    app.component(baiduMap.name, baiduMap);
-  }
-});
-
 export default {
-  Amap,
-  BaiduMap
+  Amap
 };

+ 103 - 128
src/components/ReMap/src/Amap.vue

@@ -1,45 +1,17 @@
-<template>
-  <div
-    id="mapview"
-    ref="mapview"
-    v-loading="loading"
-    element-loading-text="地图加载中"
-    element-loading-spinner="el-icon-loading"
-    element-loading-background="rgba(0, 0, 0, 0.8)"
-  ></div>
-</template>
-
-<script lang="ts">
+<script setup lang="ts">
 import AMapLoader from "@amap/amap-jsapi-loader";
-import {
-  reactive,
-  toRefs,
-  defineComponent,
-  onBeforeMount,
-  getCurrentInstance
-} from "vue";
-
+import { reactive, getCurrentInstance, onBeforeMount, onUnmounted } from "vue";
 import { mapJson } from "/@/api/mock";
 import { deviceDetection } from "/@/utils/deviceDetection";
-
 import greenCar from "/@/assets/green.png";
 
-let MarkerCluster;
-
 export interface MapConfigureInter {
-  // eslint-disable-next-line no-undef
   on: Fn;
-  // eslint-disable-next-line no-undef
   destroy?: Fn;
-  // eslint-disable-next-line no-undef
   clearEvents?: Fn;
-  // eslint-disable-next-line no-undef
   addControl?: Fn;
-  // eslint-disable-next-line no-undef
   setCenter?: Fn;
-  // eslint-disable-next-line no-undef
   setZoom?: Fn;
-  // eslint-disable-next-line no-undef
   plugin?: Fn;
 }
 
@@ -47,116 +19,119 @@ export interface mapInter {
   loading: boolean;
 }
 
-export default defineComponent({
-  name: "Amap",
-  setup() {
-    const instance = getCurrentInstance();
-    let map: MapConfigureInter;
-
-    const mapSet: mapInter = reactive({
-      loading: deviceDetection() ? false : true
-    });
-
-    // 地图创建完成(动画关闭)
-    const complete = (): void => {
-      if (map) {
-        map.on("complete", () => {
-          mapSet.loading = false;
-        });
-      }
-    };
+let MarkerCluster;
+let map: MapConfigureInter;
 
-    // 销毁地图实例
-    const destroyMap = (): void => {
-      if (map) {
-        map.destroy() && map.clearEvents("click");
-      }
-    };
-
-    onBeforeMount(() => {
-      if (!instance) return;
-      let { MapConfigure } =
-        instance.appContext.config.globalProperties.$config;
-      let { options } = MapConfigure;
-
-      AMapLoader.load({
-        key: MapConfigure.amapKey,
-        version: "2.0",
-        plugins: ["AMap.MarkerCluster"]
-      })
-        .then(AMap => {
-          // 创建地图实例
-          map = new AMap.Map(instance.refs.mapview, options);
-
-          //地图中添加地图操作ToolBar插件
-          map.plugin(["AMap.ToolBar", "AMap.MapType"], () => {
-            map.addControl(new AMap.ToolBar());
-            //地图类型切换
-            map.addControl(
-              new AMap.MapType({
-                defaultType: 0
-              })
-            );
-          });
+const instance = getCurrentInstance();
 
-          MarkerCluster = new AMap.MarkerCluster(map, [], {
-            gridSize: 80, // 聚合网格像素大小
-            maxZoom: 14,
-            renderMarker(ctx) {
-              let { marker, data } = ctx;
-              if (Array.isArray(data) && data[0]) {
-                var { driver, plateNumber, orientation } = data[0];
-                var content = `<img style="transform: scale(1) rotate(${
-                  360 - Number(orientation)
-                }deg);" src='${greenCar}' />`;
-                marker.setContent(content);
-                marker.setLabel({
-                  direction: "bottom",
-                  offset: new AMap.Pixel(-4, 0), //设置文本标注偏移量
-                  content: `<div> ${plateNumber}(${driver})</div>` //设置文本标注内容
-                });
-                marker.setOffset(new AMap.Pixel(-18, -10));
-                marker.on("click", ({ lnglat }) => {
-                  map.setZoom(13); //设置地图层级
-                  map.setCenter(lnglat);
-                });
-              }
-            }
-          });
+const mapSet: mapInter = reactive({
+  loading: deviceDetection() ? false : true
+});
 
-          // 获取模拟车辆信息
-          mapJson()
-            .then(res => {
-              let points: object = res.info.map((v: any) => {
-                return {
-                  lnglat: [v.lng, v.lat],
-                  ...v
-                };
-              });
-              if (MarkerCluster) MarkerCluster.setData(points);
-            })
-            .catch(err => {
-              console.log("err:", err);
+// 地图创建完成(动画关闭)
+const complete = (): void => {
+  if (map) {
+    map.on("complete", () => {
+      mapSet.loading = false;
+    });
+  }
+};
+
+onBeforeMount(() => {
+  if (!instance) return;
+  let { MapConfigure } = instance.appContext.config.globalProperties.$config;
+  let { options } = MapConfigure;
+
+  AMapLoader.load({
+    key: MapConfigure.amapKey,
+    version: "2.0",
+    plugins: ["AMap.MarkerCluster"]
+  })
+    .then(AMap => {
+      // 创建地图实例
+      map = new AMap.Map(instance.refs.mapview, options);
+
+      //地图中添加地图操作ToolBar插件
+      map.plugin(["AMap.ToolBar", "AMap.MapType"], () => {
+        map.addControl(new AMap.ToolBar());
+        //地图类型切换
+        map.addControl(
+          new AMap.MapType({
+            defaultType: 0
+          })
+        );
+      });
+
+      MarkerCluster = new AMap.MarkerCluster(map, [], {
+        // 聚合网格像素大小
+        gridSize: 80,
+        maxZoom: 14,
+        renderMarker(ctx) {
+          let { marker, data } = ctx;
+          if (Array.isArray(data) && data[0]) {
+            var { driver, plateNumber, orientation } = data[0];
+            var content = `<img style="transform: scale(1) rotate(${
+              360 - Number(orientation)
+            }deg);" src='${greenCar}' />`;
+            marker.setContent(content);
+            marker.setLabel({
+              direction: "bottom",
+              //设置文本标注偏移量
+              offset: new AMap.Pixel(-4, 0),
+              //设置文本标注内容
+              content: `<div> ${plateNumber}(${driver})</div>`
             });
-
-          complete();
+            marker.setOffset(new AMap.Pixel(-18, -10));
+            marker.on("click", ({ lnglat }) => {
+              map.setZoom(13); //设置地图层级
+              map.setCenter(lnglat);
+            });
+          }
+        }
+      });
+
+      // 获取模拟车辆信息
+      mapJson()
+        .then(res => {
+          let points: object = res.info.map((v: any) => {
+            return {
+              lnglat: [v.lng, v.lat],
+              ...v
+            };
+          });
+          if (MarkerCluster) MarkerCluster.setData(points);
         })
-        .catch(() => {
-          mapSet.loading = false;
-          throw "地图加载失败,请重新加载";
+        .catch(err => {
+          console.log("err:", err);
         });
+
+      complete();
+    })
+    .catch(() => {
+      mapSet.loading = false;
+      throw "地图加载失败,请重新加载";
     });
+});
 
-    return {
-      ...toRefs(mapSet),
-      complete,
-      destroyMap,
-      greenCar
-    };
+onUnmounted(() => {
+  if (map) {
+    // 销毁地图实例
+    map.destroy() && map.clearEvents("click");
   }
 });
 </script>
 
+<template>
+  <div
+    id="mapview"
+    ref="mapview"
+    v-loading="mapSet.loading"
+    element-loading-text="地图加载中"
+    element-loading-spinner="el-icon-loading"
+    element-loading-background="rgba(0, 0, 0, 0.8)"
+  ></div>
+</template>
+
 <style lang="scss" scoped>
 #mapview {
   height: 100%;

+ 0 - 14
src/components/ReMap/src/BaiduMap.vue

@@ -1,14 +0,0 @@
-<template>
-  <div></div>
-</template>
-
-<script lang="ts">
-export default {
-  name: "BaiduMap",
-  setup() {
-    return {};
-  }
-};
-</script>
-
-<style scoped></style>

+ 492 - 550
src/components/ReSeamlessScroll/src/index.vue

@@ -1,3 +1,495 @@
+<script setup lang="ts">
+import { computed, ref, unref, nextTick } from "vue";
+import type { CSSProperties, PropType } from "vue";
+import {
+  tryOnMounted,
+  tryOnUnmounted,
+  templateRef,
+  useDebounceFn
+} from "@vueuse/core";
+import * as utilsMethods from "./utils";
+const { animationFrame, copyObj } = utilsMethods;
+animationFrame();
+
+const props = defineProps({
+  data: {
+    type: Array as PropType<unknown>
+  },
+  classOption: {
+    type: Object as PropType<unknown>
+  }
+});
+
+const emit = defineEmits<{
+  (e: "scrollEnd"): void;
+}>();
+
+let xPos = ref<number>(0);
+let yPos = ref<number>(0);
+let delay = ref<number>(0);
+let height = ref<number>(0);
+// 外容器宽度
+let width = ref<number>(0);
+// 内容实际宽度
+let realBoxWidth = ref<number>(0);
+let realBoxHeight = ref<number>(0);
+let copyHtml = ref("");
+// single 单步滚动的定时器
+let singleWaitTime = null;
+// move动画的animationFrame定时器
+let reqFrame = null;
+let startPos = null;
+//记录touchStart时候的posY
+let startPosY = null;
+//记录touchStart时候的posX
+let startPosX = null;
+// mouseenter mouseleave 控制scrollMove()的开关
+let isHover = false;
+let ease = "ease-in";
+
+// eslint-disable-next-line vue/no-setup-props-destructure
+let { classOption } = props;
+
+if (classOption["key"] === undefined) {
+  classOption["key"] = 0;
+}
+
+const wrap = templateRef<HTMLElement | null>(`wrap${classOption["key"]}`, null);
+const slotList = templateRef<HTMLElement | null>(
+  `slotList${classOption["key"]}`,
+  null
+);
+const realBox = templateRef<HTMLElement | null>(
+  `realBox${classOption["key"]}`,
+  null
+);
+
+let leftSwitchState = computed(() => {
+  return unref(xPos) < 0;
+});
+
+let rightSwitchState = computed(() => {
+  return Math.abs(unref(xPos)) < unref(realBoxWidth) - unref(width);
+});
+
+let defaultOption = computed(() => {
+  return {
+    //步长
+    step: 1,
+    //启动无缝滚动最小数据数
+    limitMoveNum: 5,
+    //是否启用鼠标hover控制
+    hoverStop: true,
+    // bottom 往下 top 往上(默认) left 向左 right 向右
+    direction: "top",
+    //开启移动端touch
+    openTouch: true,
+    //单条数据高度有值hoverStop关闭
+    singleHeight: 0,
+    //单条数据宽度有值hoverStop关闭
+    singleWidth: 0,
+    //单步停止等待时间
+    waitTime: 1000,
+    switchOffset: 30,
+    autoPlay: true,
+    navigation: false,
+    switchSingleStep: 134,
+    switchDelay: 400,
+    switchDisabledClass: "disabled",
+    // singleWidth/singleHeight 是否开启rem度量
+    isSingleRemUnit: false
+  };
+});
+
+let options = computed(() => {
+  // @ts-ignore
+  return copyObj({}, unref(defaultOption), classOption);
+});
+
+const leftSwitchClass = computed(() => {
+  return unref(leftSwitchState) ? "" : unref(options).switchDisabledClass;
+});
+
+let rightSwitchClass = computed(() => {
+  return unref(rightSwitchState) ? "" : unref(options).switchDisabledClass;
+});
+
+let leftSwitch = computed((): CSSProperties => {
+  return {
+    position: "absolute",
+    margin: `${unref(height) / 2}px 0 0 -${unref(options).switchOffset}px`,
+    transform: "translate(-100%,-50%)"
+  };
+});
+
+let rightSwitch = computed((): CSSProperties => {
+  return {
+    position: "absolute",
+    margin: `${unref(height) / 2}px 0 0 ${
+      unref(width) + unref(options).switchOffset
+    }px`,
+    transform: "translateY(-50%)"
+  };
+});
+
+let isHorizontal = computed(() => {
+  return (
+    unref(options).direction !== "bottom" && unref(options).direction !== "top"
+  );
+});
+
+let float = computed((): CSSProperties => {
+  return unref(isHorizontal)
+    ? { float: "left", overflow: "hidden" }
+    : { overflow: "hidden" };
+});
+
+let pos = computed(() => {
+  return {
+    transform: `translate(${unref(xPos)}px,${unref(yPos)}px)`,
+    transition: `all ${ease} ${unref(delay)}ms`,
+    overflow: "hidden"
+  };
+});
+
+let navigation = computed(() => {
+  return unref(options).navigation;
+});
+
+let autoPlay = computed(() => {
+  if (unref(navigation)) return false;
+  return unref(options).autoPlay;
+});
+
+let scrollSwitch = computed(() => {
+  // 从 props 解构出来的 属性 不再具有相应性.
+  return props.data.length >= unref(options).limitMoveNum;
+});
+
+let hoverStopSwitch = computed(() => {
+  return unref(options).hoverStop && unref(autoPlay) && unref(scrollSwitch);
+});
+
+let canTouchScroll = computed(() => {
+  return unref(options).openTouch;
+});
+
+let baseFontSize = computed(() => {
+  return unref(options).isSingleRemUnit
+    ? parseInt(window.getComputedStyle(document.documentElement, null).fontSize)
+    : 1;
+});
+
+let realSingleStopWidth = computed(() => {
+  return unref(options).singleWidth * unref(baseFontSize);
+});
+
+let realSingleStopHeight = computed(() => {
+  return unref(options).singleHeight * unref(baseFontSize);
+});
+
+let step = computed(() => {
+  let singleStep;
+  let step = unref(options).step;
+  if (unref(isHorizontal)) {
+    singleStep = unref(realSingleStopWidth);
+  } else {
+    singleStep = unref(realSingleStopHeight);
+  }
+  if (singleStep > 0 && singleStep % step > 0) {
+    throw "如果设置了单步滚动,step需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确";
+  }
+  return step;
+});
+
+function reset() {
+  xPos.value = 0;
+  yPos.value = 0;
+  scrollCancle();
+  scrollInitMove();
+}
+
+function leftSwitchClick() {
+  if (!unref(leftSwitchState)) return;
+  // 小于单步距离
+  if (Math.abs(unref(xPos)) < unref(options).switchSingleStep) {
+    xPos.value = 0;
+    return;
+  }
+  xPos.value += unref(options).switchSingleStep;
+}
+
+function rightSwitchClick() {
+  if (!unref(rightSwitchState)) return;
+  // 小于单步距离
+  if (
+    unref(realBoxWidth) - unref(width) + unref(xPos) <
+    unref(options).switchSingleStep
+  ) {
+    xPos.value = unref(width) - unref(realBoxWidth);
+    return;
+  }
+  xPos.value -= unref(options).switchSingleStep;
+}
+
+function scrollCancle() {
+  cancelAnimationFrame(reqFrame || "");
+}
+
+function touchStart(e) {
+  if (!unref(canTouchScroll)) return;
+  let timer;
+  //touches数组对象获得屏幕上所有的touch,取第一个touch
+  const touch = e.targetTouches[0];
+  const { waitTime, singleHeight, singleWidth } = unref(options);
+  //取第一个touch的坐标值
+  startPos = {
+    x: touch.pageX,
+    y: touch.pageY
+  };
+  //记录touchStart时候的posY
+  startPosY = unref(yPos);
+  //记录touchStart时候的posX
+  startPosX = unref(xPos);
+  if (!!singleHeight && !!singleWidth) {
+    if (timer) clearTimeout(timer);
+    timer = setTimeout(() => {
+      scrollCancle();
+    }, waitTime + 20);
+  } else {
+    scrollCancle();
+  }
+}
+
+function touchMove(e) {
+  //当屏幕有多个touch或者页面被缩放过,就不执行move操作
+  if (
+    !unref(canTouchScroll) ||
+    e.targetTouches.length > 1 ||
+    (e.scale && e.scale !== 1)
+  )
+    return;
+  const touch = e.targetTouches[0];
+  const { direction } = unref(options);
+  let endPos = {
+    x: touch.pageX - startPos.x,
+    y: touch.pageY - startPos.y
+  };
+  //阻止触摸事件的默认行为,即阻止滚屏
+  e.preventDefault();
+  //dir,1表示纵向滑动,0为横向滑动
+  const dir = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1 : 0;
+  if (
+    (dir === 1 && direction === "bottom") ||
+    (dir === 1 && direction === "top")
+  ) {
+    // 表示纵向滑动 && 运动方向为上下
+    yPos.value = startPosY + endPos.y;
+  } else if (
+    (dir === 0 && direction === "left") ||
+    (dir === 0 && direction === "right")
+  ) {
+    // 为横向滑动 && 运动方向为左右
+    xPos.value = startPosX + endPos.x;
+  }
+}
+
+function touchEnd() {
+  if (!unref(canTouchScroll)) return;
+  let timer;
+  const direction = unref(options).direction;
+  delay.value = 50;
+  if (direction === "top") {
+    if (unref(yPos) > 0) yPos.value = 0;
+  } else if (direction === "bottom") {
+    let h = (unref(realBoxHeight) / 2) * -1;
+    if (unref(yPos) < h) yPos.value = h;
+  } else if (direction === "left") {
+    if (unref(xPos) > 0) xPos.value = 0;
+  } else if (direction === "right") {
+    let w = unref(realBoxWidth) * -1;
+    if (unref(xPos) < w) xPos.value = w;
+  }
+  if (timer) clearTimeout(timer);
+  timer = setTimeout(() => {
+    delay.value = 0;
+    scrollMove();
+  }, unref(delay));
+}
+
+function enter() {
+  if (unref(hoverStopSwitch)) scrollStopMove();
+}
+
+function leave() {
+  if (unref(hoverStopSwitch)) scrollStartMove();
+}
+
+function scrollMove() {
+  // 鼠标移入时拦截scrollMove()
+  if (isHover) return;
+  //进入move立即先清除动画 防止频繁touchMove导致多动画同时进行
+  // scrollCancle();
+  reqFrame = requestAnimationFrame(function () {
+    //实际高度
+    const h = unref(realBoxHeight) / 2;
+    //宽度
+    const w = unref(realBoxWidth) / 2;
+    let { direction, waitTime } = unref(options);
+    if (direction === "top") {
+      // 上
+      if (Math.abs(unref(yPos)) >= h) {
+        emit("scrollEnd");
+        yPos.value = 0;
+      }
+      yPos.value -= step.value;
+    } else if (direction === "bottom") {
+      // 下
+      if (unref(yPos) >= 0) {
+        emit("scrollEnd");
+        yPos.value = h * -1;
+      }
+      yPos.value += step.value;
+    } else if (direction === "left") {
+      // 左
+      if (Math.abs(unref(xPos)) >= w) {
+        emit("scrollEnd");
+        xPos.value = 0;
+      }
+      xPos.value -= step.value;
+    } else if (direction === "right") {
+      // 右
+      if (unref(xPos) >= 0) {
+        emit("scrollEnd");
+        xPos.value = w * -1;
+      }
+      xPos.value += step.value;
+    }
+    if (singleWaitTime) clearTimeout(singleWaitTime);
+    if (unref(realSingleStopHeight)) {
+      //是否启动了单行暂停配置
+      if (Math.abs(unref(yPos)) % unref(realSingleStopHeight) < unref(step)) {
+        // 符合条件暂停waitTime
+        singleWaitTime = setTimeout(() => {
+          scrollMove();
+        }, waitTime);
+      } else {
+        scrollMove();
+      }
+    } else if (unref(realSingleStopWidth)) {
+      if (Math.abs(unref(xPos)) % unref(realSingleStopWidth) < unref(step)) {
+        // 符合条件暂停waitTime
+        singleWaitTime = setTimeout(() => {
+          scrollMove();
+        }, waitTime);
+      } else {
+        scrollMove();
+      }
+    } else {
+      scrollMove();
+    }
+  });
+}
+
+function scrollInitMove() {
+  nextTick(() => {
+    const { switchDelay } = unref(options);
+    //清空copy
+    copyHtml.value = "";
+    if (unref(isHorizontal)) {
+      height.value = unref(wrap).offsetHeight;
+      width.value = unref(wrap).offsetWidth;
+      let slotListWidth = unref(slotList).offsetWidth;
+      // 水平滚动设置warp width
+      if (unref(autoPlay)) {
+        // 修正offsetWidth四舍五入
+        slotListWidth = slotListWidth * 2 + 1;
+      }
+      unref(realBox).style.width = slotListWidth + "px";
+      realBoxWidth.value = slotListWidth;
+    }
+
+    if (unref(autoPlay)) {
+      ease = "ease-in";
+      delay.value = 0;
+    } else {
+      ease = "linear";
+      delay.value = switchDelay;
+      return;
+    }
+
+    // 是否可以滚动判断
+    if (unref(scrollSwitch)) {
+      let timer;
+      if (timer) clearTimeout(timer);
+      copyHtml.value = unref(slotList).innerHTML;
+      setTimeout(() => {
+        realBoxHeight.value = unref(realBox).offsetHeight;
+        scrollMove();
+      }, 0);
+    } else {
+      scrollCancle();
+      yPos.value = xPos.value = 0;
+    }
+  });
+}
+
+function scrollStartMove() {
+  //开启scrollMove
+  isHover = false;
+  scrollMove();
+}
+
+function scrollStopMove() {
+  //关闭scrollMove
+  isHover = true;
+  // 防止频频hover进出单步滚动,导致定时器乱掉
+  if (singleWaitTime) clearTimeout(singleWaitTime);
+  scrollCancle();
+}
+
+// 鼠标滚轮事件
+function wheel(e) {
+  e.preventDefault();
+  if (
+    unref(options).direction === "left" ||
+    unref(options).direction === "right"
+  )
+    return;
+  useDebounceFn(() => {
+    e.deltaY > 0 ? (yPos.value -= step.value) : (yPos.value += step.value);
+  }, 50)();
+}
+
+// watchEffect(() => {
+//   const watchData = data;
+//   if (!watchData) return;
+//   nextTick(() => {
+//     reset();
+//   });
+
+//   const watchAutoPlay = unref(autoPlay);
+//   if (watchAutoPlay) {
+//     reset();
+//   } else {
+//     scrollStopMove();
+//   }
+// });
+
+tryOnMounted(() => {
+  scrollInitMove();
+});
+
+tryOnUnmounted(() => {
+  scrollCancle();
+  clearTimeout(singleWaitTime);
+});
+
+defineExpose({
+  reset
+});
+</script>
+
 <template>
   <div :ref="'wrap' + classOption['key']">
     <div
@@ -33,553 +525,3 @@
     </div>
   </div>
 </template>
-
-<script lang="ts">
-import { defineComponent, computed, ref, unref, nextTick } from "vue";
-import {
-  tryOnMounted,
-  tryOnUnmounted,
-  templateRef,
-  useDebounceFn
-} from "@vueuse/core";
-import * as utilsMethods from "./utils";
-const { animationFrame, copyObj } = utilsMethods;
-animationFrame();
-
-export default defineComponent({
-  name: "SeamlessScroll",
-  props: {
-    data: {
-      type: Array,
-      default: () => {
-        return [];
-      }
-    },
-    classOption: {
-      type: Object,
-      default: () => {
-        return {};
-      }
-    }
-  },
-  emits: ["ScrollEnd"],
-  setup(props, { emit }) {
-    let xPos = ref(0);
-    let yPos = ref(0);
-    let delay = ref(0);
-    let copyHtml = ref("");
-    let height = ref(0);
-    // 外容器宽度
-    let width = ref(0);
-    // 内容实际宽度
-    let realBoxWidth = ref(0);
-    let realBoxHeight = ref(0);
-
-    // single 单步滚动的定时器
-    let singleWaitTime = null;
-    // move动画的animationFrame定时器
-    let reqFrame = null;
-    let startPos = null;
-    //记录touchStart时候的posY
-    let startPosY = null;
-    //记录touchStart时候的posX
-    let startPosX = null;
-    // mouseenter mouseleave 控制scrollMove()的开关
-    let isHover = false;
-    let ease = "ease-in";
-
-    // eslint-disable-next-line vue/no-setup-props-destructure
-    let { classOption } = props;
-
-    if (classOption["key"] === undefined) {
-      classOption["key"] = 0;
-    }
-
-    const wrap = templateRef<HTMLElement | null>(
-      `wrap${classOption["key"]}`,
-      null
-    );
-    const slotList = templateRef<HTMLElement | null>(
-      `slotList${classOption["key"]}`,
-      null
-    );
-    const realBox = templateRef<HTMLElement | null>(
-      `realBox${classOption["key"]}`,
-      null
-    );
-
-    let leftSwitchState = computed(() => {
-      return unref(xPos) < 0;
-    });
-
-    let rightSwitchState = computed(() => {
-      return Math.abs(unref(xPos)) < unref(realBoxWidth) - unref(width);
-    });
-
-    let defaultOption = computed(() => {
-      return {
-        //步长
-        step: 1,
-        //启动无缝滚动最小数据数
-        limitMoveNum: 5,
-        //是否启用鼠标hover控制
-        hoverStop: true,
-        // bottom 往下 top 往上(默认) left 向左 right 向右
-        direction: "top",
-        //开启移动端touch
-        openTouch: true,
-        //单条数据高度有值hoverStop关闭
-        singleHeight: 0,
-        //单条数据宽度有值hoverStop关闭
-        singleWidth: 0,
-        //单步停止等待时间
-        waitTime: 1000,
-        switchOffset: 30,
-        autoPlay: true,
-        navigation: false,
-        switchSingleStep: 134,
-        switchDelay: 400,
-        switchDisabledClass: "disabled",
-        // singleWidth/singleHeight 是否开启rem度量
-        isSingleRemUnit: false
-      };
-    });
-
-    let options = computed(() => {
-      // @ts-ignore
-      return copyObj({}, unref(defaultOption), classOption);
-    });
-
-    let leftSwitchClass = computed(() => {
-      return unref(leftSwitchState) ? "" : unref(options).switchDisabledClass;
-    });
-
-    let rightSwitchClass = computed(() => {
-      return unref(rightSwitchState) ? "" : unref(options).switchDisabledClass;
-    });
-
-    let leftSwitch = computed(() => {
-      return {
-        position: "absolute",
-        margin: `${unref(height) / 2}px 0 0 -${unref(options).switchOffset}px`,
-        transform: "translate(-100%,-50%)"
-      };
-    });
-
-    let rightSwitch = computed(() => {
-      return {
-        position: "absolute",
-        margin: `${unref(height) / 2}px 0 0 ${
-          unref(width) + unref(options).switchOffset
-        }px`,
-        transform: "translateY(-50%)"
-      };
-    });
-
-    let isHorizontal = computed(() => {
-      return (
-        unref(options).direction !== "bottom" &&
-        unref(options).direction !== "top"
-      );
-    });
-
-    let float = computed(() => {
-      return unref(isHorizontal)
-        ? { float: "left", overflow: "hidden" }
-        : { overflow: "hidden" };
-    });
-
-    let pos = computed(() => {
-      return {
-        transform: `translate(${unref(xPos)}px,${unref(yPos)}px)`,
-        transition: `all ${ease} ${unref(delay)}ms`,
-        overflow: "hidden"
-      };
-    });
-
-    let navigation = computed(() => {
-      return unref(options).navigation;
-    });
-
-    let autoPlay = computed(() => {
-      if (unref(navigation)) return false;
-      return unref(options).autoPlay;
-    });
-
-    let scrollSwitch = computed(() => {
-      // 从 props 解构出来的 属性 不再具有相应性.
-      return props.data.length >= unref(options).limitMoveNum;
-    });
-
-    let hoverStopSwitch = computed(() => {
-      return unref(options).hoverStop && unref(autoPlay) && unref(scrollSwitch);
-    });
-
-    let canTouchScroll = computed(() => {
-      return unref(options).openTouch;
-    });
-
-    let baseFontSize = computed(() => {
-      return unref(options).isSingleRemUnit
-        ? parseInt(
-            window.getComputedStyle(document.documentElement, null).fontSize
-          )
-        : 1;
-    });
-
-    let realSingleStopWidth = computed(() => {
-      return unref(options).singleWidth * unref(baseFontSize);
-    });
-
-    let realSingleStopHeight = computed(() => {
-      return unref(options).singleHeight * unref(baseFontSize);
-    });
-
-    let step = computed(() => {
-      let singleStep;
-      let step = unref(options).step;
-      if (unref(isHorizontal)) {
-        singleStep = unref(realSingleStopWidth);
-      } else {
-        singleStep = unref(realSingleStopHeight);
-      }
-      if (singleStep > 0 && singleStep % step > 0) {
-        throw "如果设置了单步滚动,step需是单步大小的约数,否则无法保证单步滚动结束的位置是否准确";
-      }
-      return step;
-    });
-
-    function reset() {
-      xPos.value = 0;
-      yPos.value = 0;
-      scrollCancle();
-      scrollInitMove();
-    }
-
-    function leftSwitchClick() {
-      if (!unref(leftSwitchState)) return;
-      // 小于单步距离
-      if (Math.abs(unref(xPos)) < unref(options).switchSingleStep) {
-        xPos.value = 0;
-        return;
-      }
-      xPos.value += unref(options).switchSingleStep;
-    }
-
-    function rightSwitchClick() {
-      if (!unref(rightSwitchState)) return;
-      // 小于单步距离
-      if (
-        unref(realBoxWidth) - unref(width) + unref(xPos) <
-        unref(options).switchSingleStep
-      ) {
-        xPos.value = unref(width) - unref(realBoxWidth);
-        return;
-      }
-      xPos.value -= unref(options).switchSingleStep;
-    }
-
-    function scrollCancle() {
-      cancelAnimationFrame(reqFrame || "");
-    }
-
-    function touchStart(e) {
-      if (!unref(canTouchScroll)) return;
-      let timer;
-      //touches数组对象获得屏幕上所有的touch,取第一个touch
-      const touch = e.targetTouches[0];
-      const { waitTime, singleHeight, singleWidth } = unref(options);
-      //取第一个touch的坐标值
-      startPos = {
-        x: touch.pageX,
-        y: touch.pageY
-      };
-      //记录touchStart时候的posY
-      startPosY = unref(yPos);
-      //记录touchStart时候的posX
-      startPosX = unref(xPos);
-      if (!!singleHeight && !!singleWidth) {
-        if (timer) clearTimeout(timer);
-        timer = setTimeout(() => {
-          scrollCancle();
-        }, waitTime + 20);
-      } else {
-        scrollCancle();
-      }
-    }
-
-    function touchMove(e) {
-      //当屏幕有多个touch或者页面被缩放过,就不执行move操作
-      if (
-        !unref(canTouchScroll) ||
-        e.targetTouches.length > 1 ||
-        (e.scale && e.scale !== 1)
-      )
-        return;
-      const touch = e.targetTouches[0];
-      const { direction } = unref(options);
-      let endPos = {
-        x: touch.pageX - startPos.x,
-        y: touch.pageY - startPos.y
-      };
-      //阻止触摸事件的默认行为,即阻止滚屏
-      e.preventDefault();
-      //dir,1表示纵向滑动,0为横向滑动
-      const dir = Math.abs(endPos.x) < Math.abs(endPos.y) ? 1 : 0;
-      if (
-        (dir === 1 && direction === "bottom") ||
-        (dir === 1 && direction === "top")
-      ) {
-        // 表示纵向滑动 && 运动方向为上下
-        yPos.value = startPosY + endPos.y;
-      } else if (
-        (dir === 0 && direction === "left") ||
-        (dir === 0 && direction === "right")
-      ) {
-        // 为横向滑动 && 运动方向为左右
-        xPos.value = startPosX + endPos.x;
-      }
-    }
-
-    function touchEnd() {
-      if (!unref(canTouchScroll)) return;
-      let timer;
-      const direction = unref(options).direction;
-      delay.value = 50;
-      if (direction === "top") {
-        if (unref(yPos) > 0) yPos.value = 0;
-      } else if (direction === "bottom") {
-        let h = (unref(realBoxHeight) / 2) * -1;
-        if (unref(yPos) < h) yPos.value = h;
-      } else if (direction === "left") {
-        if (unref(xPos) > 0) xPos.value = 0;
-      } else if (direction === "right") {
-        let w = unref(realBoxWidth) * -1;
-        if (unref(xPos) < w) xPos.value = w;
-      }
-      if (timer) clearTimeout(timer);
-      timer = setTimeout(() => {
-        delay.value = 0;
-        scrollMove();
-      }, unref(delay));
-    }
-
-    function enter() {
-      if (unref(hoverStopSwitch)) scrollStopMove();
-    }
-
-    function leave() {
-      if (unref(hoverStopSwitch)) scrollStartMove();
-    }
-
-    function scrollMove() {
-      // 鼠标移入时拦截scrollMove()
-      if (isHover) return;
-      //进入move立即先清除动画 防止频繁touchMove导致多动画同时进行
-      // scrollCancle();
-      reqFrame = requestAnimationFrame(function () {
-        //实际高度
-        const h = unref(realBoxHeight) / 2;
-        //宽度
-        const w = unref(realBoxWidth) / 2;
-        let { direction, waitTime } = unref(options);
-        if (direction === "top") {
-          // 上
-          if (Math.abs(unref(yPos)) >= h) {
-            emit("ScrollEnd");
-            yPos.value = 0;
-          }
-          yPos.value -= step.value;
-        } else if (direction === "bottom") {
-          // 下
-          if (unref(yPos) >= 0) {
-            emit("ScrollEnd");
-            yPos.value = h * -1;
-          }
-          yPos.value += step.value;
-        } else if (direction === "left") {
-          // 左
-          if (Math.abs(unref(xPos)) >= w) {
-            emit("ScrollEnd");
-            xPos.value = 0;
-          }
-          xPos.value -= step.value;
-        } else if (direction === "right") {
-          // 右
-          if (unref(xPos) >= 0) {
-            emit("ScrollEnd");
-            xPos.value = w * -1;
-          }
-          xPos.value += step.value;
-        }
-        if (singleWaitTime) clearTimeout(singleWaitTime);
-        if (unref(realSingleStopHeight)) {
-          //是否启动了单行暂停配置
-          if (
-            Math.abs(unref(yPos)) % unref(realSingleStopHeight) <
-            unref(step)
-          ) {
-            // 符合条件暂停waitTime
-            singleWaitTime = setTimeout(() => {
-              scrollMove();
-            }, waitTime);
-          } else {
-            scrollMove();
-          }
-        } else if (unref(realSingleStopWidth)) {
-          if (
-            Math.abs(unref(xPos)) % unref(realSingleStopWidth) <
-            unref(step)
-          ) {
-            // 符合条件暂停waitTime
-            singleWaitTime = setTimeout(() => {
-              scrollMove();
-            }, waitTime);
-          } else {
-            scrollMove();
-          }
-        } else {
-          scrollMove();
-        }
-      });
-    }
-
-    function scrollInitMove() {
-      nextTick(() => {
-        const { switchDelay } = unref(options);
-        //清空copy
-        copyHtml.value = "";
-        if (unref(isHorizontal)) {
-          height.value = unref(wrap).offsetHeight;
-          width.value = unref(wrap).offsetWidth;
-          let slotListWidth = unref(slotList).offsetWidth;
-          // 水平滚动设置warp width
-          if (unref(autoPlay)) {
-            // 修正offsetWidth四舍五入
-            slotListWidth = slotListWidth * 2 + 1;
-          }
-          unref(realBox).style.width = slotListWidth + "px";
-          realBoxWidth.value = slotListWidth;
-        }
-
-        if (unref(autoPlay)) {
-          ease = "ease-in";
-          delay.value = 0;
-        } else {
-          ease = "linear";
-          delay.value = switchDelay;
-          return;
-        }
-
-        // 是否可以滚动判断
-        if (unref(scrollSwitch)) {
-          let timer;
-          if (timer) clearTimeout(timer);
-          copyHtml.value = unref(slotList).innerHTML;
-          setTimeout(() => {
-            realBoxHeight.value = unref(realBox).offsetHeight;
-            scrollMove();
-          }, 0);
-        } else {
-          scrollCancle();
-          yPos.value = xPos.value = 0;
-        }
-      });
-    }
-
-    function scrollStartMove() {
-      //开启scrollMove
-      isHover = false;
-      scrollMove();
-    }
-
-    function scrollStopMove() {
-      //关闭scrollMove
-      isHover = true;
-      // 防止频频hover进出单步滚动,导致定时器乱掉
-      if (singleWaitTime) clearTimeout(singleWaitTime);
-      scrollCancle();
-    }
-
-    // watchEffect(() => {
-    //   const watchData = data;
-    //   if (!watchData) return;
-    //   nextTick(() => {
-    //     reset();
-    //   });
-
-    //   const watchAutoPlay = unref(autoPlay);
-    //   if (watchAutoPlay) {
-    //     reset();
-    //   } else {
-    //     scrollStopMove();
-    //   }
-    // });
-
-    // 鼠标滚轮事件
-    function wheel(e) {
-      e.preventDefault();
-      if (
-        unref(options).direction === "left" ||
-        unref(options).direction === "right"
-      )
-        return;
-      useDebounceFn(() => {
-        e.deltaY > 0 ? (yPos.value -= step.value) : (yPos.value += step.value);
-      }, 50)();
-    }
-
-    tryOnMounted(() => {
-      scrollInitMove();
-    });
-
-    tryOnUnmounted(() => {
-      scrollCancle();
-      clearTimeout(singleWaitTime);
-    });
-
-    return {
-      xPos,
-      yPos,
-      delay,
-      copyHtml,
-      height,
-      width,
-      realBoxWidth,
-      leftSwitchState,
-      rightSwitchState,
-      options,
-      leftSwitchClass,
-      rightSwitchClass,
-      leftSwitch,
-      rightSwitch,
-      isHorizontal,
-      float,
-      pos,
-      navigation,
-      autoPlay,
-      scrollSwitch,
-      hoverStopSwitch,
-      canTouchScroll,
-      baseFontSize,
-      realSingleStopWidth,
-      realSingleStopHeight,
-      step,
-      reset,
-      leftSwitchClick,
-      rightSwitchClick,
-      scrollCancle,
-      touchStart,
-      touchMove,
-      touchEnd,
-      enter,
-      leave,
-      scrollMove,
-      scrollInitMove,
-      scrollStartMove,
-      scrollStopMove,
-      wheel
-    };
-  }
-});
-</script>

+ 1 - 1
src/components/ReSeamlessScroll/src/utils.ts

@@ -2,7 +2,7 @@
  * @desc AnimationFrame简单兼容hack
  */
 export const animationFrame = () => {
-  window.cancelAnimationFrame = (function () {
+  window.cancelAnimationFrame = (() => {
     return (
       window.cancelAnimationFrame ||
       window.webkitCancelAnimationFrame ||

+ 1 - 1
tsconfig.json

@@ -24,7 +24,7 @@
       "/#/*": ["types/*"]
     },
     "types": ["node", "vite/client"],
-    "typeRoots": ["./node_modules/@types/", "./types"]
+    "typeRoots": ["./node_modules/@types/", "./types", "./vue-types"]
   },
   "include": [
     "src/**/*.ts",

+ 7 - 6
types/global.d.ts

@@ -20,13 +20,14 @@ declare global {
     // Global vue app instance
     __APP__: App<Element>;
     webkitCancelAnimationFrame: (handle: number) => void;
+    mozCancelAnimationFrame: (handle: number) => void;
+    oCancelAnimationFrame: (handle: number) => void;
+    msCancelAnimationFrame: (handle: number) => void;
+
     webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number;
-    mozCancelAnimationFrame: (id?: string) => any;
-    oCancelAnimationFrame: (id?: string) => any;
-    msCancelAnimationFrame: (id?: string) => any;
-    mozRequestAnimationFrame: (id?: string) => any;
-    oRequestAnimationFrame: (id?: string) => any;
-    msRequestAnimationFrame: (id?: string) => any;
+    mozRequestAnimationFrame: (callback: FrameRequestCallback) => number;
+    oRequestAnimationFrame: (callback: FrameRequestCallback) => number;
+    msRequestAnimationFrame: (callback: FrameRequestCallback) => number;
   }
 
   // vue

+ 4 - 0
types/index.d.ts

@@ -25,3 +25,7 @@ declare type ComponentRef<T extends HTMLElement = HTMLDivElement> =
   ComponentElRef<T> | null;
 
 declare type ElRef<T extends HTMLElement = HTMLDivElement> = Nullable<T>;
+
+declare type ForDataType<T> = {
+  [P in T]?: ForDataType<T[P]>;
+};

+ 112 - 12
yarn.lock

@@ -786,6 +786,17 @@
     estree-walker "^2.0.2"
     source-map "^0.6.1"
 
+"@vue/compiler-core@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.12.tgz#23998d6986a45e1ab0424130cc0ad00e33da1101"
+  integrity sha512-IGJ0JmrAaAl5KBBegPAKkoXvsfDFgN/h7K1t/+0MxqpZF1fTDVUOp3tG7q9gWa7fwzGEaIsPhjtT5C3qztdLKg==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@babel/types" "^7.15.0"
+    "@vue/shared" "3.2.12"
+    estree-walker "^2.0.2"
+    source-map "^0.6.1"
+
 "@vue/compiler-dom@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.11.tgz#d066f8e1f1812b4e881593819ade0fe6d654c776"
@@ -794,7 +805,15 @@
     "@vue/compiler-core" "3.2.11"
     "@vue/shared" "3.2.11"
 
-"@vue/compiler-sfc@^3.0.11", "@vue/compiler-sfc@^3.2.11":
+"@vue/compiler-dom@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.12.tgz#d6ba00114e73adb8b18940c3ff18797cc2b0514f"
+  integrity sha512-MulvKilA2USm8ubPfvXvNY55HVTn+zHERsXeNg437TXrmM4FRCis6zjWW47QZ3ZyxEkCdqOmuiFCtXbpnuthyw==
+  dependencies:
+    "@vue/compiler-core" "3.2.12"
+    "@vue/shared" "3.2.12"
+
+"@vue/compiler-sfc@^3.0.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.11.tgz#628fa12238760d9b9b339ac2e125a759224fadbf"
   integrity sha512-cUIaS8mgJrQ6yucj2AupWAwBRITK3W/a8wCOn9g5fJGtOl8h4APY8vN3lzP8HIJDyEeRF3I8SfRhL+oX97kSnw==
@@ -818,6 +837,30 @@
     postcss-selector-parser "^6.0.4"
     source-map "^0.6.1"
 
+"@vue/compiler-sfc@^3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.12.tgz#39555550d96051508753ba934f7260dc5ee5211e"
+  integrity sha512-EjzeMQ7H2ICj+JRw2buSFXTocdCg8e5yWQTlNM/6h/u68sTwMbIfiOJBFEwBhG/wCG7Nb6Nnz888AfHTU3hdrA==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@babel/types" "^7.15.0"
+    "@types/estree" "^0.0.48"
+    "@vue/compiler-core" "3.2.12"
+    "@vue/compiler-dom" "3.2.12"
+    "@vue/compiler-ssr" "3.2.12"
+    "@vue/ref-transform" "3.2.12"
+    "@vue/shared" "3.2.12"
+    consolidate "^0.16.0"
+    estree-walker "^2.0.2"
+    hash-sum "^2.0.0"
+    lru-cache "^5.1.1"
+    magic-string "^0.25.7"
+    merge-source-map "^1.1.0"
+    postcss "^8.1.10"
+    postcss-modules "^4.0.0"
+    postcss-selector-parser "^6.0.4"
+    source-map "^0.6.1"
+
 "@vue/compiler-ssr@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.11.tgz#702cef3429651645bdbe09fe5962803b5a621abb"
@@ -826,6 +869,14 @@
     "@vue/compiler-dom" "3.2.11"
     "@vue/shared" "3.2.11"
 
+"@vue/compiler-ssr@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.12.tgz#32e5d4bc31c371c125b43e9d07b8a8f70442b080"
+  integrity sha512-sY+VbLQ17FPr1CgirnqEgY+jbC7wI5c2Ma6u8le0+b4UKMYF9urI2pybAZc1nKz6O78FWA3OSnQFxTTLppe+9Q==
+  dependencies:
+    "@vue/compiler-dom" "3.2.12"
+    "@vue/shared" "3.2.12"
+
 "@vue/devtools-api@^6.0.0-beta.13", "@vue/devtools-api@^6.0.0-beta.14", "@vue/devtools-api@^6.0.0-beta.15":
   version "6.0.0-beta.15"
   resolved "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.0.0-beta.15.tgz#ad7cb384e062f165bcf9c83732125bffbc2ad83d"
@@ -852,6 +903,13 @@
   dependencies:
     "@vue/shared" "3.2.11"
 
+"@vue/reactivity@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.12.tgz#b482a737cbdc891f9b1ec3100f3c1804b56d080b"
+  integrity sha512-Lr5CTQjFm5mT/6DGnVNhptmba/Qg1DbD6eNWWmiHLMlpPt4q2ww9A2orEjVw0qNcdTJ04JLPEVAz5jhTZTCfIg==
+  dependencies:
+    "@vue/shared" "3.2.12"
+
 "@vue/ref-transform@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.11.tgz#4d282b9570d1485a73e7bf5d57cce27b4a7aa690"
@@ -863,6 +921,17 @@
     estree-walker "^2.0.2"
     magic-string "^0.25.7"
 
+"@vue/ref-transform@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/ref-transform/-/ref-transform-3.2.12.tgz#6f7fa46dd84447ddcf54adfb1b689b1cf4243de0"
+  integrity sha512-lS7TDda61iSf3ljokXVfN0VbOsQdmpST6MZLjxzBydFCECCJaEAr6o+K8VZ7NhUCSrl+gKXHpdXxmcvwdk66aQ==
+  dependencies:
+    "@babel/parser" "^7.15.0"
+    "@vue/compiler-core" "3.2.12"
+    "@vue/shared" "3.2.12"
+    estree-walker "^2.0.2"
+    magic-string "^0.25.7"
+
 "@vue/runtime-core@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.11.tgz#0dbe801be4bd0bfde253226797e7d304c8fdda30"
@@ -871,6 +940,14 @@
     "@vue/reactivity" "3.2.11"
     "@vue/shared" "3.2.11"
 
+"@vue/runtime-core@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.12.tgz#422662fd5b85f787222d2aea840264ba97e84a13"
+  integrity sha512-LO+ztgcmsomavYUaSq7BTteh8pmnUmvUnXUFVYdlcg3VCdYRS0ImlclpYsNHqjAk2gU+H09dr2PP0kL961xUfQ==
+  dependencies:
+    "@vue/reactivity" "3.2.12"
+    "@vue/shared" "3.2.12"
+
 "@vue/runtime-dom@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.11.tgz#04f9054a9e64bdf156c2fc22cad67cfaa8b84616"
@@ -880,17 +957,31 @@
     "@vue/shared" "3.2.11"
     csstype "^2.6.8"
 
+"@vue/runtime-dom@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.12.tgz#d9fe865dca36f9ca33ba327afdeb89ae2aa03f4c"
+  integrity sha512-+NSDqivgihvoPYbKFDmzFu1tW7SOzwc7r0b7T8vsJtooVPGxwtfAFZ6wyLtteOXXrCpyTR3kpyTCIp31uY7aJg==
+  dependencies:
+    "@vue/runtime-core" "3.2.12"
+    "@vue/shared" "3.2.12"
+    csstype "^2.6.8"
+
 "@vue/shared@3.2.11":
   version "3.2.11"
   resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.11.tgz#01899f54949caf1ac241de397bd17069632574de"
   integrity sha512-ovfXAsSsCvV9JVceWjkqC/7OF5HbgLOtCWjCIosmPGG8lxbPuavhIxRH1dTx4Dg9xLgRTNLvI3pVxG4ItQZekg==
 
-"@vueuse/core@^6.0.0":
-  version "6.3.3"
-  resolved "https://registry.npmjs.org/@vueuse/core/-/core-6.3.3.tgz#0682c01b50d28e91d3d76f27278600ee1692fa24"
-  integrity sha512-qa/0WYqcvqFKQmlkgsLGlXBrYcQeUi3fzHMIaxsD/lO/zm0IWBSN8CTFu91LwER5qNYs4DGhU5pu7jOdrTzAIQ==
+"@vue/shared@3.2.12":
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.12.tgz#304064a4b56fc6c7b9169d80e9ee62ecb4bf0a1c"
+  integrity sha512-5CkaifUCJwcTuru7FDwKFacPJuEoGUTw0LKSa5bw40B23s0TS+MGlYR1285nbV/ju3QUGlA6d6PD+GJkWy7uFg==
+
+"@vueuse/core@^6.4.1":
+  version "6.4.1"
+  resolved "https://registry.npmjs.org/@vueuse/core/-/core-6.4.1.tgz#21416997a23bfb4924a5082ed6fa959027f80d04"
+  integrity sha512-FRFeEPVq77gcMZP0mCloJY+lyHJaUQmUMaPp5fBds3fs/BbkAt7HTMMizFKHWDVjbmA20vBOjmC9tTnfD+DdEA==
   dependencies:
-    "@vueuse/shared" "6.3.3"
+    "@vueuse/shared" "6.4.1"
     vue-demi "*"
 
 "@vueuse/core@~6.1.0":
@@ -908,10 +999,10 @@
   dependencies:
     vue-demi "*"
 
-"@vueuse/shared@6.3.3":
-  version "6.3.3"
-  resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-6.3.3.tgz#4e5c600ad1ed5bf2a8630ad0bd38edb1f4269f37"
-  integrity sha512-2+YPRhFNUXEhhvKNTWBtNU6hGkft9+mfYSVjI4hZu2U8KDbNNKF/215lBPzMYI2twScDtPsAssQ+vu5t9PBy0g==
+"@vueuse/shared@6.4.1":
+  version "6.4.1"
+  resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-6.4.1.tgz#5bc84be107cead84e11c21d2c57b1e9f2c376975"
+  integrity sha512-zsaYxxZwACQbMmGg+UBjPUVemi325sDdnnB0mn+PNizE0fVC57B+vbLgdj45NBmr6P4nw6a0Y2rMupebwDWsdw==
   dependencies:
     vue-demi "*"
 
@@ -4498,14 +4589,14 @@ vue-router@^4.0.11:
   dependencies:
     "@vue/devtools-api" "^6.0.0-beta.14"
 
-vue-types@^4.0.3:
+vue-types@^4.1.0:
   version "4.1.0"
   resolved "https://registry.npmjs.org/vue-types/-/vue-types-4.1.0.tgz#8dcbbaccf9d5c3815449ac7cb8ae5864454cfff0"
   integrity sha512-oPAeKKx5vY5Q8c7lMQPQyrBIbmWQGael5XEHqO1f+Y3V/RUZNuISz7KxI4woGjh79Vy/gDDaPX9j9zKYpaaA2g==
   dependencies:
     is-plain-object "5.0.0"
 
-vue@^3.1.1, vue@^3.2.11:
+vue@^3.1.1:
   version "3.2.11"
   resolved "https://registry.npmjs.org/vue/-/vue-3.2.11.tgz#6b92295048df705ddac558fd3e3ed553e55e57c8"
   integrity sha512-JkI3/eIgfk4E0f/p319TD3EZgOwBQfftgnkRsXlT7OrRyyiyoyUXn6embPGZXSBxD3LoZ9SWhJoxLhFh5AleeA==
@@ -4514,6 +4605,15 @@ vue@^3.1.1, vue@^3.2.11:
     "@vue/runtime-dom" "3.2.11"
     "@vue/shared" "3.2.11"
 
+vue@^3.2.12:
+  version "3.2.12"
+  resolved "https://registry.npmjs.org/vue/-/vue-3.2.12.tgz#b44f55506fb6a7c4b65635e609deb5f9368aa2ce"
+  integrity sha512-VV14HtubmB56uuQaSvLkJZgoocPiN8CJI3zZA9y8h7q/Z5hcknDIFkbq5d8ku0ukZ6AJPQqMsZWcq0qryF0jgg==
+  dependencies:
+    "@vue/compiler-dom" "3.2.12"
+    "@vue/runtime-dom" "3.2.12"
+    "@vue/shared" "3.2.12"
+
 vuedraggable@^4.1.0:
   version "4.1.0"
   resolved "https://registry.npmjs.org/vuedraggable/-/vuedraggable-4.1.0.tgz#edece68adb8a4d9e06accff9dfc9040e66852270"