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
commit dd8cc8508e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 5006 additions and 2826 deletions

View File

@ -1,4 +1,4 @@
public
dist
*.d.ts
package.json
package.json

View File

@ -3,6 +3,35 @@ module.exports = {
env: {
node: true
},
globals: {
// Ref sugar (take 2)
$: "readonly",
$$: "readonly",
$ref: "readonly",
$shallowRef: "readonly",
$computed: "readonly",
// index.d.ts
// global.d.ts
Fn: "readonly",
PromiseFn: "readonly",
RefType: "readonly",
LabelValueOptions: "readonly",
EmitType: "readonly",
TargetContext: "readonly",
ComponentElRef: "readonly",
ComponentRef: "readonly",
ElRef: "readonly",
global: "readonly",
ForDataType: "readonly",
ComponentRoutes: "readonly",
// script setup
defineProps: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
withDefaults: "readonly"
},
extends: [
"plugin:vue/vue3-essential",
"eslint:recommended",

View File

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

View File

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

2607
public/sortable.min.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

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

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

View File

@ -1,5 +1,4 @@
import type { CSSProperties } from "vue";
import {
defineComponent,
onBeforeMount,
@ -40,46 +39,48 @@ const defaultOptions: Cropper.Options = {
rotatable: true
};
export default defineComponent({
name: "Cropper",
props: {
src: {
type: String,
required: true
},
alt: {
type: String
},
width: {
type: [String, Number],
default: ""
},
height: {
type: [String, Number],
default: "360px"
},
crossorigin: {
type: String || Object,
default: undefined
},
imageStyle: {
type: Object as PropType<CSSProperties>,
default() {
return {};
}
},
options: {
type: Object as PropType<Options>,
default() {
return {};
}
const props = {
src: {
type: String,
required: true
},
alt: {
type: String
},
width: {
type: [String, Number],
default: ""
},
height: {
type: [String, Number],
default: "360px"
},
crossorigin: {
type: String || Object,
default: undefined
},
imageStyle: {
type: Object as PropType<CSSProperties>,
default() {
return {};
}
},
options: {
type: Object as PropType<Options>,
default() {
return {};
}
}
};
export default defineComponent({
name: "Cropper",
props,
setup(props) {
const cropper: any = ref<Nullable<Cropper>>(null);
const imgElRef = templateRef<HTMLImageElement | null>("imgElRef", null);
const isReady = ref(false);
const isReady = ref<boolean>(false);
const getImageStyle = computed((): CSSProperties => {
return {

View File

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

View File

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

View File

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

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>
<vue-json-pretty
:path="'res'"
:deep="3"
:showLength="true"
:data="graphData"
:data="props.graphData"
></vue-json-pretty>
</template>
<script lang="ts">
import VueJsonPretty from "vue-json-pretty";
import "vue-json-pretty/lib/styles.css";
import { defineComponent } from "vue";
export default defineComponent({
name: "DataDialog",
props: {
graphData: Object
},
components: {
VueJsonPretty
}
});
</script>

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

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

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

View File

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

View File

@ -1,45 +1,17 @@
<template>
<div
id="mapview"
ref="mapview"
v-loading="loading"
element-loading-text="地图加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
></div>
</template>
<script lang="ts">
<script setup lang="ts">
import AMapLoader from "@amap/amap-jsapi-loader";
import {
reactive,
toRefs,
defineComponent,
onBeforeMount,
getCurrentInstance
} from "vue";
import { reactive, getCurrentInstance, onBeforeMount, onUnmounted } from "vue";
import { mapJson } from "/@/api/mock";
import { deviceDetection } from "/@/utils/deviceDetection";
import greenCar from "/@/assets/green.png";
let MarkerCluster;
export interface MapConfigureInter {
// eslint-disable-next-line no-undef
on: Fn;
// eslint-disable-next-line no-undef
destroy?: Fn;
// eslint-disable-next-line no-undef
clearEvents?: Fn;
// eslint-disable-next-line no-undef
addControl?: Fn;
// eslint-disable-next-line no-undef
setCenter?: Fn;
// eslint-disable-next-line no-undef
setZoom?: Fn;
// eslint-disable-next-line no-undef
plugin?: Fn;
}
@ -47,116 +19,119 @@ export interface mapInter {
loading: boolean;
}
export default defineComponent({
name: "Amap",
setup() {
const instance = getCurrentInstance();
let map: MapConfigureInter;
let MarkerCluster;
let map: MapConfigureInter;
const mapSet: mapInter = reactive({
loading: deviceDetection() ? false : true
const instance = getCurrentInstance();
const mapSet: mapInter = reactive({
loading: deviceDetection() ? false : true
});
// ()
const complete = (): void => {
if (map) {
map.on("complete", () => {
mapSet.loading = false;
});
}
};
// ()
const complete = (): void => {
if (map) {
map.on("complete", () => {
mapSet.loading = false;
});
}
};
onBeforeMount(() => {
if (!instance) return;
let { MapConfigure } = instance.appContext.config.globalProperties.$config;
let { options } = MapConfigure;
//
const destroyMap = (): void => {
if (map) {
map.destroy() && map.clearEvents("click");
}
};
AMapLoader.load({
key: MapConfigure.amapKey,
version: "2.0",
plugins: ["AMap.MarkerCluster"]
})
.then(AMap => {
//
map = new AMap.Map(instance.refs.mapview, options);
onBeforeMount(() => {
if (!instance) return;
let { MapConfigure } =
instance.appContext.config.globalProperties.$config;
let { options } = MapConfigure;
//ToolBar
map.plugin(["AMap.ToolBar", "AMap.MapType"], () => {
map.addControl(new AMap.ToolBar());
//
map.addControl(
new AMap.MapType({
defaultType: 0
})
);
});
AMapLoader.load({
key: MapConfigure.amapKey,
version: "2.0",
plugins: ["AMap.MarkerCluster"]
})
.then(AMap => {
//
map = new AMap.Map(instance.refs.mapview, options);
//ToolBar
map.plugin(["AMap.ToolBar", "AMap.MapType"], () => {
map.addControl(new AMap.ToolBar());
//
map.addControl(
new AMap.MapType({
defaultType: 0
})
);
});
MarkerCluster = new AMap.MarkerCluster(map, [], {
gridSize: 80, //
maxZoom: 14,
renderMarker(ctx) {
let { marker, data } = ctx;
if (Array.isArray(data) && data[0]) {
var { driver, plateNumber, orientation } = data[0];
var content = `<img style="transform: scale(1) rotate(${
360 - Number(orientation)
}deg);" src='${greenCar}' />`;
marker.setContent(content);
marker.setLabel({
direction: "bottom",
offset: new AMap.Pixel(-4, 0), //
content: `<div> ${plateNumber}(${driver})</div>` //
});
marker.setOffset(new AMap.Pixel(-18, -10));
marker.on("click", ({ lnglat }) => {
map.setZoom(13); //
map.setCenter(lnglat);
});
}
}
});
//
mapJson()
.then(res => {
let points: object = res.info.map((v: any) => {
return {
lnglat: [v.lng, v.lat],
...v
};
});
if (MarkerCluster) MarkerCluster.setData(points);
})
.catch(err => {
console.log("err:", err);
MarkerCluster = new AMap.MarkerCluster(map, [], {
//
gridSize: 80,
maxZoom: 14,
renderMarker(ctx) {
let { marker, data } = ctx;
if (Array.isArray(data) && data[0]) {
var { driver, plateNumber, orientation } = data[0];
var content = `<img style="transform: scale(1) rotate(${
360 - Number(orientation)
}deg);" src='${greenCar}' />`;
marker.setContent(content);
marker.setLabel({
direction: "bottom",
//
offset: new AMap.Pixel(-4, 0),
//
content: `<div> ${plateNumber}(${driver})</div>`
});
marker.setOffset(new AMap.Pixel(-18, -10));
marker.on("click", ({ lnglat }) => {
map.setZoom(13); //
map.setCenter(lnglat);
});
}
}
});
complete();
//
mapJson()
.then(res => {
let points: object = res.info.map((v: any) => {
return {
lnglat: [v.lng, v.lat],
...v
};
});
if (MarkerCluster) MarkerCluster.setData(points);
})
.catch(() => {
mapSet.loading = false;
throw "地图加载失败,请重新加载";
.catch(err => {
console.log("err:", err);
});
});
return {
...toRefs(mapSet),
complete,
destroyMap,
greenCar
};
complete();
})
.catch(() => {
mapSet.loading = false;
throw "地图加载失败,请重新加载";
});
});
onUnmounted(() => {
if (map) {
//
map.destroy() && map.clearEvents("click");
}
});
</script>
<template>
<div
id="mapview"
ref="mapview"
v-loading="mapSet.loading"
element-loading-text="地图加载中"
element-loading-spinner="el-icon-loading"
element-loading-background="rgba(0, 0, 0, 0.8)"
></div>
</template>
<style lang="scss" scoped>
#mapview {
height: 100%;

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -21,35 +21,37 @@ let overList = [];
// 存放第一个选中的元素和最后一个选中元素,只能存放这两个元素
let selectedList = [];
export default defineComponent({
name: "Selector",
props: {
HsKey: {
type: Number || String,
default: 0
},
disabled: {
type: Boolean,
default: false
},
value: {
type: Number,
default: 0
},
max: {
type: Array,
default() {
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}
},
// 回显数据的索引长度必须是2
echo: {
type: Array,
default() {
return [];
}
const props = {
HsKey: {
type: Number || String,
default: 0
},
disabled: {
type: Boolean,
default: false
},
value: {
type: Number,
default: 0
},
max: {
type: Array,
default() {
return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}
},
// 回显数据的索引长度必须是2
echo: {
type: Array,
default() {
return [];
}
}
};
export default defineComponent({
name: "Selector",
props,
emits: ["selectedVal"],
setup(props, { emit }) {
const instance = getCurrentInstance();

View File

@ -1,6 +1,6 @@
let config: object = {};
const setConfig = (cfg?: any) => {
const setConfig = (cfg?: unknown) => {
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>
<div class="screen-full" @click="toggle">
<i
@ -15,23 +21,6 @@
</div>
</template>
<script>
import { useFullscreen } from "@vueuse/core";
import { defineComponent } from "vue";
export default defineComponent({
name: "screenfull",
setup() {
const { isFullscreen, toggle } = useFullscreen();
return {
isFullscreen,
toggle
};
}
});
</script>
<style lang="scss" scoped>
.screen-full {
width: 40px;

View File

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

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 zhLocale from "element-plus/lib/locale/lang/zh-cn";
// 导航菜单配置
export const menusConfig = {
zh: {
message: {

View File

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

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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>
<div style="margin: 10px">
<el-row :gutter="24">
@ -16,20 +22,3 @@
</el-row>
</div>
</template>
<script lang="ts">
import basic from "./basic.vue";
import menuGroup from "./menuGroup.vue";
import menuDynamic from "./menuDynamic.vue";
export default {
name: "reContextmenu",
components: {
basic,
menuGroup,
menuDynamic
},
setup() {
return {};
}
};
</script>

View File

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

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>
<div style="margin: 10px">
<div class="cropper-container">
@ -9,44 +35,6 @@
</div>
</template>
<script lang="ts">
import { ref, nextTick, getCurrentInstance } from "vue";
import Cropper from "/@/components/ReCropper";
import img from "./picture.jpeg";
export default {
name: "reCropping",
components: {
Cropper
},
setup() {
const instance = getCurrentInstance();
let info = ref("");
let cropperImg = ref("");
const onCropper = (): void => {
nextTick(() => {
instance.refs.refCropper.cropper.getCroppedCanvas().toBlob(blob => {
let fileReader: FileReader = new FileReader();
fileReader.onloadend = (e: any) => {
cropperImg.value = e.target.result;
info.value = instance.refs.refCropper.cropper.getData();
};
fileReader.readAsDataURL(blob);
}, "image/jpeg");
});
};
return {
img,
info,
cropperImg,
onCropper
};
}
};
</script>
<style scoped>
.cropper-container {
display: flex;

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>
<div class="drag-container">
<!-- grid列表拖拽 -->
@ -72,64 +120,6 @@
</div>
</template>
<script lang="ts">
import draggable from "vuedraggable/src/vuedraggable";
import { reactive, toRefs, onMounted } from "vue";
export default {
name: "reDraggable",
components: { draggable },
setup() {
const myArray = reactive({
gridLists: [
{ grid: "cn", num: 1 },
{ grid: "cn", num: 2 },
{ grid: "cn", num: 3 },
{ grid: "cn", num: 4 },
{ grid: "cn", num: 5 },
{ grid: "cn", num: 6 },
{ grid: "cn", num: 7 },
{ grid: "cn", num: 8 },
{ grid: "cn", num: 9 }
],
lists: [
{ people: "cn", id: 1, name: "www.itxst.com" },
{ people: "cn", id: 2, name: "www.baidu.com" },
{ people: "cn", id: 3, name: "www.taobao.com" },
{ people: "cn", id: 4, name: "www.google.com" }
],
cutLists: [
{ people: "cn", id: 1, name: "cut1" },
{ people: "cn", id: 2, name: "cut2" },
{ people: "cn", id: 3, name: "cut3" },
{ people: "cn", id: 4, name: "cut4" }
]
});
const change = (evt): void => {
console.log("evt: ", evt);
};
onMounted(() => {
// 使sortable
// @ts-ignore
// eslint-disable-next-line no-undef
new Sortable(document.querySelector(".cut-container"), {
swap: true,
forceFallback: true,
chosenClass: "chosen",
swapClass: "highlight",
animation: 300
});
});
return {
...toRefs(myArray),
change
};
}
};
</script>
<style lang="scss" scoped>
/* grid列表拖拽 */
.grid-container {

View File

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

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>
<el-space wrap>
<el-card class="box-card">
@ -60,68 +108,6 @@
</el-space>
</template>
<script lang="ts">
import { ref, unref } from "vue";
import { templateRef } from "@vueuse/core";
import SeamlessScroll from "/@/components/ReSeamlessScroll";
export default {
name: "reSeamlessScroll",
components: {
SeamlessScroll
},
setup() {
// eslint-disable-next-line no-undef
const scroll = templateRef<ElRef | null>("scroll", null);
let listData = ref([
{
title: "无缝滚动第一行无缝滚动第一行!!!!!!!!!!"
},
{
title: "无缝滚动第二行无缝滚动第二行!!!!!!!!!!"
},
{
title: "无缝滚动第三行无缝滚动第三行!!!!!!!!!!"
},
{
title: "无缝滚动第四行无缝滚动第四行!!!!!!!!!!"
},
{
title: "无缝滚动第五行无缝滚动第五行!!!!!!!!!!"
},
{
title: "无缝滚动第六行无缝滚动第六行!!!!!!!!!!"
},
{
title: "无缝滚动第七行无缝滚动第七行!!!!!!!!!!"
},
{
title: "无缝滚动第八行无缝滚动第八行!!!!!!!!!!"
},
{
title: "无缝滚动第九行无缝滚动第九行!!!!!!!!!!"
}
]);
let classOption = ref({
direction: "top"
});
function changeDirection(val) {
unref(scroll).reset();
unref(classOption).direction = val;
}
return {
listData,
classOption,
changeDirection
};
}
};
</script>
<style lang="scss" scoped>
.box-card {
margin: 10px;

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>
<div>
<el-card
@ -21,38 +44,3 @@
</el-card>
</div>
</template>
<script lang="ts">
import { ref } from "vue";
import Selector from "/@/components/ReSelector";
export default {
name: "reSelector",
components: { Selector },
setup() {
let selectRange = ref(null);
let dataLists = ref([
{
title: "基本使用",
echo: [],
disabled: false
},
{
title: "回显模式",
echo: [2, 7],
disabled: true
}
]);
const selectedVal = ({ left, right }) => {
selectRange.value = `${left}-${right}`;
};
return {
selectedVal,
selectRange,
dataLists
};
}
};
</script>

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>
<div class="split-pane">
<splitpane :splitSet="settingLR">
@ -22,35 +39,6 @@
</div>
</template>
<script lang="ts">
import splitpane, { ContextProps } from "/@/components/ReSplitPane";
import { reactive } from "vue";
export default {
name: "reSplitPane",
components: {
splitpane
},
setup() {
const settingLR: ContextProps = reactive({
minPercent: 20,
defaultPercent: 40,
split: "vertical"
});
const settingTB: ContextProps = reactive({
minPercent: 20,
defaultPercent: 40,
split: "horizontal"
});
return {
settingLR,
settingTB
};
}
};
</script>
<style lang="scss" scoped>
$W: 100%;
$H: 80vh;

View File

@ -1,8 +1,4 @@
<template>
<div id="mse"></div>
</template>
<script lang="ts">
<script setup lang="ts">
import { onMounted } from "vue";
import Player from "xgplayer/dist/simple_player";
import volume from "xgplayer/dist/controls/volume";
@ -10,28 +6,27 @@ import playbackRate from "xgplayer/dist/controls/playbackRate";
import screenShot from "xgplayer/dist/controls/screenShot";
import { deviceDetection } from "/@/utils/deviceDetection";
export default {
name: "reVideo",
setup() {
onMounted(() => {
new Player({
id: "mse",
autoplay: false,
screenShot: true,
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
poster:
"https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
fluid: deviceDetection(),
controlPlugins: [volume, playbackRate, screenShot],
playbackRate: [0.5, 0.75, 1, 1.5, 2] //
});
});
return {};
}
};
onMounted(() => {
new Player({
id: "mse",
autoplay: false,
screenShot: true,
url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
poster:
"https://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg",
fluid: deviceDetection(),
controlPlugins: [volume, playbackRate, screenShot],
//
playbackRate: [0.5, 0.75, 1, 1.5, 2]
});
});
</script>
<style lang="scss" scoped>
<template>
<div id="mse"></div>
</template>
<style scoped>
#mse {
flex: auto;
}

View File

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

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>
<div class="errPage-container">
<el-row>
<el-col :span="12">
<h1 class="text-jumbo text-ginormous">CURD Admin</h1>
<h1 class="text-jumbo text-ginormous">Pure Admin</h1>
<h2>你没有权限去该页面</h2>
<h6>如有不满请联系你领导</h6>
</el-col>
<el-col :span="12">
<img
@ -18,20 +24,6 @@
</div>
</template>
<script lang="ts">
import imgs from "/@/assets/401.gif";
import { ref } from "vue";
export default {
name: "401",
setup() {
const img = ref(`${imgs}?${new Date()}`);
return {
img
};
}
};
</script>
<style lang="scss" scoped>
.errPage-container {
width: 800px;

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>
<div class="wscn-http404-container">
<div class="wscn-http404">
@ -8,7 +18,7 @@
<img class="pic-404__child right" :src="four_cloud" alt="404" />
</div>
<div class="bullshit">
<div class="bullshit__oops">CURD Admin</div>
<div class="bullshit__oops">Pure Admin</div>
<div class="bullshit__headline">{{ message }}</div>
<div class="bullshit__info">
Please check that the URL you entered is correct, or click the button
@ -20,26 +30,6 @@
</div>
</template>
<script>
import { computed } from "vue";
import four from "/@/assets/404.png";
import four_cloud from "/@/assets/404_cloud.png";
export default {
name: "404",
setup() {
const message = computed(() => {
return "The webmaster said that you can not enter this page...";
});
return {
message,
four,
four_cloud
};
}
};
</script>
<style lang="scss" scoped>
.wscn-http404-container {
transform: translate(-50%, -50%);

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);
// 使bpmnbpmnturbo使
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() {
// TurboLogicFlow
const lFData = toLogicflowData(demoData);
lf.value.render(lFData);
}
function catData() {
graphData.value = unref(lf).getGraphData();
dataVisible.value = true;
}
onMounted(() => {
initLf();
});
</script>
<template>
<div class="logic-flow-view">
<!-- 辅助工具栏 -->
@ -19,80 +77,6 @@
</div>
</template>
<script lang="ts">
import { ref, unref, onMounted } from "vue";
import LogicFlow from "@logicflow/core";
import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
import "@logicflow/core/dist/style/index.css";
import "@logicflow/extension/lib/style/index.css";
import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
import { BpmnNode } from "/@/components/ReFlowChart/src/config";
import demoData from "./dataTurbo.json";
export default {
name: "reFlowChart",
components: { NodePanel, Control, DataDialog },
setup() {
// eslint-disable-next-line no-undef
let lf = ref<ElRef>(null);
let graphData = ref(null);
let dataVisible = ref(false);
let config = ref({
grid: true,
background: {
color: "#f7f9ff"
},
keyboard: {
enabled: true
}
});
let nodeList = BpmnNode;
function initLf() {
//
LogicFlow.use(Snapshot);
// 使bpmnbpmnturbo使
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() {
// TurboLogicFlow
const lFData = toLogicflowData(demoData);
lf.value.render(lFData);
}
function catData() {
graphData.value = unref(lf).getGraphData();
dataVisible.value = true;
}
onMounted(() => {
initLf();
});
return {
lf,
graphData,
dataVisible,
config,
nodeList,
catData
};
}
};
</script>
<style scoped>
#LF-Turbo {
width: 100vw;

View File

@ -1,3 +1,57 @@
<script setup lang="ts">
import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getVerify, getLogin } from "/@/api/user";
import { useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage";
import { warnMessage, successMessage } from "/@/utils/message";
const router = useRouter();
//
const refreshGetVerify = async () => {
let { svg } = await getVerify();
contextInfo.svg = svg;
};
const contextInfo: ContextProps = reactive({
userName: "",
passWord: "",
verify: null,
svg: null
});
const toPage = (info: Object): void => {
storageSession.setItem("info", info);
router.push("/");
};
//
const onLogin = async () => {
let { userName, passWord, verify } = contextInfo;
let { code, info, accessToken } = await getLogin({
username: userName,
password: passWord,
verify: verify
});
code === 0
? successMessage(info) &&
toPage({
username: userName,
accessToken
})
: warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
</script>
<template>
<div class="login">
<info
@ -7,72 +61,3 @@
/>
</div>
</template>
<script lang="ts">
import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getVerify, getLogin } from "/@/api/user";
import { useRouter } from "vue-router";
import { storageSession } from "/@/utils/storage";
import { warnMessage, successMessage } from "/@/utils/message";
export default {
name: "login",
components: {
info
},
setup() {
const router = useRouter();
//
const refreshGetVerify = async () => {
let { svg } = await getVerify();
contextInfo.svg = svg;
};
const contextInfo: ContextProps = reactive({
userName: "",
passWord: "",
verify: null,
svg: null
});
const toPage = (info: Object): void => {
storageSession.setItem("info", info);
router.push("/");
};
//
const onLogin = async () => {
let { userName, passWord, verify } = contextInfo;
let { code, info, accessToken } = await getLogin({
username: userName,
password: passWord,
verify: verify
});
code === 0
? successMessage(info) &&
toPage({
username: userName,
accessToken
})
: warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
return {
contextInfo,
onLogin,
router,
toPage,
refreshVerify
};
}
};
</script>

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>
<div class="app-container">
<el-radio-group v-model="auth" @change="changRole">
@ -8,30 +23,3 @@
<p v-auth="'v-test'">只有test可看</p>
</div>
</template>
<script lang="ts">
import { ref } from "vue";
import { storageSession } from "/@/utils/storage";
export default {
name: "permissionButton",
setup() {
const auth = ref(storageSession.getItem("info").username || "admin");
function changRole(value) {
storageSession.setItem("info", {
username: value,
accessToken: `eyJhbGciOiJIUzUxMiJ9.${value}`
});
window.location.reload();
}
return {
auth,
changRole
};
}
};
</script>
<style scoped></style>

View File

@ -1,3 +1,26 @@
<script setup lang="ts">
import { ref, unref } from "vue";
import { storageSession } from "/@/utils/storage";
let purview = ref<string>(storageSession.getItem("info").username);
function changRole() {
if (unref(purview) === "admin") {
storageSession.setItem("info", {
username: "test",
accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
});
window.location.reload();
} else {
storageSession.setItem("info", {
username: "admin",
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin"
});
window.location.reload();
}
}
</script>
<template>
<div class="app-container">
<h4>
@ -10,35 +33,3 @@
<el-button type="primary" @click="changRole">切换角色</el-button>
</div>
</template>
<script lang="ts">
import { ref, unref } from "vue";
import { storageSession } from "/@/utils/storage";
export default {
name: "permissionPage",
setup() {
let purview: string = ref(storageSession.getItem("info").username);
function changRole() {
if (unref(purview) === "admin") {
storageSession.setItem("info", {
username: "test",
accessToken: "eyJhbGciOiJIUzUxMiJ9.test"
});
window.location.reload();
} else {
storageSession.setItem("info", {
username: "admin",
accessToken: "eyJhbGciOiJIUzUxMiJ9.admin"
});
window.location.reload();
}
}
return {
purview,
changRole
};
}
};
</script>

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>
<div></div>
</template>
<script lang="ts">
import { defineComponent, unref } from "vue";
import { useRouter } from "vue-router";
export default defineComponent({
name: "redirect",
setup() {
const { currentRoute, replace } = useRouter();
const { params, query } = unref(currentRoute);
const { path } = params;
const _path = Array.isArray(path) ? path.join("/") : path;
replace({
path: "/" + _path,
query
});
return {};
}
});
</script>

View File

@ -1,3 +1,47 @@
<script setup lang="ts">
import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getRegist, getVerify } from "/@/api/user";
import { useRouter } from "vue-router";
import { warnMessage, successMessage } from "/@/utils/message";
const router = useRouter();
//
const refreshGetVerify = async () => {
let { svg } = await getVerify();
contextInfo.svg = svg;
};
const contextInfo: ContextProps = reactive({
userName: "",
passWord: "",
verify: null,
svg: null
});
//
const onRegist = async () => {
let { userName, passWord, verify } = contextInfo;
let { code, info } = await getRegist({
username: userName,
password: passWord,
verify: verify
});
code === 0
? successMessage(info) && router.push("/login")
: warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
</script>
<template>
<div class="register">
<info
@ -7,61 +51,3 @@
/>
</div>
</template>
<script lang="ts">
import { reactive, onBeforeMount } from "vue";
import info, { ContextProps } from "../components/ReInfo/index.vue";
import { getRegist, getVerify } from "/@/api/user";
import { useRouter } from "vue-router";
import { warnMessage, successMessage } from "/@/utils/message";
export default {
name: "register",
components: {
info
},
setup() {
const router = useRouter();
//
const refreshGetVerify = async () => {
let { svg } = await getVerify();
contextInfo.svg = svg;
};
const contextInfo: ContextProps = reactive({
userName: "",
passWord: "",
verify: null,
svg: null
});
//
const onRegist = async () => {
let { userName, passWord, verify } = contextInfo;
let { code, info } = await getRegist({
username: userName,
password: passWord,
verify: verify
});
code === 0
? successMessage(info) && router.push("/login")
: warnMessage(info);
};
const refreshVerify = (): void => {
refreshGetVerify();
};
onBeforeMount(() => {
// refreshGetVerify();
});
return {
contextInfo,
onRegist,
router,
refreshVerify
};
}
};
</script>

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>
<div class="config">
<el-drawer
@ -14,7 +90,7 @@
<vxe-table
ref="xTable"
border
:data="tableData"
:data="configData.tableData"
@checkbox-change="checkboxChangeEvent"
@checkbox-all="checkboxChangeEvent"
>
@ -40,9 +116,9 @@
</vxe-table>
<vxe-pager
perfect
v-model:current-page="tablePage.currentPage"
v-model:page-size="tablePage.pageSize"
:total="tablePage.total"
v-model:current-page="configData.tablePage.currentPage"
v-model:page-size="configData.tablePage.pageSize"
:total="configData.tablePage.total"
:layouts="[
'PrevJump',
'PrevPage',
@ -57,12 +133,12 @@
<template #left>
<span class="page-left">
<vxe-checkbox
v-model="isAllChecked"
:indeterminate="isIndeterminate"
v-model="configData.isAllChecked"
:indeterminate="configData.isIndeterminate"
@change="changeAllEvent"
></vxe-checkbox>
<span class="select-count"
>已选中{{ selectRecords.length }}</span
>已选中{{ configData.selectRecords.length }}</span
>
<vxe-button size="small">{{ $t("message.hsdelete") }}</vxe-button>
</span>
@ -73,98 +149,6 @@
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs } from "vue";
import { propTypes } from "/@/utils/propTypes";
import { VxeTableEvents } from "vxe-table";
import { templateRef } from "@vueuse/core";
export default defineComponent({
props: {
drawer: propTypes.bool.def(false),
drawTitle: propTypes.string.def(""),
direction: propTypes.string.def("rtl")
},
emits: ["handleClose"],
setup(props, ctx) {
const { emit } = ctx;
const xTable = templateRef<any>("xTable", null);
const configData = reactive({
tableData: [
{
name: "禁用",
dataval: "0"
},
{
name: "启用",
dataval: "1"
}
],
isAllChecked: false,
isIndeterminate: false,
selectRecords: [] as any[],
tablePage: {
total: 0,
currentPage: 1,
pageSize: 10
}
});
//
function handleClose() {
configData.isAllChecked = false;
configData.isIndeterminate = false;
emit("handleClose");
}
function editConfig(row) {
console.log(
"%crow===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
row
);
}
function delConfig(row) {
console.log(
"%crow===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
row
);
}
const changeAllEvent = () => {
setTimeout(() => {
console.log(xTable);
}, 1000);
const $table = xTable.value;
$table.setAllCheckboxRow(configData.isAllChecked);
configData.selectRecords = $table.getCheckboxRecords();
};
const checkboxChangeEvent: VxeTableEvents.CheckboxChange = ({
records
}) => {
const $table = xTable.value;
configData.isAllChecked = $table.isAllCheckboxChecked();
configData.isIndeterminate = $table.isCheckboxIndeterminate();
configData.selectRecords = records;
};
return {
...toRefs(configData),
handleClose,
editConfig,
delConfig,
changeAllEvent,
checkboxChangeEvent
};
}
});
</script>
<style lang="scss" scoped>
.list {
padding: 10px;

View File

@ -1,10 +1,208 @@
<script setup lang="ts">
import Config from "./config.vue";
import { reactive, ref, unref, nextTick } from "vue";
import XEUtils from "xe-utils";
import { cloneDeep } from "lodash-es";
import { templateRef } from "@vueuse/core";
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
import {
VXETable,
VxeTableInstance,
VxeTableEvents,
VxeFormPropTypes
} from "vxe-table";
type onEditNRow = {
name: string;
model: string;
};
const dictData = reactive({
submitLoading: false,
showEdit: false,
selectRow: null,
filterName: "",
tableData: [
{
id: 1,
name: "状态",
model: "",
children: [
{
id: "1-1",
name: "服务状态",
model: "serviceStatus"
},
{
id: "1-2",
name: "在线状态",
model: "onlienStatus"
}
]
},
{ id: 2, name: "操作系统", model: "operatingSystem" }
],
formData: {
name: "",
model: ""
},
formItems: [
{
field: "name",
title: "字典名称",
span: 24,
itemRender: {
name: "$input",
props: { placeholder: "请输入字典名称" }
}
},
{
field: "model",
title: "字典类型",
span: 24,
itemRender: {
name: "$input",
props: {
placeholder: "请输入字典类型",
//vxe-tablevxe-input
disabled: true
}
}
},
{
align: "right",
span: 24,
itemRender: {
name: "$buttons",
children: [
{ props: { type: "submit", content: "提交", status: "primary" } },
{ props: { type: "reset", content: "重置" } }
]
}
}
] as VxeFormPropTypes.Items
});
let originData = cloneDeep(dictData.tableData);
const xTree = templateRef<HTMLElement | any>("xTree", null);
const handleSearch = () => {
const filterName = XEUtils.toValueString(dictData.filterName).trim();
if (filterName) {
const options = { children: "children" };
const searchProps = ["name"];
dictData.tableData = XEUtils.searchTree(
originData,
item =>
searchProps.some(
key => XEUtils.toValueString(item[key]).indexOf(filterName) > -1
),
options
);
//
nextTick(() => {
const $table = xTree.value;
$table.setAllTreeExpand(true);
});
} else {
dictData.tableData = originData;
}
};
// 100
const searchEvent = XEUtils.debounce(
function () {
handleSearch();
},
100,
{ leading: false, trailing: true }
);
const confirmEvent = async () => {
const type = await VXETable.modal.confirm("您确定要删除吗?");
(await type) === "confirm" &&
VXETable.modal.message({
content: "测试数据,不可删除",
status: "error"
});
};
function commonFn(value, disabled) {
dictData.selectRow = value;
dictData.showEdit = true;
dictData.formItems[1].itemRender.props.disabled = disabled;
}
//
function onAdd() {
commonFn(null, false);
}
//
function onAddChild(row?: object) {
console.log("onAddChild", row);
commonFn(null, false);
}
//
function onEdit(row?: onEditNRow) {
dictData.formData = {
name: row.name,
model: row.model ? row.model : "暂无字典类型"
};
commonFn(row, true);
// VXETable.modal.message({
// content: "",
// status: "error"
// });
}
//
const { clipboardRef } = useCopyToClipboard();
const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
clipboardRef.value = unref(row).model;
};
const xTable = ref({} as VxeTableInstance);
const submitEvent = () => {
dictData.submitLoading = true;
setTimeout(() => {
const $table = xTable.value;
dictData.submitLoading = false;
dictData.showEdit = false;
if (dictData.selectRow) {
VXETable.modal.message({ content: "保存成功", status: "success" });
Object.assign(dictData.selectRow, dictData.formData);
} else {
VXETable.modal.message({ content: "新增成功", status: "success" });
$table.insert(dictData.formData);
}
}, 500);
};
let drawer = ref(false);
function onDeploy(value?: object) {
console.log("onDeploy", value);
drawer.value = true;
}
function handleClose() {
drawer.value = false;
}
</script>
<template>
<div class="dict-container">
<!-- 工具栏 -->
<vxe-toolbar>
<template #buttons>
<vxe-input
v-model="filterName"
v-model="dictData.filterName"
:placeholder="$t('message.hssearch')"
@keyup="searchEvent"
></vxe-input>
@ -41,7 +239,7 @@
iconOpen: 'fa fa-minus-square-o',
iconClose: 'fa fa-plus-square-o'
}"
:data="tableData"
:data="dictData.tableData"
@cell-dblclick="cellDBLClickEvent"
>
<vxe-table-column
@ -89,16 +287,16 @@
<vxe-modal
resize
width="450"
v-model="showEdit"
:title="selectRow ? '编辑' : '新增'"
:loading="submitLoading"
v-model="dictData.showEdit"
:title="dictData.selectRow ? '编辑' : '新增'"
:loading="dictData.submitLoading"
@hide="$refs.xForm.reset()"
>
<template #default>
<vxe-form
ref="xForm"
:data="formData"
:items="formItems"
:data="dictData.formData"
:items="dictData.formItems"
title-align="right"
title-width="100"
@submit="submitEvent"
@ -109,229 +307,7 @@
<Config :drawer="drawer" drawTitle="字典列表" @handleClose="handleClose" />
</div>
</template>
<script lang="ts">
import { reactive, ref, unref, nextTick, toRefs } from "vue";
import XEUtils from "xe-utils";
import { cloneDeep } from "lodash-es";
import { templateRef } from "@vueuse/core";
import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
import {
VXETable,
VxeTableInstance,
VxeTableEvents,
VxeFormPropTypes
} from "vxe-table";
import Config from "./config.vue";
export default {
name: "dict",
components: {
Config
},
setup() {
const dictData = reactive({
submitLoading: false,
showEdit: false,
selectRow: null,
filterName: "",
tableData: [
{
id: 1,
name: "状态",
model: "",
children: [
{
id: "1-1",
name: "服务状态",
model: "serviceStatus"
},
{
id: "1-2",
name: "在线状态",
model: "onlienStatus"
}
]
},
{ id: 2, name: "操作系统", model: "operatingSystem" }
],
formData: {
name: "",
model: ""
},
formItems: [
{
field: "name",
title: "字典名称",
span: 24,
itemRender: {
name: "$input",
props: { placeholder: "请输入字典名称" }
}
},
{
field: "model",
title: "字典类型",
span: 24,
itemRender: {
name: "$input",
props: {
placeholder: "请输入字典类型",
//vxe-tablevxe-input
disabled: true
}
}
},
{
align: "right",
span: 24,
itemRender: {
name: "$buttons",
children: [
{ props: { type: "submit", content: "提交", status: "primary" } },
{ props: { type: "reset", content: "重置" } }
]
}
}
] as VxeFormPropTypes.Items
});
let originData = cloneDeep(dictData.tableData);
const xTree = templateRef<HTMLElement | any>("xTree", null);
const formatDate = (value: any) => {
return XEUtils.toDateString(value, "yyyy-MM-dd HH:mm:ss.S");
};
const handleSearch = () => {
const filterName = XEUtils.toValueString(dictData.filterName).trim();
if (filterName) {
const options = { children: "children" };
const searchProps = ["name"];
dictData.tableData = XEUtils.searchTree(
originData,
item =>
searchProps.some(
key => XEUtils.toValueString(item[key]).indexOf(filterName) > -1
),
options
);
//
nextTick(() => {
const $table = xTree.value;
$table.setAllTreeExpand(true);
});
} else {
dictData.tableData = originData;
}
};
// 100
const searchEvent = XEUtils.debounce(
function () {
handleSearch();
},
100,
{ leading: false, trailing: true }
);
const confirmEvent = async () => {
const type = await VXETable.modal.confirm("您确定要删除吗?");
(await type) === "confirm" &&
VXETable.modal.message({
content: "测试数据,不可删除",
status: "error"
});
};
function commonFn(value, disabled) {
dictData.selectRow = value;
dictData.showEdit = true;
dictData.formItems[1].itemRender.props.disabled = disabled;
}
//
function onAdd() {
commonFn(null, false);
}
//
function onAddChild(row: any) {
console.log(
"%crow===>>>: ",
"color: MidnightBlue; background: Aquamarine; font-size: 20px;",
row
);
commonFn(null, false);
}
//
function onEdit(row: any) {
dictData.formData = {
name: row.name,
model: row.model ? row.model : "暂无字典类型"
};
commonFn(row, true);
// VXETable.modal.message({
// content: "",
// status: "error"
// });
}
//
const { clipboardRef } = useCopyToClipboard();
const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
clipboardRef.value = unref(row).model;
};
const xTable = ref({} as VxeTableInstance);
const submitEvent = () => {
dictData.submitLoading = true;
setTimeout(() => {
const $table = xTable.value;
dictData.submitLoading = false;
dictData.showEdit = false;
if (dictData.selectRow) {
VXETable.modal.message({ content: "保存成功", status: "success" });
Object.assign(dictData.selectRow, dictData.formData);
} else {
VXETable.modal.message({ content: "新增成功", status: "success" });
$table.insert(dictData.formData);
}
}, 500);
};
let drawer = ref(false);
function onDeploy() {
drawer.value = true;
}
function handleClose() {
drawer.value = false;
}
return {
...toRefs(dictData),
formatDate,
searchEvent,
confirmEvent,
cellDBLClickEvent,
submitEvent,
onEdit,
onAddChild,
onAdd,
onDeploy,
drawer,
handleClose
};
}
};
</script>
<style lang="scss" scoped>
.dict-container {
margin: 10px;

View File

@ -1,252 +1,242 @@
<script setup lang="ts">
import { reactive } from "vue";
import { VxeGridProps } from "vxe-table";
const gridOptions = reactive({
border: true,
resizable: true,
keepSource: true,
height: 500,
printConfig: {},
importConfig: {},
exportConfig: {},
pagerConfig: {
perfect: true,
pageSize: 15
},
editConfig: {
trigger: "click",
mode: "row",
showStatus: true
},
toolbarConfig: {
buttons: [
{
code: "insert_actived",
name: "message.hsadd",
status: "perfect",
icon: "fa fa-plus"
},
{
code: "mark_cancel",
name: "message.hsmark",
status: "perfect",
icon: "fa fa-trash-o"
},
{
code: "save",
name: "message.hssave",
status: "perfect",
icon: "fa fa-save"
}
],
perfect: true,
refresh: {
icon: "fa fa-refresh",
iconLoading: "fa fa-spinner fa-spin"
},
import: {
icon: "fa fa-upload"
},
export: {
icon: "fa fa-download"
},
print: {
icon: "fa fa-print"
},
zoom: {
iconIn: "fa fa-arrows-alt",
iconOut: "fa fa-expand"
},
custom: {
icon: "fa fa-cog"
}
},
proxyConfig: {
props: {
result: "result",
total: "page.total"
},
ajax: {
// Promise
query: ({ page }) => {
return new Promise(resolve => {
setTimeout(() => {
const list = [
{
id: 10001,
name: "Test1",
nickname: "T1",
role: "Develop",
sex: "Man",
age: 28,
address: "Shenzhen"
},
{
id: 10002,
name: "Test2",
nickname: "T2",
role: "Test",
sex: "Women",
age: 22,
address: "Guangzhou"
},
{
id: 10003,
name: "Test3",
nickname: "T3",
role: "PM",
sex: "Man",
age: 32,
address: "Shanghai"
},
{
id: 10004,
name: "Test4",
nickname: "T4",
role: "Designer",
sex: "Women ",
age: 23,
address: "Shenzhen"
},
{
id: 10005,
name: "Test5",
nickname: "T5",
role: "Develop",
sex: "Women ",
age: 30,
address: "Shanghai"
},
{
id: 10006,
name: "Test6",
nickname: "T6",
role: "Designer",
sex: "Women ",
age: 21,
address: "Shenzhen"
},
{
id: 10007,
name: "Test7",
nickname: "T7",
role: "Test",
sex: "Man ",
age: 29,
address: "vxe-table 从入门到放弃"
},
{
id: 10008,
name: "Test8",
nickname: "T8",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen"
},
{
id: 10009,
name: "Test9",
nickname: "T9",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen"
},
{
id: 100010,
name: "Test10",
nickname: "T10",
role: "Develop",
sex: "Man ",
age: 35,
address: "Guangzhou"
},
{
id: 100011,
name: "Test11",
nickname: "T11",
role: "Test",
sex: "Women ",
age: 26,
address: "vxe-table 从入门到放弃"
},
{
id: 100012,
name: "Test12",
nickname: "T12",
role: "Develop",
sex: "Man ",
age: 34,
address: "Guangzhou"
},
{
id: 100013,
name: "Test13",
nickname: "T13",
role: "Test",
sex: "Women ",
age: 22,
address: "Shenzhen"
}
];
resolve({
page: {
total: list.length
},
result: list.slice(
(page.currentPage - 1) * page.pageSize,
page.currentPage * page.pageSize
)
});
}, 100);
});
},
// body { removeRecords }
delete: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({});
}, 100);
});
},
// body { insertRecords, updateRecords, removeRecords, pendingRecords }
save: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({});
}, 100);
});
}
}
},
columns: [
{ type: "checkbox", width: 50 },
{ type: "seq", width: 60 },
{ field: "name", title: "Name", editRender: { name: "input" } },
{ field: "nickname", title: "Nickname", editRender: { name: "input" } },
{ field: "role", title: "Role", editRender: { name: "input" } },
{
field: "address",
title: "Address",
showOverflow: true,
editRender: { name: "input" }
}
]
} as VxeGridProps);
</script>
<template>
<vxe-grid v-bind="gridOptions" style="width: 98%"></vxe-grid>
</template>
<script lang="ts">
import { reactive } from "vue";
import { VxeGridProps } from "vxe-table";
export default {
name: "user",
setup() {
const gridOptions = reactive({
border: true,
resizable: true,
keepSource: true,
height: 500,
printConfig: {},
importConfig: {},
exportConfig: {},
pagerConfig: {
perfect: true,
pageSize: 15
},
editConfig: {
trigger: "click",
mode: "row",
showStatus: true
},
toolbarConfig: {
buttons: [
{
code: "insert_actived",
name: "message.hsadd",
status: "perfect",
icon: "fa fa-plus"
},
{
code: "mark_cancel",
name: "message.hsmark",
status: "perfect",
icon: "fa fa-trash-o"
},
{
code: "save",
name: "message.hssave",
status: "perfect",
icon: "fa fa-save"
}
],
perfect: true,
refresh: {
icon: "fa fa-refresh",
iconLoading: "fa fa-spinner fa-spin"
},
import: {
icon: "fa fa-upload"
},
export: {
icon: "fa fa-download"
},
print: {
icon: "fa fa-print"
},
zoom: {
iconIn: "fa fa-arrows-alt",
iconOut: "fa fa-expand"
},
custom: {
icon: "fa fa-cog"
}
},
proxyConfig: {
props: {
result: "result",
total: "page.total"
},
ajax: {
// Promise
query: ({ page }) => {
return new Promise(resolve => {
setTimeout(() => {
const list = [
{
id: 10001,
name: "Test1",
nickname: "T1",
role: "Develop",
sex: "Man",
age: 28,
address: "Shenzhen"
},
{
id: 10002,
name: "Test2",
nickname: "T2",
role: "Test",
sex: "Women",
age: 22,
address: "Guangzhou"
},
{
id: 10003,
name: "Test3",
nickname: "T3",
role: "PM",
sex: "Man",
age: 32,
address: "Shanghai"
},
{
id: 10004,
name: "Test4",
nickname: "T4",
role: "Designer",
sex: "Women ",
age: 23,
address: "Shenzhen"
},
{
id: 10005,
name: "Test5",
nickname: "T5",
role: "Develop",
sex: "Women ",
age: 30,
address: "Shanghai"
},
{
id: 10006,
name: "Test6",
nickname: "T6",
role: "Designer",
sex: "Women ",
age: 21,
address: "Shenzhen"
},
{
id: 10007,
name: "Test7",
nickname: "T7",
role: "Test",
sex: "Man ",
age: 29,
address: "vxe-table 从入门到放弃"
},
{
id: 10008,
name: "Test8",
nickname: "T8",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen"
},
{
id: 10009,
name: "Test9",
nickname: "T9",
role: "Develop",
sex: "Man ",
age: 35,
address: "Shenzhen"
},
{
id: 100010,
name: "Test10",
nickname: "T10",
role: "Develop",
sex: "Man ",
age: 35,
address: "Guangzhou"
},
{
id: 100011,
name: "Test11",
nickname: "T11",
role: "Test",
sex: "Women ",
age: 26,
address: "vxe-table 从入门到放弃"
},
{
id: 100012,
name: "Test12",
nickname: "T12",
role: "Develop",
sex: "Man ",
age: 34,
address: "Guangzhou"
},
{
id: 100013,
name: "Test13",
nickname: "T13",
role: "Test",
sex: "Women ",
age: 22,
address: "Shenzhen"
}
];
resolve({
page: {
total: list.length
},
result: list.slice(
(page.currentPage - 1) * page.pageSize,
page.currentPage * page.pageSize
)
});
}, 100);
});
},
// body { removeRecords }
delete: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({});
}, 100);
});
},
// body { insertRecords, updateRecords, removeRecords, pendingRecords }
save: () => {
return new Promise(resolve => {
setTimeout(() => {
resolve({});
}, 100);
});
}
}
},
columns: [
{ type: "checkbox", width: 50 },
{ type: "seq", width: 60 },
{ field: "name", title: "Name", editRender: { name: "input" } },
{ field: "nickname", title: "Nickname", editRender: { name: "input" } },
{ field: "role", title: "Role", editRender: { name: "input" } },
{
field: "address",
title: "Address",
showOverflow: true,
editRender: { name: "input" }
}
]
} as VxeGridProps);
return {
gridOptions
};
}
};
</script>
<style scoped></style>

View File

@ -1,3 +1,170 @@
<script setup lang="ts">
import Flop from "/@/components/ReFlop";
import { ref, computed, onMounted, nextTick } from "vue";
import { deviceDetection } from "/@/utils/deviceDetection";
import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
import { echartsJson } from "/@/api/mock";
import echarts from "/@/plugins/echarts";
import { ECharts } from "echarts";
//线
let brokenLine: ECharts;
let mobile = ref<boolean>(deviceDetection());
let date: Date = new Date();
let loading = ref<boolean>(true);
setTimeout(() => {
loading.value = !loading.value;
nextTick(() => {
initbrokenLine();
});
}, 500);
let greetings = computed(() => {
if (date.getHours() >= 0 && date.getHours() < 12) {
return "上午阳光明媚,祝你薪水翻倍🌞!";
} else if (date.getHours() >= 12 && date.getHours() < 18) {
return "下午小风娇好,愿你青春不老😃!";
} else {
return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!";
}
});
function initbrokenLine() {
const lineRefDom = document.getElementById("brokenLine");
if (!lineRefDom) return;
// @ts-ignore
brokenLine = echarts.init(lineRefDom);
brokenLine.clear(); //
echartsJson().then(({ info }) => {
brokenLine.setOption({
title: {
text: "上海 空气质量指数",
left: "1%"
},
tooltip: {
trigger: "axis"
},
grid: {
left: "5%",
right: "15%",
bottom: "10%"
},
xAxis: {
data: info.map(function (item) {
return item[0];
})
},
yAxis: {},
toolbox: {
right: 10,
feature: {
saveAsImage: {}
}
},
dataZoom: [
{
startValue: "2014-06-01"
},
{
type: "inside"
}
],
visualMap: {
top: 50,
right: 10,
pieces: [
{
gt: 0,
lte: 50,
color: "#93CE07"
},
{
gt: 50,
lte: 100,
color: "#FBDB0F"
},
{
gt: 100,
lte: 150,
color: "#FC7D02"
},
{
gt: 150,
lte: 200,
color: "#FD0100"
},
{
gt: 200,
lte: 300,
color: "#AA069F"
},
{
gt: 300,
color: "#AC3B2A"
}
],
outOfRange: {
color: "#999"
}
},
series: {
name: "上海 空气质量指数",
type: "line",
data: info.map(function (item) {
return item[1];
}),
markLine: {
silent: true,
lineStyle: {
color: "#333"
},
data: [
{
yAxis: 50
},
{
yAxis: 100
},
{
yAxis: 150
},
{
yAxis: 200
},
{
yAxis: 300
}
]
}
}
});
});
}
const openDepot = (): void => {
window.open("https://github.com/xiaoxian521/vue-pure-admin");
};
onMounted(() => {
nextTick(() => {
useEventListener("resize", () => {
if (!brokenLine) return;
useTimeoutFn(() => {
brokenLine.resize();
}, 180);
});
});
});
tryOnUnmounted(() => {
if (!brokenLine) return;
brokenLine.dispose();
brokenLine = null;
});
</script>
<template>
<div class="welcome">
<el-affix>
@ -26,185 +193,6 @@
</div>
</template>
<script lang="ts">
import Flop from "/@/components/ReFlop";
import { ref, computed, onMounted, nextTick } from "vue";
import { deviceDetection } from "/@/utils/deviceDetection";
import { useEventListener, tryOnUnmounted, useTimeoutFn } from "@vueuse/core";
import { echartsJson } from "/@/api/mock";
import echarts from "/@/plugins/echarts";
let brokenLine: any = null; //线
export default {
name: "welcome",
components: {
Flop
},
setup() {
let mobile = ref(deviceDetection());
let date: Date = new Date();
let loading = ref(true);
setTimeout(() => {
loading.value = !loading.value;
nextTick(() => {
initbrokenLine();
});
}, 500);
let greetings = computed(() => {
if (date.getHours() >= 0 && date.getHours() < 12) {
return "上午阳光明媚,祝你薪水翻倍🌞!";
} else if (date.getHours() >= 12 && date.getHours() < 18) {
return "下午小风娇好,愿你青春不老😃!";
} else {
return "折一根天使羽毛,愿拂去您的疲惫烦恼忧伤🌛!";
}
});
function initbrokenLine() {
const lineRefDom = document.getElementById("brokenLine");
if (!lineRefDom) return;
brokenLine = echarts.init(lineRefDom);
brokenLine.clear(); //
echartsJson().then(({ info }) => {
brokenLine.setOption({
title: {
text: "上海 空气质量指数",
left: "1%"
},
tooltip: {
trigger: "axis"
},
grid: {
left: "5%",
right: "15%",
bottom: "10%"
},
xAxis: {
data: info.map(function (item) {
return item[0];
})
},
yAxis: {},
toolbox: {
right: 10,
feature: {
saveAsImage: {}
}
},
dataZoom: [
{
startValue: "2014-06-01"
},
{
type: "inside"
}
],
visualMap: {
top: 50,
right: 10,
pieces: [
{
gt: 0,
lte: 50,
color: "#93CE07"
},
{
gt: 50,
lte: 100,
color: "#FBDB0F"
},
{
gt: 100,
lte: 150,
color: "#FC7D02"
},
{
gt: 150,
lte: 200,
color: "#FD0100"
},
{
gt: 200,
lte: 300,
color: "#AA069F"
},
{
gt: 300,
color: "#AC3B2A"
}
],
outOfRange: {
color: "#999"
}
},
series: {
name: "上海 空气质量指数",
type: "line",
data: info.map(function (item) {
return item[1];
}),
markLine: {
silent: true,
lineStyle: {
color: "#333"
},
data: [
{
yAxis: 50
},
{
yAxis: 100
},
{
yAxis: 150
},
{
yAxis: 200
},
{
yAxis: 300
}
]
}
}
});
});
}
const openDepot = (): void => {
window.open("https://github.com/xiaoxian521/vue-pure-admin");
};
onMounted(() => {
nextTick(() => {
useEventListener("resize", () => {
if (!brokenLine) return;
useTimeoutFn(() => {
brokenLine.resize();
}, 180);
});
});
});
tryOnUnmounted(() => {
if (!brokenLine) return;
brokenLine.dispose();
brokenLine = null;
});
return {
greetings,
mobile,
loading,
openDepot
};
}
};
</script>
<style lang="scss" scoped>
.welcome {
width: 100%;

View File

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

49
types/global.d.ts vendored
View File

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

4
types/index.d.ts vendored
View File

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

View File

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