mirror of
				https://github.com/pure-admin/vue-pure-admin.git
				synced 2025-11-03 13:44:47 +08:00 
			
		
		
		
	
						commit
						dd8cc8508e
					
				
							
								
								
									
										29
									
								
								.eslintrc.js
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								.eslintrc.js
									
									
									
									
									
								
							@ -3,6 +3,35 @@ module.exports = {
 | 
			
		||||
  env: {
 | 
			
		||||
    node: true
 | 
			
		||||
  },
 | 
			
		||||
  globals: {
 | 
			
		||||
    // Ref sugar (take 2)
 | 
			
		||||
    $: "readonly",
 | 
			
		||||
    $$: "readonly",
 | 
			
		||||
    $ref: "readonly",
 | 
			
		||||
    $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",
 | 
			
		||||
    ComponentRoutes: "readonly",
 | 
			
		||||
 | 
			
		||||
    // script setup
 | 
			
		||||
    defineProps: "readonly",
 | 
			
		||||
    defineEmits: "readonly",
 | 
			
		||||
    defineExpose: "readonly",
 | 
			
		||||
    withDefaults: "readonly"
 | 
			
		||||
  },
 | 
			
		||||
  extends: [
 | 
			
		||||
    "plugin:vue/vue3-essential",
 | 
			
		||||
    "eslint:recommended",
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
    <link rel="stylesheet" href="/iconfont.css" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>后台管理系统</title>
 | 
			
		||||
    <script src="https://cdn.bootcdn.net/ajax/libs/Sortable/1.13.0/Sortable.js"></script>
 | 
			
		||||
    <script src="/sortable.min.js"></script>
 | 
			
		||||
    <script>
 | 
			
		||||
      window.process = {};
 | 
			
		||||
    </script>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								package.json
									
									
									
									
									
								
							@ -8,20 +8,20 @@
 | 
			
		||||
    "build": "rimraf dist && cross-env vite build",
 | 
			
		||||
    "preview": "vite preview",
 | 
			
		||||
    "preview:build": "yarn build && vite preview",
 | 
			
		||||
    "clean:cache": "rm -rf node_modules && 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/",
 | 
			
		||||
    "lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
 | 
			
		||||
    "lint:pretty": "pretty-quick --staged",
 | 
			
		||||
    "lint:all": "yarn lint:eslint && yarn lint:prettier && yarn lint:stylelint && yarn lint:pretty",
 | 
			
		||||
    "lint": "yarn lint:eslint && yarn lint:prettier && yarn lint:stylelint && yarn lint:pretty",
 | 
			
		||||
    "prepare": "husky install"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@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",
 | 
			
		||||
@ -41,12 +41,13 @@
 | 
			
		||||
    "pinia": "^2.0.0-rc.6",
 | 
			
		||||
    "resize-observer-polyfill": "^1.5.1",
 | 
			
		||||
    "responsive-storage": "^1.0.9",
 | 
			
		||||
    "sortablejs": "1.13.0",
 | 
			
		||||
    "v-contextmenu": "^3.0.0",
 | 
			
		||||
    "vue": "^3.2.11",
 | 
			
		||||
    "vue": "3.2.11",
 | 
			
		||||
    "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",
 | 
			
		||||
@ -65,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.11",
 | 
			
		||||
    "@vue/eslint-config-prettier": "^6.0.0",
 | 
			
		||||
    "@vue/eslint-config-typescript": "^7.0.0",
 | 
			
		||||
    "autoprefixer": "^10.2.4",
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2607
									
								
								public/sortable.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2607
									
								
								public/sortable.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										41
									
								
								src/App.vue
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								src/App.vue
									
									
									
									
									
								
							@ -1,28 +1,25 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-config-provider :locale="currentLocale">
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </el-config-provider>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { getCurrentInstance } from "vue";
 | 
			
		||||
import { ElConfigProvider } from "element-plus";
 | 
			
		||||
import zhCn from "element-plus/lib/locale/lang/zh-cn";
 | 
			
		||||
import en from "element-plus/lib/locale/lang/en";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "app",
 | 
			
		||||
  components: {
 | 
			
		||||
    [ElConfigProvider.name]: ElConfigProvider
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    // eslint-disable-next-line vue/return-in-computed-property
 | 
			
		||||
    currentLocale() {
 | 
			
		||||
      switch (this.$storage.locale?.locale) {
 | 
			
		||||
        case "zh":
 | 
			
		||||
          return zhCn;
 | 
			
		||||
        case "en":
 | 
			
		||||
          return en;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
let locale: string =
 | 
			
		||||
  getCurrentInstance().appContext.config.globalProperties.$storage?.locale
 | 
			
		||||
    ?.locale;
 | 
			
		||||
 | 
			
		||||
let currentLocale = () => {
 | 
			
		||||
  switch (locale) {
 | 
			
		||||
    case "zh":
 | 
			
		||||
      return zhCn;
 | 
			
		||||
    case "en":
 | 
			
		||||
      return en;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <el-config-provider :locale="currentLocale()">
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </el-config-provider>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import type { CSSProperties } from "vue";
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  defineComponent,
 | 
			
		||||
  onBeforeMount,
 | 
			
		||||
@ -40,46 +39,48 @@ const defaultOptions: Cropper.Options = {
 | 
			
		||||
  rotatable: true
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Cropper",
 | 
			
		||||
  props: {
 | 
			
		||||
    src: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      required: true
 | 
			
		||||
    },
 | 
			
		||||
    alt: {
 | 
			
		||||
      type: String
 | 
			
		||||
    },
 | 
			
		||||
    width: {
 | 
			
		||||
      type: [String, Number],
 | 
			
		||||
      default: ""
 | 
			
		||||
    },
 | 
			
		||||
    height: {
 | 
			
		||||
      type: [String, Number],
 | 
			
		||||
      default: "360px"
 | 
			
		||||
    },
 | 
			
		||||
    crossorigin: {
 | 
			
		||||
      type: String || Object,
 | 
			
		||||
      default: undefined
 | 
			
		||||
    },
 | 
			
		||||
    imageStyle: {
 | 
			
		||||
      type: Object as PropType<CSSProperties>,
 | 
			
		||||
      default() {
 | 
			
		||||
        return {};
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    options: {
 | 
			
		||||
      type: Object as PropType<Options>,
 | 
			
		||||
      default() {
 | 
			
		||||
        return {};
 | 
			
		||||
      }
 | 
			
		||||
const props = {
 | 
			
		||||
  src: {
 | 
			
		||||
    type: String,
 | 
			
		||||
    required: true
 | 
			
		||||
  },
 | 
			
		||||
  alt: {
 | 
			
		||||
    type: String
 | 
			
		||||
  },
 | 
			
		||||
  width: {
 | 
			
		||||
    type: [String, Number],
 | 
			
		||||
    default: ""
 | 
			
		||||
  },
 | 
			
		||||
  height: {
 | 
			
		||||
    type: [String, Number],
 | 
			
		||||
    default: "360px"
 | 
			
		||||
  },
 | 
			
		||||
  crossorigin: {
 | 
			
		||||
    type: String || Object,
 | 
			
		||||
    default: undefined
 | 
			
		||||
  },
 | 
			
		||||
  imageStyle: {
 | 
			
		||||
    type: Object as PropType<CSSProperties>,
 | 
			
		||||
    default() {
 | 
			
		||||
      return {};
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  options: {
 | 
			
		||||
    type: Object as PropType<Options>,
 | 
			
		||||
    default() {
 | 
			
		||||
      return {};
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Cropper",
 | 
			
		||||
  props,
 | 
			
		||||
  setup(props) {
 | 
			
		||||
    const cropper: any = ref<Nullable<Cropper>>(null);
 | 
			
		||||
    const imgElRef = templateRef<HTMLImageElement | null>("imgElRef", null);
 | 
			
		||||
 | 
			
		||||
    const isReady = ref(false);
 | 
			
		||||
    const isReady = ref<boolean>(false);
 | 
			
		||||
 | 
			
		||||
    const getImageStyle = computed((): CSSProperties => {
 | 
			
		||||
      return {
 | 
			
		||||
 | 
			
		||||
@ -2,19 +2,21 @@ import { defineComponent, ref } from "vue";
 | 
			
		||||
import { propTypes } from "/@/utils/propTypes";
 | 
			
		||||
import "./filpper.css";
 | 
			
		||||
 | 
			
		||||
const props = {
 | 
			
		||||
  // front paper text
 | 
			
		||||
  // 前牌文字
 | 
			
		||||
  frontText: propTypes.number.def(0),
 | 
			
		||||
  // back paper text
 | 
			
		||||
  // 后牌文字
 | 
			
		||||
  backText: propTypes.number.def(1),
 | 
			
		||||
  // flipping duration, please be consistent with the CSS animation-duration value.
 | 
			
		||||
  // 翻牌动画时间,与CSS中设置的animation-duration保持一致
 | 
			
		||||
  duration: propTypes.number.def(600)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Filpper",
 | 
			
		||||
  props: {
 | 
			
		||||
    // front paper text
 | 
			
		||||
    // 前牌文字
 | 
			
		||||
    frontText: propTypes.number.def(0),
 | 
			
		||||
    // back paper text
 | 
			
		||||
    // 后牌文字
 | 
			
		||||
    backText: propTypes.number.def(1),
 | 
			
		||||
    // flipping duration, please be consistent with the CSS animation-duration value.
 | 
			
		||||
    // 翻牌动画时间,与CSS中设置的animation-duration保持一致
 | 
			
		||||
    duration: propTypes.number.def(600)
 | 
			
		||||
  },
 | 
			
		||||
  props,
 | 
			
		||||
  setup(props) {
 | 
			
		||||
    // eslint-disable-next-line vue/no-setup-props-destructure
 | 
			
		||||
    const { frontText, backText, duration } = props;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,109 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, unref, nextTick, onUnmounted } from "vue";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import flippers from "./Filpper";
 | 
			
		||||
 | 
			
		||||
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 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 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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
nextTick(() => {
 | 
			
		||||
  flipObjs.value = [
 | 
			
		||||
    unref(flipperHour1),
 | 
			
		||||
    unref(flipperHour2),
 | 
			
		||||
    unref(flipperMinute1),
 | 
			
		||||
    unref(flipperMinute2),
 | 
			
		||||
    unref(flipperSecond1),
 | 
			
		||||
    unref(flipperSecond2)
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  init();
 | 
			
		||||
  run();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onUnmounted(() => {
 | 
			
		||||
  if (timer.value) {
 | 
			
		||||
    clearInterval(timer.value);
 | 
			
		||||
    timer.value = null;
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="flip-clock">
 | 
			
		||||
    <flippers ref="flipperHour1" />
 | 
			
		||||
@ -11,147 +117,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref, unref, nextTick, onUnmounted } from "vue";
 | 
			
		||||
import flippers from "./Filpper";
 | 
			
		||||
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "Flop",
 | 
			
		||||
  components: {
 | 
			
		||||
    flippers
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    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 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 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);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      flipObjs.value = [
 | 
			
		||||
        unref(flipperHour1),
 | 
			
		||||
        unref(flipperHour2),
 | 
			
		||||
        unref(flipperMinute1),
 | 
			
		||||
        unref(flipperMinute2),
 | 
			
		||||
        unref(flipperSecond1),
 | 
			
		||||
        unref(flipperSecond2)
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      init();
 | 
			
		||||
      run();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    onUnmounted(() => {
 | 
			
		||||
      if (timer.value) {
 | 
			
		||||
        clearInterval(timer.value);
 | 
			
		||||
        timer.value = null;
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      timer,
 | 
			
		||||
      flipObjs,
 | 
			
		||||
      init,
 | 
			
		||||
      run,
 | 
			
		||||
      formatDate,
 | 
			
		||||
      padLeftZero,
 | 
			
		||||
      flipperHour1,
 | 
			
		||||
      flipperHour2,
 | 
			
		||||
      flipperMinute1,
 | 
			
		||||
      flipperMinute2,
 | 
			
		||||
      flipperSecond1,
 | 
			
		||||
      flipperSecond2
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
.flip-clock .m-flipper {
 | 
			
		||||
  margin: 0 3px;
 | 
			
		||||
 | 
			
		||||
@ -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";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,25 @@
 | 
			
		||||
<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="['hamburger', props.isActive ? 'is-active' : '']"
 | 
			
		||||
      viewBox="0 0 1024 1024"
 | 
			
		||||
      xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
      width="64"
 | 
			
		||||
@ -15,26 +32,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 +46,7 @@ export default defineComponent({
 | 
			
		||||
  height: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.hamburger.is-active {
 | 
			
		||||
.is-active {
 | 
			
		||||
  transform: rotate(180deg);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,99 @@
 | 
			
		||||
<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 => {
 | 
			
		||||
  // @ts-expect-error
 | 
			
		||||
  instance.refs.ruleForm.validate((valid: boolean) => {
 | 
			
		||||
    if (valid) {
 | 
			
		||||
      emit("onBehavior", evt);
 | 
			
		||||
    } else {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 刷新验证码
 | 
			
		||||
const refreshVerify = (): void => {
 | 
			
		||||
  emit("refreshVerify");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 表单重置
 | 
			
		||||
const resetForm = (): void => {
 | 
			
		||||
  // @ts-expect-error
 | 
			
		||||
  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 +143,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,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
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
let MarkerCluster;
 | 
			
		||||
let map: MapConfigureInter;
 | 
			
		||||
 | 
			
		||||
    const mapSet: mapInter = reactive({
 | 
			
		||||
      loading: deviceDetection() ? false : true
 | 
			
		||||
const instance = getCurrentInstance();
 | 
			
		||||
 | 
			
		||||
const mapSet: mapInter = reactive({
 | 
			
		||||
  loading: deviceDetection() ? false : true
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 地图创建完成(动画关闭)
 | 
			
		||||
const complete = (): void => {
 | 
			
		||||
  if (map) {
 | 
			
		||||
    map.on("complete", () => {
 | 
			
		||||
      mapSet.loading = false;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    // 地图创建完成(动画关闭)
 | 
			
		||||
    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;
 | 
			
		||||
 | 
			
		||||
    // 销毁地图实例
 | 
			
		||||
    const destroyMap = (): void => {
 | 
			
		||||
      if (map) {
 | 
			
		||||
        map.destroy() && map.clearEvents("click");
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
  AMapLoader.load({
 | 
			
		||||
    key: MapConfigure.amapKey,
 | 
			
		||||
    version: "2.0",
 | 
			
		||||
    plugins: ["AMap.MarkerCluster"]
 | 
			
		||||
  })
 | 
			
		||||
    .then(AMap => {
 | 
			
		||||
      // 创建地图实例
 | 
			
		||||
      map = new AMap.Map(instance.refs.mapview, options);
 | 
			
		||||
 | 
			
		||||
    onBeforeMount(() => {
 | 
			
		||||
      if (!instance) return;
 | 
			
		||||
      let { MapConfigure } =
 | 
			
		||||
        instance.appContext.config.globalProperties.$config;
 | 
			
		||||
      let { options } = MapConfigure;
 | 
			
		||||
      //地图中添加地图操作ToolBar插件
 | 
			
		||||
      map.plugin(["AMap.ToolBar", "AMap.MapType"], () => {
 | 
			
		||||
        map.addControl(new AMap.ToolBar());
 | 
			
		||||
        //地图类型切换
 | 
			
		||||
        map.addControl(
 | 
			
		||||
          new AMap.MapType({
 | 
			
		||||
            defaultType: 0
 | 
			
		||||
          })
 | 
			
		||||
        );
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      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>` //设置文本标注内容
 | 
			
		||||
                });
 | 
			
		||||
                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(err => {
 | 
			
		||||
              console.log("err:", err);
 | 
			
		||||
      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);
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
          complete();
 | 
			
		||||
      // 获取模拟车辆信息
 | 
			
		||||
      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);
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...toRefs(mapSet),
 | 
			
		||||
      complete,
 | 
			
		||||
      destroyMap,
 | 
			
		||||
      greenCar
 | 
			
		||||
    };
 | 
			
		||||
      complete();
 | 
			
		||||
    })
 | 
			
		||||
    .catch(() => {
 | 
			
		||||
      mapSet.loading = false;
 | 
			
		||||
      throw "地图加载失败,请重新加载";
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
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%;
 | 
			
		||||
 | 
			
		||||
@ -1,14 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
export default {
 | 
			
		||||
  name: "BaiduMap",
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -2,7 +2,7 @@
 | 
			
		||||
 * @desc AnimationFrame简单兼容hack
 | 
			
		||||
 */
 | 
			
		||||
export const animationFrame = () => {
 | 
			
		||||
  window.cancelAnimationFrame = (function () {
 | 
			
		||||
  window.cancelAnimationFrame = (() => {
 | 
			
		||||
    return (
 | 
			
		||||
      window.cancelAnimationFrame ||
 | 
			
		||||
      window.webkitCancelAnimationFrame ||
 | 
			
		||||
 | 
			
		||||
@ -21,35 +21,37 @@ let overList = [];
 | 
			
		||||
// 存放第一个选中的元素和最后一个选中元素,只能存放这两个元素
 | 
			
		||||
let selectedList = [];
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Selector",
 | 
			
		||||
  props: {
 | 
			
		||||
    HsKey: {
 | 
			
		||||
      type: Number || String,
 | 
			
		||||
      default: 0
 | 
			
		||||
    },
 | 
			
		||||
    disabled: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false
 | 
			
		||||
    },
 | 
			
		||||
    value: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      default: 0
 | 
			
		||||
    },
 | 
			
		||||
    max: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      default() {
 | 
			
		||||
        return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    // 回显数据的索引,长度必须是2
 | 
			
		||||
    echo: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      default() {
 | 
			
		||||
        return [];
 | 
			
		||||
      }
 | 
			
		||||
const props = {
 | 
			
		||||
  HsKey: {
 | 
			
		||||
    type: Number || String,
 | 
			
		||||
    default: 0
 | 
			
		||||
  },
 | 
			
		||||
  disabled: {
 | 
			
		||||
    type: Boolean,
 | 
			
		||||
    default: false
 | 
			
		||||
  },
 | 
			
		||||
  value: {
 | 
			
		||||
    type: Number,
 | 
			
		||||
    default: 0
 | 
			
		||||
  },
 | 
			
		||||
  max: {
 | 
			
		||||
    type: Array,
 | 
			
		||||
    default() {
 | 
			
		||||
      return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  // 回显数据的索引,长度必须是2
 | 
			
		||||
  echo: {
 | 
			
		||||
    type: Array,
 | 
			
		||||
    default() {
 | 
			
		||||
      return [];
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "Selector",
 | 
			
		||||
  props,
 | 
			
		||||
  emits: ["selectedVal"],
 | 
			
		||||
  setup(props, { emit }) {
 | 
			
		||||
    const instance = getCurrentInstance();
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
let config: object = {};
 | 
			
		||||
 | 
			
		||||
const setConfig = (cfg?: any) => {
 | 
			
		||||
const setConfig = (cfg?: unknown) => {
 | 
			
		||||
  config = Object.assign(config, cfg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,9 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { useFullscreen } from "@vueuse/core";
 | 
			
		||||
 | 
			
		||||
const { isFullscreen, toggle } = useFullscreen();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="screen-full" @click="toggle">
 | 
			
		||||
    <i
 | 
			
		||||
@ -15,23 +21,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { useFullscreen } from "@vueuse/core";
 | 
			
		||||
import { defineComponent } from "vue";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "screenfull",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const { isFullscreen, toggle } = useFullscreen();
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      isFullscreen,
 | 
			
		||||
      toggle
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.screen-full {
 | 
			
		||||
  width: 40px;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/main.ts
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/main.ts
									
									
									
									
									
								
							@ -1,19 +1,17 @@
 | 
			
		||||
import { createApp, Directive } from "vue";
 | 
			
		||||
import App from "./App.vue";
 | 
			
		||||
import router from "./router";
 | 
			
		||||
import { setupStore } from "/@/store";
 | 
			
		||||
 | 
			
		||||
import { useElementPlus } from "../src/plugins/element-plus";
 | 
			
		||||
import { useTable } from "../src/plugins/vxe-table";
 | 
			
		||||
import { createApp, Directive } from "vue";
 | 
			
		||||
import { usI18n } from "../src/plugins/i18n";
 | 
			
		||||
import { useTable } from "../src/plugins/vxe-table";
 | 
			
		||||
import { useElementPlus } from "../src/plugins/element-plus";
 | 
			
		||||
 | 
			
		||||
import "animate.css";
 | 
			
		||||
// 导入公共样式
 | 
			
		||||
import "./style/index.scss";
 | 
			
		||||
// 导入字体图标
 | 
			
		||||
import "./assets/iconfont/iconfont.js";
 | 
			
		||||
import "./assets/iconfont/iconfont.css";
 | 
			
		||||
import "animate.css";
 | 
			
		||||
 | 
			
		||||
import "v-contextmenu/dist/themes/default.css";
 | 
			
		||||
 | 
			
		||||
import { setConfig, getConfig } from "./config";
 | 
			
		||||
@ -25,7 +23,7 @@ app.config.globalProperties.$config = getConfig();
 | 
			
		||||
 | 
			
		||||
// 响应式storage
 | 
			
		||||
import Storage from "responsive-storage";
 | 
			
		||||
 | 
			
		||||
// @ts-ignore
 | 
			
		||||
app.use(Storage, {
 | 
			
		||||
  // 默认显示首页tag
 | 
			
		||||
  routesInStorage: {
 | 
			
		||||
@ -58,7 +56,7 @@ Object.keys(directives).forEach(key => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 获取项目动态全局配置
 | 
			
		||||
export const getServerConfig = async (): Promise<any> => {
 | 
			
		||||
export const getServerConfig = async (): Promise<undefined> => {
 | 
			
		||||
  return axios({
 | 
			
		||||
    baseURL: "",
 | 
			
		||||
    method: "get",
 | 
			
		||||
@ -87,10 +85,7 @@ export const getServerConfig = async (): Promise<any> => {
 | 
			
		||||
 | 
			
		||||
getServerConfig().then(async () => {
 | 
			
		||||
  setupStore(app);
 | 
			
		||||
 | 
			
		||||
  app.use(router).use(useElementPlus).use(useTable).use(usI18n);
 | 
			
		||||
 | 
			
		||||
  await router.isReady();
 | 
			
		||||
 | 
			
		||||
  app.mount("#app");
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ import enVxeTable from "vxe-table/lib/locale/lang/en-US";
 | 
			
		||||
import enLocale from "element-plus/lib/locale/lang/en";
 | 
			
		||||
import zhLocale from "element-plus/lib/locale/lang/zh-cn";
 | 
			
		||||
 | 
			
		||||
// 导航菜单配置
 | 
			
		||||
export const menusConfig = {
 | 
			
		||||
  zh: {
 | 
			
		||||
    message: {
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import "xe-utils";
 | 
			
		||||
import { App } from "vue";
 | 
			
		||||
import { i18n } from "../i18n/index";
 | 
			
		||||
import "font-awesome/css/font-awesome.css";
 | 
			
		||||
import "xe-utils";
 | 
			
		||||
import {
 | 
			
		||||
  // 核心
 | 
			
		||||
  VXETable,
 | 
			
		||||
@ -62,6 +62,7 @@ VXETable.setup({
 | 
			
		||||
    clearable: true
 | 
			
		||||
  },
 | 
			
		||||
  // 对组件内置的提示语进行国际化翻译
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  i18n: (key, args) => i18n.global.t(key, args),
 | 
			
		||||
  // 可选,对参数中的列头、校验提示..等进行自动翻译(只对支持国际化的有效)
 | 
			
		||||
  translate(key, args) {
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,11 @@
 | 
			
		||||
import { createRouter, createWebHashHistory, Router } from "vue-router";
 | 
			
		||||
import {
 | 
			
		||||
  createRouter,
 | 
			
		||||
  createWebHashHistory,
 | 
			
		||||
  Router,
 | 
			
		||||
  RouteComponent
 | 
			
		||||
} from "vue-router";
 | 
			
		||||
 | 
			
		||||
import Layout from "/@/layout/index.vue";
 | 
			
		||||
import homeRouter from "./modules/home";
 | 
			
		||||
import flowChartRouter from "./modules/flowchart";
 | 
			
		||||
import editorRouter from "./modules/editor";
 | 
			
		||||
@ -9,17 +15,15 @@ import errorRouter from "./modules/error";
 | 
			
		||||
import externalLink from "./modules/externalLink";
 | 
			
		||||
import remainingRouter from "./modules/remaining"; //静态路由
 | 
			
		||||
 | 
			
		||||
import { storageSession } from "../utils/storage";
 | 
			
		||||
import { i18n } from "/@/plugins/i18n";
 | 
			
		||||
import { getAsyncRoutes } from "/@/api/routes";
 | 
			
		||||
import { storageSession } from "../utils/storage";
 | 
			
		||||
import { usePermissionStoreHook } from "/@/store/modules/permission";
 | 
			
		||||
 | 
			
		||||
import { getAsyncRoutes } from "/@/api/routes";
 | 
			
		||||
 | 
			
		||||
import Layout from "/@/layout/index.vue";
 | 
			
		||||
// https://cn.vitejs.dev/guide/features.html#glob-import
 | 
			
		||||
const modulesRoutes = import.meta.glob("/src/views/*/*/*.vue");
 | 
			
		||||
 | 
			
		||||
const constantRoutes: Array<any> = [
 | 
			
		||||
const constantRoutes: Array<RouteComponent> = [
 | 
			
		||||
  homeRouter,
 | 
			
		||||
  flowChartRouter,
 | 
			
		||||
  editorRouter,
 | 
			
		||||
@ -125,8 +129,10 @@ const whiteList = ["/login", "/register"];
 | 
			
		||||
router.beforeEach((to, _from, next) => {
 | 
			
		||||
  const name = storageSession.getItem("info");
 | 
			
		||||
  NProgress.start();
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  const { t } = i18n.global;
 | 
			
		||||
  to.meta.title ? (document.title = t(to.meta.title)) : ""; // 动态title
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  to.meta.title ? (document.title = t(to.meta.title)) : "";
 | 
			
		||||
  if (name) {
 | 
			
		||||
    if (_from?.name) {
 | 
			
		||||
      next();
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,6 @@ class algorithmProxy implements ProxyAlgorithm {
 | 
			
		||||
    return Object.keys(val)
 | 
			
		||||
      .map(v => {
 | 
			
		||||
        return {
 | 
			
		||||
          // @ts-ignore
 | 
			
		||||
          ...val[v],
 | 
			
		||||
          key: v
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,8 @@ import { excludeProps } from "./utils";
 | 
			
		||||
 */
 | 
			
		||||
export const defaultConfig: AxiosRequestConfig = {
 | 
			
		||||
  baseURL: "",
 | 
			
		||||
  timeout: 10000, //10秒超时
 | 
			
		||||
  //10秒超时
 | 
			
		||||
  timeout: 10000,
 | 
			
		||||
  headers: {
 | 
			
		||||
    Accept: "application/json, text/plain, */*",
 | 
			
		||||
    "Content-Type": "application/json",
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,12 @@
 | 
			
		||||
export const hasClass = (ele: Element, cls: string): any => {
 | 
			
		||||
export const hasClass = (ele: RefType<any>, cls: string): any => {
 | 
			
		||||
  return !!ele.className.match(new RegExp("(\\s|^)" + cls + "(\\s|$)"));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const addClass = (ele: Element, cls: string, extracls?: string): any => {
 | 
			
		||||
export const addClass = (
 | 
			
		||||
  ele: RefType<any>,
 | 
			
		||||
  cls: string,
 | 
			
		||||
  extracls?: string
 | 
			
		||||
): any => {
 | 
			
		||||
  if (!hasClass(ele, cls)) ele.className += " " + cls;
 | 
			
		||||
  if (extracls) {
 | 
			
		||||
    if (!hasClass(ele, extracls)) ele.className += " " + extracls;
 | 
			
		||||
@ -10,7 +14,7 @@ export const addClass = (ele: Element, cls: string, extracls?: string): any => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const removeClass = (
 | 
			
		||||
  ele: Element,
 | 
			
		||||
  ele: RefType<any>,
 | 
			
		||||
  cls: string,
 | 
			
		||||
  extracls?: string
 | 
			
		||||
): any => {
 | 
			
		||||
@ -29,7 +33,7 @@ export const removeClass = (
 | 
			
		||||
export const toggleClass = (
 | 
			
		||||
  flag: boolean,
 | 
			
		||||
  clsName: string,
 | 
			
		||||
  target?: HTMLElement
 | 
			
		||||
  target?: RefType<any>
 | 
			
		||||
): any => {
 | 
			
		||||
  const targetEl = target || document.body;
 | 
			
		||||
  let { className } = targetEl;
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,16 @@ import NProgress from "nprogress";
 | 
			
		||||
import "nprogress/nprogress.css";
 | 
			
		||||
 | 
			
		||||
NProgress.configure({
 | 
			
		||||
  easing: "ease", // 动画方式
 | 
			
		||||
  speed: 500, // 递增进度条的速度
 | 
			
		||||
  showSpinner: true, // 是否显示加载ico
 | 
			
		||||
  trickleSpeed: 200, // 自动递增间隔
 | 
			
		||||
  minimum: 0.3 // 初始化时的最小百分比
 | 
			
		||||
  // 动画方式
 | 
			
		||||
  easing: "ease",
 | 
			
		||||
  // 递增进度条的速度
 | 
			
		||||
  speed: 500,
 | 
			
		||||
  // 是否显示加载ico
 | 
			
		||||
  showSpinner: true,
 | 
			
		||||
  // 自动递增间隔
 | 
			
		||||
  trickleSpeed: 200,
 | 
			
		||||
  // 初始化时的最小百分比
 | 
			
		||||
  minimum: 0.3
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default NProgress;
 | 
			
		||||
 | 
			
		||||
@ -30,4 +30,5 @@ propTypes.extend([
 | 
			
		||||
    type: undefined
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export { propTypes };
 | 
			
		||||
 | 
			
		||||
@ -1,24 +1,17 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
 | 
			
		||||
const url = ref(
 | 
			
		||||
  process.env.NODE_ENV === "production"
 | 
			
		||||
    ? "/manages/html/button.html"
 | 
			
		||||
    : "/html/button.html"
 | 
			
		||||
);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <iframe :src="url" frameborder="0" class="iframe"></iframe>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reButton",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const url = ref(
 | 
			
		||||
      process.env.NODE_ENV === "production"
 | 
			
		||||
        ? "/manages/html/button.html"
 | 
			
		||||
        : "/html/button.html"
 | 
			
		||||
    );
 | 
			
		||||
    return {
 | 
			
		||||
      url
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.iframe {
 | 
			
		||||
  width: 98%;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,9 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import basic from "./basic.vue";
 | 
			
		||||
import menuGroup from "./menuGroup.vue";
 | 
			
		||||
import menuDynamic from "./menuDynamic.vue";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div style="margin: 10px">
 | 
			
		||||
    <el-row :gutter="24">
 | 
			
		||||
@ -16,20 +22,3 @@
 | 
			
		||||
    </el-row>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import basic from "./basic.vue";
 | 
			
		||||
import menuGroup from "./menuGroup.vue";
 | 
			
		||||
import menuDynamic from "./menuDynamic.vue";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reContextmenu",
 | 
			
		||||
  components: {
 | 
			
		||||
    basic,
 | 
			
		||||
    menuGroup,
 | 
			
		||||
    menuDynamic
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,7 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div style="margin: 10px">
 | 
			
		||||
    <el-row :gutter="24">
 | 
			
		||||
@ -30,21 +34,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reCountTo",
 | 
			
		||||
  components: {
 | 
			
		||||
    ReNormalCountTo,
 | 
			
		||||
    ReboundCountTo
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.flex {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,29 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, nextTick, getCurrentInstance } from "vue";
 | 
			
		||||
import Cropper from "/@/components/ReCropper";
 | 
			
		||||
import img from "./picture.jpeg";
 | 
			
		||||
 | 
			
		||||
const instance = getCurrentInstance();
 | 
			
		||||
let info = ref<object>(null);
 | 
			
		||||
let cropperImg = ref<string>("");
 | 
			
		||||
 | 
			
		||||
const onCropper = (): void => {
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    // @ts-expect-error
 | 
			
		||||
    instance.refs.refCropper.cropper.getCroppedCanvas().toBlob(blob => {
 | 
			
		||||
      let fileReader: FileReader = new FileReader();
 | 
			
		||||
      fileReader.onloadend = (e: ProgressEvent) => {
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        cropperImg.value = e.target.result;
 | 
			
		||||
        // @ts-expect-error
 | 
			
		||||
        info.value = instance.refs.refCropper.cropper.getData();
 | 
			
		||||
      };
 | 
			
		||||
      fileReader.readAsDataURL(blob);
 | 
			
		||||
    }, "image/jpeg");
 | 
			
		||||
  });
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div style="margin: 10px">
 | 
			
		||||
    <div class="cropper-container">
 | 
			
		||||
@ -9,44 +35,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref, nextTick, getCurrentInstance } from "vue";
 | 
			
		||||
import Cropper from "/@/components/ReCropper";
 | 
			
		||||
import img from "./picture.jpeg";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reCropping",
 | 
			
		||||
  components: {
 | 
			
		||||
    Cropper
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const instance = getCurrentInstance();
 | 
			
		||||
    let info = ref("");
 | 
			
		||||
    let cropperImg = ref("");
 | 
			
		||||
 | 
			
		||||
    const onCropper = (): void => {
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        instance.refs.refCropper.cropper.getCroppedCanvas().toBlob(blob => {
 | 
			
		||||
          let fileReader: FileReader = new FileReader();
 | 
			
		||||
          fileReader.onloadend = (e: any) => {
 | 
			
		||||
            cropperImg.value = e.target.result;
 | 
			
		||||
            info.value = instance.refs.refCropper.cropper.getData();
 | 
			
		||||
          };
 | 
			
		||||
          fileReader.readAsDataURL(blob);
 | 
			
		||||
        }, "image/jpeg");
 | 
			
		||||
      });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      img,
 | 
			
		||||
      info,
 | 
			
		||||
      cropperImg,
 | 
			
		||||
      onCropper
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.cropper-container {
 | 
			
		||||
  display: flex;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,51 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, onMounted } from "vue";
 | 
			
		||||
import draggable from "vuedraggable/src/vuedraggable";
 | 
			
		||||
 | 
			
		||||
let gridLists = ref<Array<Object>>([
 | 
			
		||||
  { grid: "cn", num: 1 },
 | 
			
		||||
  { grid: "cn", num: 2 },
 | 
			
		||||
  { grid: "cn", num: 3 },
 | 
			
		||||
  { grid: "cn", num: 4 },
 | 
			
		||||
  { grid: "cn", num: 5 },
 | 
			
		||||
  { grid: "cn", num: 6 },
 | 
			
		||||
  { grid: "cn", num: 7 },
 | 
			
		||||
  { grid: "cn", num: 8 },
 | 
			
		||||
  { grid: "cn", num: 9 }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
let lists = ref<Array<Object>>([
 | 
			
		||||
  { people: "cn", id: 1, name: "www.itxst.com" },
 | 
			
		||||
  { people: "cn", id: 2, name: "www.baidu.com" },
 | 
			
		||||
  { people: "cn", id: 3, name: "www.taobao.com" },
 | 
			
		||||
  { people: "cn", id: 4, name: "www.google.com" }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
let cutLists = ref<Array<Object>>([
 | 
			
		||||
  { people: "cn", id: 1, name: "cut1" },
 | 
			
		||||
  { people: "cn", id: 2, name: "cut2" },
 | 
			
		||||
  { people: "cn", id: 3, name: "cut3" },
 | 
			
		||||
  { people: "cn", id: 4, name: "cut4" }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
const change = (evt): void => {
 | 
			
		||||
  console.log("evt: ", evt);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  // 使用原生sortable实现元素位置切换
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  // eslint-disable-next-line no-undef
 | 
			
		||||
  new Sortable(document.querySelector(".cut-container"), {
 | 
			
		||||
    swap: true,
 | 
			
		||||
    forceFallback: true,
 | 
			
		||||
    chosenClass: "chosen",
 | 
			
		||||
    swapClass: "highlight",
 | 
			
		||||
    animation: 300
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="drag-container">
 | 
			
		||||
    <!-- grid列表拖拽 -->
 | 
			
		||||
@ -72,64 +120,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import draggable from "vuedraggable/src/vuedraggable";
 | 
			
		||||
import { reactive, toRefs, onMounted } from "vue";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reDraggable",
 | 
			
		||||
  components: { draggable },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const myArray = reactive({
 | 
			
		||||
      gridLists: [
 | 
			
		||||
        { grid: "cn", num: 1 },
 | 
			
		||||
        { grid: "cn", num: 2 },
 | 
			
		||||
        { grid: "cn", num: 3 },
 | 
			
		||||
        { grid: "cn", num: 4 },
 | 
			
		||||
        { grid: "cn", num: 5 },
 | 
			
		||||
        { grid: "cn", num: 6 },
 | 
			
		||||
        { grid: "cn", num: 7 },
 | 
			
		||||
        { grid: "cn", num: 8 },
 | 
			
		||||
        { grid: "cn", num: 9 }
 | 
			
		||||
      ],
 | 
			
		||||
      lists: [
 | 
			
		||||
        { people: "cn", id: 1, name: "www.itxst.com" },
 | 
			
		||||
        { people: "cn", id: 2, name: "www.baidu.com" },
 | 
			
		||||
        { people: "cn", id: 3, name: "www.taobao.com" },
 | 
			
		||||
        { people: "cn", id: 4, name: "www.google.com" }
 | 
			
		||||
      ],
 | 
			
		||||
      cutLists: [
 | 
			
		||||
        { people: "cn", id: 1, name: "cut1" },
 | 
			
		||||
        { people: "cn", id: 2, name: "cut2" },
 | 
			
		||||
        { people: "cn", id: 3, name: "cut3" },
 | 
			
		||||
        { people: "cn", id: 4, name: "cut4" }
 | 
			
		||||
      ]
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const change = (evt): void => {
 | 
			
		||||
      console.log("evt: ", evt);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      // 使用原生sortable实现元素位置切换
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
      // eslint-disable-next-line no-undef
 | 
			
		||||
      new Sortable(document.querySelector(".cut-container"), {
 | 
			
		||||
        swap: true,
 | 
			
		||||
        forceFallback: true,
 | 
			
		||||
        chosenClass: "chosen",
 | 
			
		||||
        swapClass: "highlight",
 | 
			
		||||
        animation: 300
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...toRefs(myArray),
 | 
			
		||||
      change
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
/* grid列表拖拽 */
 | 
			
		||||
.grid-container {
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,13 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { Amap } from "/@/components/ReMap";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="map">
 | 
			
		||||
    <Amap />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { Amap } from "/@/components/ReMap";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reMap",
 | 
			
		||||
  components: {
 | 
			
		||||
    Amap
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.map {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,51 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, unref } from "vue";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import SeamlessScroll from "/@/components/ReSeamlessScroll";
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line no-undef
 | 
			
		||||
const scroll = templateRef<ElRef | null>("scroll", null);
 | 
			
		||||
 | 
			
		||||
let listData = ref<Array<Object>>([
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第一行无缝滚动第一行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第二行无缝滚动第二行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第三行无缝滚动第三行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第四行无缝滚动第四行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第五行无缝滚动第五行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第六行无缝滚动第六行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第七行无缝滚动第七行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第八行无缝滚动第八行!!!!!!!!!!"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "无缝滚动第九行无缝滚动第九行!!!!!!!!!!"
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
let classOption = ref<Object>({
 | 
			
		||||
  direction: "top"
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function changeDirection(val) {
 | 
			
		||||
  unref(scroll).reset();
 | 
			
		||||
  unref(classOption).direction = val;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <el-space wrap>
 | 
			
		||||
    <el-card class="box-card">
 | 
			
		||||
@ -60,68 +108,6 @@
 | 
			
		||||
  </el-space>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref, unref } from "vue";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
 | 
			
		||||
import SeamlessScroll from "/@/components/ReSeamlessScroll";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reSeamlessScroll",
 | 
			
		||||
  components: {
 | 
			
		||||
    SeamlessScroll
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    // eslint-disable-next-line no-undef
 | 
			
		||||
    const scroll = templateRef<ElRef | null>("scroll", null);
 | 
			
		||||
 | 
			
		||||
    let listData = ref([
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第一行无缝滚动第一行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第二行无缝滚动第二行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第三行无缝滚动第三行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第四行无缝滚动第四行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第五行无缝滚动第五行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第六行无缝滚动第六行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第七行无缝滚动第七行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第八行无缝滚动第八行!!!!!!!!!!"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "无缝滚动第九行无缝滚动第九行!!!!!!!!!!"
 | 
			
		||||
      }
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    let classOption = ref({
 | 
			
		||||
      direction: "top"
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function changeDirection(val) {
 | 
			
		||||
      unref(scroll).reset();
 | 
			
		||||
      unref(classOption).direction = val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      listData,
 | 
			
		||||
      classOption,
 | 
			
		||||
      changeDirection
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.box-card {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,26 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import Selector from "/@/components/ReSelector";
 | 
			
		||||
 | 
			
		||||
let selectRange = ref<string>("");
 | 
			
		||||
let dataLists = ref<Array<Object>>([
 | 
			
		||||
  {
 | 
			
		||||
    title: "基本使用",
 | 
			
		||||
    echo: [],
 | 
			
		||||
    disabled: false
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    title: "回显模式",
 | 
			
		||||
    echo: [2, 7],
 | 
			
		||||
    disabled: true
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
const selectedVal = ({ left, right }): void => {
 | 
			
		||||
  selectRange.value = `${left}-${right}`;
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <el-card
 | 
			
		||||
@ -21,38 +44,3 @@
 | 
			
		||||
    </el-card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import Selector from "/@/components/ReSelector";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reSelector",
 | 
			
		||||
  components: { Selector },
 | 
			
		||||
  setup() {
 | 
			
		||||
    let selectRange = ref(null);
 | 
			
		||||
    let dataLists = ref([
 | 
			
		||||
      {
 | 
			
		||||
        title: "基本使用",
 | 
			
		||||
        echo: [],
 | 
			
		||||
        disabled: false
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        title: "回显模式",
 | 
			
		||||
        echo: [2, 7],
 | 
			
		||||
        disabled: true
 | 
			
		||||
      }
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const selectedVal = ({ left, right }) => {
 | 
			
		||||
      selectRange.value = `${left}-${right}`;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      selectedVal,
 | 
			
		||||
      selectRange,
 | 
			
		||||
      dataLists
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,20 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import splitpane, { ContextProps } from "/@/components/ReSplitPane";
 | 
			
		||||
import { reactive } from "vue";
 | 
			
		||||
 | 
			
		||||
const settingLR: ContextProps = reactive({
 | 
			
		||||
  minPercent: 20,
 | 
			
		||||
  defaultPercent: 40,
 | 
			
		||||
  split: "vertical"
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const settingTB: ContextProps = reactive({
 | 
			
		||||
  minPercent: 20,
 | 
			
		||||
  defaultPercent: 40,
 | 
			
		||||
  split: "horizontal"
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="split-pane">
 | 
			
		||||
    <splitpane :splitSet="settingLR">
 | 
			
		||||
@ -22,35 +39,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import splitpane, { ContextProps } from "/@/components/ReSplitPane";
 | 
			
		||||
import { reactive } from "vue";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reSplitPane",
 | 
			
		||||
  components: {
 | 
			
		||||
    splitpane
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const settingLR: ContextProps = reactive({
 | 
			
		||||
      minPercent: 20,
 | 
			
		||||
      defaultPercent: 40,
 | 
			
		||||
      split: "vertical"
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const settingTB: ContextProps = reactive({
 | 
			
		||||
      minPercent: 20,
 | 
			
		||||
      defaultPercent: 40,
 | 
			
		||||
      split: "horizontal"
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      settingLR,
 | 
			
		||||
      settingTB
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
$W: 100%;
 | 
			
		||||
$H: 80vh;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,4 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div id="mse"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { onMounted } from "vue";
 | 
			
		||||
import Player from "xgplayer/dist/simple_player";
 | 
			
		||||
import volume from "xgplayer/dist/controls/volume";
 | 
			
		||||
@ -10,28 +6,27 @@ import playbackRate from "xgplayer/dist/controls/playbackRate";
 | 
			
		||||
import screenShot from "xgplayer/dist/controls/screenShot";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reVideo",
 | 
			
		||||
  setup() {
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      new Player({
 | 
			
		||||
        id: "mse",
 | 
			
		||||
        autoplay: false,
 | 
			
		||||
        screenShot: true,
 | 
			
		||||
        url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
 | 
			
		||||
        poster:
 | 
			
		||||
          "https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
 | 
			
		||||
        fluid: deviceDetection(),
 | 
			
		||||
        controlPlugins: [volume, playbackRate, screenShot],
 | 
			
		||||
        playbackRate: [0.5, 0.75, 1, 1.5, 2] //传入倍速可选数组
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  new Player({
 | 
			
		||||
    id: "mse",
 | 
			
		||||
    autoplay: false,
 | 
			
		||||
    screenShot: true,
 | 
			
		||||
    url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
 | 
			
		||||
    poster:
 | 
			
		||||
      "https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
 | 
			
		||||
    fluid: deviceDetection(),
 | 
			
		||||
    controlPlugins: [volume, playbackRate, screenShot],
 | 
			
		||||
    //传入倍速可选数组
 | 
			
		||||
    playbackRate: [0.5, 0.75, 1, 1.5, 2]
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
<template>
 | 
			
		||||
  <div id="mse"></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
#mse {
 | 
			
		||||
  flex: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,47 +1,40 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reEditor"
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { onMounted, onBeforeUnmount, ref, unref } from "vue";
 | 
			
		||||
import WangEditor from "wangeditor";
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line no-undef
 | 
			
		||||
const editor = ref(null);
 | 
			
		||||
const html = ref(null);
 | 
			
		||||
let instance: WangEditor;
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  instance = new WangEditor(unref(editor));
 | 
			
		||||
  Object.assign(instance.config, {
 | 
			
		||||
    onchange() {
 | 
			
		||||
      html.value = instance.txt.html();
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  instance.create();
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onBeforeUnmount(() => {
 | 
			
		||||
  instance.destroy();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <div ref="editor"></div>
 | 
			
		||||
    <div :innerHTML="content.html"></div>
 | 
			
		||||
    <div :innerHTML="html"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { onMounted, onBeforeUnmount, ref, reactive } from "vue";
 | 
			
		||||
import WangEditor from "wangeditor";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reEditor",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const editor = ref();
 | 
			
		||||
    const content = reactive({
 | 
			
		||||
      html: "",
 | 
			
		||||
      text: ""
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let instance;
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      instance = new WangEditor(editor.value);
 | 
			
		||||
      Object.assign(instance.config, {
 | 
			
		||||
        onchange() {
 | 
			
		||||
          content.html = instance.txt.html();
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      instance.create();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    onBeforeUnmount(() => {
 | 
			
		||||
      instance.destroy();
 | 
			
		||||
      instance = null;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      editor,
 | 
			
		||||
      content
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
:deep(.w-e-text-container) {
 | 
			
		||||
  z-index: 99 !important;
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,16 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import imgs from "/@/assets/401.gif";
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
 | 
			
		||||
const img = ref(`${imgs}?${new Date()}`);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="errPage-container">
 | 
			
		||||
    <el-row>
 | 
			
		||||
      <el-col :span="12">
 | 
			
		||||
        <h1 class="text-jumbo text-ginormous">CURD Admin</h1>
 | 
			
		||||
        <h1 class="text-jumbo text-ginormous">Pure Admin</h1>
 | 
			
		||||
        <h2>你没有权限去该页面</h2>
 | 
			
		||||
        <h6>如有不满请联系你领导</h6>
 | 
			
		||||
      </el-col>
 | 
			
		||||
      <el-col :span="12">
 | 
			
		||||
        <img
 | 
			
		||||
@ -18,20 +24,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import imgs from "/@/assets/401.gif";
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "401",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const img = ref(`${imgs}?${new Date()}`);
 | 
			
		||||
    return {
 | 
			
		||||
      img
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.errPage-container {
 | 
			
		||||
  width: 800px;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,13 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import four from "/@/assets/404.png";
 | 
			
		||||
import four_cloud from "/@/assets/404_cloud.png";
 | 
			
		||||
 | 
			
		||||
const message = computed(() => {
 | 
			
		||||
  return "The webmaster said that you can not enter this page...";
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="wscn-http404-container">
 | 
			
		||||
    <div class="wscn-http404">
 | 
			
		||||
@ -8,7 +18,7 @@
 | 
			
		||||
        <img class="pic-404__child right" :src="four_cloud" alt="404" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="bullshit">
 | 
			
		||||
        <div class="bullshit__oops">CURD Admin</div>
 | 
			
		||||
        <div class="bullshit__oops">Pure Admin</div>
 | 
			
		||||
        <div class="bullshit__headline">{{ message }}</div>
 | 
			
		||||
        <div class="bullshit__info">
 | 
			
		||||
          Please check that the URL you entered is correct, or click the button
 | 
			
		||||
@ -20,26 +30,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { computed } from "vue";
 | 
			
		||||
import four from "/@/assets/404.png";
 | 
			
		||||
import four_cloud from "/@/assets/404_cloud.png";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "404",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const message = computed(() => {
 | 
			
		||||
      return "The webmaster said that you can not enter this page...";
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      message,
 | 
			
		||||
      four,
 | 
			
		||||
      four_cloud
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.wscn-http404-container {
 | 
			
		||||
  transform: translate(-50%, -50%);
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,61 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, unref, onMounted } from "vue";
 | 
			
		||||
import LogicFlow from "@logicflow/core";
 | 
			
		||||
import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
 | 
			
		||||
import "@logicflow/core/dist/style/index.css";
 | 
			
		||||
import "@logicflow/extension/lib/style/index.css";
 | 
			
		||||
import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
 | 
			
		||||
import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
 | 
			
		||||
import { BpmnNode } from "/@/components/ReFlowChart/src/config";
 | 
			
		||||
import demoData from "./dataTurbo.json";
 | 
			
		||||
 | 
			
		||||
let lf = ref(null);
 | 
			
		||||
let graphData = ref(null);
 | 
			
		||||
let dataVisible = ref<boolean>(false);
 | 
			
		||||
let config = ref({
 | 
			
		||||
  grid: true,
 | 
			
		||||
  background: {
 | 
			
		||||
    color: "#f7f9ff"
 | 
			
		||||
  },
 | 
			
		||||
  keyboard: {
 | 
			
		||||
    enabled: true
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
let nodeList = BpmnNode;
 | 
			
		||||
 | 
			
		||||
function initLf() {
 | 
			
		||||
  // 画布配置
 | 
			
		||||
  LogicFlow.use(Snapshot);
 | 
			
		||||
  // 使用bpmn插件,引入bpmn元素,这些元素可以在turbo中转换后使用
 | 
			
		||||
  LogicFlow.use(BpmnElement);
 | 
			
		||||
  // 启动右键菜单
 | 
			
		||||
  LogicFlow.use(Menu);
 | 
			
		||||
  const domLf = new LogicFlow({
 | 
			
		||||
    ...unref(config),
 | 
			
		||||
    container: document.querySelector("#LF-Turbo")
 | 
			
		||||
  });
 | 
			
		||||
  lf.value = domLf;
 | 
			
		||||
  // 设置边类型bpmn:sequenceFlow为默认类型
 | 
			
		||||
  unref(lf).setDefaultEdgeType("bpmn:sequenceFlow");
 | 
			
		||||
  onRender();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onRender() {
 | 
			
		||||
  // Turbo数据转换为LogicFlow内部识别的数据结构
 | 
			
		||||
  const lFData = toLogicflowData(demoData);
 | 
			
		||||
  lf.value.render(lFData);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function catData() {
 | 
			
		||||
  graphData.value = unref(lf).getGraphData();
 | 
			
		||||
  dataVisible.value = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  initLf();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="logic-flow-view">
 | 
			
		||||
    <!-- 辅助工具栏 -->
 | 
			
		||||
@ -19,80 +77,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref, unref, onMounted } from "vue";
 | 
			
		||||
import LogicFlow from "@logicflow/core";
 | 
			
		||||
import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
 | 
			
		||||
import "@logicflow/core/dist/style/index.css";
 | 
			
		||||
import "@logicflow/extension/lib/style/index.css";
 | 
			
		||||
import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
 | 
			
		||||
 | 
			
		||||
import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
 | 
			
		||||
import { BpmnNode } from "/@/components/ReFlowChart/src/config";
 | 
			
		||||
import demoData from "./dataTurbo.json";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "reFlowChart",
 | 
			
		||||
  components: { NodePanel, Control, DataDialog },
 | 
			
		||||
  setup() {
 | 
			
		||||
    // eslint-disable-next-line no-undef
 | 
			
		||||
    let lf = ref<ElRef>(null);
 | 
			
		||||
    let graphData = ref(null);
 | 
			
		||||
    let dataVisible = ref(false);
 | 
			
		||||
    let config = ref({
 | 
			
		||||
      grid: true,
 | 
			
		||||
      background: {
 | 
			
		||||
        color: "#f7f9ff"
 | 
			
		||||
      },
 | 
			
		||||
      keyboard: {
 | 
			
		||||
        enabled: true
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    let nodeList = BpmnNode;
 | 
			
		||||
 | 
			
		||||
    function initLf() {
 | 
			
		||||
      // 画布配置
 | 
			
		||||
      LogicFlow.use(Snapshot);
 | 
			
		||||
      // 使用bpmn插件,引入bpmn元素,这些元素可以在turbo中转换后使用
 | 
			
		||||
      LogicFlow.use(BpmnElement);
 | 
			
		||||
      // 启动右键菜单
 | 
			
		||||
      LogicFlow.use(Menu);
 | 
			
		||||
      const domLf = new LogicFlow({
 | 
			
		||||
        ...unref(config),
 | 
			
		||||
        container: document.querySelector("#LF-Turbo")
 | 
			
		||||
      });
 | 
			
		||||
      lf.value = domLf;
 | 
			
		||||
      // 设置边类型bpmn:sequenceFlow为默认类型
 | 
			
		||||
      unref(lf).setDefaultEdgeType("bpmn:sequenceFlow");
 | 
			
		||||
      onRender();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function onRender() {
 | 
			
		||||
      // Turbo数据转换为LogicFlow内部识别的数据结构
 | 
			
		||||
      const lFData = toLogicflowData(demoData);
 | 
			
		||||
      lf.value.render(lFData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function catData() {
 | 
			
		||||
      graphData.value = unref(lf).getGraphData();
 | 
			
		||||
      dataVisible.value = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      initLf();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      lf,
 | 
			
		||||
      graphData,
 | 
			
		||||
      dataVisible,
 | 
			
		||||
      config,
 | 
			
		||||
      nodeList,
 | 
			
		||||
      catData
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
#LF-Turbo {
 | 
			
		||||
  width: 100vw;
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,57 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { reactive, onBeforeMount } from "vue";
 | 
			
		||||
import info, { ContextProps } from "../components/ReInfo/index.vue";
 | 
			
		||||
import { getVerify, getLogin } from "/@/api/user";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import { warnMessage, successMessage } from "/@/utils/message";
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
 | 
			
		||||
// 刷新验证码
 | 
			
		||||
const refreshGetVerify = async () => {
 | 
			
		||||
  let { svg } = await getVerify();
 | 
			
		||||
  contextInfo.svg = svg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const contextInfo: ContextProps = reactive({
 | 
			
		||||
  userName: "",
 | 
			
		||||
  passWord: "",
 | 
			
		||||
  verify: null,
 | 
			
		||||
  svg: null
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const toPage = (info: Object): void => {
 | 
			
		||||
  storageSession.setItem("info", info);
 | 
			
		||||
  router.push("/");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 登录
 | 
			
		||||
const onLogin = async () => {
 | 
			
		||||
  let { userName, passWord, verify } = contextInfo;
 | 
			
		||||
  let { code, info, accessToken } = await getLogin({
 | 
			
		||||
    username: userName,
 | 
			
		||||
    password: passWord,
 | 
			
		||||
    verify: verify
 | 
			
		||||
  });
 | 
			
		||||
  code === 0
 | 
			
		||||
    ? successMessage(info) &&
 | 
			
		||||
      toPage({
 | 
			
		||||
        username: userName,
 | 
			
		||||
        accessToken
 | 
			
		||||
      })
 | 
			
		||||
    : warnMessage(info);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const refreshVerify = (): void => {
 | 
			
		||||
  refreshGetVerify();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onBeforeMount(() => {
 | 
			
		||||
  // refreshGetVerify();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="login">
 | 
			
		||||
    <info
 | 
			
		||||
@ -7,72 +61,3 @@
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { reactive, onBeforeMount } from "vue";
 | 
			
		||||
import info, { ContextProps } from "../components/ReInfo/index.vue";
 | 
			
		||||
import { getVerify, getLogin } from "/@/api/user";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
import { warnMessage, successMessage } from "/@/utils/message";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "login",
 | 
			
		||||
  components: {
 | 
			
		||||
    info
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const router = useRouter();
 | 
			
		||||
 | 
			
		||||
    // 刷新验证码
 | 
			
		||||
    const refreshGetVerify = async () => {
 | 
			
		||||
      let { svg } = await getVerify();
 | 
			
		||||
      contextInfo.svg = svg;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const contextInfo: ContextProps = reactive({
 | 
			
		||||
      userName: "",
 | 
			
		||||
      passWord: "",
 | 
			
		||||
      verify: null,
 | 
			
		||||
      svg: null
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const toPage = (info: Object): void => {
 | 
			
		||||
      storageSession.setItem("info", info);
 | 
			
		||||
      router.push("/");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 登录
 | 
			
		||||
    const onLogin = async () => {
 | 
			
		||||
      let { userName, passWord, verify } = contextInfo;
 | 
			
		||||
      let { code, info, accessToken } = await getLogin({
 | 
			
		||||
        username: userName,
 | 
			
		||||
        password: passWord,
 | 
			
		||||
        verify: verify
 | 
			
		||||
      });
 | 
			
		||||
      code === 0
 | 
			
		||||
        ? successMessage(info) &&
 | 
			
		||||
          toPage({
 | 
			
		||||
            username: userName,
 | 
			
		||||
            accessToken
 | 
			
		||||
          })
 | 
			
		||||
        : warnMessage(info);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const refreshVerify = (): void => {
 | 
			
		||||
      refreshGetVerify();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onBeforeMount(() => {
 | 
			
		||||
      // refreshGetVerify();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      contextInfo,
 | 
			
		||||
      onLogin,
 | 
			
		||||
      router,
 | 
			
		||||
      toPage,
 | 
			
		||||
      refreshVerify
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,18 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
 | 
			
		||||
const auth = ref<Boolean>(storageSession.getItem("info").username || "admin");
 | 
			
		||||
 | 
			
		||||
function changRole(value) {
 | 
			
		||||
  storageSession.setItem("info", {
 | 
			
		||||
    username: value,
 | 
			
		||||
    accessToken: `eyJhbGciOiJIUzUxMiJ9.${value}`
 | 
			
		||||
  });
 | 
			
		||||
  window.location.reload();
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-container">
 | 
			
		||||
    <el-radio-group v-model="auth" @change="changRole">
 | 
			
		||||
@ -8,30 +23,3 @@
 | 
			
		||||
    <p v-auth="'v-test'">只有test可看</p>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref } from "vue";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "permissionButton",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const auth = ref(storageSession.getItem("info").username || "admin");
 | 
			
		||||
 | 
			
		||||
    function changRole(value) {
 | 
			
		||||
      storageSession.setItem("info", {
 | 
			
		||||
        username: value,
 | 
			
		||||
        accessToken: `eyJhbGciOiJIUzUxMiJ9.${value}`
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      window.location.reload();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      auth,
 | 
			
		||||
      changRole
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,26 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { ref, unref } from "vue";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
 | 
			
		||||
let purview = ref<string>(storageSession.getItem("info").username);
 | 
			
		||||
 | 
			
		||||
function changRole() {
 | 
			
		||||
  if (unref(purview) === "admin") {
 | 
			
		||||
    storageSession.setItem("info", {
 | 
			
		||||
      username: "test",
 | 
			
		||||
      accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
 | 
			
		||||
    });
 | 
			
		||||
    window.location.reload();
 | 
			
		||||
  } else {
 | 
			
		||||
    storageSession.setItem("info", {
 | 
			
		||||
      username: "admin",
 | 
			
		||||
      accessToken: "eyJhbGciOiJIUzUxMiJ9.admin"
 | 
			
		||||
    });
 | 
			
		||||
    window.location.reload();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="app-container">
 | 
			
		||||
    <h4>
 | 
			
		||||
@ -10,35 +33,3 @@
 | 
			
		||||
    <el-button type="primary" @click="changRole">切换角色</el-button>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { ref, unref } from "vue";
 | 
			
		||||
import { storageSession } from "/@/utils/storage";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "permissionPage",
 | 
			
		||||
  setup() {
 | 
			
		||||
    let purview: string = ref(storageSession.getItem("info").username);
 | 
			
		||||
 | 
			
		||||
    function changRole() {
 | 
			
		||||
      if (unref(purview) === "admin") {
 | 
			
		||||
        storageSession.setItem("info", {
 | 
			
		||||
          username: "test",
 | 
			
		||||
          accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
 | 
			
		||||
        });
 | 
			
		||||
        window.location.reload();
 | 
			
		||||
      } else {
 | 
			
		||||
        storageSession.setItem("info", {
 | 
			
		||||
          username: "admin",
 | 
			
		||||
          accessToken: "eyJhbGciOiJIUzUxMiJ9.admin"
 | 
			
		||||
        });
 | 
			
		||||
        window.location.reload();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      purview,
 | 
			
		||||
      changRole
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,20 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { unref } from "vue";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const { currentRoute, replace } = useRouter();
 | 
			
		||||
 | 
			
		||||
const { params, query } = unref(currentRoute);
 | 
			
		||||
const { path } = params;
 | 
			
		||||
 | 
			
		||||
const _path = Array.isArray(path) ? path.join("/") : path;
 | 
			
		||||
 | 
			
		||||
replace({
 | 
			
		||||
  path: "/" + _path,
 | 
			
		||||
  query
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div></div>
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, unref } from "vue";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: "redirect",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const { currentRoute, replace } = useRouter();
 | 
			
		||||
 | 
			
		||||
    const { params, query } = unref(currentRoute);
 | 
			
		||||
    const { path } = params;
 | 
			
		||||
 | 
			
		||||
    const _path = Array.isArray(path) ? path.join("/") : path;
 | 
			
		||||
 | 
			
		||||
    replace({
 | 
			
		||||
      path: "/" + _path,
 | 
			
		||||
      query
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {};
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,47 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { reactive, onBeforeMount } from "vue";
 | 
			
		||||
import info, { ContextProps } from "../components/ReInfo/index.vue";
 | 
			
		||||
import { getRegist, getVerify } from "/@/api/user";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
import { warnMessage, successMessage } from "/@/utils/message";
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
 | 
			
		||||
// 刷新验证码
 | 
			
		||||
const refreshGetVerify = async () => {
 | 
			
		||||
  let { svg } = await getVerify();
 | 
			
		||||
  contextInfo.svg = svg;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const contextInfo: ContextProps = reactive({
 | 
			
		||||
  userName: "",
 | 
			
		||||
  passWord: "",
 | 
			
		||||
  verify: null,
 | 
			
		||||
  svg: null
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 注册
 | 
			
		||||
const onRegist = async () => {
 | 
			
		||||
  let { userName, passWord, verify } = contextInfo;
 | 
			
		||||
  let { code, info } = await getRegist({
 | 
			
		||||
    username: userName,
 | 
			
		||||
    password: passWord,
 | 
			
		||||
    verify: verify
 | 
			
		||||
  });
 | 
			
		||||
  code === 0
 | 
			
		||||
    ? successMessage(info) && router.push("/login")
 | 
			
		||||
    : warnMessage(info);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const refreshVerify = (): void => {
 | 
			
		||||
  refreshGetVerify();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onBeforeMount(() => {
 | 
			
		||||
  // refreshGetVerify();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="register">
 | 
			
		||||
    <info
 | 
			
		||||
@ -7,61 +51,3 @@
 | 
			
		||||
    />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { reactive, onBeforeMount } from "vue";
 | 
			
		||||
import info, { ContextProps } from "../components/ReInfo/index.vue";
 | 
			
		||||
import { getRegist, getVerify } from "/@/api/user";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
import { warnMessage, successMessage } from "/@/utils/message";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "register",
 | 
			
		||||
  components: {
 | 
			
		||||
    info
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const router = useRouter();
 | 
			
		||||
 | 
			
		||||
    // 刷新验证码
 | 
			
		||||
    const refreshGetVerify = async () => {
 | 
			
		||||
      let { svg } = await getVerify();
 | 
			
		||||
      contextInfo.svg = svg;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const contextInfo: ContextProps = reactive({
 | 
			
		||||
      userName: "",
 | 
			
		||||
      passWord: "",
 | 
			
		||||
      verify: null,
 | 
			
		||||
      svg: null
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 注册
 | 
			
		||||
    const onRegist = async () => {
 | 
			
		||||
      let { userName, passWord, verify } = contextInfo;
 | 
			
		||||
      let { code, info } = await getRegist({
 | 
			
		||||
        username: userName,
 | 
			
		||||
        password: passWord,
 | 
			
		||||
        verify: verify
 | 
			
		||||
      });
 | 
			
		||||
      code === 0
 | 
			
		||||
        ? successMessage(info) && router.push("/login")
 | 
			
		||||
        : warnMessage(info);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const refreshVerify = (): void => {
 | 
			
		||||
      refreshGetVerify();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onBeforeMount(() => {
 | 
			
		||||
      // refreshGetVerify();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      contextInfo,
 | 
			
		||||
      onRegist,
 | 
			
		||||
      router,
 | 
			
		||||
      refreshVerify
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,79 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { reactive } from "vue";
 | 
			
		||||
import { VxeTableEvents } from "vxe-table";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
 | 
			
		||||
interface Props {
 | 
			
		||||
  drawer: boolean;
 | 
			
		||||
  drawTitle?: string;
 | 
			
		||||
  direction?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
withDefaults(defineProps<Props>(), {
 | 
			
		||||
  drawer: false,
 | 
			
		||||
  drawTitle: "",
 | 
			
		||||
  direction: "rtl"
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits<{
 | 
			
		||||
  (e: "handleClose"): void;
 | 
			
		||||
}>();
 | 
			
		||||
 | 
			
		||||
const xTable = templateRef<any>("xTable", null);
 | 
			
		||||
 | 
			
		||||
const configData = reactive({
 | 
			
		||||
  tableData: [
 | 
			
		||||
    {
 | 
			
		||||
      name: "禁用",
 | 
			
		||||
      dataval: "0"
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      name: "启用",
 | 
			
		||||
      dataval: "1"
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  isAllChecked: false,
 | 
			
		||||
  isIndeterminate: false,
 | 
			
		||||
  selectRecords: [] as any[],
 | 
			
		||||
  tablePage: {
 | 
			
		||||
    total: 0,
 | 
			
		||||
    currentPage: 1,
 | 
			
		||||
    pageSize: 10
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 抽屉关闭
 | 
			
		||||
function handleClose() {
 | 
			
		||||
  configData.isAllChecked = false;
 | 
			
		||||
  configData.isIndeterminate = false;
 | 
			
		||||
  emit("handleClose");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function editConfig(row) {
 | 
			
		||||
  console.log("editConfig", row);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function delConfig(row) {
 | 
			
		||||
  console.log("delConfig", row);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const changeAllEvent = () => {
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    console.log(xTable);
 | 
			
		||||
  }, 1000);
 | 
			
		||||
  const $table = xTable.value;
 | 
			
		||||
  $table.setAllCheckboxRow(configData.isAllChecked);
 | 
			
		||||
  configData.selectRecords = $table.getCheckboxRecords();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const checkboxChangeEvent: VxeTableEvents.CheckboxChange = ({ records }) => {
 | 
			
		||||
  const $table = xTable.value;
 | 
			
		||||
  configData.isAllChecked = $table.isAllCheckboxChecked();
 | 
			
		||||
  configData.isIndeterminate = $table.isCheckboxIndeterminate();
 | 
			
		||||
  configData.selectRecords = records;
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="config">
 | 
			
		||||
    <el-drawer
 | 
			
		||||
@ -14,7 +90,7 @@
 | 
			
		||||
        <vxe-table
 | 
			
		||||
          ref="xTable"
 | 
			
		||||
          border
 | 
			
		||||
          :data="tableData"
 | 
			
		||||
          :data="configData.tableData"
 | 
			
		||||
          @checkbox-change="checkboxChangeEvent"
 | 
			
		||||
          @checkbox-all="checkboxChangeEvent"
 | 
			
		||||
        >
 | 
			
		||||
@ -40,9 +116,9 @@
 | 
			
		||||
        </vxe-table>
 | 
			
		||||
        <vxe-pager
 | 
			
		||||
          perfect
 | 
			
		||||
          v-model:current-page="tablePage.currentPage"
 | 
			
		||||
          v-model:page-size="tablePage.pageSize"
 | 
			
		||||
          :total="tablePage.total"
 | 
			
		||||
          v-model:current-page="configData.tablePage.currentPage"
 | 
			
		||||
          v-model:page-size="configData.tablePage.pageSize"
 | 
			
		||||
          :total="configData.tablePage.total"
 | 
			
		||||
          :layouts="[
 | 
			
		||||
            'PrevJump',
 | 
			
		||||
            'PrevPage',
 | 
			
		||||
@ -57,12 +133,12 @@
 | 
			
		||||
          <template #left>
 | 
			
		||||
            <span class="page-left">
 | 
			
		||||
              <vxe-checkbox
 | 
			
		||||
                v-model="isAllChecked"
 | 
			
		||||
                :indeterminate="isIndeterminate"
 | 
			
		||||
                v-model="configData.isAllChecked"
 | 
			
		||||
                :indeterminate="configData.isIndeterminate"
 | 
			
		||||
                @change="changeAllEvent"
 | 
			
		||||
              ></vxe-checkbox>
 | 
			
		||||
              <span class="select-count"
 | 
			
		||||
                >已选中{{ selectRecords.length }}条</span
 | 
			
		||||
                >已选中{{ configData.selectRecords.length }}条</span
 | 
			
		||||
              >
 | 
			
		||||
              <vxe-button size="small">{{ $t("message.hsdelete") }}</vxe-button>
 | 
			
		||||
            </span>
 | 
			
		||||
@ -73,98 +149,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, reactive, toRefs } from "vue";
 | 
			
		||||
import { propTypes } from "/@/utils/propTypes";
 | 
			
		||||
import { VxeTableEvents } from "vxe-table";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  props: {
 | 
			
		||||
    drawer: propTypes.bool.def(false),
 | 
			
		||||
    drawTitle: propTypes.string.def(""),
 | 
			
		||||
    direction: propTypes.string.def("rtl")
 | 
			
		||||
  },
 | 
			
		||||
  emits: ["handleClose"],
 | 
			
		||||
  setup(props, ctx) {
 | 
			
		||||
    const { emit } = ctx;
 | 
			
		||||
 | 
			
		||||
    const xTable = templateRef<any>("xTable", null);
 | 
			
		||||
 | 
			
		||||
    const configData = reactive({
 | 
			
		||||
      tableData: [
 | 
			
		||||
        {
 | 
			
		||||
          name: "禁用",
 | 
			
		||||
          dataval: "0"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          name: "启用",
 | 
			
		||||
          dataval: "1"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      isAllChecked: false,
 | 
			
		||||
      isIndeterminate: false,
 | 
			
		||||
      selectRecords: [] as any[],
 | 
			
		||||
      tablePage: {
 | 
			
		||||
        total: 0,
 | 
			
		||||
        currentPage: 1,
 | 
			
		||||
        pageSize: 10
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    // 抽屉关闭
 | 
			
		||||
    function handleClose() {
 | 
			
		||||
      configData.isAllChecked = false;
 | 
			
		||||
      configData.isIndeterminate = false;
 | 
			
		||||
      emit("handleClose");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function editConfig(row) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        "%crow===>>>: ",
 | 
			
		||||
        "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
 | 
			
		||||
        row
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function delConfig(row) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        "%crow===>>>: ",
 | 
			
		||||
        "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
 | 
			
		||||
        row
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const changeAllEvent = () => {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        console.log(xTable);
 | 
			
		||||
      }, 1000);
 | 
			
		||||
      const $table = xTable.value;
 | 
			
		||||
      $table.setAllCheckboxRow(configData.isAllChecked);
 | 
			
		||||
      configData.selectRecords = $table.getCheckboxRecords();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const checkboxChangeEvent: VxeTableEvents.CheckboxChange = ({
 | 
			
		||||
      records
 | 
			
		||||
    }) => {
 | 
			
		||||
      const $table = xTable.value;
 | 
			
		||||
      configData.isAllChecked = $table.isAllCheckboxChecked();
 | 
			
		||||
      configData.isIndeterminate = $table.isCheckboxIndeterminate();
 | 
			
		||||
      configData.selectRecords = records;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...toRefs(configData),
 | 
			
		||||
      handleClose,
 | 
			
		||||
      editConfig,
 | 
			
		||||
      delConfig,
 | 
			
		||||
      changeAllEvent,
 | 
			
		||||
      checkboxChangeEvent
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.list {
 | 
			
		||||
  padding: 10px;
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,208 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import Config from "./config.vue";
 | 
			
		||||
import { reactive, ref, unref, nextTick } from "vue";
 | 
			
		||||
import XEUtils from "xe-utils";
 | 
			
		||||
import { cloneDeep } from "lodash-es";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
 | 
			
		||||
import {
 | 
			
		||||
  VXETable,
 | 
			
		||||
  VxeTableInstance,
 | 
			
		||||
  VxeTableEvents,
 | 
			
		||||
  VxeFormPropTypes
 | 
			
		||||
} from "vxe-table";
 | 
			
		||||
type onEditNRow = {
 | 
			
		||||
  name: string;
 | 
			
		||||
  model: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const dictData = reactive({
 | 
			
		||||
  submitLoading: false,
 | 
			
		||||
  showEdit: false,
 | 
			
		||||
  selectRow: null,
 | 
			
		||||
  filterName: "",
 | 
			
		||||
  tableData: [
 | 
			
		||||
    {
 | 
			
		||||
      id: 1,
 | 
			
		||||
      name: "状态",
 | 
			
		||||
      model: "",
 | 
			
		||||
      children: [
 | 
			
		||||
        {
 | 
			
		||||
          id: "1-1",
 | 
			
		||||
          name: "服务状态",
 | 
			
		||||
          model: "serviceStatus"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          id: "1-2",
 | 
			
		||||
          name: "在线状态",
 | 
			
		||||
          model: "onlienStatus"
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    { id: 2, name: "操作系统", model: "operatingSystem" }
 | 
			
		||||
  ],
 | 
			
		||||
  formData: {
 | 
			
		||||
    name: "",
 | 
			
		||||
    model: ""
 | 
			
		||||
  },
 | 
			
		||||
  formItems: [
 | 
			
		||||
    {
 | 
			
		||||
      field: "name",
 | 
			
		||||
      title: "字典名称",
 | 
			
		||||
      span: 24,
 | 
			
		||||
      itemRender: {
 | 
			
		||||
        name: "$input",
 | 
			
		||||
        props: { placeholder: "请输入字典名称" }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      field: "model",
 | 
			
		||||
      title: "字典类型",
 | 
			
		||||
      span: 24,
 | 
			
		||||
      itemRender: {
 | 
			
		||||
        name: "$input",
 | 
			
		||||
        props: {
 | 
			
		||||
          placeholder: "请输入字典类型",
 | 
			
		||||
          //这里vxe-table文档并没有提到,可以配置所选组件的所有属性,比如这里可以配置关于vxe-input的所有属性
 | 
			
		||||
          disabled: true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      align: "right",
 | 
			
		||||
      span: 24,
 | 
			
		||||
      itemRender: {
 | 
			
		||||
        name: "$buttons",
 | 
			
		||||
        children: [
 | 
			
		||||
          { props: { type: "submit", content: "提交", status: "primary" } },
 | 
			
		||||
          { props: { type: "reset", content: "重置" } }
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ] as VxeFormPropTypes.Items
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
let originData = cloneDeep(dictData.tableData);
 | 
			
		||||
 | 
			
		||||
const xTree = templateRef<HTMLElement | any>("xTree", null);
 | 
			
		||||
 | 
			
		||||
const handleSearch = () => {
 | 
			
		||||
  const filterName = XEUtils.toValueString(dictData.filterName).trim();
 | 
			
		||||
 | 
			
		||||
  if (filterName) {
 | 
			
		||||
    const options = { children: "children" };
 | 
			
		||||
    const searchProps = ["name"];
 | 
			
		||||
 | 
			
		||||
    dictData.tableData = XEUtils.searchTree(
 | 
			
		||||
      originData,
 | 
			
		||||
      item =>
 | 
			
		||||
        searchProps.some(
 | 
			
		||||
          key => XEUtils.toValueString(item[key]).indexOf(filterName) > -1
 | 
			
		||||
        ),
 | 
			
		||||
      options
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    // 搜索之后默认展开所有子节点
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
      const $table = xTree.value;
 | 
			
		||||
      $table.setAllTreeExpand(true);
 | 
			
		||||
    });
 | 
			
		||||
  } else {
 | 
			
		||||
    dictData.tableData = originData;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 创建一个防防抖函数,调用频率间隔 100 毫秒
 | 
			
		||||
const searchEvent = XEUtils.debounce(
 | 
			
		||||
  function () {
 | 
			
		||||
    handleSearch();
 | 
			
		||||
  },
 | 
			
		||||
  100,
 | 
			
		||||
  { leading: false, trailing: true }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const confirmEvent = async () => {
 | 
			
		||||
  const type = await VXETable.modal.confirm("您确定要删除吗?");
 | 
			
		||||
  (await type) === "confirm" &&
 | 
			
		||||
    VXETable.modal.message({
 | 
			
		||||
      content: "测试数据,不可删除",
 | 
			
		||||
      status: "error"
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function commonFn(value, disabled) {
 | 
			
		||||
  dictData.selectRow = value;
 | 
			
		||||
  dictData.showEdit = true;
 | 
			
		||||
  dictData.formItems[1].itemRender.props.disabled = disabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 新增
 | 
			
		||||
function onAdd() {
 | 
			
		||||
  commonFn(null, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 新增子类型
 | 
			
		||||
function onAddChild(row?: object) {
 | 
			
		||||
  console.log("onAddChild", row);
 | 
			
		||||
  commonFn(null, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 编辑
 | 
			
		||||
function onEdit(row?: onEditNRow) {
 | 
			
		||||
  dictData.formData = {
 | 
			
		||||
    name: row.name,
 | 
			
		||||
    model: row.model ? row.model : "暂无字典类型"
 | 
			
		||||
  };
 | 
			
		||||
  commonFn(row, true);
 | 
			
		||||
  // VXETable.modal.message({
 | 
			
		||||
  //   content: "测试数据,不可编辑",
 | 
			
		||||
  //   status: "error"
 | 
			
		||||
  // });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 拷贝当前列表项的数据(字典类型)
 | 
			
		||||
const { clipboardRef } = useCopyToClipboard();
 | 
			
		||||
const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
 | 
			
		||||
  clipboardRef.value = unref(row).model;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const xTable = ref({} as VxeTableInstance);
 | 
			
		||||
 | 
			
		||||
const submitEvent = () => {
 | 
			
		||||
  dictData.submitLoading = true;
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    const $table = xTable.value;
 | 
			
		||||
    dictData.submitLoading = false;
 | 
			
		||||
    dictData.showEdit = false;
 | 
			
		||||
    if (dictData.selectRow) {
 | 
			
		||||
      VXETable.modal.message({ content: "保存成功", status: "success" });
 | 
			
		||||
      Object.assign(dictData.selectRow, dictData.formData);
 | 
			
		||||
    } else {
 | 
			
		||||
      VXETable.modal.message({ content: "新增成功", status: "success" });
 | 
			
		||||
      $table.insert(dictData.formData);
 | 
			
		||||
    }
 | 
			
		||||
  }, 500);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
let drawer = ref(false);
 | 
			
		||||
 | 
			
		||||
function onDeploy(value?: object) {
 | 
			
		||||
  console.log("onDeploy", value);
 | 
			
		||||
  drawer.value = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function handleClose() {
 | 
			
		||||
  drawer.value = false;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="dict-container">
 | 
			
		||||
    <!-- 工具栏 -->
 | 
			
		||||
    <vxe-toolbar>
 | 
			
		||||
      <template #buttons>
 | 
			
		||||
        <vxe-input
 | 
			
		||||
          v-model="filterName"
 | 
			
		||||
          v-model="dictData.filterName"
 | 
			
		||||
          :placeholder="$t('message.hssearch')"
 | 
			
		||||
          @keyup="searchEvent"
 | 
			
		||||
        ></vxe-input>
 | 
			
		||||
@ -41,7 +239,7 @@
 | 
			
		||||
        iconOpen: 'fa fa-minus-square-o',
 | 
			
		||||
        iconClose: 'fa fa-plus-square-o'
 | 
			
		||||
      }"
 | 
			
		||||
      :data="tableData"
 | 
			
		||||
      :data="dictData.tableData"
 | 
			
		||||
      @cell-dblclick="cellDBLClickEvent"
 | 
			
		||||
    >
 | 
			
		||||
      <vxe-table-column
 | 
			
		||||
@ -89,16 +287,16 @@
 | 
			
		||||
    <vxe-modal
 | 
			
		||||
      resize
 | 
			
		||||
      width="450"
 | 
			
		||||
      v-model="showEdit"
 | 
			
		||||
      :title="selectRow ? '编辑' : '新增'"
 | 
			
		||||
      :loading="submitLoading"
 | 
			
		||||
      v-model="dictData.showEdit"
 | 
			
		||||
      :title="dictData.selectRow ? '编辑' : '新增'"
 | 
			
		||||
      :loading="dictData.submitLoading"
 | 
			
		||||
      @hide="$refs.xForm.reset()"
 | 
			
		||||
    >
 | 
			
		||||
      <template #default>
 | 
			
		||||
        <vxe-form
 | 
			
		||||
          ref="xForm"
 | 
			
		||||
          :data="formData"
 | 
			
		||||
          :items="formItems"
 | 
			
		||||
          :data="dictData.formData"
 | 
			
		||||
          :items="dictData.formItems"
 | 
			
		||||
          title-align="right"
 | 
			
		||||
          title-width="100"
 | 
			
		||||
          @submit="submitEvent"
 | 
			
		||||
@ -109,229 +307,7 @@
 | 
			
		||||
    <Config :drawer="drawer" drawTitle="字典列表" @handleClose="handleClose" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { reactive, ref, unref, nextTick, toRefs } from "vue";
 | 
			
		||||
import XEUtils from "xe-utils";
 | 
			
		||||
import { cloneDeep } from "lodash-es";
 | 
			
		||||
import { templateRef } from "@vueuse/core";
 | 
			
		||||
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
 | 
			
		||||
import {
 | 
			
		||||
  VXETable,
 | 
			
		||||
  VxeTableInstance,
 | 
			
		||||
  VxeTableEvents,
 | 
			
		||||
  VxeFormPropTypes
 | 
			
		||||
} from "vxe-table";
 | 
			
		||||
import Config from "./config.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: "dict",
 | 
			
		||||
  components: {
 | 
			
		||||
    Config
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    const dictData = reactive({
 | 
			
		||||
      submitLoading: false,
 | 
			
		||||
      showEdit: false,
 | 
			
		||||
      selectRow: null,
 | 
			
		||||
      filterName: "",
 | 
			
		||||
      tableData: [
 | 
			
		||||
        {
 | 
			
		||||
          id: 1,
 | 
			
		||||
          name: "状态",
 | 
			
		||||
          model: "",
 | 
			
		||||
          children: [
 | 
			
		||||
            {
 | 
			
		||||
              id: "1-1",
 | 
			
		||||
              name: "服务状态",
 | 
			
		||||
              model: "serviceStatus"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              id: "1-2",
 | 
			
		||||
              name: "在线状态",
 | 
			
		||||
              model: "onlienStatus"
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        },
 | 
			
		||||
        { id: 2, name: "操作系统", model: "operatingSystem" }
 | 
			
		||||
      ],
 | 
			
		||||
      formData: {
 | 
			
		||||
        name: "",
 | 
			
		||||
        model: ""
 | 
			
		||||
      },
 | 
			
		||||
      formItems: [
 | 
			
		||||
        {
 | 
			
		||||
          field: "name",
 | 
			
		||||
          title: "字典名称",
 | 
			
		||||
          span: 24,
 | 
			
		||||
          itemRender: {
 | 
			
		||||
            name: "$input",
 | 
			
		||||
            props: { placeholder: "请输入字典名称" }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          field: "model",
 | 
			
		||||
          title: "字典类型",
 | 
			
		||||
          span: 24,
 | 
			
		||||
          itemRender: {
 | 
			
		||||
            name: "$input",
 | 
			
		||||
            props: {
 | 
			
		||||
              placeholder: "请输入字典类型",
 | 
			
		||||
              //这里vxe-table文档并没有提到,可以配置所选组件的所有属性,比如这里可以配置关于vxe-input的所有属性
 | 
			
		||||
              disabled: true
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          align: "right",
 | 
			
		||||
          span: 24,
 | 
			
		||||
          itemRender: {
 | 
			
		||||
            name: "$buttons",
 | 
			
		||||
            children: [
 | 
			
		||||
              { props: { type: "submit", content: "提交", status: "primary" } },
 | 
			
		||||
              { props: { type: "reset", content: "重置" } }
 | 
			
		||||
            ]
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      ] as VxeFormPropTypes.Items
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    let originData = cloneDeep(dictData.tableData);
 | 
			
		||||
 | 
			
		||||
    const xTree = templateRef<HTMLElement | any>("xTree", null);
 | 
			
		||||
 | 
			
		||||
    const formatDate = (value: any) => {
 | 
			
		||||
      return XEUtils.toDateString(value, "yyyy-MM-dd HH:mm:ss.S");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleSearch = () => {
 | 
			
		||||
      const filterName = XEUtils.toValueString(dictData.filterName).trim();
 | 
			
		||||
 | 
			
		||||
      if (filterName) {
 | 
			
		||||
        const options = { children: "children" };
 | 
			
		||||
        const searchProps = ["name"];
 | 
			
		||||
 | 
			
		||||
        dictData.tableData = XEUtils.searchTree(
 | 
			
		||||
          originData,
 | 
			
		||||
          item =>
 | 
			
		||||
            searchProps.some(
 | 
			
		||||
              key => XEUtils.toValueString(item[key]).indexOf(filterName) > -1
 | 
			
		||||
            ),
 | 
			
		||||
          options
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // 搜索之后默认展开所有子节点
 | 
			
		||||
        nextTick(() => {
 | 
			
		||||
          const $table = xTree.value;
 | 
			
		||||
          $table.setAllTreeExpand(true);
 | 
			
		||||
        });
 | 
			
		||||
      } else {
 | 
			
		||||
        dictData.tableData = originData;
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // 创建一个防防抖函数,调用频率间隔 100 毫秒
 | 
			
		||||
    const searchEvent = XEUtils.debounce(
 | 
			
		||||
      function () {
 | 
			
		||||
        handleSearch();
 | 
			
		||||
      },
 | 
			
		||||
      100,
 | 
			
		||||
      { leading: false, trailing: true }
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    const confirmEvent = async () => {
 | 
			
		||||
      const type = await VXETable.modal.confirm("您确定要删除吗?");
 | 
			
		||||
      (await type) === "confirm" &&
 | 
			
		||||
        VXETable.modal.message({
 | 
			
		||||
          content: "测试数据,不可删除",
 | 
			
		||||
          status: "error"
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    function commonFn(value, disabled) {
 | 
			
		||||
      dictData.selectRow = value;
 | 
			
		||||
      dictData.showEdit = true;
 | 
			
		||||
      dictData.formItems[1].itemRender.props.disabled = disabled;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 新增
 | 
			
		||||
    function onAdd() {
 | 
			
		||||
      commonFn(null, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 新增子类型
 | 
			
		||||
    function onAddChild(row: any) {
 | 
			
		||||
      console.log(
 | 
			
		||||
        "%crow===>>>: ",
 | 
			
		||||
        "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
 | 
			
		||||
        row
 | 
			
		||||
      );
 | 
			
		||||
      commonFn(null, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 编辑
 | 
			
		||||
    function onEdit(row: any) {
 | 
			
		||||
      dictData.formData = {
 | 
			
		||||
        name: row.name,
 | 
			
		||||
        model: row.model ? row.model : "暂无字典类型"
 | 
			
		||||
      };
 | 
			
		||||
      commonFn(row, true);
 | 
			
		||||
      // VXETable.modal.message({
 | 
			
		||||
      //   content: "测试数据,不可编辑",
 | 
			
		||||
      //   status: "error"
 | 
			
		||||
      // });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 拷贝当前列表项的数据(字典类型)
 | 
			
		||||
    const { clipboardRef } = useCopyToClipboard();
 | 
			
		||||
    const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
 | 
			
		||||
      clipboardRef.value = unref(row).model;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const xTable = ref({} as VxeTableInstance);
 | 
			
		||||
 | 
			
		||||
    const submitEvent = () => {
 | 
			
		||||
      dictData.submitLoading = true;
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        const $table = xTable.value;
 | 
			
		||||
        dictData.submitLoading = false;
 | 
			
		||||
        dictData.showEdit = false;
 | 
			
		||||
        if (dictData.selectRow) {
 | 
			
		||||
          VXETable.modal.message({ content: "保存成功", status: "success" });
 | 
			
		||||
          Object.assign(dictData.selectRow, dictData.formData);
 | 
			
		||||
        } else {
 | 
			
		||||
          VXETable.modal.message({ content: "新增成功", status: "success" });
 | 
			
		||||
          $table.insert(dictData.formData);
 | 
			
		||||
        }
 | 
			
		||||
      }, 500);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let drawer = ref(false);
 | 
			
		||||
 | 
			
		||||
    function onDeploy() {
 | 
			
		||||
      drawer.value = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function handleClose() {
 | 
			
		||||
      drawer.value = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      ...toRefs(dictData),
 | 
			
		||||
      formatDate,
 | 
			
		||||
      searchEvent,
 | 
			
		||||
      confirmEvent,
 | 
			
		||||
      cellDBLClickEvent,
 | 
			
		||||
      submitEvent,
 | 
			
		||||
      onEdit,
 | 
			
		||||
      onAddChild,
 | 
			
		||||
      onAdd,
 | 
			
		||||
      onDeploy,
 | 
			
		||||
      drawer,
 | 
			
		||||
      handleClose
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.dict-container {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
 | 
			
		||||
@ -1,252 +1,242 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import { reactive } from "vue";
 | 
			
		||||
import { VxeGridProps } from "vxe-table";
 | 
			
		||||
 | 
			
		||||
const gridOptions = reactive({
 | 
			
		||||
  border: true,
 | 
			
		||||
  resizable: true,
 | 
			
		||||
  keepSource: true,
 | 
			
		||||
  height: 500,
 | 
			
		||||
  printConfig: {},
 | 
			
		||||
  importConfig: {},
 | 
			
		||||
  exportConfig: {},
 | 
			
		||||
  pagerConfig: {
 | 
			
		||||
    perfect: true,
 | 
			
		||||
    pageSize: 15
 | 
			
		||||
  },
 | 
			
		||||
  editConfig: {
 | 
			
		||||
    trigger: "click",
 | 
			
		||||
    mode: "row",
 | 
			
		||||
    showStatus: true
 | 
			
		||||
  },
 | 
			
		||||
  toolbarConfig: {
 | 
			
		||||
    buttons: [
 | 
			
		||||
      {
 | 
			
		||||
        code: "insert_actived",
 | 
			
		||||
        name: "message.hsadd",
 | 
			
		||||
        status: "perfect",
 | 
			
		||||
        icon: "fa fa-plus"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        code: "mark_cancel",
 | 
			
		||||
        name: "message.hsmark",
 | 
			
		||||
        status: "perfect",
 | 
			
		||||
        icon: "fa fa-trash-o"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        code: "save",
 | 
			
		||||
        name: "message.hssave",
 | 
			
		||||
        status: "perfect",
 | 
			
		||||
        icon: "fa fa-save"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    perfect: true,
 | 
			
		||||
    refresh: {
 | 
			
		||||
      icon: "fa fa-refresh",
 | 
			
		||||
      iconLoading: "fa fa-spinner fa-spin"
 | 
			
		||||
    },
 | 
			
		||||
    import: {
 | 
			
		||||
      icon: "fa fa-upload"
 | 
			
		||||
    },
 | 
			
		||||
    export: {
 | 
			
		||||
      icon: "fa fa-download"
 | 
			
		||||
    },
 | 
			
		||||
    print: {
 | 
			
		||||
      icon: "fa fa-print"
 | 
			
		||||
    },
 | 
			
		||||
    zoom: {
 | 
			
		||||
      iconIn: "fa fa-arrows-alt",
 | 
			
		||||
      iconOut: "fa fa-expand"
 | 
			
		||||
    },
 | 
			
		||||
    custom: {
 | 
			
		||||
      icon: "fa fa-cog"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  proxyConfig: {
 | 
			
		||||
    props: {
 | 
			
		||||
      result: "result",
 | 
			
		||||
      total: "page.total"
 | 
			
		||||
    },
 | 
			
		||||
    ajax: {
 | 
			
		||||
      // 接收 Promise
 | 
			
		||||
      query: ({ page }) => {
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
          setTimeout(() => {
 | 
			
		||||
            const list = [
 | 
			
		||||
              {
 | 
			
		||||
                id: 10001,
 | 
			
		||||
                name: "Test1",
 | 
			
		||||
                nickname: "T1",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Man",
 | 
			
		||||
                age: 28,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10002,
 | 
			
		||||
                name: "Test2",
 | 
			
		||||
                nickname: "T2",
 | 
			
		||||
                role: "Test",
 | 
			
		||||
                sex: "Women",
 | 
			
		||||
                age: 22,
 | 
			
		||||
                address: "Guangzhou"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10003,
 | 
			
		||||
                name: "Test3",
 | 
			
		||||
                nickname: "T3",
 | 
			
		||||
                role: "PM",
 | 
			
		||||
                sex: "Man",
 | 
			
		||||
                age: 32,
 | 
			
		||||
                address: "Shanghai"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10004,
 | 
			
		||||
                name: "Test4",
 | 
			
		||||
                nickname: "T4",
 | 
			
		||||
                role: "Designer",
 | 
			
		||||
                sex: "Women ",
 | 
			
		||||
                age: 23,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10005,
 | 
			
		||||
                name: "Test5",
 | 
			
		||||
                nickname: "T5",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Women ",
 | 
			
		||||
                age: 30,
 | 
			
		||||
                address: "Shanghai"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10006,
 | 
			
		||||
                name: "Test6",
 | 
			
		||||
                nickname: "T6",
 | 
			
		||||
                role: "Designer",
 | 
			
		||||
                sex: "Women ",
 | 
			
		||||
                age: 21,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10007,
 | 
			
		||||
                name: "Test7",
 | 
			
		||||
                nickname: "T7",
 | 
			
		||||
                role: "Test",
 | 
			
		||||
                sex: "Man ",
 | 
			
		||||
                age: 29,
 | 
			
		||||
                address: "vxe-table 从入门到放弃"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10008,
 | 
			
		||||
                name: "Test8",
 | 
			
		||||
                nickname: "T8",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Man ",
 | 
			
		||||
                age: 35,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 10009,
 | 
			
		||||
                name: "Test9",
 | 
			
		||||
                nickname: "T9",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Man ",
 | 
			
		||||
                age: 35,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 100010,
 | 
			
		||||
                name: "Test10",
 | 
			
		||||
                nickname: "T10",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Man ",
 | 
			
		||||
                age: 35,
 | 
			
		||||
                address: "Guangzhou"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 100011,
 | 
			
		||||
                name: "Test11",
 | 
			
		||||
                nickname: "T11",
 | 
			
		||||
                role: "Test",
 | 
			
		||||
                sex: "Women ",
 | 
			
		||||
                age: 26,
 | 
			
		||||
                address: "vxe-table 从入门到放弃"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 100012,
 | 
			
		||||
                name: "Test12",
 | 
			
		||||
                nickname: "T12",
 | 
			
		||||
                role: "Develop",
 | 
			
		||||
                sex: "Man ",
 | 
			
		||||
                age: 34,
 | 
			
		||||
                address: "Guangzhou"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                id: 100013,
 | 
			
		||||
                name: "Test13",
 | 
			
		||||
                nickname: "T13",
 | 
			
		||||
                role: "Test",
 | 
			
		||||
                sex: "Women ",
 | 
			
		||||
                age: 22,
 | 
			
		||||
                address: "Shenzhen"
 | 
			
		||||
              }
 | 
			
		||||
            ];
 | 
			
		||||
            resolve({
 | 
			
		||||
              page: {
 | 
			
		||||
                total: list.length
 | 
			
		||||
              },
 | 
			
		||||
              result: list.slice(
 | 
			
		||||
                (page.currentPage - 1) * page.pageSize,
 | 
			
		||||
                page.currentPage * page.pageSize
 | 
			
		||||
              )
 | 
			
		||||
            });
 | 
			
		||||
          }, 100);
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      // body 对象: { removeRecords }
 | 
			
		||||
      delete: () => {
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
          setTimeout(() => {
 | 
			
		||||
            resolve({});
 | 
			
		||||
          }, 100);
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
      // body 对象: { insertRecords, updateRecords, removeRecords, pendingRecords }
 | 
			
		||||
      save: () => {
 | 
			
		||||
        return new Promise(resolve => {
 | 
			
		||||
          setTimeout(() => {
 | 
			
		||||
            resolve({});
 | 
			
		||||
          }, 100);
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  columns: [
 | 
			
		||||
    { type: "checkbox", width: 50 },
 | 
			
		||||
    { type: "seq", width: 60 },
 | 
			
		||||
    { field: "name", title: "Name", editRender: { name: "input" } },
 | 
			
		||||
    { field: "nickname", title: "Nickname", editRender: { name: "input" } },
 | 
			
		||||
    { field: "role", title: "Role", editRender: { name: "input" } },
 | 
			
		||||
    {
 | 
			
		||||
      field: "address",
 | 
			
		||||
      title: "Address",
 | 
			
		||||
      showOverflow: true,
 | 
			
		||||
      editRender: { name: "input" }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
} as VxeGridProps);
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <vxe-grid v-bind="gridOptions" style="width: 98%"></vxe-grid>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { reactive } from "vue";
 | 
			
		||||
import { VxeGridProps } from "vxe-table";
 | 
			
		||||
export default {
 | 
			
		||||
  name: "user",
 | 
			
		||||
  setup() {
 | 
			
		||||
    const gridOptions = reactive({
 | 
			
		||||
      border: true,
 | 
			
		||||
      resizable: true,
 | 
			
		||||
      keepSource: true,
 | 
			
		||||
      height: 500,
 | 
			
		||||
      printConfig: {},
 | 
			
		||||
      importConfig: {},
 | 
			
		||||
      exportConfig: {},
 | 
			
		||||
      pagerConfig: {
 | 
			
		||||
        perfect: true,
 | 
			
		||||
        pageSize: 15
 | 
			
		||||
      },
 | 
			
		||||
      editConfig: {
 | 
			
		||||
        trigger: "click",
 | 
			
		||||
        mode: "row",
 | 
			
		||||
        showStatus: true
 | 
			
		||||
      },
 | 
			
		||||
      toolbarConfig: {
 | 
			
		||||
        buttons: [
 | 
			
		||||
          {
 | 
			
		||||
            code: "insert_actived",
 | 
			
		||||
            name: "message.hsadd",
 | 
			
		||||
            status: "perfect",
 | 
			
		||||
            icon: "fa fa-plus"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            code: "mark_cancel",
 | 
			
		||||
            name: "message.hsmark",
 | 
			
		||||
            status: "perfect",
 | 
			
		||||
            icon: "fa fa-trash-o"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            code: "save",
 | 
			
		||||
            name: "message.hssave",
 | 
			
		||||
            status: "perfect",
 | 
			
		||||
            icon: "fa fa-save"
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        perfect: true,
 | 
			
		||||
        refresh: {
 | 
			
		||||
          icon: "fa fa-refresh",
 | 
			
		||||
          iconLoading: "fa fa-spinner fa-spin"
 | 
			
		||||
        },
 | 
			
		||||
        import: {
 | 
			
		||||
          icon: "fa fa-upload"
 | 
			
		||||
        },
 | 
			
		||||
        export: {
 | 
			
		||||
          icon: "fa fa-download"
 | 
			
		||||
        },
 | 
			
		||||
        print: {
 | 
			
		||||
          icon: "fa fa-print"
 | 
			
		||||
        },
 | 
			
		||||
        zoom: {
 | 
			
		||||
          iconIn: "fa fa-arrows-alt",
 | 
			
		||||
          iconOut: "fa fa-expand"
 | 
			
		||||
        },
 | 
			
		||||
        custom: {
 | 
			
		||||
          icon: "fa fa-cog"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      proxyConfig: {
 | 
			
		||||
        props: {
 | 
			
		||||
          result: "result",
 | 
			
		||||
          total: "page.total"
 | 
			
		||||
        },
 | 
			
		||||
        ajax: {
 | 
			
		||||
          // 接收 Promise
 | 
			
		||||
          query: ({ page }) => {
 | 
			
		||||
            return new Promise(resolve => {
 | 
			
		||||
              setTimeout(() => {
 | 
			
		||||
                const list = [
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10001,
 | 
			
		||||
                    name: "Test1",
 | 
			
		||||
                    nickname: "T1",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Man",
 | 
			
		||||
                    age: 28,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10002,
 | 
			
		||||
                    name: "Test2",
 | 
			
		||||
                    nickname: "T2",
 | 
			
		||||
                    role: "Test",
 | 
			
		||||
                    sex: "Women",
 | 
			
		||||
                    age: 22,
 | 
			
		||||
                    address: "Guangzhou"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10003,
 | 
			
		||||
                    name: "Test3",
 | 
			
		||||
                    nickname: "T3",
 | 
			
		||||
                    role: "PM",
 | 
			
		||||
                    sex: "Man",
 | 
			
		||||
                    age: 32,
 | 
			
		||||
                    address: "Shanghai"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10004,
 | 
			
		||||
                    name: "Test4",
 | 
			
		||||
                    nickname: "T4",
 | 
			
		||||
                    role: "Designer",
 | 
			
		||||
                    sex: "Women ",
 | 
			
		||||
                    age: 23,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10005,
 | 
			
		||||
                    name: "Test5",
 | 
			
		||||
                    nickname: "T5",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Women ",
 | 
			
		||||
                    age: 30,
 | 
			
		||||
                    address: "Shanghai"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10006,
 | 
			
		||||
                    name: "Test6",
 | 
			
		||||
                    nickname: "T6",
 | 
			
		||||
                    role: "Designer",
 | 
			
		||||
                    sex: "Women ",
 | 
			
		||||
                    age: 21,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10007,
 | 
			
		||||
                    name: "Test7",
 | 
			
		||||
                    nickname: "T7",
 | 
			
		||||
                    role: "Test",
 | 
			
		||||
                    sex: "Man ",
 | 
			
		||||
                    age: 29,
 | 
			
		||||
                    address: "vxe-table 从入门到放弃"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10008,
 | 
			
		||||
                    name: "Test8",
 | 
			
		||||
                    nickname: "T8",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Man ",
 | 
			
		||||
                    age: 35,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 10009,
 | 
			
		||||
                    name: "Test9",
 | 
			
		||||
                    nickname: "T9",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Man ",
 | 
			
		||||
                    age: 35,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 100010,
 | 
			
		||||
                    name: "Test10",
 | 
			
		||||
                    nickname: "T10",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Man ",
 | 
			
		||||
                    age: 35,
 | 
			
		||||
                    address: "Guangzhou"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 100011,
 | 
			
		||||
                    name: "Test11",
 | 
			
		||||
                    nickname: "T11",
 | 
			
		||||
                    role: "Test",
 | 
			
		||||
                    sex: "Women ",
 | 
			
		||||
                    age: 26,
 | 
			
		||||
                    address: "vxe-table 从入门到放弃"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 100012,
 | 
			
		||||
                    name: "Test12",
 | 
			
		||||
                    nickname: "T12",
 | 
			
		||||
                    role: "Develop",
 | 
			
		||||
                    sex: "Man ",
 | 
			
		||||
                    age: 34,
 | 
			
		||||
                    address: "Guangzhou"
 | 
			
		||||
                  },
 | 
			
		||||
                  {
 | 
			
		||||
                    id: 100013,
 | 
			
		||||
                    name: "Test13",
 | 
			
		||||
                    nickname: "T13",
 | 
			
		||||
                    role: "Test",
 | 
			
		||||
                    sex: "Women ",
 | 
			
		||||
                    age: 22,
 | 
			
		||||
                    address: "Shenzhen"
 | 
			
		||||
                  }
 | 
			
		||||
                ];
 | 
			
		||||
                resolve({
 | 
			
		||||
                  page: {
 | 
			
		||||
                    total: list.length
 | 
			
		||||
                  },
 | 
			
		||||
                  result: list.slice(
 | 
			
		||||
                    (page.currentPage - 1) * page.pageSize,
 | 
			
		||||
                    page.currentPage * page.pageSize
 | 
			
		||||
                  )
 | 
			
		||||
                });
 | 
			
		||||
              }, 100);
 | 
			
		||||
            });
 | 
			
		||||
          },
 | 
			
		||||
          // body 对象: { removeRecords }
 | 
			
		||||
          delete: () => {
 | 
			
		||||
            return new Promise(resolve => {
 | 
			
		||||
              setTimeout(() => {
 | 
			
		||||
                resolve({});
 | 
			
		||||
              }, 100);
 | 
			
		||||
            });
 | 
			
		||||
          },
 | 
			
		||||
          // body 对象: { insertRecords, updateRecords, removeRecords, pendingRecords }
 | 
			
		||||
          save: () => {
 | 
			
		||||
            return new Promise(resolve => {
 | 
			
		||||
              setTimeout(() => {
 | 
			
		||||
                resolve({});
 | 
			
		||||
              }, 100);
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      columns: [
 | 
			
		||||
        { type: "checkbox", width: 50 },
 | 
			
		||||
        { type: "seq", width: 60 },
 | 
			
		||||
        { field: "name", title: "Name", editRender: { name: "input" } },
 | 
			
		||||
        { field: "nickname", title: "Nickname", editRender: { name: "input" } },
 | 
			
		||||
        { field: "role", title: "Role", editRender: { name: "input" } },
 | 
			
		||||
        {
 | 
			
		||||
          field: "address",
 | 
			
		||||
          title: "Address",
 | 
			
		||||
          showOverflow: true,
 | 
			
		||||
          editRender: { name: "input" }
 | 
			
		||||
        }
 | 
			
		||||
      ]
 | 
			
		||||
    } as VxeGridProps);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      gridOptions
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,170 @@
 | 
			
		||||
<script setup lang="ts">
 | 
			
		||||
import Flop from "/@/components/ReFlop";
 | 
			
		||||
import { ref, computed, onMounted, nextTick } from "vue";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
 | 
			
		||||
import { echartsJson } from "/@/api/mock";
 | 
			
		||||
import echarts from "/@/plugins/echarts";
 | 
			
		||||
import { ECharts } from "echarts";
 | 
			
		||||
 | 
			
		||||
//折线图实例
 | 
			
		||||
let brokenLine: ECharts;
 | 
			
		||||
let mobile = ref<boolean>(deviceDetection());
 | 
			
		||||
let date: Date = new Date();
 | 
			
		||||
let loading = ref<boolean>(true);
 | 
			
		||||
 | 
			
		||||
setTimeout(() => {
 | 
			
		||||
  loading.value = !loading.value;
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    initbrokenLine();
 | 
			
		||||
  });
 | 
			
		||||
}, 500);
 | 
			
		||||
 | 
			
		||||
let greetings = computed(() => {
 | 
			
		||||
  if (date.getHours() >= 0 && date.getHours() < 12) {
 | 
			
		||||
    return "上午阳光明媚,祝你薪水翻倍🌞!";
 | 
			
		||||
  } else if (date.getHours() >= 12 && date.getHours() < 18) {
 | 
			
		||||
    return "下午小风娇好,愿你青春不老😃!";
 | 
			
		||||
  } else {
 | 
			
		||||
    return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!";
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function initbrokenLine() {
 | 
			
		||||
  const lineRefDom = document.getElementById("brokenLine");
 | 
			
		||||
  if (!lineRefDom) return;
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  brokenLine = echarts.init(lineRefDom);
 | 
			
		||||
  brokenLine.clear(); //清除旧画布 重新渲染
 | 
			
		||||
 | 
			
		||||
  echartsJson().then(({ info }) => {
 | 
			
		||||
    brokenLine.setOption({
 | 
			
		||||
      title: {
 | 
			
		||||
        text: "上海 空气质量指数",
 | 
			
		||||
        left: "1%"
 | 
			
		||||
      },
 | 
			
		||||
      tooltip: {
 | 
			
		||||
        trigger: "axis"
 | 
			
		||||
      },
 | 
			
		||||
      grid: {
 | 
			
		||||
        left: "5%",
 | 
			
		||||
        right: "15%",
 | 
			
		||||
        bottom: "10%"
 | 
			
		||||
      },
 | 
			
		||||
      xAxis: {
 | 
			
		||||
        data: info.map(function (item) {
 | 
			
		||||
          return item[0];
 | 
			
		||||
        })
 | 
			
		||||
      },
 | 
			
		||||
      yAxis: {},
 | 
			
		||||
      toolbox: {
 | 
			
		||||
        right: 10,
 | 
			
		||||
        feature: {
 | 
			
		||||
          saveAsImage: {}
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      dataZoom: [
 | 
			
		||||
        {
 | 
			
		||||
          startValue: "2014-06-01"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          type: "inside"
 | 
			
		||||
        }
 | 
			
		||||
      ],
 | 
			
		||||
      visualMap: {
 | 
			
		||||
        top: 50,
 | 
			
		||||
        right: 10,
 | 
			
		||||
        pieces: [
 | 
			
		||||
          {
 | 
			
		||||
            gt: 0,
 | 
			
		||||
            lte: 50,
 | 
			
		||||
            color: "#93CE07"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            gt: 50,
 | 
			
		||||
            lte: 100,
 | 
			
		||||
            color: "#FBDB0F"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            gt: 100,
 | 
			
		||||
            lte: 150,
 | 
			
		||||
            color: "#FC7D02"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            gt: 150,
 | 
			
		||||
            lte: 200,
 | 
			
		||||
            color: "#FD0100"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            gt: 200,
 | 
			
		||||
            lte: 300,
 | 
			
		||||
            color: "#AA069F"
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            gt: 300,
 | 
			
		||||
            color: "#AC3B2A"
 | 
			
		||||
          }
 | 
			
		||||
        ],
 | 
			
		||||
        outOfRange: {
 | 
			
		||||
          color: "#999"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      series: {
 | 
			
		||||
        name: "上海 空气质量指数",
 | 
			
		||||
        type: "line",
 | 
			
		||||
        data: info.map(function (item) {
 | 
			
		||||
          return item[1];
 | 
			
		||||
        }),
 | 
			
		||||
        markLine: {
 | 
			
		||||
          silent: true,
 | 
			
		||||
          lineStyle: {
 | 
			
		||||
            color: "#333"
 | 
			
		||||
          },
 | 
			
		||||
          data: [
 | 
			
		||||
            {
 | 
			
		||||
              yAxis: 50
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              yAxis: 100
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              yAxis: 150
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              yAxis: 200
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              yAxis: 300
 | 
			
		||||
            }
 | 
			
		||||
          ]
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const openDepot = (): void => {
 | 
			
		||||
  window.open("https://github.com/xiaoxian521/vue-pure-admin");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  nextTick(() => {
 | 
			
		||||
    useEventListener("resize", () => {
 | 
			
		||||
      if (!brokenLine) return;
 | 
			
		||||
      useTimeoutFn(() => {
 | 
			
		||||
        brokenLine.resize();
 | 
			
		||||
      }, 180);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
tryOnUnmounted(() => {
 | 
			
		||||
  if (!brokenLine) return;
 | 
			
		||||
  brokenLine.dispose();
 | 
			
		||||
  brokenLine = null;
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="welcome">
 | 
			
		||||
    <el-affix>
 | 
			
		||||
@ -26,185 +193,6 @@
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Flop from "/@/components/ReFlop";
 | 
			
		||||
import { ref, computed, onMounted, nextTick } from "vue";
 | 
			
		||||
import { deviceDetection } from "/@/utils/deviceDetection";
 | 
			
		||||
import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
 | 
			
		||||
import { echartsJson } from "/@/api/mock";
 | 
			
		||||
import echarts from "/@/plugins/echarts";
 | 
			
		||||
 | 
			
		||||
let brokenLine: any = null; //折线图实例
 | 
			
		||||
export default {
 | 
			
		||||
  name: "welcome",
 | 
			
		||||
  components: {
 | 
			
		||||
    Flop
 | 
			
		||||
  },
 | 
			
		||||
  setup() {
 | 
			
		||||
    let mobile = ref(deviceDetection());
 | 
			
		||||
    let date: Date = new Date();
 | 
			
		||||
    let loading = ref(true);
 | 
			
		||||
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      loading.value = !loading.value;
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        initbrokenLine();
 | 
			
		||||
      });
 | 
			
		||||
    }, 500);
 | 
			
		||||
 | 
			
		||||
    let greetings = computed(() => {
 | 
			
		||||
      if (date.getHours() >= 0 && date.getHours() < 12) {
 | 
			
		||||
        return "上午阳光明媚,祝你薪水翻倍🌞!";
 | 
			
		||||
      } else if (date.getHours() >= 12 && date.getHours() < 18) {
 | 
			
		||||
        return "下午小风娇好,愿你青春不老😃!";
 | 
			
		||||
      } else {
 | 
			
		||||
        return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!";
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    function initbrokenLine() {
 | 
			
		||||
      const lineRefDom = document.getElementById("brokenLine");
 | 
			
		||||
      if (!lineRefDom) return;
 | 
			
		||||
      brokenLine = echarts.init(lineRefDom);
 | 
			
		||||
      brokenLine.clear(); //清除旧画布 重新渲染
 | 
			
		||||
 | 
			
		||||
      echartsJson().then(({ info }) => {
 | 
			
		||||
        brokenLine.setOption({
 | 
			
		||||
          title: {
 | 
			
		||||
            text: "上海 空气质量指数",
 | 
			
		||||
            left: "1%"
 | 
			
		||||
          },
 | 
			
		||||
          tooltip: {
 | 
			
		||||
            trigger: "axis"
 | 
			
		||||
          },
 | 
			
		||||
          grid: {
 | 
			
		||||
            left: "5%",
 | 
			
		||||
            right: "15%",
 | 
			
		||||
            bottom: "10%"
 | 
			
		||||
          },
 | 
			
		||||
          xAxis: {
 | 
			
		||||
            data: info.map(function (item) {
 | 
			
		||||
              return item[0];
 | 
			
		||||
            })
 | 
			
		||||
          },
 | 
			
		||||
          yAxis: {},
 | 
			
		||||
          toolbox: {
 | 
			
		||||
            right: 10,
 | 
			
		||||
            feature: {
 | 
			
		||||
              saveAsImage: {}
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          dataZoom: [
 | 
			
		||||
            {
 | 
			
		||||
              startValue: "2014-06-01"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              type: "inside"
 | 
			
		||||
            }
 | 
			
		||||
          ],
 | 
			
		||||
          visualMap: {
 | 
			
		||||
            top: 50,
 | 
			
		||||
            right: 10,
 | 
			
		||||
            pieces: [
 | 
			
		||||
              {
 | 
			
		||||
                gt: 0,
 | 
			
		||||
                lte: 50,
 | 
			
		||||
                color: "#93CE07"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                gt: 50,
 | 
			
		||||
                lte: 100,
 | 
			
		||||
                color: "#FBDB0F"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                gt: 100,
 | 
			
		||||
                lte: 150,
 | 
			
		||||
                color: "#FC7D02"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                gt: 150,
 | 
			
		||||
                lte: 200,
 | 
			
		||||
                color: "#FD0100"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                gt: 200,
 | 
			
		||||
                lte: 300,
 | 
			
		||||
                color: "#AA069F"
 | 
			
		||||
              },
 | 
			
		||||
              {
 | 
			
		||||
                gt: 300,
 | 
			
		||||
                color: "#AC3B2A"
 | 
			
		||||
              }
 | 
			
		||||
            ],
 | 
			
		||||
            outOfRange: {
 | 
			
		||||
              color: "#999"
 | 
			
		||||
            }
 | 
			
		||||
          },
 | 
			
		||||
          series: {
 | 
			
		||||
            name: "上海 空气质量指数",
 | 
			
		||||
            type: "line",
 | 
			
		||||
            data: info.map(function (item) {
 | 
			
		||||
              return item[1];
 | 
			
		||||
            }),
 | 
			
		||||
            markLine: {
 | 
			
		||||
              silent: true,
 | 
			
		||||
              lineStyle: {
 | 
			
		||||
                color: "#333"
 | 
			
		||||
              },
 | 
			
		||||
              data: [
 | 
			
		||||
                {
 | 
			
		||||
                  yAxis: 50
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  yAxis: 100
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  yAxis: 150
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  yAxis: 200
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  yAxis: 300
 | 
			
		||||
                }
 | 
			
		||||
              ]
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const openDepot = (): void => {
 | 
			
		||||
      window.open("https://github.com/xiaoxian521/vue-pure-admin");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        useEventListener("resize", () => {
 | 
			
		||||
          if (!brokenLine) return;
 | 
			
		||||
          useTimeoutFn(() => {
 | 
			
		||||
            brokenLine.resize();
 | 
			
		||||
          }, 180);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    tryOnUnmounted(() => {
 | 
			
		||||
      if (!brokenLine) return;
 | 
			
		||||
      brokenLine.dispose();
 | 
			
		||||
      brokenLine = null;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      greetings,
 | 
			
		||||
      mobile,
 | 
			
		||||
      loading,
 | 
			
		||||
      openDepot
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.welcome {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "target": "esnext",
 | 
			
		||||
    "module": "esnext",
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "strict": false,
 | 
			
		||||
    "jsx": "preserve",
 | 
			
		||||
    "importHelpers": true,
 | 
			
		||||
    "moduleResolution": "node",
 | 
			
		||||
    "experimentalDecorators": true,
 | 
			
		||||
    "strictFunctionTypes": false,
 | 
			
		||||
    "skipLibCheck": true,
 | 
			
		||||
    "esModuleInterop": true,
 | 
			
		||||
    "isolatedModules": true,
 | 
			
		||||
@ -16,27 +17,14 @@
 | 
			
		||||
    "baseUrl": ".",
 | 
			
		||||
    "allowJs": false,
 | 
			
		||||
    "resolveJsonModule": true, // 包含导入的模块。json的扩展
 | 
			
		||||
    "lib": [
 | 
			
		||||
      "dom",
 | 
			
		||||
      "esnext"
 | 
			
		||||
    ],
 | 
			
		||||
    "lib": ["dom", "esnext"],
 | 
			
		||||
    "incremental": true,
 | 
			
		||||
    "paths": {
 | 
			
		||||
      "/@/*": [
 | 
			
		||||
        "src/*"
 | 
			
		||||
      ],
 | 
			
		||||
      "/#/*": [
 | 
			
		||||
        "types/*"
 | 
			
		||||
      ]
 | 
			
		||||
      "/@/*": ["src/*"],
 | 
			
		||||
      "/#/*": ["types/*"]
 | 
			
		||||
    },
 | 
			
		||||
    "types": [
 | 
			
		||||
      "node",
 | 
			
		||||
      "vite/client"
 | 
			
		||||
    ],
 | 
			
		||||
    "typeRoots": [
 | 
			
		||||
      "./node_modules/@types/",
 | 
			
		||||
      "./types"
 | 
			
		||||
    ]
 | 
			
		||||
    "types": ["node", "vite/client"],
 | 
			
		||||
    "typeRoots": ["./node_modules/@types/", "./types"]
 | 
			
		||||
  },
 | 
			
		||||
  "include": [
 | 
			
		||||
    "src/**/*.ts",
 | 
			
		||||
@ -46,9 +34,5 @@
 | 
			
		||||
    "mock/*.ts",
 | 
			
		||||
    "vite.config.ts"
 | 
			
		||||
  ],
 | 
			
		||||
  "exclude": [
 | 
			
		||||
    "node_modules",
 | 
			
		||||
    "dist",
 | 
			
		||||
    "**/*.js"
 | 
			
		||||
  ]
 | 
			
		||||
  "exclude": ["node_modules", "dist", "**/*.js"]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										49
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										49
									
								
								types/global.d.ts
									
									
									
									
										vendored
									
									
								
							@ -16,53 +16,54 @@ declare global {
 | 
			
		||||
    };
 | 
			
		||||
    lastBuildTime: string;
 | 
			
		||||
  };
 | 
			
		||||
  declare interface Window {
 | 
			
		||||
  interface Window {
 | 
			
		||||
    // Global vue app instance
 | 
			
		||||
    __APP__: App<Element>;
 | 
			
		||||
    webkitCancelAnimationFrame: (id?: any) => any;
 | 
			
		||||
    webkitRequestAnimationFrame: (id?: any) => any;
 | 
			
		||||
    mozCancelAnimationFrame: (id?: any) => any;
 | 
			
		||||
    oCancelAnimationFrame: (id?: any) => any;
 | 
			
		||||
    msCancelAnimationFrame: (id?: any) => any;
 | 
			
		||||
    mozRequestAnimationFrame: (id?: any) => any;
 | 
			
		||||
    oRequestAnimationFrame: (id?: any) => any;
 | 
			
		||||
    msRequestAnimationFrame: (id?: any) => any;
 | 
			
		||||
    webkitCancelAnimationFrame: (handle: number) => void;
 | 
			
		||||
    mozCancelAnimationFrame: (handle: number) => void;
 | 
			
		||||
    oCancelAnimationFrame: (handle: number) => void;
 | 
			
		||||
    msCancelAnimationFrame: (handle: number) => void;
 | 
			
		||||
 | 
			
		||||
    webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number;
 | 
			
		||||
    mozRequestAnimationFrame: (callback: FrameRequestCallback) => number;
 | 
			
		||||
    oRequestAnimationFrame: (callback: FrameRequestCallback) => number;
 | 
			
		||||
    msRequestAnimationFrame: (callback: FrameRequestCallback) => number;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // vue
 | 
			
		||||
  declare type PropType<T> = VuePropType<T>;
 | 
			
		||||
  type PropType<T> = VuePropType<T>;
 | 
			
		||||
 | 
			
		||||
  export type Writable<T> = {
 | 
			
		||||
  type Writable<T> = {
 | 
			
		||||
    -readonly [P in keyof T]: T[P];
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  declare type Nullable<T> = T | null;
 | 
			
		||||
  declare type NonNullable<T> = T extends null | undefined ? never : T;
 | 
			
		||||
  declare type Recordable<T = any> = Record<string, T>;
 | 
			
		||||
  declare type ReadonlyRecordable<T = any> = {
 | 
			
		||||
  type Nullable<T> = T | null;
 | 
			
		||||
  type NonNullable<T> = T extends null | undefined ? never : T;
 | 
			
		||||
  type Recordable<T = any> = Record<string, T>;
 | 
			
		||||
  type ReadonlyRecordable<T = any> = {
 | 
			
		||||
    readonly [key: string]: T;
 | 
			
		||||
  };
 | 
			
		||||
  declare type Indexable<T = any> = {
 | 
			
		||||
  type Indexable<T = any> = {
 | 
			
		||||
    [key: string]: T;
 | 
			
		||||
  };
 | 
			
		||||
  declare type DeepPartial<T> = {
 | 
			
		||||
  type DeepPartial<T> = {
 | 
			
		||||
    [P in keyof T]?: DeepPartial<T[P]>;
 | 
			
		||||
  };
 | 
			
		||||
  declare type TimeoutHandle = ReturnType<typeof setTimeout>;
 | 
			
		||||
  declare type IntervalHandle = ReturnType<typeof setInterval>;
 | 
			
		||||
  type TimeoutHandle = ReturnType<typeof setTimeout>;
 | 
			
		||||
  type IntervalHandle = ReturnType<typeof setInterval>;
 | 
			
		||||
 | 
			
		||||
  declare interface ChangeEvent extends Event {
 | 
			
		||||
  interface ChangeEvent extends Event {
 | 
			
		||||
    target: HTMLInputElement;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  declare interface WheelEvent {
 | 
			
		||||
  interface WheelEvent {
 | 
			
		||||
    path?: EventTarget[];
 | 
			
		||||
  }
 | 
			
		||||
  interface ImportMetaEnv extends ViteEnv {
 | 
			
		||||
    __: unknown;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  declare interface ViteEnv {
 | 
			
		||||
  interface ViteEnv {
 | 
			
		||||
    VITE_PORT: number;
 | 
			
		||||
    VITE_USE_MOCK: boolean;
 | 
			
		||||
    VITE_USE_PWA: boolean;
 | 
			
		||||
@ -79,9 +80,9 @@ declare global {
 | 
			
		||||
    VITE_GENERATE_UI: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  declare function parseInt(s: string | number, radix?: number): number;
 | 
			
		||||
  function parseInt(s: string | number, radix?: number): number;
 | 
			
		||||
 | 
			
		||||
  declare function parseFloat(string: string | number): number;
 | 
			
		||||
  function parseFloat(string: string | number): number;
 | 
			
		||||
 | 
			
		||||
  namespace JSX {
 | 
			
		||||
    // tslint:disable no-empty-interface
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										4
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								types/index.d.ts
									
									
									
									
										vendored
									
									
								
							@ -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]>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								yarn.lock
									
									
									
									
									
								
							@ -794,7 +794,7 @@
 | 
			
		||||
    "@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-sfc@3.2.11", "@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==
 | 
			
		||||
@ -885,12 +885,12 @@
 | 
			
		||||
  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==
 | 
			
		||||
"@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 +908,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 "*"
 | 
			
		||||
 | 
			
		||||
@ -3865,6 +3865,11 @@ snake-case@^3.0.4:
 | 
			
		||||
    dot-case "^3.0.4"
 | 
			
		||||
    tslib "^2.0.3"
 | 
			
		||||
 | 
			
		||||
sortablejs@1.13.0:
 | 
			
		||||
  version "1.13.0"
 | 
			
		||||
  resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.13.0.tgz#3ab2473f8c69ca63569e80b1cd1b5669b51269e9"
 | 
			
		||||
  integrity sha512-RBJirPY0spWCrU5yCmWM1eFs/XgX2J5c6b275/YyxFRgnzPhKl/TDeU2hNR8Dt7ITq66NRPM4UlOt+e5O4CFHg==
 | 
			
		||||
 | 
			
		||||
sortablejs@1.14.0:
 | 
			
		||||
  version "1.14.0"
 | 
			
		||||
  resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
 | 
			
		||||
@ -4493,14 +4498,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.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==
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user