Merge pull request #38 from xiaoxian521/refactor/setup

Refactor/setup
This commit is contained in:
啝裳
2021-09-19 15:41:33 +08:00
committed by GitHub
59 changed files with 5006 additions and 2826 deletions

View File

@@ -3,6 +3,35 @@ module.exports = {
env: { env: {
node: true 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: [ extends: [
"plugin:vue/vue3-essential", "plugin:vue/vue3-essential",
"eslint:recommended", "eslint:recommended",

View File

@@ -6,7 +6,7 @@
<link rel="stylesheet" href="/iconfont.css" /> <link rel="stylesheet" href="/iconfont.css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>后台管理系统</title> <title>后台管理系统</title>
<script src="https://cdn.bootcdn.net/ajax/libs/Sortable/1.13.0/Sortable.js"></script> <script src="/sortable.min.js"></script>
<script> <script>
window.process = {}; window.process = {};
</script> </script>

View File

@@ -8,20 +8,20 @@
"build": "rimraf dist && cross-env vite build", "build": "rimraf dist && cross-env vite build",
"preview": "vite preview", "preview": "vite preview",
"preview:build": "yarn build && 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: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: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: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:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
"lint:pretty": "pretty-quick --staged", "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" "prepare": "husky install"
}, },
"dependencies": { "dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1", "@amap/amap-jsapi-loader": "^1.0.1",
"@logicflow/core": "^0.4.6", "@logicflow/core": "^0.4.6",
"@logicflow/extension": "^0.4.6", "@logicflow/extension": "^0.4.6",
"@vueuse/core": "^6.0.0", "@vueuse/core": "^6.4.1",
"animate.css": "^4.1.1", "animate.css": "^4.1.1",
"await-to-js": "^3.0.0", "await-to-js": "^3.0.0",
"axios": "^0.21.1", "axios": "^0.21.1",
@@ -41,12 +41,13 @@
"pinia": "^2.0.0-rc.6", "pinia": "^2.0.0-rc.6",
"resize-observer-polyfill": "^1.5.1", "resize-observer-polyfill": "^1.5.1",
"responsive-storage": "^1.0.9", "responsive-storage": "^1.0.9",
"sortablejs": "1.13.0",
"v-contextmenu": "^3.0.0", "v-contextmenu": "^3.0.0",
"vue": "^3.2.11", "vue": "3.2.11",
"vue-i18n": "^9.2.0-beta.3", "vue-i18n": "^9.2.0-beta.3",
"vue-json-pretty": "^2.0.2", "vue-json-pretty": "^2.0.2",
"vue-router": "^4.0.11", "vue-router": "^4.0.11",
"vue-types": "^4.0.3", "vue-types": "^4.1.0",
"vuedraggable": "^4.1.0", "vuedraggable": "^4.1.0",
"vxe-table": "^4.0.27", "vxe-table": "^4.0.27",
"wangeditor": "^4.7.7", "wangeditor": "^4.7.7",
@@ -65,7 +66,7 @@
"@typescript-eslint/parser": "^4.31.0", "@typescript-eslint/parser": "^4.31.0",
"@vitejs/plugin-vue": "^1.6.0", "@vitejs/plugin-vue": "^1.6.0",
"@vitejs/plugin-vue-jsx": "^1.1.7", "@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-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^7.0.0", "@vue/eslint-config-typescript": "^7.0.0",
"autoprefixer": "^10.2.4", "autoprefixer": "^10.2.4",

2607
public/sortable.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,25 @@
<template> <script setup lang="ts">
<el-config-provider :locale="currentLocale"> import { getCurrentInstance } from "vue";
<router-view />
</el-config-provider>
</template>
<script>
import { ElConfigProvider } from "element-plus"; import { ElConfigProvider } from "element-plus";
import zhCn from "element-plus/lib/locale/lang/zh-cn"; import zhCn from "element-plus/lib/locale/lang/zh-cn";
import en from "element-plus/lib/locale/lang/en"; import en from "element-plus/lib/locale/lang/en";
export default {
name: "app", let locale: string =
components: { getCurrentInstance().appContext.config.globalProperties.$storage?.locale
[ElConfigProvider.name]: ElConfigProvider ?.locale;
},
computed: { let currentLocale = () => {
// eslint-disable-next-line vue/return-in-computed-property switch (locale) {
currentLocale() {
switch (this.$storage.locale?.locale) {
case "zh": case "zh":
return zhCn; return zhCn;
case "en": case "en":
return en; return en;
} }
}
}
}; };
</script> </script>
<template>
<el-config-provider :locale="currentLocale()">
<router-view />
</el-config-provider>
</template>

View File

@@ -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> <template>
<el-breadcrumb class="app-breadcrumb" separator="/"> <el-breadcrumb class="app-breadcrumb" separator="/">
<transition-group appear name="breadcrumb"> <transition-group appear name="breadcrumb">
@@ -15,62 +64,6 @@
</el-breadcrumb> </el-breadcrumb>
</template> </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> <style lang="scss" scoped>
.app-breadcrumb.el-breadcrumb { .app-breadcrumb.el-breadcrumb {
display: inline-block; display: inline-block;

View File

@@ -1,5 +1,4 @@
import type { CSSProperties } from "vue"; import type { CSSProperties } from "vue";
import { import {
defineComponent, defineComponent,
onBeforeMount, onBeforeMount,
@@ -40,9 +39,7 @@ const defaultOptions: Cropper.Options = {
rotatable: true rotatable: true
}; };
export default defineComponent({ const props = {
name: "Cropper",
props: {
src: { src: {
type: String, type: String,
required: true required: true
@@ -74,12 +71,16 @@ export default defineComponent({
return {}; return {};
} }
} }
}, };
export default defineComponent({
name: "Cropper",
props,
setup(props) { setup(props) {
const cropper: any = ref<Nullable<Cropper>>(null); const cropper: any = ref<Nullable<Cropper>>(null);
const imgElRef = templateRef<HTMLImageElement | null>("imgElRef", null); const imgElRef = templateRef<HTMLImageElement | null>("imgElRef", null);
const isReady = ref(false); const isReady = ref<boolean>(false);
const getImageStyle = computed((): CSSProperties => { const getImageStyle = computed((): CSSProperties => {
return { return {

View File

@@ -2,9 +2,7 @@ import { defineComponent, ref } from "vue";
import { propTypes } from "/@/utils/propTypes"; import { propTypes } from "/@/utils/propTypes";
import "./filpper.css"; import "./filpper.css";
export default defineComponent({ const props = {
name: "Filpper",
props: {
// front paper text // front paper text
// 前牌文字 // 前牌文字
frontText: propTypes.number.def(0), frontText: propTypes.number.def(0),
@@ -14,7 +12,11 @@ export default defineComponent({
// flipping duration, please be consistent with the CSS animation-duration value. // flipping duration, please be consistent with the CSS animation-duration value.
// 翻牌动画时间与CSS中设置的animation-duration保持一致 // 翻牌动画时间与CSS中设置的animation-duration保持一致
duration: propTypes.number.def(600) duration: propTypes.number.def(600)
}, };
export default defineComponent({
name: "Filpper",
props,
setup(props) { setup(props) {
// eslint-disable-next-line vue/no-setup-props-destructure // eslint-disable-next-line vue/no-setup-props-destructure
const { frontText, backText, duration } = props; const { frontText, backText, duration } = props;

View File

@@ -1,60 +1,29 @@
<template> <script setup lang="ts">
<div class="flip-clock">
<flippers ref="flipperHour1" />
<flippers ref="flipperHour2" />
<em>:</em>
<flippers ref="flipperMinute1" />
<flippers ref="flipperMinute2" />
<em>:</em>
<flippers ref="flipperSecond1" />
<flippers ref="flipperSecond2" />
</div>
</template>
<script lang="ts">
import { ref, unref, nextTick, onUnmounted } from "vue"; import { ref, unref, nextTick, onUnmounted } from "vue";
import { templateRef } from "@vueuse/core";
import flippers from "./Filpper"; import flippers from "./Filpper";
import { templateRef } from "@vueuse/core"; let timer = ref(null);
export default { let flipObjs = ref([]);
name: "Flop",
components: {
flippers
},
setup() {
let timer = ref(null);
let flipObjs = ref([]);
const flipperHour1 = templateRef<HTMLElement | null>("flipperHour1", null); const flipperHour1 = templateRef<HTMLElement | null>("flipperHour1", null);
const flipperHour2 = templateRef<HTMLElement | null>("flipperHour2", null); const flipperHour2 = templateRef<HTMLElement | null>("flipperHour2", null);
const flipperMinute1 = templateRef<HTMLElement | null>( const flipperMinute1 = templateRef<HTMLElement | null>("flipperMinute1", null);
"flipperMinute1", const flipperMinute2 = templateRef<HTMLElement | null>("flipperMinute2", null);
null const flipperSecond1 = templateRef<HTMLElement | null>("flipperSecond1", null);
); const flipperSecond2 = templateRef<HTMLElement | null>("flipperSecond2", null);
const flipperMinute2 = templateRef<HTMLElement | null>(
"flipperMinute2",
null
);
const flipperSecond1 = templateRef<HTMLElement | null>(
"flipperSecond1",
null
);
const flipperSecond2 = templateRef<HTMLElement | null>(
"flipperSecond2",
null
);
// 初始化数字 // 初始化数字
const init = () => { const init = () => {
let now = new Date(); let now = new Date();
let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss"); let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
for (let i = 0; i < flipObjs.value.length; i++) { for (let i = 0; i < flipObjs.value.length; i++) {
flipObjs?.value[i]?.setFront(nowTimeStr[i]); flipObjs?.value[i]?.setFront(nowTimeStr[i]);
} }
}; };
// 开始计时 // 开始计时
const run = () => { const run = () => {
timer.value = setInterval(() => { timer.value = setInterval(() => {
// 获取当前时间 // 获取当前时间
let now = new Date(); let now = new Date();
@@ -67,10 +36,10 @@ export default {
flipObjs?.value[i]?.flipDown(nowTimeStr[i], nextTimeStr[i]); flipObjs?.value[i]?.flipDown(nowTimeStr[i], nextTimeStr[i]);
} }
}, 1000); }, 1000);
}; };
// 正则格式化日期 // 正则格式化日期
const formatDate = (date: Date, dateFormat: string) => { const formatDate = (date: Date, dateFormat: string) => {
/* 单独格式化年份根据y的字符数量输出年份 /* 单独格式化年份根据y的字符数量输出年份
* 例如yyyy => 2019 * 例如yyyy => 2019
yy => 19 yy => 19
@@ -106,14 +75,14 @@ export default {
} }
} }
return dateFormat; return dateFormat;
}; };
// 日期时间补零 // 日期时间补零
const padLeftZero = (str: string | any[]) => { const padLeftZero = (str: string | any[]) => {
return ("00" + str).substr(str.length); return ("00" + str).substr(str.length);
}; };
nextTick(() => { nextTick(() => {
flipObjs.value = [ flipObjs.value = [
unref(flipperHour1), unref(flipperHour1),
unref(flipperHour2), unref(flipperHour2),
@@ -125,33 +94,29 @@ export default {
init(); init();
run(); run();
}); });
onUnmounted(() => { onUnmounted(() => {
if (timer.value) { if (timer.value) {
clearInterval(timer.value); clearInterval(timer.value);
timer.value = null; timer.value = null;
} }
}); });
return {
timer,
flipObjs,
init,
run,
formatDate,
padLeftZero,
flipperHour1,
flipperHour2,
flipperMinute1,
flipperMinute2,
flipperSecond1,
flipperSecond2
};
}
};
</script> </script>
<template>
<div class="flip-clock">
<flippers ref="flipperHour1" />
<flippers ref="flipperHour2" />
<em>:</em>
<flippers ref="flipperMinute1" />
<flippers ref="flipperMinute2" />
<em>:</em>
<flippers ref="flipperSecond1" />
<flippers ref="flipperSecond2" />
</div>
</template>
<style> <style>
.flip-clock .m-flipper { .flip-clock .m-flipper {
margin: 0 3px; margin: 0 3px;

View File

@@ -1,54 +1,26 @@
<template> <script setup lang="ts">
<div class="control-container"> import { ref, unref, onMounted } from "vue";
<!-- 功能按钮 -->
<ul>
<li
v-for="(item, key) in titleLists"
:key="key"
:title="item.text"
:style="{ background: focusIndex === key ? '#ccc' : '' }"
@mouseenter.prevent="onEnter(key)"
@mouseleave.prevent="focusIndex = -1"
>
<button
:ref="'controlButton' + key"
:disabled="item.disabled"
:style="{
cursor: item.disabled === false ? 'pointer' : 'not-allowed'
}"
@click="onControl(item, key)"
>
<span :class="'iconfont ' + item.icon"></span>
<p>{{ item.text }}</p>
</button>
</li>
</ul>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, unref, onMounted } from "vue";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
import { LogicFlow } from "@logicflow/core";
export default defineComponent({ interface Props {
name: "Control", lf: LogicFlow;
props: { catTurboData?: boolean;
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); const props = withDefaults(defineProps<Props>(), {
let titleLists = ref([ 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", icon: "icon-zoom-out-hs",
text: "缩小", text: "缩小",
@@ -84,9 +56,9 @@ export default defineComponent({
text: "查看数据", text: "查看数据",
disabled: false disabled: false
} }
]); ]);
const onControl = (item, key) => { const onControl = (item, key) => {
["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach( ["zoom", "zoom", "resetZoom", "undo", "redo", "getSnapshot"].forEach(
(v, i) => { (v, i) => {
let domControl = props.lf; let domControl = props.lf;
@@ -101,31 +73,48 @@ export default defineComponent({
} }
} }
); );
}; };
const onEnter = key => { const onEnter = key => {
focusIndex.value = key; focusIndex.value = key;
}; };
onMounted(() => { onMounted(() => {
props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => { props.lf.on("history:change", ({ data: { undoAble, redoAble } }) => {
unref(titleLists)[3].disabled = unref(controlButton3).disabled = unref(titleLists)[3].disabled = unref(controlButton3).disabled = !undoAble;
!undoAble; unref(titleLists)[4].disabled = unref(controlButton4).disabled = !redoAble;
unref(titleLists)[4].disabled = unref(controlButton4).disabled =
!redoAble;
}); });
});
return {
focusIndex,
titleLists,
onControl,
onEnter
};
}
}); });
</script> </script>
<template>
<div class="control-container">
<!-- 功能按钮 -->
<ul>
<li
v-for="(item, key) in titleLists"
:key="key"
:title="item.text"
:style="{ background: focusIndex === key ? '#ccc' : '' }"
@mouseenter.prevent="onEnter(key)"
@mouseleave.prevent="focusIndex = -1"
>
<button
:ref="'controlButton' + key"
:disabled="item.disabled"
:style="{
cursor: item.disabled === false ? 'pointer' : 'not-allowed'
}"
@click="onControl(item, key)"
>
<span :class="'iconfont ' + item.icon"></span>
<p>{{ item.text }}</p>
</button>
</li>
</ul>
</div>
</template>
<style scoped> <style scoped>
@import "./assets/iconfont/iconfont.css"; @import "./assets/iconfont/iconfont.css";

View File

@@ -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> <template>
<vue-json-pretty <vue-json-pretty
:path="'res'" :path="'res'"
:deep="3" :deep="3"
:showLength="true" :showLength="true"
:data="graphData" :data="props.graphData"
></vue-json-pretty> ></vue-json-pretty>
</template> </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>

View File

@@ -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> <template>
<!-- 左侧bpmn元素选择器 --> <!-- 左侧bpmn元素选择器 -->
<div class="node-panel"> <div class="node-panel">
<div <div
class="node-item" class="node-item"
v-for="item in nodeList" v-for="item in props.nodeList"
:key="item.text" :key="item.text"
@mousedown="nodeDragNode(item)" @mousedown="nodeDragNode(item)"
> >
@@ -18,43 +45,6 @@
</div> </div>
</template> </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> <style scoped>
.node-panel { .node-panel {
position: absolute; position: absolute;

View File

@@ -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> <template>
<div style="padding: 0 15px" @click="toggleClick"> <div :class="classes.container" @click="toggleClick">
<svg <svg
:class="{ 'is-active': isActive }" :class="['hamburger', props.isActive ? 'is-active' : '']"
class="hamburger"
viewBox="0 0 1024 1024" viewBox="0 0 1024 1024"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="64" width="64"
@@ -15,26 +32,11 @@
</div> </div>
</template> </template>
<script> <style module="classes" scoped>
import { defineComponent } from "vue"; .container {
export default defineComponent({ padding: 0 15px;
name: "HamBurger", }
props: { </style>
isActive: {
type: Boolean,
default: false
}
},
emits: ["toggleClick"],
setup(props, ctx) {
const toggleClick = () => {
ctx.emit("toggleClick");
};
return { toggleClick };
}
});
</script>
<style scoped> <style scoped>
.hamburger { .hamburger {
@@ -44,7 +46,7 @@ export default defineComponent({
height: 20px; height: 20px;
} }
.hamburger.is-active { .is-active {
transform: rotate(180deg); transform: rotate(180deg);
} }
</style> </style>

View File

@@ -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> <template>
<div class="info"> <div class="info">
<el-form :model="model" :rules="rules" ref="ruleForm" class="rule-form"> <el-form :model="model" :rules="rules" ref="ruleForm" class="rule-form">
@@ -47,123 +143,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
.info { .info {
width: 30vw; width: 30vw;

View File

@@ -1,6 +1,5 @@
import { App } from "vue"; import { App } from "vue";
import amap from "./src/Amap.vue"; import amap from "./src/Amap.vue";
import baiduMap from "./src/BaiduMap.vue";
export const Amap = Object.assign(amap, { export const Amap = Object.assign(amap, {
install(app: App) { 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 { export default {
Amap, Amap
BaiduMap
}; };

View File

@@ -1,45 +1,17 @@
<template> <script setup lang="ts">
<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">
import AMapLoader from "@amap/amap-jsapi-loader"; import AMapLoader from "@amap/amap-jsapi-loader";
import { import { reactive, getCurrentInstance, onBeforeMount, onUnmounted } from "vue";
reactive,
toRefs,
defineComponent,
onBeforeMount,
getCurrentInstance
} from "vue";
import { mapJson } from "/@/api/mock"; import { mapJson } from "/@/api/mock";
import { deviceDetection } from "/@/utils/deviceDetection"; import { deviceDetection } from "/@/utils/deviceDetection";
import greenCar from "/@/assets/green.png"; import greenCar from "/@/assets/green.png";
let MarkerCluster;
export interface MapConfigureInter { export interface MapConfigureInter {
// eslint-disable-next-line no-undef
on: Fn; on: Fn;
// eslint-disable-next-line no-undef
destroy?: Fn; destroy?: Fn;
// eslint-disable-next-line no-undef
clearEvents?: Fn; clearEvents?: Fn;
// eslint-disable-next-line no-undef
addControl?: Fn; addControl?: Fn;
// eslint-disable-next-line no-undef
setCenter?: Fn; setCenter?: Fn;
// eslint-disable-next-line no-undef
setZoom?: Fn; setZoom?: Fn;
// eslint-disable-next-line no-undef
plugin?: Fn; plugin?: Fn;
} }
@@ -47,36 +19,27 @@ export interface mapInter {
loading: boolean; loading: boolean;
} }
export default defineComponent({ let MarkerCluster;
name: "Amap", let map: MapConfigureInter;
setup() {
const instance = getCurrentInstance();
let map: MapConfigureInter;
const mapSet: mapInter = reactive({ const instance = getCurrentInstance();
const mapSet: mapInter = reactive({
loading: deviceDetection() ? false : true loading: deviceDetection() ? false : true
}); });
// 地图创建完成(动画关闭) // 地图创建完成(动画关闭)
const complete = (): void => { const complete = (): void => {
if (map) { if (map) {
map.on("complete", () => { map.on("complete", () => {
mapSet.loading = false; mapSet.loading = false;
}); });
} }
}; };
// 销毁地图实例 onBeforeMount(() => {
const destroyMap = (): void => {
if (map) {
map.destroy() && map.clearEvents("click");
}
};
onBeforeMount(() => {
if (!instance) return; if (!instance) return;
let { MapConfigure } = let { MapConfigure } = instance.appContext.config.globalProperties.$config;
instance.appContext.config.globalProperties.$config;
let { options } = MapConfigure; let { options } = MapConfigure;
AMapLoader.load({ AMapLoader.load({
@@ -100,7 +63,8 @@ export default defineComponent({
}); });
MarkerCluster = new AMap.MarkerCluster(map, [], { MarkerCluster = new AMap.MarkerCluster(map, [], {
gridSize: 80, // 聚合网格像素大小 // 聚合网格像素大小
gridSize: 80,
maxZoom: 14, maxZoom: 14,
renderMarker(ctx) { renderMarker(ctx) {
let { marker, data } = ctx; let { marker, data } = ctx;
@@ -112,8 +76,10 @@ export default defineComponent({
marker.setContent(content); marker.setContent(content);
marker.setLabel({ marker.setLabel({
direction: "bottom", direction: "bottom",
offset: new AMap.Pixel(-4, 0), //设置文本标注偏移量 //设置文本标注偏移量
content: `<div> ${plateNumber}(${driver})</div>` //设置文本标注内容 offset: new AMap.Pixel(-4, 0),
//设置文本标注内容
content: `<div> ${plateNumber}(${driver})</div>`
}); });
marker.setOffset(new AMap.Pixel(-18, -10)); marker.setOffset(new AMap.Pixel(-18, -10));
marker.on("click", ({ lnglat }) => { marker.on("click", ({ lnglat }) => {
@@ -145,18 +111,27 @@ export default defineComponent({
mapSet.loading = false; mapSet.loading = false;
throw "地图加载失败,请重新加载"; throw "地图加载失败,请重新加载";
}); });
}); });
return { onUnmounted(() => {
...toRefs(mapSet), if (map) {
complete, // 销毁地图实例
destroyMap, map.destroy() && map.clearEvents("click");
greenCar
};
} }
}); });
</script> </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> <style lang="scss" scoped>
#mapview { #mapview {
height: 100%; height: 100%;

View File

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

View File

@@ -1,41 +1,6 @@
<template> <script setup lang="ts">
<div :ref="'wrap' + classOption['key']"> import { computed, ref, unref, nextTick } from "vue";
<div import type { CSSProperties, PropType } from "vue";
:style="leftSwitch"
v-if="navigation"
:class="leftSwitchClass"
@click="leftSwitchClick"
>
<slot name="left-switch"></slot>
</div>
<div
:style="rightSwitch"
v-if="navigation"
:class="rightSwitchClass"
@click="rightSwitchClick"
>
<slot name="right-switch"></slot>
</div>
<div
:ref="'realBox' + classOption['key']"
:style="pos"
@mouseenter="enter"
@mouseleave="leave"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@mousewheel="wheel"
>
<div :ref="'slotList' + classOption['key']" :style="float">
<slot></slot>
</div>
<div v-html="copyHtml" :style="float"></div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, computed, ref, unref, nextTick } from "vue";
import { import {
tryOnMounted, tryOnMounted,
tryOnUnmounted, tryOnUnmounted,
@@ -46,77 +11,68 @@ import * as utilsMethods from "./utils";
const { animationFrame, copyObj } = utilsMethods; const { animationFrame, copyObj } = utilsMethods;
animationFrame(); animationFrame();
export default defineComponent({ const props = defineProps({
name: "SeamlessScroll",
props: {
data: { data: {
type: Array, type: Array as PropType<unknown>
default: () => {
return [];
}
}, },
classOption: { classOption: {
type: Object, type: Object as PropType<unknown>
default: () => {
return {};
} }
} });
},
emits: ["ScrollEnd"],
setup(props, { emit }) {
let xPos = ref(0);
let yPos = ref(0);
let delay = ref(0);
let copyHtml = ref("");
let height = ref(0);
// 外容器宽度
let width = ref(0);
// 内容实际宽度
let realBoxWidth = ref(0);
let realBoxHeight = ref(0);
// single 单步滚动的定时器 const emit = defineEmits<{
let singleWaitTime = null; (e: "scrollEnd"): void;
// move动画的animationFrame定时器 }>();
let reqFrame = null;
let startPos = null;
//记录touchStart时候的posY
let startPosY = null;
//记录touchStart时候的posX
let startPosX = null;
// mouseenter mouseleave 控制scrollMove()的开关
let isHover = false;
let ease = "ease-in";
// eslint-disable-next-line vue/no-setup-props-destructure let xPos = ref<number>(0);
let { classOption } = props; let yPos = ref<number>(0);
let delay = ref<number>(0);
let height = ref<number>(0);
// 外容器宽度
let width = ref<number>(0);
// 内容实际宽度
let realBoxWidth = ref<number>(0);
let realBoxHeight = ref<number>(0);
let copyHtml = ref("");
// single 单步滚动的定时器
let singleWaitTime = null;
// move动画的animationFrame定时器
let reqFrame = null;
let startPos = null;
//记录touchStart时候的posY
let startPosY = null;
//记录touchStart时候的posX
let startPosX = null;
// mouseenter mouseleave 控制scrollMove()的开关
let isHover = false;
let ease = "ease-in";
if (classOption["key"] === undefined) { // eslint-disable-next-line vue/no-setup-props-destructure
let { classOption } = props;
if (classOption["key"] === undefined) {
classOption["key"] = 0; classOption["key"] = 0;
} }
const wrap = templateRef<HTMLElement | null>( const wrap = templateRef<HTMLElement | null>(`wrap${classOption["key"]}`, null);
`wrap${classOption["key"]}`, const slotList = templateRef<HTMLElement | null>(
null
);
const slotList = templateRef<HTMLElement | null>(
`slotList${classOption["key"]}`, `slotList${classOption["key"]}`,
null null
); );
const realBox = templateRef<HTMLElement | null>( const realBox = templateRef<HTMLElement | null>(
`realBox${classOption["key"]}`, `realBox${classOption["key"]}`,
null null
); );
let leftSwitchState = computed(() => { let leftSwitchState = computed(() => {
return unref(xPos) < 0; return unref(xPos) < 0;
}); });
let rightSwitchState = computed(() => { let rightSwitchState = computed(() => {
return Math.abs(unref(xPos)) < unref(realBoxWidth) - unref(width); return Math.abs(unref(xPos)) < unref(realBoxWidth) - unref(width);
}); });
let defaultOption = computed(() => { let defaultOption = computed(() => {
return { return {
//步长 //步长
step: 1, step: 1,
@@ -143,30 +99,30 @@ export default defineComponent({
// singleWidth/singleHeight 是否开启rem度量 // singleWidth/singleHeight 是否开启rem度量
isSingleRemUnit: false isSingleRemUnit: false
}; };
}); });
let options = computed(() => { let options = computed(() => {
// @ts-ignore // @ts-ignore
return copyObj({}, unref(defaultOption), classOption); return copyObj({}, unref(defaultOption), classOption);
}); });
let leftSwitchClass = computed(() => { const leftSwitchClass = computed(() => {
return unref(leftSwitchState) ? "" : unref(options).switchDisabledClass; return unref(leftSwitchState) ? "" : unref(options).switchDisabledClass;
}); });
let rightSwitchClass = computed(() => { let rightSwitchClass = computed(() => {
return unref(rightSwitchState) ? "" : unref(options).switchDisabledClass; return unref(rightSwitchState) ? "" : unref(options).switchDisabledClass;
}); });
let leftSwitch = computed(() => { let leftSwitch = computed((): CSSProperties => {
return { return {
position: "absolute", position: "absolute",
margin: `${unref(height) / 2}px 0 0 -${unref(options).switchOffset}px`, margin: `${unref(height) / 2}px 0 0 -${unref(options).switchOffset}px`,
transform: "translate(-100%,-50%)" transform: "translate(-100%,-50%)"
}; };
}); });
let rightSwitch = computed(() => { let rightSwitch = computed((): CSSProperties => {
return { return {
position: "absolute", position: "absolute",
margin: `${unref(height) / 2}px 0 0 ${ margin: `${unref(height) / 2}px 0 0 ${
@@ -174,68 +130,65 @@ export default defineComponent({
}px`, }px`,
transform: "translateY(-50%)" transform: "translateY(-50%)"
}; };
}); });
let isHorizontal = computed(() => { let isHorizontal = computed(() => {
return ( return (
unref(options).direction !== "bottom" && unref(options).direction !== "bottom" && unref(options).direction !== "top"
unref(options).direction !== "top"
); );
}); });
let float = computed(() => { let float = computed((): CSSProperties => {
return unref(isHorizontal) return unref(isHorizontal)
? { float: "left", overflow: "hidden" } ? { float: "left", overflow: "hidden" }
: { overflow: "hidden" }; : { overflow: "hidden" };
}); });
let pos = computed(() => { let pos = computed(() => {
return { return {
transform: `translate(${unref(xPos)}px,${unref(yPos)}px)`, transform: `translate(${unref(xPos)}px,${unref(yPos)}px)`,
transition: `all ${ease} ${unref(delay)}ms`, transition: `all ${ease} ${unref(delay)}ms`,
overflow: "hidden" overflow: "hidden"
}; };
}); });
let navigation = computed(() => { let navigation = computed(() => {
return unref(options).navigation; return unref(options).navigation;
}); });
let autoPlay = computed(() => { let autoPlay = computed(() => {
if (unref(navigation)) return false; if (unref(navigation)) return false;
return unref(options).autoPlay; return unref(options).autoPlay;
}); });
let scrollSwitch = computed(() => { let scrollSwitch = computed(() => {
// 从 props 解构出来的 属性 不再具有相应性. // 从 props 解构出来的 属性 不再具有相应性.
return props.data.length >= unref(options).limitMoveNum; return props.data.length >= unref(options).limitMoveNum;
}); });
let hoverStopSwitch = computed(() => { let hoverStopSwitch = computed(() => {
return unref(options).hoverStop && unref(autoPlay) && unref(scrollSwitch); return unref(options).hoverStop && unref(autoPlay) && unref(scrollSwitch);
}); });
let canTouchScroll = computed(() => { let canTouchScroll = computed(() => {
return unref(options).openTouch; return unref(options).openTouch;
}); });
let baseFontSize = computed(() => { let baseFontSize = computed(() => {
return unref(options).isSingleRemUnit return unref(options).isSingleRemUnit
? parseInt( ? parseInt(window.getComputedStyle(document.documentElement, null).fontSize)
window.getComputedStyle(document.documentElement, null).fontSize
)
: 1; : 1;
}); });
let realSingleStopWidth = computed(() => { let realSingleStopWidth = computed(() => {
return unref(options).singleWidth * unref(baseFontSize); return unref(options).singleWidth * unref(baseFontSize);
}); });
let realSingleStopHeight = computed(() => { let realSingleStopHeight = computed(() => {
return unref(options).singleHeight * unref(baseFontSize); return unref(options).singleHeight * unref(baseFontSize);
}); });
let step = computed(() => { let step = computed(() => {
let singleStep; let singleStep;
let step = unref(options).step; let step = unref(options).step;
if (unref(isHorizontal)) { if (unref(isHorizontal)) {
@@ -247,16 +200,16 @@ export default defineComponent({
throw "如果设置了单步滚动step需是单步大小的约数否则无法保证单步滚动结束的位置是否准确"; throw "如果设置了单步滚动step需是单步大小的约数否则无法保证单步滚动结束的位置是否准确";
} }
return step; return step;
}); });
function reset() { function reset() {
xPos.value = 0; xPos.value = 0;
yPos.value = 0; yPos.value = 0;
scrollCancle(); scrollCancle();
scrollInitMove(); scrollInitMove();
} }
function leftSwitchClick() { function leftSwitchClick() {
if (!unref(leftSwitchState)) return; if (!unref(leftSwitchState)) return;
// 小于单步距离 // 小于单步距离
if (Math.abs(unref(xPos)) < unref(options).switchSingleStep) { if (Math.abs(unref(xPos)) < unref(options).switchSingleStep) {
@@ -264,9 +217,9 @@ export default defineComponent({
return; return;
} }
xPos.value += unref(options).switchSingleStep; xPos.value += unref(options).switchSingleStep;
} }
function rightSwitchClick() { function rightSwitchClick() {
if (!unref(rightSwitchState)) return; if (!unref(rightSwitchState)) return;
// 小于单步距离 // 小于单步距离
if ( if (
@@ -277,13 +230,13 @@ export default defineComponent({
return; return;
} }
xPos.value -= unref(options).switchSingleStep; xPos.value -= unref(options).switchSingleStep;
} }
function scrollCancle() { function scrollCancle() {
cancelAnimationFrame(reqFrame || ""); cancelAnimationFrame(reqFrame || "");
} }
function touchStart(e) { function touchStart(e) {
if (!unref(canTouchScroll)) return; if (!unref(canTouchScroll)) return;
let timer; let timer;
//touches数组对象获得屏幕上所有的touch取第一个touch //touches数组对象获得屏幕上所有的touch取第一个touch
@@ -306,9 +259,9 @@ export default defineComponent({
} else { } else {
scrollCancle(); scrollCancle();
} }
} }
function touchMove(e) { function touchMove(e) {
//当屏幕有多个touch或者页面被缩放过就不执行move操作 //当屏幕有多个touch或者页面被缩放过就不执行move操作
if ( if (
!unref(canTouchScroll) || !unref(canTouchScroll) ||
@@ -339,9 +292,9 @@ export default defineComponent({
// 为横向滑动 && 运动方向为左右 // 为横向滑动 && 运动方向为左右
xPos.value = startPosX + endPos.x; xPos.value = startPosX + endPos.x;
} }
} }
function touchEnd() { function touchEnd() {
if (!unref(canTouchScroll)) return; if (!unref(canTouchScroll)) return;
let timer; let timer;
const direction = unref(options).direction; const direction = unref(options).direction;
@@ -362,17 +315,17 @@ export default defineComponent({
delay.value = 0; delay.value = 0;
scrollMove(); scrollMove();
}, unref(delay)); }, unref(delay));
} }
function enter() { function enter() {
if (unref(hoverStopSwitch)) scrollStopMove(); if (unref(hoverStopSwitch)) scrollStopMove();
} }
function leave() { function leave() {
if (unref(hoverStopSwitch)) scrollStartMove(); if (unref(hoverStopSwitch)) scrollStartMove();
} }
function scrollMove() { function scrollMove() {
// 鼠标移入时拦截scrollMove() // 鼠标移入时拦截scrollMove()
if (isHover) return; if (isHover) return;
//进入move立即先清除动画 防止频繁touchMove导致多动画同时进行 //进入move立即先清除动画 防止频繁touchMove导致多动画同时进行
@@ -386,28 +339,28 @@ export default defineComponent({
if (direction === "top") { if (direction === "top") {
// 上 // 上
if (Math.abs(unref(yPos)) >= h) { if (Math.abs(unref(yPos)) >= h) {
emit("ScrollEnd"); emit("scrollEnd");
yPos.value = 0; yPos.value = 0;
} }
yPos.value -= step.value; yPos.value -= step.value;
} else if (direction === "bottom") { } else if (direction === "bottom") {
// 下 // 下
if (unref(yPos) >= 0) { if (unref(yPos) >= 0) {
emit("ScrollEnd"); emit("scrollEnd");
yPos.value = h * -1; yPos.value = h * -1;
} }
yPos.value += step.value; yPos.value += step.value;
} else if (direction === "left") { } else if (direction === "left") {
// 左 // 左
if (Math.abs(unref(xPos)) >= w) { if (Math.abs(unref(xPos)) >= w) {
emit("ScrollEnd"); emit("scrollEnd");
xPos.value = 0; xPos.value = 0;
} }
xPos.value -= step.value; xPos.value -= step.value;
} else if (direction === "right") { } else if (direction === "right") {
// 右 // 右
if (unref(xPos) >= 0) { if (unref(xPos) >= 0) {
emit("ScrollEnd"); emit("scrollEnd");
xPos.value = w * -1; xPos.value = w * -1;
} }
xPos.value += step.value; xPos.value += step.value;
@@ -415,10 +368,7 @@ export default defineComponent({
if (singleWaitTime) clearTimeout(singleWaitTime); if (singleWaitTime) clearTimeout(singleWaitTime);
if (unref(realSingleStopHeight)) { if (unref(realSingleStopHeight)) {
//是否启动了单行暂停配置 //是否启动了单行暂停配置
if ( if (Math.abs(unref(yPos)) % unref(realSingleStopHeight) < unref(step)) {
Math.abs(unref(yPos)) % unref(realSingleStopHeight) <
unref(step)
) {
// 符合条件暂停waitTime // 符合条件暂停waitTime
singleWaitTime = setTimeout(() => { singleWaitTime = setTimeout(() => {
scrollMove(); scrollMove();
@@ -427,10 +377,7 @@ export default defineComponent({
scrollMove(); scrollMove();
} }
} else if (unref(realSingleStopWidth)) { } else if (unref(realSingleStopWidth)) {
if ( if (Math.abs(unref(xPos)) % unref(realSingleStopWidth) < unref(step)) {
Math.abs(unref(xPos)) % unref(realSingleStopWidth) <
unref(step)
) {
// 符合条件暂停waitTime // 符合条件暂停waitTime
singleWaitTime = setTimeout(() => { singleWaitTime = setTimeout(() => {
scrollMove(); scrollMove();
@@ -442,9 +389,9 @@ export default defineComponent({
scrollMove(); scrollMove();
} }
}); });
} }
function scrollInitMove() { function scrollInitMove() {
nextTick(() => { nextTick(() => {
const { switchDelay } = unref(options); const { switchDelay } = unref(options);
//清空copy //清空copy
@@ -485,39 +432,24 @@ export default defineComponent({
yPos.value = xPos.value = 0; yPos.value = xPos.value = 0;
} }
}); });
} }
function scrollStartMove() { function scrollStartMove() {
//开启scrollMove //开启scrollMove
isHover = false; isHover = false;
scrollMove(); scrollMove();
} }
function scrollStopMove() { function scrollStopMove() {
//关闭scrollMove //关闭scrollMove
isHover = true; isHover = true;
// 防止频频hover进出单步滚动,导致定时器乱掉 // 防止频频hover进出单步滚动,导致定时器乱掉
if (singleWaitTime) clearTimeout(singleWaitTime); if (singleWaitTime) clearTimeout(singleWaitTime);
scrollCancle(); scrollCancle();
} }
// watchEffect(() => { // 鼠标滚轮事件
// const watchData = data; function wheel(e) {
// if (!watchData) return;
// nextTick(() => {
// reset();
// });
// const watchAutoPlay = unref(autoPlay);
// if (watchAutoPlay) {
// reset();
// } else {
// scrollStopMove();
// }
// });
// 鼠标滚轮事件
function wheel(e) {
e.preventDefault(); e.preventDefault();
if ( if (
unref(options).direction === "left" || unref(options).direction === "left" ||
@@ -527,59 +459,69 @@ export default defineComponent({
useDebounceFn(() => { useDebounceFn(() => {
e.deltaY > 0 ? (yPos.value -= step.value) : (yPos.value += step.value); e.deltaY > 0 ? (yPos.value -= step.value) : (yPos.value += step.value);
}, 50)(); }, 50)();
} }
tryOnMounted(() => { // watchEffect(() => {
// const watchData = data;
// if (!watchData) return;
// nextTick(() => {
// reset();
// });
// const watchAutoPlay = unref(autoPlay);
// if (watchAutoPlay) {
// reset();
// } else {
// scrollStopMove();
// }
// });
tryOnMounted(() => {
scrollInitMove(); scrollInitMove();
}); });
tryOnUnmounted(() => { tryOnUnmounted(() => {
scrollCancle(); scrollCancle();
clearTimeout(singleWaitTime); clearTimeout(singleWaitTime);
}); });
return { defineExpose({
xPos, reset
yPos,
delay,
copyHtml,
height,
width,
realBoxWidth,
leftSwitchState,
rightSwitchState,
options,
leftSwitchClass,
rightSwitchClass,
leftSwitch,
rightSwitch,
isHorizontal,
float,
pos,
navigation,
autoPlay,
scrollSwitch,
hoverStopSwitch,
canTouchScroll,
baseFontSize,
realSingleStopWidth,
realSingleStopHeight,
step,
reset,
leftSwitchClick,
rightSwitchClick,
scrollCancle,
touchStart,
touchMove,
touchEnd,
enter,
leave,
scrollMove,
scrollInitMove,
scrollStartMove,
scrollStopMove,
wheel
};
}
}); });
</script> </script>
<template>
<div :ref="'wrap' + classOption['key']">
<div
:style="leftSwitch"
v-if="navigation"
:class="leftSwitchClass"
@click="leftSwitchClick"
>
<slot name="left-switch"></slot>
</div>
<div
:style="rightSwitch"
v-if="navigation"
:class="rightSwitchClass"
@click="rightSwitchClick"
>
<slot name="right-switch"></slot>
</div>
<div
:ref="'realBox' + classOption['key']"
:style="pos"
@mouseenter="enter"
@mouseleave="leave"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
@mousewheel="wheel"
>
<div :ref="'slotList' + classOption['key']" :style="float">
<slot></slot>
</div>
<div v-html="copyHtml" :style="float"></div>
</div>
</div>
</template>

View File

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

View File

@@ -21,9 +21,7 @@ let overList = [];
// 存放第一个选中的元素和最后一个选中元素,只能存放这两个元素 // 存放第一个选中的元素和最后一个选中元素,只能存放这两个元素
let selectedList = []; let selectedList = [];
export default defineComponent({ const props = {
name: "Selector",
props: {
HsKey: { HsKey: {
type: Number || String, type: Number || String,
default: 0 default: 0
@@ -49,7 +47,11 @@ export default defineComponent({
return []; return [];
} }
} }
}, };
export default defineComponent({
name: "Selector",
props,
emits: ["selectedVal"], emits: ["selectedVal"],
setup(props, { emit }) { setup(props, { emit }) {
const instance = getCurrentInstance(); const instance = getCurrentInstance();

View File

@@ -1,6 +1,6 @@
let config: object = {}; let config: object = {};
const setConfig = (cfg?: any) => { const setConfig = (cfg?: unknown) => {
config = Object.assign(config, cfg); config = Object.assign(config, cfg);
}; };

View File

@@ -1,3 +1,9 @@
<script setup lang="ts">
import { useFullscreen } from "@vueuse/core";
const { isFullscreen, toggle } = useFullscreen();
</script>
<template> <template>
<div class="screen-full" @click="toggle"> <div class="screen-full" @click="toggle">
<i <i
@@ -15,23 +21,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
.screen-full { .screen-full {
width: 40px; width: 40px;

View File

@@ -1,19 +1,17 @@
import { createApp, Directive } from "vue";
import App from "./App.vue"; import App from "./App.vue";
import router from "./router"; import router from "./router";
import { setupStore } from "/@/store"; import { setupStore } from "/@/store";
import { createApp, Directive } from "vue";
import { useElementPlus } from "../src/plugins/element-plus";
import { useTable } from "../src/plugins/vxe-table";
import { usI18n } from "../src/plugins/i18n"; 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 "./style/index.scss";
// 导入字体图标 // 导入字体图标
import "./assets/iconfont/iconfont.js"; import "./assets/iconfont/iconfont.js";
import "./assets/iconfont/iconfont.css"; import "./assets/iconfont/iconfont.css";
import "animate.css";
import "v-contextmenu/dist/themes/default.css"; import "v-contextmenu/dist/themes/default.css";
import { setConfig, getConfig } from "./config"; import { setConfig, getConfig } from "./config";
@@ -25,7 +23,7 @@ app.config.globalProperties.$config = getConfig();
// 响应式storage // 响应式storage
import Storage from "responsive-storage"; import Storage from "responsive-storage";
// @ts-ignore
app.use(Storage, { app.use(Storage, {
// 默认显示首页tag // 默认显示首页tag
routesInStorage: { routesInStorage: {
@@ -58,7 +56,7 @@ Object.keys(directives).forEach(key => {
}); });
// 获取项目动态全局配置 // 获取项目动态全局配置
export const getServerConfig = async (): Promise<any> => { export const getServerConfig = async (): Promise<undefined> => {
return axios({ return axios({
baseURL: "", baseURL: "",
method: "get", method: "get",
@@ -87,10 +85,7 @@ export const getServerConfig = async (): Promise<any> => {
getServerConfig().then(async () => { getServerConfig().then(async () => {
setupStore(app); setupStore(app);
app.use(router).use(useElementPlus).use(useTable).use(usI18n); app.use(router).use(useElementPlus).use(useTable).use(usI18n);
await router.isReady(); await router.isReady();
app.mount("#app"); app.mount("#app");
}); });

View File

@@ -7,6 +7,7 @@ import enVxeTable from "vxe-table/lib/locale/lang/en-US";
import enLocale from "element-plus/lib/locale/lang/en"; import enLocale from "element-plus/lib/locale/lang/en";
import zhLocale from "element-plus/lib/locale/lang/zh-cn"; import zhLocale from "element-plus/lib/locale/lang/zh-cn";
// 导航菜单配置
export const menusConfig = { export const menusConfig = {
zh: { zh: {
message: { message: {

View File

@@ -1,7 +1,7 @@
import "xe-utils";
import { App } from "vue"; import { App } from "vue";
import { i18n } from "../i18n/index"; import { i18n } from "../i18n/index";
import "font-awesome/css/font-awesome.css"; import "font-awesome/css/font-awesome.css";
import "xe-utils";
import { import {
// 核心 // 核心
VXETable, VXETable,
@@ -62,6 +62,7 @@ VXETable.setup({
clearable: true clearable: true
}, },
// 对组件内置的提示语进行国际化翻译 // 对组件内置的提示语进行国际化翻译
// @ts-ignore
i18n: (key, args) => i18n.global.t(key, args), i18n: (key, args) => i18n.global.t(key, args),
// 可选,对参数中的列头、校验提示..等进行自动翻译(只对支持国际化的有效) // 可选,对参数中的列头、校验提示..等进行自动翻译(只对支持国际化的有效)
translate(key, args) { translate(key, args) {

View File

@@ -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 homeRouter from "./modules/home";
import flowChartRouter from "./modules/flowchart"; import flowChartRouter from "./modules/flowchart";
import editorRouter from "./modules/editor"; import editorRouter from "./modules/editor";
@@ -9,17 +15,15 @@ import errorRouter from "./modules/error";
import externalLink from "./modules/externalLink"; import externalLink from "./modules/externalLink";
import remainingRouter from "./modules/remaining"; //静态路由 import remainingRouter from "./modules/remaining"; //静态路由
import { storageSession } from "../utils/storage";
import { i18n } from "/@/plugins/i18n"; import { i18n } from "/@/plugins/i18n";
import { getAsyncRoutes } from "/@/api/routes";
import { storageSession } from "../utils/storage";
import { usePermissionStoreHook } from "/@/store/modules/permission"; 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 // https://cn.vitejs.dev/guide/features.html#glob-import
const modulesRoutes = import.meta.glob("/src/views/*/*/*.vue"); const modulesRoutes = import.meta.glob("/src/views/*/*/*.vue");
const constantRoutes: Array<any> = [ const constantRoutes: Array<RouteComponent> = [
homeRouter, homeRouter,
flowChartRouter, flowChartRouter,
editorRouter, editorRouter,
@@ -125,8 +129,10 @@ const whiteList = ["/login", "/register"];
router.beforeEach((to, _from, next) => { router.beforeEach((to, _from, next) => {
const name = storageSession.getItem("info"); const name = storageSession.getItem("info");
NProgress.start(); NProgress.start();
// @ts-ignore
const { t } = i18n.global; 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 (name) {
if (_from?.name) { if (_from?.name) {
next(); next();

View File

@@ -10,7 +10,6 @@ class algorithmProxy implements ProxyAlgorithm {
return Object.keys(val) return Object.keys(val)
.map(v => { .map(v => {
return { return {
// @ts-ignore
...val[v], ...val[v],
key: v key: v
}; };

View File

@@ -5,7 +5,8 @@ import { excludeProps } from "./utils";
*/ */
export const defaultConfig: AxiosRequestConfig = { export const defaultConfig: AxiosRequestConfig = {
baseURL: "", baseURL: "",
timeout: 10000, //10秒超时 //10秒超时
timeout: 10000,
headers: { headers: {
Accept: "application/json, text/plain, */*", Accept: "application/json, text/plain, */*",
"Content-Type": "application/json", "Content-Type": "application/json",

View File

@@ -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|$)")); 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 (!hasClass(ele, cls)) ele.className += " " + cls;
if (extracls) { if (extracls) {
if (!hasClass(ele, extracls)) ele.className += " " + 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 = ( export const removeClass = (
ele: Element, ele: RefType<any>,
cls: string, cls: string,
extracls?: string extracls?: string
): any => { ): any => {
@@ -29,7 +33,7 @@ export const removeClass = (
export const toggleClass = ( export const toggleClass = (
flag: boolean, flag: boolean,
clsName: string, clsName: string,
target?: HTMLElement target?: RefType<any>
): any => { ): any => {
const targetEl = target || document.body; const targetEl = target || document.body;
let { className } = targetEl; let { className } = targetEl;

View File

@@ -2,11 +2,16 @@ import NProgress from "nprogress";
import "nprogress/nprogress.css"; import "nprogress/nprogress.css";
NProgress.configure({ NProgress.configure({
easing: "ease", // 动画方式 // 动画方式
speed: 500, // 递增进度条的速度 easing: "ease",
showSpinner: true, // 是否显示加载ico // 递增进度条的速度
trickleSpeed: 200, // 自动递增间隔 speed: 500,
minimum: 0.3 // 初始化时的最小百分比 // 是否显示加载ico
showSpinner: true,
// 自动递增间隔
trickleSpeed: 200,
// 初始化时的最小百分比
minimum: 0.3
}); });
export default NProgress; export default NProgress;

View File

@@ -30,4 +30,5 @@ propTypes.extend([
type: undefined type: undefined
} }
]); ]);
export { propTypes }; export { propTypes };

View File

@@ -1,24 +1,17 @@
<template> <script setup lang="ts">
<iframe :src="url" frameborder="0" class="iframe"></iframe>
</template>
<script lang="ts">
import { ref } from "vue"; import { ref } from "vue";
export default {
name: "reButton", const url = ref(
setup() {
const url = ref(
process.env.NODE_ENV === "production" process.env.NODE_ENV === "production"
? "/manages/html/button.html" ? "/manages/html/button.html"
: "/html/button.html" : "/html/button.html"
); );
return {
url
};
}
};
</script> </script>
<template>
<iframe :src="url" frameborder="0" class="iframe"></iframe>
</template>
<style scoped> <style scoped>
.iframe { .iframe {
width: 98%; width: 98%;

View File

@@ -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> <template>
<div style="margin: 10px"> <div style="margin: 10px">
<el-row :gutter="24"> <el-row :gutter="24">
@@ -16,20 +22,3 @@
</el-row> </el-row>
</div> </div>
</template> </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>

View File

@@ -1,3 +1,7 @@
<script setup lang="ts">
import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
</script>
<template> <template>
<div style="margin: 10px"> <div style="margin: 10px">
<el-row :gutter="24"> <el-row :gutter="24">
@@ -30,21 +34,6 @@
</div> </div>
</template> </template>
<script lang="ts">
import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
export default {
name: "reCountTo",
components: {
ReNormalCountTo,
ReboundCountTo
},
setup() {
return {};
}
};
</script>
<style lang="scss" scoped> <style lang="scss" scoped>
.flex { .flex {
display: flex; display: flex;

View File

@@ -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> <template>
<div style="margin: 10px"> <div style="margin: 10px">
<div class="cropper-container"> <div class="cropper-container">
@@ -9,44 +35,6 @@
</div> </div>
</template> </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> <style scoped>
.cropper-container { .cropper-container {
display: flex; display: flex;

View File

@@ -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> <template>
<div class="drag-container"> <div class="drag-container">
<!-- grid列表拖拽 --> <!-- grid列表拖拽 -->
@@ -72,64 +120,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
/* grid列表拖拽 */ /* grid列表拖拽 */
.grid-container { .grid-container {

View File

@@ -1,22 +1,13 @@
<script setup lang="ts">
import { Amap } from "/@/components/ReMap";
</script>
<template> <template>
<div class="map"> <div class="map">
<Amap /> <Amap />
</div> </div>
</template> </template>
<script lang="ts">
import { Amap } from "/@/components/ReMap";
export default {
name: "reMap",
components: {
Amap
},
setup() {
return {};
}
};
</script>
<style scoped> <style scoped>
.map { .map {
width: 100%; width: 100%;

View File

@@ -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> <template>
<el-space wrap> <el-space wrap>
<el-card class="box-card"> <el-card class="box-card">
@@ -60,68 +108,6 @@
</el-space> </el-space>
</template> </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> <style lang="scss" scoped>
.box-card { .box-card {
margin: 10px; margin: 10px;

View File

@@ -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> <template>
<div> <div>
<el-card <el-card
@@ -21,38 +44,3 @@
</el-card> </el-card>
</div> </div>
</template> </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>

View File

@@ -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> <template>
<div class="split-pane"> <div class="split-pane">
<splitpane :splitSet="settingLR"> <splitpane :splitSet="settingLR">
@@ -22,35 +39,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
$W: 100%; $W: 100%;
$H: 80vh; $H: 80vh;

View File

@@ -1,8 +1,4 @@
<template> <script setup lang="ts">
<div id="mse"></div>
</template>
<script lang="ts">
import { onMounted } from "vue"; import { onMounted } from "vue";
import Player from "xgplayer/dist/simple_player"; import Player from "xgplayer/dist/simple_player";
import volume from "xgplayer/dist/controls/volume"; import volume from "xgplayer/dist/controls/volume";
@@ -10,10 +6,7 @@ import playbackRate from "xgplayer/dist/controls/playbackRate";
import screenShot from "xgplayer/dist/controls/screenShot"; import screenShot from "xgplayer/dist/controls/screenShot";
import { deviceDetection } from "/@/utils/deviceDetection"; import { deviceDetection } from "/@/utils/deviceDetection";
export default { onMounted(() => {
name: "reVideo",
setup() {
onMounted(() => {
new Player({ new Player({
id: "mse", id: "mse",
autoplay: false, autoplay: false,
@@ -23,15 +16,17 @@ export default {
"https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg", "https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
fluid: deviceDetection(), fluid: deviceDetection(),
controlPlugins: [volume, playbackRate, screenShot], controlPlugins: [volume, playbackRate, screenShot],
playbackRate: [0.5, 0.75, 1, 1.5, 2] //传入倍速可选数组 //传入倍速可选数组
playbackRate: [0.5, 0.75, 1, 1.5, 2]
}); });
}); });
return {};
}
};
</script> </script>
<style lang="scss" scoped> <template>
<div id="mse"></div>
</template>
<style scoped>
#mse { #mse {
flex: auto; flex: auto;
} }

View File

@@ -1,47 +1,40 @@
<template> <script lang="ts">
<div> export default {
<div ref="editor"></div> name: "reEditor"
<div :innerHTML="content.html"></div> };
</div> </script>
</template>
<script> <script setup lang="ts">
import { onMounted, onBeforeUnmount, ref, reactive } from "vue"; import { onMounted, onBeforeUnmount, ref, unref } from "vue";
import WangEditor from "wangeditor"; import WangEditor from "wangeditor";
export default { // eslint-disable-next-line no-undef
name: "reEditor", const editor = ref(null);
setup() { const html = ref(null);
const editor = ref(); let instance: WangEditor;
const content = reactive({
html: "",
text: ""
});
let instance; onMounted(() => {
onMounted(() => { instance = new WangEditor(unref(editor));
instance = new WangEditor(editor.value);
Object.assign(instance.config, { Object.assign(instance.config, {
onchange() { onchange() {
content.html = instance.txt.html(); html.value = instance.txt.html();
} }
}); });
instance.create(); instance.create();
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
instance.destroy(); instance.destroy();
instance = null; });
});
return {
editor,
content
};
}
};
</script> </script>
<template>
<div>
<div ref="editor"></div>
<div :innerHTML="html"></div>
</div>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep(.w-e-text-container) { :deep(.w-e-text-container) {
z-index: 99 !important; z-index: 99 !important;

View File

@@ -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> <template>
<div class="errPage-container"> <div class="errPage-container">
<el-row> <el-row>
<el-col :span="12"> <el-col :span="12">
<h1 class="text-jumbo text-ginormous">CURD Admin</h1> <h1 class="text-jumbo text-ginormous">Pure Admin</h1>
<h2>你没有权限去该页面</h2> <h2>你没有权限去该页面</h2>
<h6>如有不满请联系你领导</h6>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<img <img
@@ -18,20 +24,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
.errPage-container { .errPage-container {
width: 800px; width: 800px;

View File

@@ -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> <template>
<div class="wscn-http404-container"> <div class="wscn-http404-container">
<div class="wscn-http404"> <div class="wscn-http404">
@@ -8,7 +18,7 @@
<img class="pic-404__child right" :src="four_cloud" alt="404" /> <img class="pic-404__child right" :src="four_cloud" alt="404" />
</div> </div>
<div class="bullshit"> <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__headline">{{ message }}</div>
<div class="bullshit__info"> <div class="bullshit__info">
Please check that the URL you entered is correct, or click the button Please check that the URL you entered is correct, or click the button
@@ -20,26 +30,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
.wscn-http404-container { .wscn-http404-container {
transform: translate(-50%, -50%); transform: translate(-50%, -50%);

View File

@@ -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> <template>
<div class="logic-flow-view"> <div class="logic-flow-view">
<!-- 辅助工具栏 --> <!-- 辅助工具栏 -->
@@ -19,80 +77,6 @@
</div> </div>
</template> </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> <style scoped>
#LF-Turbo { #LF-Turbo {
width: 100vw; width: 100vw;

View File

@@ -1,48 +1,33 @@
<template> <script setup lang="ts">
<div class="login">
<info
:ruleForm="contextInfo"
@on-behavior="onLogin"
@refreshVerify="refreshVerify"
/>
</div>
</template>
<script lang="ts">
import { reactive, onBeforeMount } from "vue"; import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue"; import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getVerify, getLogin } from "/@/api/user"; import { getVerify, getLogin } from "/@/api/user";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage"; import { storageSession } from "/@/utils/storage";
import { warnMessage, successMessage } from "/@/utils/message"; import { warnMessage, successMessage } from "/@/utils/message";
export default {
name: "login",
components: {
info
},
setup() {
const router = useRouter();
// 刷新验证码 const router = useRouter();
const refreshGetVerify = async () => {
// 刷新验证码
const refreshGetVerify = async () => {
let { svg } = await getVerify(); let { svg } = await getVerify();
contextInfo.svg = svg; contextInfo.svg = svg;
}; };
const contextInfo: ContextProps = reactive({ const contextInfo: ContextProps = reactive({
userName: "", userName: "",
passWord: "", passWord: "",
verify: null, verify: null,
svg: null svg: null
}); });
const toPage = (info: Object): void => { const toPage = (info: Object): void => {
storageSession.setItem("info", info); storageSession.setItem("info", info);
router.push("/"); router.push("/");
}; };
// 登录 // 登录
const onLogin = async () => { const onLogin = async () => {
let { userName, passWord, verify } = contextInfo; let { userName, passWord, verify } = contextInfo;
let { code, info, accessToken } = await getLogin({ let { code, info, accessToken } = await getLogin({
username: userName, username: userName,
@@ -56,23 +41,23 @@ export default {
accessToken accessToken
}) })
: warnMessage(info); : warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
return {
contextInfo,
onLogin,
router,
toPage,
refreshVerify
};
}
}; };
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
</script> </script>
<template>
<div class="login">
<info
:ruleForm="contextInfo"
@on-behavior="onLogin"
@refreshVerify="refreshVerify"
/>
</div>
</template>

View File

@@ -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> <template>
<div class="app-container"> <div class="app-container">
<el-radio-group v-model="auth" @change="changRole"> <el-radio-group v-model="auth" @change="changRole">
@@ -8,30 +23,3 @@
<p v-auth="'v-test'">只有test可看</p> <p v-auth="'v-test'">只有test可看</p>
</div> </div>
</template> </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>

View File

@@ -1,25 +1,10 @@
<template> <script setup lang="ts">
<div class="app-container">
<h4>
当前角色
<span style="font-size: 26px">{{ purview }}</span>
<p style="color: #ffa500">
查看左侧菜单变化(系统管理)模拟后台根据不同角色返回对应路由
</p>
</h4>
<el-button type="primary" @click="changRole">切换角色</el-button>
</div>
</template>
<script lang="ts">
import { ref, unref } from "vue"; import { ref, unref } from "vue";
import { storageSession } from "/@/utils/storage"; import { storageSession } from "/@/utils/storage";
export default {
name: "permissionPage",
setup() {
let purview: string = ref(storageSession.getItem("info").username);
function changRole() { let purview = ref<string>(storageSession.getItem("info").username);
function changRole() {
if (unref(purview) === "admin") { if (unref(purview) === "admin") {
storageSession.setItem("info", { storageSession.setItem("info", {
username: "test", username: "test",
@@ -33,12 +18,18 @@ export default {
}); });
window.location.reload(); window.location.reload();
} }
} }
return {
purview,
changRole
};
}
};
</script> </script>
<template>
<div class="app-container">
<h4>
当前角色
<span style="font-size: 26px">{{ purview }}</span>
<p style="color: #ffa500">
查看左侧菜单变化(系统管理)模拟后台根据不同角色返回对应路由
</p>
</h4>
<el-button type="primary" @click="changRole">切换角色</el-button>
</div>
</template>

View File

@@ -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> <template>
<div></div> <div></div>
</template> </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>

View File

@@ -1,42 +1,27 @@
<template> <script setup lang="ts">
<div class="register">
<info
:ruleForm="contextInfo"
@on-behavior="onRegist"
@refreshVerify="refreshVerify"
/>
</div>
</template>
<script lang="ts">
import { reactive, onBeforeMount } from "vue"; import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue"; import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getRegist, getVerify } from "/@/api/user"; import { getRegist, getVerify } from "/@/api/user";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { warnMessage, successMessage } from "/@/utils/message"; import { warnMessage, successMessage } from "/@/utils/message";
export default {
name: "register",
components: {
info
},
setup() {
const router = useRouter();
// 刷新验证码 const router = useRouter();
const refreshGetVerify = async () => {
// 刷新验证码
const refreshGetVerify = async () => {
let { svg } = await getVerify(); let { svg } = await getVerify();
contextInfo.svg = svg; contextInfo.svg = svg;
}; };
const contextInfo: ContextProps = reactive({ const contextInfo: ContextProps = reactive({
userName: "", userName: "",
passWord: "", passWord: "",
verify: null, verify: null,
svg: null svg: null
}); });
// 注册 // 注册
const onRegist = async () => { const onRegist = async () => {
let { userName, passWord, verify } = contextInfo; let { userName, passWord, verify } = contextInfo;
let { code, info } = await getRegist({ let { code, info } = await getRegist({
username: userName, username: userName,
@@ -46,22 +31,23 @@ export default {
code === 0 code === 0
? successMessage(info) && router.push("/login") ? successMessage(info) && router.push("/login")
: warnMessage(info); : warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
return {
contextInfo,
onRegist,
router,
refreshVerify
};
}
}; };
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
</script> </script>
<template>
<div class="register">
<info
:ruleForm="contextInfo"
@on-behavior="onRegist"
@refreshVerify="refreshVerify"
/>
</div>
</template>

View File

@@ -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> <template>
<div class="config"> <div class="config">
<el-drawer <el-drawer
@@ -14,7 +90,7 @@
<vxe-table <vxe-table
ref="xTable" ref="xTable"
border border
:data="tableData" :data="configData.tableData"
@checkbox-change="checkboxChangeEvent" @checkbox-change="checkboxChangeEvent"
@checkbox-all="checkboxChangeEvent" @checkbox-all="checkboxChangeEvent"
> >
@@ -40,9 +116,9 @@
</vxe-table> </vxe-table>
<vxe-pager <vxe-pager
perfect perfect
v-model:current-page="tablePage.currentPage" v-model:current-page="configData.tablePage.currentPage"
v-model:page-size="tablePage.pageSize" v-model:page-size="configData.tablePage.pageSize"
:total="tablePage.total" :total="configData.tablePage.total"
:layouts="[ :layouts="[
'PrevJump', 'PrevJump',
'PrevPage', 'PrevPage',
@@ -57,12 +133,12 @@
<template #left> <template #left>
<span class="page-left"> <span class="page-left">
<vxe-checkbox <vxe-checkbox
v-model="isAllChecked" v-model="configData.isAllChecked"
:indeterminate="isIndeterminate" :indeterminate="configData.isIndeterminate"
@change="changeAllEvent" @change="changeAllEvent"
></vxe-checkbox> ></vxe-checkbox>
<span class="select-count" <span class="select-count"
>已选中{{ selectRecords.length }}</span >已选中{{ configData.selectRecords.length }}</span
> >
<vxe-button size="small">{{ $t("message.hsdelete") }}</vxe-button> <vxe-button size="small">{{ $t("message.hsdelete") }}</vxe-button>
</span> </span>
@@ -73,98 +149,6 @@
</div> </div>
</template> </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> <style lang="scss" scoped>
.list { .list {
padding: 10px; padding: 10px;

View File

@@ -1,116 +1,6 @@
<template> <script setup lang="ts">
<div class="dict-container"> import Config from "./config.vue";
<!-- 工具栏 --> import { reactive, ref, unref, nextTick } from "vue";
<vxe-toolbar>
<template #buttons>
<vxe-input
v-model="filterName"
:placeholder="$t('message.hssearch')"
@keyup="searchEvent"
></vxe-input>
</template>
<template #tools>
<vxe-button
icon="el-icon-circle-plus-outline"
status="primary"
@click="onAdd"
>{{ $t("message.hsadd") }}</vxe-button
>
<vxe-button
icon="el-icon-folder-opened"
status="primary"
@click="$refs.xTree.setAllTreeExpand(true)"
>{{ $t("message.hsexpendAll") }}</vxe-button
>
<vxe-button
icon="el-icon-folder"
status="primary"
@click="$refs.xTree.clearTreeExpand()"
>{{ $t("message.hscollapseAll") }}</vxe-button
>
</template>
</vxe-toolbar>
<!-- 列表 -->
<vxe-table
ref="xTree"
border
resizable
:tree-config="{
children: 'children',
iconOpen: 'fa fa-minus-square-o',
iconClose: 'fa fa-plus-square-o'
}"
:data="tableData"
@cell-dblclick="cellDBLClickEvent"
>
<vxe-table-column
tree-node
field="name"
title="字典名称"
></vxe-table-column>
<vxe-table-column title="字典类型">
<template #default="{ row }">
<el-tooltip
effect="dark"
:content="'双击复制:' + row.model"
placement="right"
>
<span class="text-model">{{ row.model }}</span>
</el-tooltip>
</template>
</vxe-table-column>
<vxe-table-column title="操作" width="330" fixed="right">
<template #default="{ row }">
<vxe-button type="text" icon="el-icon-edit" @click="onEdit(row)"
>编辑</vxe-button
>
<vxe-button
type="text"
icon="el-icon-circle-plus-outline"
@click="onAddChild(row)"
>新增子类型</vxe-button
>
<vxe-button
v-show="row.model"
type="text"
icon="el-icon-setting"
@click="onDeploy(row)"
>字典配置</vxe-button
>
<vxe-button type="text" icon="el-icon-delete" @click="confirmEvent"
>删除</vxe-button
>
</template>
</vxe-table-column>
</vxe-table>
<!-- 修改添加弹框 -->
<vxe-modal
resize
width="450"
v-model="showEdit"
:title="selectRow ? '编辑' : '新增'"
:loading="submitLoading"
@hide="$refs.xForm.reset()"
>
<template #default>
<vxe-form
ref="xForm"
:data="formData"
:items="formItems"
title-align="right"
title-width="100"
@submit="submitEvent"
></vxe-form>
</template>
</vxe-modal>
<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 XEUtils from "xe-utils";
import { cloneDeep } from "lodash-es"; import { cloneDeep } from "lodash-es";
import { templateRef } from "@vueuse/core"; import { templateRef } from "@vueuse/core";
@@ -121,15 +11,12 @@ import {
VxeTableEvents, VxeTableEvents,
VxeFormPropTypes VxeFormPropTypes
} from "vxe-table"; } from "vxe-table";
import Config from "./config.vue"; type onEditNRow = {
name: string;
model: string;
};
export default { const dictData = reactive({
name: "dict",
components: {
Config
},
setup() {
const dictData = reactive({
submitLoading: false, submitLoading: false,
showEdit: false, showEdit: false,
selectRow: null, selectRow: null,
@@ -193,17 +80,13 @@ export default {
} }
} }
] as VxeFormPropTypes.Items ] as VxeFormPropTypes.Items
}); });
let originData = cloneDeep(dictData.tableData); let originData = cloneDeep(dictData.tableData);
const xTree = templateRef<HTMLElement | any>("xTree", null); const xTree = templateRef<HTMLElement | any>("xTree", null);
const formatDate = (value: any) => { const handleSearch = () => {
return XEUtils.toDateString(value, "yyyy-MM-dd HH:mm:ss.S");
};
const handleSearch = () => {
const filterName = XEUtils.toValueString(dictData.filterName).trim(); const filterName = XEUtils.toValueString(dictData.filterName).trim();
if (filterName) { if (filterName) {
@@ -227,49 +110,45 @@ export default {
} else { } else {
dictData.tableData = originData; dictData.tableData = originData;
} }
}; };
// 创建一个防防抖函数,调用频率间隔 100 毫秒 // 创建一个防防抖函数,调用频率间隔 100 毫秒
const searchEvent = XEUtils.debounce( const searchEvent = XEUtils.debounce(
function () { function () {
handleSearch(); handleSearch();
}, },
100, 100,
{ leading: false, trailing: true } { leading: false, trailing: true }
); );
const confirmEvent = async () => { const confirmEvent = async () => {
const type = await VXETable.modal.confirm("您确定要删除吗?"); const type = await VXETable.modal.confirm("您确定要删除吗?");
(await type) === "confirm" && (await type) === "confirm" &&
VXETable.modal.message({ VXETable.modal.message({
content: "测试数据,不可删除", content: "测试数据,不可删除",
status: "error" status: "error"
}); });
}; };
function commonFn(value, disabled) { function commonFn(value, disabled) {
dictData.selectRow = value; dictData.selectRow = value;
dictData.showEdit = true; dictData.showEdit = true;
dictData.formItems[1].itemRender.props.disabled = disabled; dictData.formItems[1].itemRender.props.disabled = disabled;
} }
// 新增 // 新增
function onAdd() { function onAdd() {
commonFn(null, false); commonFn(null, false);
} }
// 新增子类型 // 新增子类型
function onAddChild(row: any) { function onAddChild(row?: object) {
console.log( console.log("onAddChild", row);
"%crow===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
row
);
commonFn(null, false); commonFn(null, false);
} }
// 编辑 // 编辑
function onEdit(row: any) { function onEdit(row?: onEditNRow) {
dictData.formData = { dictData.formData = {
name: row.name, name: row.name,
model: row.model ? row.model : "暂无字典类型" model: row.model ? row.model : "暂无字典类型"
@@ -279,17 +158,17 @@ export default {
// content: "测试数据,不可编辑", // content: "测试数据,不可编辑",
// status: "error" // status: "error"
// }); // });
} }
// 拷贝当前列表项的数据(字典类型) // 拷贝当前列表项的数据(字典类型)
const { clipboardRef } = useCopyToClipboard(); const { clipboardRef } = useCopyToClipboard();
const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => { const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
clipboardRef.value = unref(row).model; clipboardRef.value = unref(row).model;
}; };
const xTable = ref({} as VxeTableInstance); const xTable = ref({} as VxeTableInstance);
const submitEvent = () => { const submitEvent = () => {
dictData.submitLoading = true; dictData.submitLoading = true;
setTimeout(() => { setTimeout(() => {
const $table = xTable.value; const $table = xTable.value;
@@ -303,35 +182,132 @@ export default {
$table.insert(dictData.formData); $table.insert(dictData.formData);
} }
}, 500); }, 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
};
}
}; };
let drawer = ref(false);
function onDeploy(value?: object) {
console.log("onDeploy", value);
drawer.value = true;
}
function handleClose() {
drawer.value = false;
}
</script> </script>
<template>
<div class="dict-container">
<!-- 工具栏 -->
<vxe-toolbar>
<template #buttons>
<vxe-input
v-model="dictData.filterName"
:placeholder="$t('message.hssearch')"
@keyup="searchEvent"
></vxe-input>
</template>
<template #tools>
<vxe-button
icon="el-icon-circle-plus-outline"
status="primary"
@click="onAdd"
>{{ $t("message.hsadd") }}</vxe-button
>
<vxe-button
icon="el-icon-folder-opened"
status="primary"
@click="$refs.xTree.setAllTreeExpand(true)"
>{{ $t("message.hsexpendAll") }}</vxe-button
>
<vxe-button
icon="el-icon-folder"
status="primary"
@click="$refs.xTree.clearTreeExpand()"
>{{ $t("message.hscollapseAll") }}</vxe-button
>
</template>
</vxe-toolbar>
<!-- 列表 -->
<vxe-table
ref="xTree"
border
resizable
:tree-config="{
children: 'children',
iconOpen: 'fa fa-minus-square-o',
iconClose: 'fa fa-plus-square-o'
}"
:data="dictData.tableData"
@cell-dblclick="cellDBLClickEvent"
>
<vxe-table-column
tree-node
field="name"
title="字典名称"
></vxe-table-column>
<vxe-table-column title="字典类型">
<template #default="{ row }">
<el-tooltip
effect="dark"
:content="'双击复制:' + row.model"
placement="right"
>
<span class="text-model">{{ row.model }}</span>
</el-tooltip>
</template>
</vxe-table-column>
<vxe-table-column title="操作" width="330" fixed="right">
<template #default="{ row }">
<vxe-button type="text" icon="el-icon-edit" @click="onEdit(row)"
>编辑</vxe-button
>
<vxe-button
type="text"
icon="el-icon-circle-plus-outline"
@click="onAddChild(row)"
>新增子类型</vxe-button
>
<vxe-button
v-show="row.model"
type="text"
icon="el-icon-setting"
@click="onDeploy(row)"
>字典配置</vxe-button
>
<vxe-button type="text" icon="el-icon-delete" @click="confirmEvent"
>删除</vxe-button
>
</template>
</vxe-table-column>
</vxe-table>
<!-- 修改添加弹框 -->
<vxe-modal
resize
width="450"
v-model="dictData.showEdit"
:title="dictData.selectRow ? '编辑' : '新增'"
:loading="dictData.submitLoading"
@hide="$refs.xForm.reset()"
>
<template #default>
<vxe-form
ref="xForm"
:data="dictData.formData"
:items="dictData.formItems"
title-align="right"
title-width="100"
@submit="submitEvent"
></vxe-form>
</template>
</vxe-modal>
<Config :drawer="drawer" drawTitle="字典列表" @handleClose="handleClose" />
</div>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
.dict-container { .dict-container {
margin: 10px; margin: 10px;

View File

@@ -1,14 +1,8 @@
<template> <script setup lang="ts">
<vxe-grid v-bind="gridOptions" style="width: 98%"></vxe-grid>
</template>
<script lang="ts">
import { reactive } from "vue"; import { reactive } from "vue";
import { VxeGridProps } from "vxe-table"; import { VxeGridProps } from "vxe-table";
export default {
name: "user", const gridOptions = reactive({
setup() {
const gridOptions = reactive({
border: true, border: true,
resizable: true, resizable: true,
keepSource: true, keepSource: true,
@@ -240,13 +234,9 @@ export default {
editRender: { name: "input" } editRender: { name: "input" }
} }
] ]
} as VxeGridProps); } as VxeGridProps);
return {
gridOptions
};
}
};
</script> </script>
<style scoped></style> <template>
<vxe-grid v-bind="gridOptions" style="width: 98%"></vxe-grid>
</template>

View File

@@ -1,58 +1,26 @@
<template> <script setup lang="ts">
<div class="welcome">
<el-affix>
<div class="top-content">
<div class="left-mark">
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
title="直达仓库地址"
alt
@click="openDepot"
/>
<span>{{ greetings }}</span>
</div>
<Flop v-if="!mobile" />
</div>
</el-affix>
<!-- 图表 -->
<el-card class="box-card">
<el-skeleton style="height: 50vh" :rows="8" :loading="loading" animated>
<template #default>
<div id="brokenLine"></div>
</template>
</el-skeleton>
</el-card>
</div>
</template>
<script lang="ts">
import Flop from "/@/components/ReFlop"; import Flop from "/@/components/ReFlop";
import { ref, computed, onMounted, nextTick } from "vue"; import { ref, computed, onMounted, nextTick } from "vue";
import { deviceDetection } from "/@/utils/deviceDetection"; import { deviceDetection } from "/@/utils/deviceDetection";
import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core"; import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
import { echartsJson } from "/@/api/mock"; import { echartsJson } from "/@/api/mock";
import echarts from "/@/plugins/echarts"; import echarts from "/@/plugins/echarts";
import { ECharts } from "echarts";
let brokenLine: any = null; //折线图实例 //折线图实例
export default { let brokenLine: ECharts;
name: "welcome", let mobile = ref<boolean>(deviceDetection());
components: { let date: Date = new Date();
Flop let loading = ref<boolean>(true);
},
setup() {
let mobile = ref(deviceDetection());
let date: Date = new Date();
let loading = ref(true);
setTimeout(() => { setTimeout(() => {
loading.value = !loading.value; loading.value = !loading.value;
nextTick(() => { nextTick(() => {
initbrokenLine(); initbrokenLine();
}); });
}, 500); }, 500);
let greetings = computed(() => { let greetings = computed(() => {
if (date.getHours() >= 0 && date.getHours() < 12) { if (date.getHours() >= 0 && date.getHours() < 12) {
return "上午阳光明媚,祝你薪水翻倍🌞!"; return "上午阳光明媚,祝你薪水翻倍🌞!";
} else if (date.getHours() >= 12 && date.getHours() < 18) { } else if (date.getHours() >= 12 && date.getHours() < 18) {
@@ -60,11 +28,12 @@ export default {
} else { } else {
return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!"; return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!";
} }
}); });
function initbrokenLine() { function initbrokenLine() {
const lineRefDom = document.getElementById("brokenLine"); const lineRefDom = document.getElementById("brokenLine");
if (!lineRefDom) return; if (!lineRefDom) return;
// @ts-ignore
brokenLine = echarts.init(lineRefDom); brokenLine = echarts.init(lineRefDom);
brokenLine.clear(); //清除旧画布 重新渲染 brokenLine.clear(); //清除旧画布 重新渲染
@@ -172,13 +141,13 @@ export default {
} }
}); });
}); });
} }
const openDepot = (): void => { const openDepot = (): void => {
window.open("https://github.com/xiaoxian521/vue-pure-admin"); window.open("https://github.com/xiaoxian521/vue-pure-admin");
}; };
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
useEventListener("resize", () => { useEventListener("resize", () => {
if (!brokenLine) return; if (!brokenLine) return;
@@ -187,24 +156,43 @@ export default {
}, 180); }, 180);
}); });
}); });
}); });
tryOnUnmounted(() => { tryOnUnmounted(() => {
if (!brokenLine) return; if (!brokenLine) return;
brokenLine.dispose(); brokenLine.dispose();
brokenLine = null; brokenLine = null;
}); });
return {
greetings,
mobile,
loading,
openDepot
};
}
};
</script> </script>
<template>
<div class="welcome">
<el-affix>
<div class="top-content">
<div class="left-mark">
<img
src="https://avatars.githubusercontent.com/u/44761321?s=400&u=30907819abd29bb3779bc247910873e7c7f7c12f&v=4"
title="直达仓库地址"
alt
@click="openDepot"
/>
<span>{{ greetings }}</span>
</div>
<Flop v-if="!mobile" />
</div>
</el-affix>
<!-- 图表 -->
<el-card class="box-card">
<el-skeleton style="height: 50vh" :rows="8" :loading="loading" animated>
<template #default>
<div id="brokenLine"></div>
</template>
</el-skeleton>
</el-card>
</div>
</template>
<style lang="scss" scoped> <style lang="scss" scoped>
.welcome { .welcome {
width: 100%; width: 100%;

View File

@@ -2,11 +2,12 @@
"compilerOptions": { "compilerOptions": {
"target": "esnext", "target": "esnext",
"module": "esnext", "module": "esnext",
"moduleResolution": "node",
"strict": false, "strict": false,
"jsx": "preserve", "jsx": "preserve",
"importHelpers": true, "importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true, "experimentalDecorators": true,
"strictFunctionTypes": false,
"skipLibCheck": true, "skipLibCheck": true,
"esModuleInterop": true, "esModuleInterop": true,
"isolatedModules": true, "isolatedModules": true,
@@ -16,27 +17,14 @@
"baseUrl": ".", "baseUrl": ".",
"allowJs": false, "allowJs": false,
"resolveJsonModule": true, // 包含导入的模块。json的扩展 "resolveJsonModule": true, // 包含导入的模块。json的扩展
"lib": [ "lib": ["dom", "esnext"],
"dom",
"esnext"
],
"incremental": true, "incremental": true,
"paths": { "paths": {
"/@/*": [ "/@/*": ["src/*"],
"src/*" "/#/*": ["types/*"]
],
"/#/*": [
"types/*"
]
}, },
"types": [ "types": ["node", "vite/client"],
"node", "typeRoots": ["./node_modules/@types/", "./types"]
"vite/client"
],
"typeRoots": [
"./node_modules/@types/",
"./types"
]
}, },
"include": [ "include": [
"src/**/*.ts", "src/**/*.ts",
@@ -46,9 +34,5 @@
"mock/*.ts", "mock/*.ts",
"vite.config.ts" "vite.config.ts"
], ],
"exclude": [ "exclude": ["node_modules", "dist", "**/*.js"]
"node_modules",
"dist",
"**/*.js"
]
} }

49
types/global.d.ts vendored
View File

@@ -16,53 +16,54 @@ declare global {
}; };
lastBuildTime: string; lastBuildTime: string;
}; };
declare interface Window { interface Window {
// Global vue app instance // Global vue app instance
__APP__: App<Element>; __APP__: App<Element>;
webkitCancelAnimationFrame: (id?: any) => any; webkitCancelAnimationFrame: (handle: number) => void;
webkitRequestAnimationFrame: (id?: any) => any; mozCancelAnimationFrame: (handle: number) => void;
mozCancelAnimationFrame: (id?: any) => any; oCancelAnimationFrame: (handle: number) => void;
oCancelAnimationFrame: (id?: any) => any; msCancelAnimationFrame: (handle: number) => void;
msCancelAnimationFrame: (id?: any) => any;
mozRequestAnimationFrame: (id?: any) => any; webkitRequestAnimationFrame: (callback: FrameRequestCallback) => number;
oRequestAnimationFrame: (id?: any) => any; mozRequestAnimationFrame: (callback: FrameRequestCallback) => number;
msRequestAnimationFrame: (id?: any) => any; oRequestAnimationFrame: (callback: FrameRequestCallback) => number;
msRequestAnimationFrame: (callback: FrameRequestCallback) => number;
} }
// vue // 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]; -readonly [P in keyof T]: T[P];
}; };
declare type Nullable<T> = T | null; type Nullable<T> = T | null;
declare type NonNullable<T> = T extends null | undefined ? never : T; type NonNullable<T> = T extends null | undefined ? never : T;
declare type Recordable<T = any> = Record<string, T>; type Recordable<T = any> = Record<string, T>;
declare type ReadonlyRecordable<T = any> = { type ReadonlyRecordable<T = any> = {
readonly [key: string]: T; readonly [key: string]: T;
}; };
declare type Indexable<T = any> = { type Indexable<T = any> = {
[key: string]: T; [key: string]: T;
}; };
declare type DeepPartial<T> = { type DeepPartial<T> = {
[P in keyof T]?: DeepPartial<T[P]>; [P in keyof T]?: DeepPartial<T[P]>;
}; };
declare type TimeoutHandle = ReturnType<typeof setTimeout>; type TimeoutHandle = ReturnType<typeof setTimeout>;
declare type IntervalHandle = ReturnType<typeof setInterval>; type IntervalHandle = ReturnType<typeof setInterval>;
declare interface ChangeEvent extends Event { interface ChangeEvent extends Event {
target: HTMLInputElement; target: HTMLInputElement;
} }
declare interface WheelEvent { interface WheelEvent {
path?: EventTarget[]; path?: EventTarget[];
} }
interface ImportMetaEnv extends ViteEnv { interface ImportMetaEnv extends ViteEnv {
__: unknown; __: unknown;
} }
declare interface ViteEnv { interface ViteEnv {
VITE_PORT: number; VITE_PORT: number;
VITE_USE_MOCK: boolean; VITE_USE_MOCK: boolean;
VITE_USE_PWA: boolean; VITE_USE_PWA: boolean;
@@ -79,9 +80,9 @@ declare global {
VITE_GENERATE_UI: string; 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 { namespace JSX {
// tslint:disable no-empty-interface // tslint:disable no-empty-interface

4
types/index.d.ts vendored
View File

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

View File

@@ -794,7 +794,7 @@
"@vue/compiler-core" "3.2.11" "@vue/compiler-core" "3.2.11"
"@vue/shared" "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" version "3.2.11"
resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.11.tgz#628fa12238760d9b9b339ac2e125a759224fadbf" resolved "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.11.tgz#628fa12238760d9b9b339ac2e125a759224fadbf"
integrity sha512-cUIaS8mgJrQ6yucj2AupWAwBRITK3W/a8wCOn9g5fJGtOl8h4APY8vN3lzP8HIJDyEeRF3I8SfRhL+oX97kSnw== integrity sha512-cUIaS8mgJrQ6yucj2AupWAwBRITK3W/a8wCOn9g5fJGtOl8h4APY8vN3lzP8HIJDyEeRF3I8SfRhL+oX97kSnw==
@@ -885,12 +885,12 @@
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.11.tgz#01899f54949caf1ac241de397bd17069632574de" resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.11.tgz#01899f54949caf1ac241de397bd17069632574de"
integrity sha512-ovfXAsSsCvV9JVceWjkqC/7OF5HbgLOtCWjCIosmPGG8lxbPuavhIxRH1dTx4Dg9xLgRTNLvI3pVxG4ItQZekg== integrity sha512-ovfXAsSsCvV9JVceWjkqC/7OF5HbgLOtCWjCIosmPGG8lxbPuavhIxRH1dTx4Dg9xLgRTNLvI3pVxG4ItQZekg==
"@vueuse/core@^6.0.0": "@vueuse/core@^6.4.1":
version "6.3.3" version "6.4.1"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-6.3.3.tgz#0682c01b50d28e91d3d76f27278600ee1692fa24" resolved "https://registry.npmjs.org/@vueuse/core/-/core-6.4.1.tgz#21416997a23bfb4924a5082ed6fa959027f80d04"
integrity sha512-qa/0WYqcvqFKQmlkgsLGlXBrYcQeUi3fzHMIaxsD/lO/zm0IWBSN8CTFu91LwER5qNYs4DGhU5pu7jOdrTzAIQ== integrity sha512-FRFeEPVq77gcMZP0mCloJY+lyHJaUQmUMaPp5fBds3fs/BbkAt7HTMMizFKHWDVjbmA20vBOjmC9tTnfD+DdEA==
dependencies: dependencies:
"@vueuse/shared" "6.3.3" "@vueuse/shared" "6.4.1"
vue-demi "*" vue-demi "*"
"@vueuse/core@~6.1.0": "@vueuse/core@~6.1.0":
@@ -908,10 +908,10 @@
dependencies: dependencies:
vue-demi "*" vue-demi "*"
"@vueuse/shared@6.3.3": "@vueuse/shared@6.4.1":
version "6.3.3" version "6.4.1"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-6.3.3.tgz#4e5c600ad1ed5bf2a8630ad0bd38edb1f4269f37" resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-6.4.1.tgz#5bc84be107cead84e11c21d2c57b1e9f2c376975"
integrity sha512-2+YPRhFNUXEhhvKNTWBtNU6hGkft9+mfYSVjI4hZu2U8KDbNNKF/215lBPzMYI2twScDtPsAssQ+vu5t9PBy0g== integrity sha512-zsaYxxZwACQbMmGg+UBjPUVemi325sDdnnB0mn+PNizE0fVC57B+vbLgdj45NBmr6P4nw6a0Y2rMupebwDWsdw==
dependencies: dependencies:
vue-demi "*" vue-demi "*"
@@ -3865,6 +3865,11 @@ snake-case@^3.0.4:
dot-case "^3.0.4" dot-case "^3.0.4"
tslib "^2.0.3" 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: sortablejs@1.14.0:
version "1.14.0" version "1.14.0"
resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8" resolved "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz#6d2e17ccbdb25f464734df621d4f35d4ab35b3d8"
@@ -4493,14 +4498,14 @@ vue-router@^4.0.11:
dependencies: dependencies:
"@vue/devtools-api" "^6.0.0-beta.14" "@vue/devtools-api" "^6.0.0-beta.14"
vue-types@^4.0.3: vue-types@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.npmjs.org/vue-types/-/vue-types-4.1.0.tgz#8dcbbaccf9d5c3815449ac7cb8ae5864454cfff0" resolved "https://registry.npmjs.org/vue-types/-/vue-types-4.1.0.tgz#8dcbbaccf9d5c3815449ac7cb8ae5864454cfff0"
integrity sha512-oPAeKKx5vY5Q8c7lMQPQyrBIbmWQGael5XEHqO1f+Y3V/RUZNuISz7KxI4woGjh79Vy/gDDaPX9j9zKYpaaA2g== integrity sha512-oPAeKKx5vY5Q8c7lMQPQyrBIbmWQGael5XEHqO1f+Y3V/RUZNuISz7KxI4woGjh79Vy/gDDaPX9j9zKYpaaA2g==
dependencies: dependencies:
is-plain-object "5.0.0" 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" version "3.2.11"
resolved "https://registry.npmjs.org/vue/-/vue-3.2.11.tgz#6b92295048df705ddac558fd3e3ed553e55e57c8" resolved "https://registry.npmjs.org/vue/-/vue-3.2.11.tgz#6b92295048df705ddac558fd3e3ed553e55e57c8"
integrity sha512-JkI3/eIgfk4E0f/p319TD3EZgOwBQfftgnkRsXlT7OrRyyiyoyUXn6embPGZXSBxD3LoZ9SWhJoxLhFh5AleeA== integrity sha512-JkI3/eIgfk4E0f/p319TD3EZgOwBQfftgnkRsXlT7OrRyyiyoyUXn6embPGZXSBxD3LoZ9SWhJoxLhFh5AleeA==