chore: code format

This commit is contained in:
xiaojunnuo
2025-06-29 14:09:09 +08:00
parent 04422a4637
commit 4fcfd089d8
644 changed files with 10845 additions and 13184 deletions
+2 -1
View File
@@ -15,7 +15,8 @@
"serve": "vite preview", "serve": "vite preview",
"preview": "vite preview", "preview": "vite preview",
"pretty-quick": "pretty-quick", "pretty-quick": "pretty-quick",
"lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/", "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue --ext .ts --ext .tsx src/",
"format": "prettier --write src",
"upgrade": "yarn upgrade-interactive --latest", "upgrade": "yarn upgrade-interactive --latest",
"tsc": "vue-tsc --noEmit --skipLibCheck", "tsc": "vue-tsc --noEmit --skipLibCheck",
"circle:check": "pnpm dependency-cruise --validate --output-type err-html -f dependency-report.html src", "circle:check": "pnpm dependency-cruise --validate --output-type err-html -f dependency-report.html src",
@@ -10,6 +10,10 @@ import { cloneDeep, debounce as lodashDebounce } from "lodash-es";
import { initWorkers } from "./workers"; import { initWorkers } from "./workers";
import { importJavascriptContribution, importJsonContribution, importMonacoYaml, importYamlContribution } from "./async-import"; import { importJavascriptContribution, importJsonContribution, importMonacoYaml, importYamlContribution } from "./async-import";
defineOptions({
name: "CodeEditor",
});
/** /**
* config: * config:
* value: '', // 编辑器初始文本 * value: '', // 编辑器初始文本
@@ -18,7 +18,7 @@
<script> <script>
export default { export default {
name: "PiContainer" name: "PiContainer",
}; };
</script> </script>
@@ -1,21 +1,17 @@
<template> <template>
<div class="cron-editor"> <div class="cron-editor">
<div class="flex-o"> <div class="flex-o">
<cron-light :disabled="disabled" :readonly="readonly" :period="period" class="flex-o cron-ant" <cron-light :disabled="disabled" :readonly="readonly" :period="period" class="flex-o cron-ant" locale="zh-CN" format="quartz" :model-value="modelValue" @update:model-value="onUpdate" @error="onError" />
locale="zh-CN" format="quartz" :model-value="modelValue" @update:model-value="onUpdate" </div>
@error="onError" /> <div class="mt-5 flex">
</div> <a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
<div class="mt-5 flex"> <fs-icon icon="ion:close-circle" class="pointer fs-16 ml-5 color-gray" :title="t('certd.cron.clearTip')" @click="onClear"></fs-icon>
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input> </div>
<fs-icon icon="ion:close-circle" class="pointer fs-16 ml-5 color-gray" :title="t('certd.cron.clearTip')" <div class="helper">{{ t("certd.cron.nextTrigger") }}{{ nextTime }}</div>
@click="onClear"></fs-icon> <div class="fs-helper">{{ errorMessage }}</div>
</div> </div>
<div class="helper">{{ t('certd.cron.nextTrigger') }}{{ nextTime }}</div>
<div class="fs-helper">{{ errorMessage }}</div>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import parser from "cron-parser"; import parser from "cron-parser";
import { computed, ref } from "vue"; import { computed, ref } from "vue";
@@ -25,108 +21,107 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
import { getCronNextTimes } from "/@/components/cron-editor/utils"; import { getCronNextTimes } from "/@/components/cron-editor/utils";
defineOptions({ defineOptions({
name: "CronEditor", name: "CronEditor",
}); });
const props = defineProps<{ const props = defineProps<{
modelValue?: string; modelValue?: string;
disabled?: boolean; disabled?: boolean;
readonly?: boolean; readonly?: boolean;
allowEveryMin?: boolean; allowEveryMin?: boolean;
}>(); }>();
const period = ref<string>(""); const period = ref<string>("");
if (props.modelValue == null || props.modelValue.endsWith("* * *")) { if (props.modelValue == null || props.modelValue.endsWith("* * *")) {
period.value = "day"; period.value = "day";
} else if (props.modelValue.endsWith("* *")) { } else if (props.modelValue.endsWith("* *")) {
period.value = "month"; period.value = "month";
} else if (props.modelValue.endsWith("*")) { } else if (props.modelValue.endsWith("*")) {
period.value = "year"; period.value = "year";
} }
const emit = defineEmits<{ const emit = defineEmits<{
"update:modelValue": any; "update:modelValue": any;
change: any; change: any;
}>(); }>();
const errorMessage = ref<string | null>(null); const errorMessage = ref<string | null>(null);
const onUpdate = (value: string) => { const onUpdate = (value: string) => {
if (value === props.modelValue) { if (value === props.modelValue) {
return; return;
} }
const arr: string[] = value.split(" "); const arr: string[] = value.split(" ");
if (arr[0] === "*") { if (arr[0] === "*") {
arr[0] = "0"; arr[0] = "0";
} }
if (!props.allowEveryMin) { if (!props.allowEveryMin) {
if (arr[1] === "*") { if (arr[1] === "*") {
arr[1] = "0"; arr[1] = "0";
} }
} }
value = arr.join(" "); value = arr.join(" ");
emit("update:modelValue", value); emit("update:modelValue", value);
errorMessage.value = undefined; errorMessage.value = undefined;
}; };
const onPeriod = (value: string) => { const onPeriod = (value: string) => {
period.value = value; period.value = value;
}; };
const onChange = (e: any) => { const onChange = (e: any) => {
const value = e.target.value; const value = e.target.value;
onUpdate(value); onUpdate(value);
}; };
const onError = (error: any) => { const onError = (error: any) => {
errorMessage.value = error; errorMessage.value = error;
}; };
const onClear = () => { const onClear = () => {
if (props.disabled) { if (props.disabled) {
return; return;
} }
onUpdate(""); onUpdate("");
}; };
const nextTime = computed(() => { const nextTime = computed(() => {
if (props.modelValue == null) { if (props.modelValue == null) {
return t("certd.cron.tip"); return t("certd.cron.tip");
} }
try { try {
const nextTimes = getCronNextTimes(props.modelValue, 2); const nextTimes = getCronNextTimes(props.modelValue, 2);
return nextTimes.join(""); return nextTimes.join("");
} catch (e) { } catch (e) {
console.log(e); console.log(e);
return t("certd.cron.tip"); return t("certd.cron.tip");
} }
}); });
</script> </script>
<style lang="less"> <style lang="less">
.cron-editor { .cron-editor {
.cron-ant { .cron-ant {
flex-wrap: wrap; flex-wrap: wrap;
&*> { &* > {
margin-bottom: 2px; margin-bottom: 2px;
display: flex; display: flex;
align-items: center; align-items: center;
} }
.vcron-select-list { .vcron-select-list {
min-width: 56px; min-width: 56px;
} }
.vcron-select-input { .vcron-select-input {
min-height: 22px; min-height: 22px;
background-color: #fff; background-color: #fff;
} }
.vcron-select-container { .vcron-select-container {
display: flex; display: flex;
align-items: center; align-items: center;
} }
} }
} }
</style> </style>
@@ -26,7 +26,9 @@
import { defineComponent, onMounted, ref } from "vue"; import { defineComponent, onMounted, ref } from "vue";
import * as api from "./api"; import * as api from "./api";
import { Modal, notification } from "ant-design-vue"; import { Modal, notification } from "ant-design-vue";
defineOptions({
name: "EmailEditor",
});
const props = defineProps<{}>(); const props = defineProps<{}>();
const VNodes = defineComponent({ const VNodes = defineComponent({
props: { props: {
@@ -16,7 +16,7 @@ import dayjs from "dayjs";
import { computed } from "vue"; import { computed } from "vue";
defineOptions({ defineOptions({
name: "ExpiresTimeText" name: "ExpiresTimeText",
}); });
const props = defineProps<{ const props = defineProps<{
@@ -15,7 +15,7 @@ Author: Pedro Oliveira <kanytu@gmail . com>
.hljs-literal, .hljs-literal,
.hljs-symbol, .hljs-symbol,
.hljs-bullet { .hljs-bullet {
color: #6897BB; color: #6897bb;
} }
.hljs-keyword, .hljs-keyword,
@@ -42,7 +42,7 @@ Author: Pedro Oliveira <kanytu@gmail . com>
.hljs-string, .hljs-string,
.hljs-attribute, .hljs-attribute,
.hljs-addition { .hljs-addition {
color: #6A8759; color: #6a8759;
} }
.hljs-section, .hljs-section,
@@ -8,7 +8,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #FFFFFF; background: #ffffff;
} }
.hljs, .hljs,
@@ -21,7 +21,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-selector-tag, .hljs-selector-tag,
.hljs-doctag, .hljs-doctag,
.hljs-name { .hljs-name {
color: #00979D; color: #00979d;
} }
.hljs-built_in, .hljs-built_in,
@@ -29,7 +29,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-bullet, .hljs-bullet,
.hljs-code, .hljs-code,
.hljs-addition { .hljs-addition {
color: #D35400; color: #d35400;
} }
.hljs-regexp, .hljs-regexp,
@@ -39,7 +39,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-link, .hljs-link,
.hljs-selector-attr, .hljs-selector-attr,
.hljs-selector-pseudo { .hljs-selector-pseudo {
color: #00979D; color: #00979d;
} }
.hljs-type, .hljs-type,
@@ -49,7 +49,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-quote, .hljs-quote,
.hljs-template-tag, .hljs-template-tag,
.hljs-deletion { .hljs-deletion {
color: #005C5F; color: #005c5f;
} }
.hljs-title, .hljs-title,
@@ -59,15 +59,15 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
} }
.hljs-comment { .hljs-comment {
color: rgba(149,165,166,.8); color: rgba(149, 165, 166, 0.8);
} }
.hljs-meta-keyword { .hljs-meta-keyword {
color: #728E00; color: #728e00;
} }
.hljs-meta { .hljs-meta {
color: #728E00; color: #728e00;
color: #434f54; color: #434f54;
} }
@@ -80,9 +80,9 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
} }
.hljs-function { .hljs-function {
color: #728E00; color: #728e00;
} }
.hljs-number { .hljs-number {
color: #8A7B52; color: #8a7b52;
} }
@@ -8,14 +8,14 @@ Brown Paper style from goldblog.com.ua (c) Zaripov Yura <yur4ik7@ukr.net>
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background:#b7a68e url(./brown-papersq.png); background: #b7a68e url(./brown-papersq.png);
} }
.hljs-keyword, .hljs-keyword,
.hljs-selector-tag, .hljs-selector-tag,
.hljs-literal { .hljs-literal {
color:#005599; color: #005599;
font-weight:bold; font-weight: bold;
} }
.hljs, .hljs,
@@ -45,8 +45,6 @@ Ported by Fabrício Tavares de Oliveira
color: #88f; color: #88f;
} }
.hljs-keyword, .hljs-keyword,
.hljs-selector-tag, .hljs-selector-tag,
.hljs-title, .hljs-title,
@@ -4,7 +4,6 @@ Darcula color scheme from the JetBrains family of IDEs
*/ */
.hljs { .hljs {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
@@ -3,4 +3,4 @@
Please use darcula.css instead. Please use darcula.css instead.
*/ */
@import url('darcula.css'); @import url("darcula.css");
@@ -8,10 +8,9 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #F0F0F0; background: #f0f0f0;
} }
/* Base color: saturation 0; */ /* Base color: saturation 0; */
.hljs, .hljs,
@@ -32,7 +31,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
font-weight: bold; font-weight: bold;
} }
/* User color: hue: 0 */ /* User color: hue: 0 */
.hljs-type, .hljs-type,
@@ -59,14 +57,13 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
.hljs-link, .hljs-link,
.hljs-selector-attr, .hljs-selector-attr,
.hljs-selector-pseudo { .hljs-selector-pseudo {
color: #BC6060; color: #bc6060;
} }
/* Language color: hue: 90; */ /* Language color: hue: 90; */
.hljs-literal { .hljs-literal {
color: #78A960; color: #78a960;
} }
.hljs-built_in, .hljs-built_in,
@@ -76,7 +73,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
color: #397300; color: #397300;
} }
/* Meta color: hue: 200 */ /* Meta color: hue: 200 */
.hljs-meta { .hljs-meta {
@@ -87,7 +83,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
color: #4d99bf; color: #4d99bf;
} }
/* Misc effects */ /* Misc effects */
.hljs-emphasis { .hljs-emphasis {
@@ -10,7 +10,8 @@ Date: 2013-04-02
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #eee; color: black; background: #eee;
color: black;
} }
.hljs-link, .hljs-link,
@@ -68,7 +68,7 @@ Google Code style (c) Aahan Krish <geekpanth3r@gmail.com>
.hljs-selector-id, .hljs-selector-id,
.hljs-selector-class { .hljs-selector-class {
color: #9B703F color: #9b703f;
} }
.hljs-addition { .hljs-addition {
@@ -60,8 +60,8 @@ grayscale style (c) MY Sun <simonmysun@gmail.com>
} }
.hljs-regexp { .hljs-regexp {
color: #333; color: #333;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat;
} }
.hljs-symbol, .hljs-symbol,
@@ -84,7 +84,7 @@ grayscale style (c) MY Sun <simonmysun@gmail.com>
.hljs-deletion { .hljs-deletion {
color: #fff; color: #fff;
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat;
} }
.hljs-addition { .hljs-addition {
@@ -47,7 +47,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-literal, .hljs-literal,
.hljs-deletion, .hljs-deletion,
.hljs-link { .hljs-link {
color: #cc6666 color: #cc6666;
} }
/*color: fg_green*/ /*color: fg_green*/
@@ -64,7 +64,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-attribute, .hljs-attribute,
.hljs-code, .hljs-code,
.hljs-selector-id { .hljs-selector-id {
color: #b294bb; color: #b294bb;
} }
/*color: fg_blue*/ /*color: fg_blue*/
@@ -72,7 +72,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-selector-tag, .hljs-selector-tag,
.hljs-bullet, .hljs-bullet,
.hljs-tag { .hljs-tag {
color: #81a2be; color: #81a2be;
} }
/*color: fg_aqua*/ /*color: fg_aqua*/
@@ -61,7 +61,7 @@
.hljs-number, .hljs-number,
.hljs-deletion { .hljs-deletion {
color:#ff73fd; color: #ff73fd;
} }
.hljs-emphasis { .hljs-emphasis {
@@ -6,7 +6,8 @@ Monokai style - ported by Luigi Maselli - http://grigio.org
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #272822; color: #ddd; background: #272822;
color: #ddd;
} }
.hljs-tag, .hljs-tag,
@@ -72,7 +72,7 @@
} }
.hljs-selector-class { .hljs-selector-class {
color: #A082BD color: #a082bd;
} }
.hljs-keyword, .hljs-keyword,
@@ -21,12 +21,13 @@ NOTE_2: Color names provided in comments were derived using "Name that Color" on
http://chir.ag/projects/name-that-color http://chir.ag/projects/name-that-color
*/ */
.hljs { /* Common set of rules required by highlight.js (don'r remove!) */ .hljs {
display: block; /* Common set of rules required by highlight.js (don'r remove!) */
overflow-x: auto; display: block;
padding: 0.5em; overflow-x: auto;
background: #FFFFDF; /* Half and Half (approx.) */ padding: 0.5em;
/* --- Uncomment to add PureBASIC native IDE styled font! background: #ffffdf; /* Half and Half (approx.) */
/* --- Uncomment to add PureBASIC native IDE styled font!
font-family: Consolas; font-family: Consolas;
*/ */
} }
@@ -39,7 +40,7 @@ NOTE_2: Color names provided in comments were derived using "Name that Color" on
.hljs-attr, .hljs-attr,
.hljs-params, .hljs-params,
.hljs-subst { .hljs-subst {
color: #000000; /* Black */ color: #000000; /* Black */
} }
.hljs-comment, /* --- used for PureBASIC Comments --- */ .hljs-comment, /* --- used for PureBASIC Comments --- */
@@ -47,14 +48,14 @@ NOTE_2: Color names provided in comments were derived using "Name that Color" on
.hljs-section, .hljs-section,
.hljs-selector-pseudo, .hljs-selector-pseudo,
.hljs-addition { .hljs-addition {
color: #00AAAA; /* Persian Green (approx.) */ color: #00aaaa; /* Persian Green (approx.) */
} }
.hljs-title, /* --- used for PureBASIC Procedures Names --- */ .hljs-title, /* --- used for PureBASIC Procedures Names --- */
.hljs-tag, .hljs-tag,
.hljs-variable, .hljs-variable,
.hljs-code { .hljs-code {
color: #006666; /* Blue Stone (approx.) */ color: #006666; /* Blue Stone (approx.) */
} }
.hljs-keyword, /* --- used for PureBASIC Keywords --- */ .hljs-keyword, /* --- used for PureBASIC Keywords --- */
@@ -63,34 +64,34 @@ NOTE_2: Color names provided in comments were derived using "Name that Color" on
.hljs-selector-class, .hljs-selector-class,
.hljs-built_in, .hljs-built_in,
.hljs-builtin-name { .hljs-builtin-name {
color: #006666; /* Blue Stone (approx.) */ color: #006666; /* Blue Stone (approx.) */
font-weight: bold; font-weight: bold;
} }
.hljs-string, /* --- used for PureBASIC Strings --- */ .hljs-string, /* --- used for PureBASIC Strings --- */
.hljs-selector-attr { .hljs-selector-attr {
color: #0080FF; /* Azure Radiance (approx.) */ color: #0080ff; /* Azure Radiance (approx.) */
} }
.hljs-symbol, /* --- used for PureBASIC Constants --- */ .hljs-symbol, /* --- used for PureBASIC Constants --- */
.hljs-link, .hljs-link,
.hljs-deletion, .hljs-deletion,
.hljs-attribute { .hljs-attribute {
color: #924B72; /* Cannon Pink (approx.) */ color: #924b72; /* Cannon Pink (approx.) */
} }
.hljs-meta, .hljs-meta,
.hljs-literal, .hljs-literal,
.hljs-selector-id { .hljs-selector-id {
color: #924B72; /* Cannon Pink (approx.) */ color: #924b72; /* Cannon Pink (approx.) */
font-weight: bold; font-weight: bold;
} }
.hljs-strong, .hljs-strong,
.hljs-name { .hljs-name {
font-weight: bold; font-weight: bold;
} }
.hljs-emphasis { .hljs-emphasis {
font-style: italic; font-style: italic;
} }
@@ -4,7 +4,6 @@ Qt Creator dark color scheme
*/ */
.hljs { .hljs {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
@@ -32,8 +31,7 @@ Qt Creator dark color scheme
color: #ff55ff; color: #ff55ff;
} }
.hljs-code .hljs-code .hljs-selector-class {
.hljs-selector-class {
color: #aaaaff; color: #aaaaff;
} }
@@ -4,7 +4,6 @@ Qt Creator light color scheme
*/ */
.hljs { .hljs {
display: block; display: block;
overflow-x: auto; overflow-x: auto;
@@ -32,8 +31,7 @@ Qt Creator light color scheme
color: #000080; color: #000080;
} }
.hljs-code .hljs-code .hljs-selector-class {
.hljs-selector-class {
color: #800080; color: #800080;
} }
@@ -59,7 +57,7 @@ Qt Creator light color scheme
.hljs-variable, .hljs-variable,
.hljs-params, .hljs-params,
.hljs-class .hljs-title { .hljs-class .hljs-title {
color: #0055AF; color: #0055af;
} }
.hljs-string, .hljs-string,
@@ -44,7 +44,6 @@ Railscasts-like style (c) Visoft, Inc. (Damien White)
color: #da4939; color: #da4939;
} }
.hljs-symbol, .hljs-symbol,
.hljs-bullet, .hljs-bullet,
.hljs-built_in, .hljs-built_in,
@@ -12,7 +12,6 @@ Style with support for rainbow parens
color: #d1d9e1; color: #d1d9e1;
} }
.hljs-comment, .hljs-comment,
.hljs-quote { .hljs-quote {
color: #969896; color: #969896;
@@ -50,7 +49,7 @@ Style with support for rainbow parens
.hljs-template-variable, .hljs-template-variable,
.hljs-selector-id, .hljs-selector-id,
.hljs-class .hljs-title { .hljs-class .hljs-title {
color: #ffcc66; color: #ffcc66;
} }
.hljs-section, .hljs-section,
@@ -8,7 +8,7 @@
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #F0F0F0; background: #f0f0f0;
} }
/* Base color: saturation 0; */ /* Base color: saturation 0; */
@@ -31,15 +31,15 @@
} }
.hljs-attribute { .hljs-attribute {
color: #0E9A00; color: #0e9a00;
} }
.hljs-function { .hljs-function {
color: #99069A; color: #99069a;
} }
.hljs-builtin-name { .hljs-builtin-name {
color: #99069A; color: #99069a;
} }
/* User color: hue: 0 */ /* User color: hue: 0 */
@@ -68,24 +68,22 @@
.hljs-link, .hljs-link,
.hljs-selector-attr, .hljs-selector-attr,
.hljs-selector-pseudo { .hljs-selector-pseudo {
color: #BC6060; color: #bc6060;
} }
/* Language color: hue: 90; */ /* Language color: hue: 90; */
.hljs-literal { .hljs-literal {
color: #78A960; color: #78a960;
} }
.hljs-built_in, .hljs-built_in,
.hljs-bullet, .hljs-bullet,
.hljs-code, .hljs-code,
.hljs-addition { .hljs-addition {
color: #0C9A9A; color: #0c9a9a;
} }
/* Meta color: hue: 200 */ /* Meta color: hue: 200 */
.hljs-meta { .hljs-meta {
@@ -96,7 +94,6 @@
color: #4d99bf; color: #4d99bf;
} }
/* Misc effects */ /* Misc effects */
.hljs-emphasis { .hljs-emphasis {
@@ -9,11 +9,11 @@ School Book style from goldblog.com.ua (c) Zaripov Yura <yur4ik7@ukr.net>
overflow-x: auto; overflow-x: auto;
padding: 15px 0.5em 0.5em 30px; padding: 15px 0.5em 0.5em 30px;
font-size: 11px; font-size: 11px;
line-height:16px; line-height: 16px;
} }
pre{ pre {
background:#f6f6ae url(./school-book.png); background: #f6f6ae url(./school-book.png);
border-top: solid 2px #d2e8b9; border-top: solid 2px #d2e8b9;
border-bottom: solid 1px #d2e8b9; border-bottom: solid 1px #d2e8b9;
} }
@@ -21,8 +21,8 @@ pre{
.hljs-keyword, .hljs-keyword,
.hljs-selector-tag, .hljs-selector-tag,
.hljs-literal { .hljs-literal {
color:#005599; color: #005599;
font-weight:bold; font-weight: bold;
} }
.hljs, .hljs,
@@ -58,7 +58,6 @@ Visual Studio-like style based on original C# coloring by Jason Diamond <jason@d
color: #00b0e8; color: #00b0e8;
} }
.hljs-emphasis { .hljs-emphasis {
font-style: italic; font-style: italic;
} }
@@ -7,39 +7,39 @@
display: block; display: block;
overflow-x: auto; overflow-x: auto;
padding: 0.5em; padding: 0.5em;
background: #1E1E1E; background: #1e1e1e;
color: #DCDCDC; color: #dcdcdc;
} }
.hljs-keyword, .hljs-keyword,
.hljs-literal, .hljs-literal,
.hljs-symbol, .hljs-symbol,
.hljs-name { .hljs-name {
color: #569CD6; color: #569cd6;
} }
.hljs-link { .hljs-link {
color: #569CD6; color: #569cd6;
text-decoration: underline; text-decoration: underline;
} }
.hljs-built_in, .hljs-built_in,
.hljs-type { .hljs-type {
color: #4EC9B0; color: #4ec9b0;
} }
.hljs-number, .hljs-number,
.hljs-class { .hljs-class {
color: #B8D7A3; color: #b8d7a3;
} }
.hljs-string, .hljs-string,
.hljs-meta-string { .hljs-meta-string {
color: #D69D85; color: #d69d85;
} }
.hljs-regexp, .hljs-regexp,
.hljs-template-tag { .hljs-template-tag {
color: #9A5334; color: #9a5334;
} }
.hljs-subst, .hljs-subst,
@@ -47,34 +47,34 @@
.hljs-title, .hljs-title,
.hljs-params, .hljs-params,
.hljs-formula { .hljs-formula {
color: #DCDCDC; color: #dcdcdc;
} }
.hljs-comment, .hljs-comment,
.hljs-quote { .hljs-quote {
color: #57A64A; color: #57a64a;
font-style: italic; font-style: italic;
} }
.hljs-doctag { .hljs-doctag {
color: #608B4E; color: #608b4e;
} }
.hljs-meta, .hljs-meta,
.hljs-meta-keyword, .hljs-meta-keyword,
.hljs-tag { .hljs-tag {
color: #9B9B9B; color: #9b9b9b;
} }
.hljs-variable, .hljs-variable,
.hljs-template-variable { .hljs-template-variable {
color: #BD63C5; color: #bd63c5;
} }
.hljs-attr, .hljs-attr,
.hljs-attribute, .hljs-attribute,
.hljs-builtin-name { .hljs-builtin-name {
color: #9CDCFE; color: #9cdcfe;
} }
.hljs-section { .hljs-section {
@@ -99,7 +99,7 @@
.hljs-selector-class, .hljs-selector-class,
.hljs-selector-attr, .hljs-selector-attr,
.hljs-selector-pseudo { .hljs-selector-pseudo {
color: #D7BA7D; color: #d7ba7d;
} }
.hljs-addition { .hljs-addition {
@@ -1,4 +1,3 @@
/* /*
xt256.css xt256.css
@@ -70,7 +70,6 @@ based on dark.css by Ivan Sagalaev
color: #7f9f7f; color: #7f9f7f;
} }
.hljs-emphasis { .hljs-emphasis {
font-style: italic; font-style: italic;
} }
@@ -18,18 +18,18 @@ export default defineComponent({
code: { code: {
type: String, type: String,
required: false, required: false,
default: "" default: "",
}, },
formatHtml: { formatHtml: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
lang: { lang: {
type: String, type: String,
required: false, required: false,
default: "" default: "",
} },
}, },
setup(props: any, ctx: any) { setup(props: any, ctx: any) {
const highlightHTMLRef: Ref = ref(""); const highlightHTMLRef: Ref = ref("");
@@ -42,7 +42,7 @@ export default defineComponent({
doHighlight(); doHighlight();
}, },
{ {
immediate: true immediate: true,
} }
); );
@@ -52,9 +52,9 @@ export default defineComponent({
} }
return { return {
highlightHTMLRef, highlightHTMLRef,
doHighlight doHighlight,
}; };
} },
}); });
</script> </script>
@@ -3,40 +3,40 @@
// 功能 // 功能
// 将HTML字符串格式化 // 将HTML字符串格式化
const format = (function() { const format = (function () {
function style_html(html_source, indent_size, indent_character, max_char) { function style_html(html_source, indent_size, indent_character, max_char) {
var Parser, multi_parser; var Parser, multi_parser;
function Parser() { function Parser() {
this.pos = 0; this.pos = 0;
this.token = ''; this.token = "";
this.current_mode = 'CONTENT'; this.current_mode = "CONTENT";
this.tags = { this.tags = {
parent: 'parent1', parent: "parent1",
parentcount: 1, parentcount: 1,
parent1: '' parent1: "",
}; };
this.tag_type = ''; this.tag_type = "";
this.token_text = this.last_token = this.last_text = this.token_type = ''; this.token_text = this.last_token = this.last_text = this.token_type = "";
this.Utils = { this.Utils = {
whitespace: "\n\r\t ".split(''), whitespace: "\n\r\t ".split(""),
single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','), single_token: "br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed".split(","),
extra_liners: 'head,body,/html'.split(','), extra_liners: "head,body,/html".split(","),
in_array: function(what, arr) { in_array: function (what, arr) {
for (var i = 0; i < arr.length; i++) { for (var i = 0; i < arr.length; i++) {
if (what === arr[i]) { if (what === arr[i]) {
return true; return true;
} }
} }
return false; return false;
} },
} };
this.get_content = function() { this.get_content = function () {
var char = ''; var char = "";
var content = []; var content = [];
var space = false; var space = false;
while (this.input.charAt(this.pos) !== '<') { while (this.input.charAt(this.pos) !== "<") {
if (this.pos >= this.input.length) { if (this.pos >= this.input.length) {
return content.length ? content.join('') : ['', 'TK_EOF']; return content.length ? content.join("") : ["", "TK_EOF"];
} }
char = this.input.charAt(this.pos); char = this.input.charAt(this.pos);
this.pos++; this.pos++;
@@ -49,78 +49,78 @@ const format = (function() {
continue; continue;
} else if (space) { } else if (space) {
if (this.line_char_count >= this.max_char) { if (this.line_char_count >= this.max_char) {
content.push('\n'); content.push("\n");
for (var i = 0; i < this.indent_level; i++) { for (var i = 0; i < this.indent_level; i++) {
content.push(this.indent_string); content.push(this.indent_string);
} }
this.line_char_count = 0; this.line_char_count = 0;
} else { } else {
content.push(' '); content.push(" ");
this.line_char_count++; this.line_char_count++;
} }
space = false; space = false;
} }
content.push(char); content.push(char);
} }
return content.length ? content.join('') : ''; return content.length ? content.join("") : "";
} };
this.get_script = function() { this.get_script = function () {
var char = ''; var char = "";
var content = []; var content = [];
var reg_match = new RegExp('\<\/script' + '\>', 'igm'); var reg_match = new RegExp("</script" + ">", "igm");
reg_match.lastIndex = this.pos; reg_match.lastIndex = this.pos;
var reg_array = reg_match.exec(this.input); var reg_array = reg_match.exec(this.input);
var end_script = reg_array ? reg_array.index: this.input.length; var end_script = reg_array ? reg_array.index : this.input.length;
while (this.pos < end_script) { while (this.pos < end_script) {
if (this.pos >= this.input.length) { if (this.pos >= this.input.length) {
return content.length ? content.join('') : ['', 'TK_EOF']; return content.length ? content.join("") : ["", "TK_EOF"];
} }
char = this.input.charAt(this.pos); char = this.input.charAt(this.pos);
this.pos++; this.pos++;
content.push(char); content.push(char);
} }
return content.length ? content.join('') : ''; return content.length ? content.join("") : "";
} };
this.record_tag = function(tag) { this.record_tag = function (tag) {
if (this.tags[tag + 'count']) { if (this.tags[tag + "count"]) {
this.tags[tag + 'count']++; this.tags[tag + "count"]++;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; this.tags[tag + this.tags[tag + "count"]] = this.indent_level;
} else { } else {
this.tags[tag + 'count'] = 1; this.tags[tag + "count"] = 1;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level; this.tags[tag + this.tags[tag + "count"]] = this.indent_level;
} }
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; this.tags[tag + this.tags[tag + "count"] + "parent"] = this.tags.parent;
this.tags.parent = tag + this.tags[tag + 'count']; this.tags.parent = tag + this.tags[tag + "count"];
} };
this.retrieve_tag = function(tag) { this.retrieve_tag = function (tag) {
if (this.tags[tag + 'count']) { if (this.tags[tag + "count"]) {
var temp_parent = this.tags.parent; var temp_parent = this.tags.parent;
while (temp_parent) { while (temp_parent) {
if (tag + this.tags[tag + 'count'] === temp_parent) { if (tag + this.tags[tag + "count"] === temp_parent) {
break; break;
} }
temp_parent = this.tags[temp_parent + 'parent']; temp_parent = this.tags[temp_parent + "parent"];
} }
if (temp_parent) { if (temp_parent) {
this.indent_level = this.tags[tag + this.tags[tag + 'count']]; this.indent_level = this.tags[tag + this.tags[tag + "count"]];
this.tags.parent = this.tags[temp_parent + 'parent']; this.tags.parent = this.tags[temp_parent + "parent"];
} }
delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; delete this.tags[tag + this.tags[tag + "count"] + "parent"];
delete this.tags[tag + this.tags[tag + 'count']]; delete this.tags[tag + this.tags[tag + "count"]];
if (this.tags[tag + 'count'] == 1) { if (this.tags[tag + "count"] == 1) {
delete this.tags[tag + 'count']; delete this.tags[tag + "count"];
} else { } else {
this.tags[tag + 'count']--; this.tags[tag + "count"]--;
} }
} }
} };
this.get_tag = function() { this.get_tag = function () {
var char = ''; var char = "";
var content = []; var content = [];
var space = false; var space = false;
do { do {
if (this.pos >= this.input.length) { if (this.pos >= this.input.length) {
return content.length ? content.join('') : ['', 'TK_EOF']; return content.length ? content.join("") : ["", "TK_EOF"];
} }
char = this.input.charAt(this.pos); char = this.input.charAt(this.pos);
this.pos++; this.pos++;
@@ -131,92 +131,92 @@ const format = (function() {
continue; continue;
} }
if (char === "'" || char === '"') { if (char === "'" || char === '"') {
if (!content[1] || content[1] !== '!') { if (!content[1] || content[1] !== "!") {
char += this.get_unformatted(char); char += this.get_unformatted(char);
space = true; space = true;
} }
} }
if (char === '=') { if (char === "=") {
space = false; space = false;
} }
if (content.length && content[content.length - 1] !== '=' && char !== '>' && space) { if (content.length && content[content.length - 1] !== "=" && char !== ">" && space) {
if (this.line_char_count >= this.max_char) { if (this.line_char_count >= this.max_char) {
this.print_newline(false, content); this.print_newline(false, content);
this.line_char_count = 0; this.line_char_count = 0;
} else { } else {
content.push(' '); content.push(" ");
this.line_char_count++; this.line_char_count++;
} }
space = false; space = false;
} }
content.push(char); content.push(char);
} while ( char !== '>'); } while (char !== ">");
var tag_complete = content.join(''); var tag_complete = content.join("");
var tag_index; var tag_index;
if (tag_complete.indexOf(' ') != -1) { if (tag_complete.indexOf(" ") != -1) {
tag_index = tag_complete.indexOf(' '); tag_index = tag_complete.indexOf(" ");
} else { } else {
tag_index = tag_complete.indexOf('>'); tag_index = tag_complete.indexOf(">");
} }
var tag_check = tag_complete.substring(1, tag_index).toLowerCase(); var tag_check = tag_complete.substring(1, tag_index).toLowerCase();
if (tag_complete.charAt(tag_complete.length - 2) === '/' || this.Utils.in_array(tag_check, this.Utils.single_token)) { if (tag_complete.charAt(tag_complete.length - 2) === "/" || this.Utils.in_array(tag_check, this.Utils.single_token)) {
this.tag_type = 'SINGLE'; this.tag_type = "SINGLE";
} else if (tag_check === 'script') { } else if (tag_check === "script") {
this.record_tag(tag_check); this.record_tag(tag_check);
this.tag_type = 'SCRIPT'; this.tag_type = "SCRIPT";
} else if (tag_check === 'style') { } else if (tag_check === "style") {
this.record_tag(tag_check); this.record_tag(tag_check);
this.tag_type = 'STYLE'; this.tag_type = "STYLE";
} else if (tag_check.charAt(0) === '!') { } else if (tag_check.charAt(0) === "!") {
if (tag_check.indexOf('[if') != -1) { if (tag_check.indexOf("[if") != -1) {
if (tag_complete.indexOf('!IE') != -1) { if (tag_complete.indexOf("!IE") != -1) {
var comment = this.get_unformatted('-->', tag_complete); var comment = this.get_unformatted("-->", tag_complete);
content.push(comment); content.push(comment);
} }
this.tag_type = 'START'; this.tag_type = "START";
} else if (tag_check.indexOf('[endif') != -1) { } else if (tag_check.indexOf("[endif") != -1) {
this.tag_type = 'END'; this.tag_type = "END";
this.unindent(); this.unindent();
} else if (tag_check.indexOf('[cdata[') != -1) { } else if (tag_check.indexOf("[cdata[") != -1) {
var comment = this.get_unformatted(']]>', tag_complete); var comment = this.get_unformatted("]]>", tag_complete);
content.push(comment); content.push(comment);
this.tag_type = 'SINGLE'; this.tag_type = "SINGLE";
} else { } else {
var comment = this.get_unformatted('-->', tag_complete); var comment = this.get_unformatted("-->", tag_complete);
content.push(comment); content.push(comment);
this.tag_type = 'SINGLE'; this.tag_type = "SINGLE";
} }
} else { } else {
if (tag_check.charAt(0) === '/') { if (tag_check.charAt(0) === "/") {
this.retrieve_tag(tag_check.substring(1)); this.retrieve_tag(tag_check.substring(1));
this.tag_type = 'END'; this.tag_type = "END";
} else { } else {
this.record_tag(tag_check); this.record_tag(tag_check);
this.tag_type = 'START'; this.tag_type = "START";
} }
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) {
this.print_newline(true, this.output); this.print_newline(true, this.output);
} }
} }
return content.join(''); return content.join("");
} };
this.get_unformatted = function(delimiter, orig_tag) { this.get_unformatted = function (delimiter, orig_tag) {
if (orig_tag && orig_tag.indexOf(delimiter) != -1) { if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
return ''; return "";
} }
var char = ''; var char = "";
var content = ''; var content = "";
var space = true; var space = true;
do { do {
char = this.input.charAt(this.pos); char = this.input.charAt(this.pos);
this.pos++ this.pos++;
if (this.Utils.in_array(char, this.Utils.whitespace)) { if (this.Utils.in_array(char, this.Utils.whitespace)) {
if (!space) { if (!space) {
this.line_char_count--; this.line_char_count--;
continue; continue;
} }
if (char === '\n' || char === '\r') { if (char === "\n" || char === "\r") {
content += '\n'; content += "\n";
for (var i = 0; i < this.indent_level; i++) { for (var i = 0; i < this.indent_level; i++) {
content += this.indent_string; content += this.indent_string;
} }
@@ -228,44 +228,43 @@ const format = (function() {
content += char; content += char;
this.line_char_count++; this.line_char_count++;
space = true; space = true;
} while (content.indexOf(delimiter) == -1);
} while ( content . indexOf ( delimiter ) == -1);
return content; return content;
} };
this.get_token = function() { this.get_token = function () {
var token; var token;
if (this.last_token === 'TK_TAG_SCRIPT') { if (this.last_token === "TK_TAG_SCRIPT") {
var temp_token = this.get_script(); var temp_token = this.get_script();
if (typeof temp_token !== 'string') { if (typeof temp_token !== "string") {
return temp_token; return temp_token;
} }
//token = js_beautify(temp_token, this.indent_size, this.indent_character, this.indent_level); //token = js_beautify(temp_token, this.indent_size, this.indent_character, this.indent_level);
//return [token, 'TK_CONTENT']; //return [token, 'TK_CONTENT'];
return [temp_token, 'TK_CONTENT']; return [temp_token, "TK_CONTENT"];
} }
if (this.current_mode === 'CONTENT') { if (this.current_mode === "CONTENT") {
token = this.get_content(); token = this.get_content();
if (typeof token !== 'string') { if (typeof token !== "string") {
return token; return token;
} else { } else {
return [token, 'TK_CONTENT']; return [token, "TK_CONTENT"];
} }
} }
if (this.current_mode === 'TAG') { if (this.current_mode === "TAG") {
token = this.get_tag(); token = this.get_tag();
if (typeof token !== 'string') { if (typeof token !== "string") {
return token; return token;
} else { } else {
var tag_name_type = 'TK_TAG_' + this.tag_type; var tag_name_type = "TK_TAG_" + this.tag_type;
return [token, tag_name_type]; return [token, tag_name_type];
} }
} }
} };
this.printer = function(js_source, indent_character, indent_size, max_char) { this.printer = function (js_source, indent_character, indent_size, max_char) {
this.input = js_source || ''; this.input = js_source || "";
this.output = []; this.output = [];
this.indent_character = indent_character || ' '; this.indent_character = indent_character || " ";
this.indent_string = ''; this.indent_string = "";
this.indent_size = indent_size || 2; this.indent_size = indent_size || 2;
this.indent_level = 0; this.indent_level = 0;
this.max_char = max_char || 70; this.max_char = max_char || 70;
@@ -273,7 +272,7 @@ const format = (function() {
for (var i = 0; i < this.indent_size; i++) { for (var i = 0; i < this.indent_size; i++) {
this.indent_string += this.indent_character; this.indent_string += this.indent_character;
} }
this.print_newline = function(ignore, arr) { this.print_newline = function (ignore, arr) {
this.line_char_count = 0; this.line_char_count = 0;
if (!arr || !arr.length) { if (!arr || !arr.length) {
return; return;
@@ -283,23 +282,23 @@ const format = (function() {
arr.pop(); arr.pop();
} }
} }
arr.push('\n'); arr.push("\n");
for (var i = 0; i < this.indent_level; i++) { for (var i = 0; i < this.indent_level; i++) {
arr.push(this.indent_string); arr.push(this.indent_string);
} }
} };
this.print_token = function(text) { this.print_token = function (text) {
this.output.push(text); this.output.push(text);
} };
this.indent = function() { this.indent = function () {
this.indent_level++; this.indent_level++;
} };
this.unindent = function() { this.unindent = function () {
if (this.indent_level > 0) { if (this.indent_level > 0) {
this.indent_level--; this.indent_level--;
} }
} };
} };
return this; return this;
} }
multi_parser = new Parser(); multi_parser = new Parser();
@@ -308,58 +307,56 @@ const format = (function() {
var t = multi_parser.get_token(); var t = multi_parser.get_token();
multi_parser.token_text = t[0]; multi_parser.token_text = t[0];
multi_parser.token_type = t[1]; multi_parser.token_type = t[1];
if (multi_parser.token_type === 'TK_EOF') { if (multi_parser.token_type === "TK_EOF") {
break; break;
} }
switch (multi_parser.token_type) { switch (multi_parser.token_type) {
case 'TK_TAG_START': case "TK_TAG_START":
case 'TK_TAG_SCRIPT': case "TK_TAG_SCRIPT":
case 'TK_TAG_STYLE': case "TK_TAG_STYLE":
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.indent();
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_END':
multi_parser.print_newline(true, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_TAG_SINGLE':
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = 'CONTENT';
break;
case 'TK_CONTENT':
if (multi_parser.token_text !== '') {
multi_parser.print_newline(false, multi_parser.output); multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text); multi_parser.print_token(multi_parser.token_text);
} multi_parser.indent();
multi_parser.current_mode = 'TAG'; multi_parser.current_mode = "CONTENT";
break; break;
case "TK_TAG_END":
multi_parser.print_newline(true, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = "CONTENT";
break;
case "TK_TAG_SINGLE":
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
multi_parser.current_mode = "CONTENT";
break;
case "TK_CONTENT":
if (multi_parser.token_text !== "") {
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
}
multi_parser.current_mode = "TAG";
break;
} }
multi_parser.last_token = multi_parser.token_type; multi_parser.last_token = multi_parser.token_type;
multi_parser.last_text = multi_parser.token_text; multi_parser.last_text = multi_parser.token_text;
} }
return multi_parser.output.join(''); return multi_parser.output.join("");
} }
return function(data) { return function (data) {
var dataHolder = ['__dataHolder_', [Math.random(), Math.random(), Math.random(), Math.random()].join('_').replace(/[^0-9]/g, '_'), '_'].join('_'); var dataHolder = ["__dataHolder_", [Math.random(), Math.random(), Math.random(), Math.random()].join("_").replace(/[^0-9]/g, "_"), "_"].join("_");
var dataHolders = {}; var dataHolders = {};
var index = 0; var index = 0;
data = data.replace(/(\")(data:[^\"]*)(\")/g, data = data.replace(/(\")(data:[^\"]*)(\")/g, function ($0, $1, $2, $3) {
function($0, $1, $2, $3) {
var name = dataHolder + index++; var name = dataHolder + index++;
dataHolders[name] = $2; dataHolders[name] = $2;
return $1 + name + $3; return $1 + name + $3;
}) });
data = style_html(data, 2, ' ', 0x10000000); data = style_html(data, 2, " ", 0x10000000);
data = data.replace(new RegExp(dataHolder + '[0-9]+', 'g'), data = data.replace(new RegExp(dataHolder + "[0-9]+", "g"), function ($0) {
function($0) {
return dataHolders[$0]; return dataHolders[$0];
}); });
return data; return data;
} };
})(); })();
export default format export default format;
@@ -1,6 +1,6 @@
<template> <template>
<a-select> <a-select>
<a-select-option v-for="item of options" :keu="item.value" :value="item.value" :label="item.label"> <a-select-option v-for="item of options" :key="item.value" :value="item.value" :label="item.label">
<span class="flex-o"> <span class="flex-o">
<fs-icon :icon="item.icon" class="fs-16 color-blue mr-5" /> <fs-icon :icon="item.icon" class="fs-16 color-blue mr-5" />
{{ item.label }} {{ item.label }}
@@ -10,12 +10,12 @@ export default {
props: { props: {
modelValue: { modelValue: {
type: String, type: String,
default: undefined default: undefined,
}, },
// eslint-disable-next-line vue/require-default-prop // eslint-disable-next-line vue/require-default-prop
from: { from: {
type: [String, Array] type: [String, Array],
} },
}, },
emits: ["update:modelValue"], emits: ["update:modelValue"],
setup(props: any, ctx: any) { setup(props: any, ctx: any) {
@@ -35,7 +35,7 @@ export default {
currentStageIndex: currentStageIndex.value, currentStageIndex: currentStageIndex.value,
currentTaskIndex: currentTaskIndex.value, currentTaskIndex: currentTaskIndex.value,
currentStepIndex: currentStepIndex.value, currentStepIndex: currentStepIndex.value,
currentTask: currentTask.value currentTask: currentTask.value,
}); });
if (props.from) { if (props.from) {
if (typeof props.from === "string") { if (typeof props.from === "string") {
@@ -73,9 +73,9 @@ export default {
} }
return { return {
options, options,
onChanged onChanged,
}; };
} },
}; };
</script> </script>
@@ -2,6 +2,10 @@
import { ref } from "vue"; import { ref } from "vue";
import TutorialSteps from "/@/components/tutorial/tutorial-steps.vue"; import TutorialSteps from "/@/components/tutorial/tutorial-steps.vue";
defineOptions({
name: "TutorialModal",
});
const props = defineProps<{ const props = defineProps<{
showIcon?: boolean; showIcon?: boolean;
}>(); }>();
@@ -16,23 +20,18 @@ const slots = defineSlots();
<template> <template>
<div class="tutorial-button pointer" @click="open"> <div class="tutorial-button pointer" @click="open">
<template v-if="!slots.default"> <template v-if="!slots.default">
<fs-icon <fs-icon v-if="showIcon === false" icon="ant-design:question-circle-outlined" class="mr-0.5"></fs-icon>
v-if="showIcon === false" <div class="hidden md:block">{{ $t("tutorial.title") }}</div>
icon="ant-design:question-circle-outlined"
class="mr-0.5"
></fs-icon>
<div class="hidden md:block">{{$t('tutorial.title')}}</div>
</template> </template>
<slot></slot> <slot></slot>
<a-modal v-model:open="openedRef" class="tutorial-modal" width="90%"> <a-modal v-model:open="openedRef" class="tutorial-modal" width="90%">
<template #title>{{$t('tutorial.title')}}</template> <template #title>{{ $t("tutorial.title") }}</template>
<tutorial-steps v-if="openedRef" /> <tutorial-steps v-if="openedRef" />
<template #footer></template> <template #footer></template>
</a-modal> </a-modal>
</div> </div>
</template> </template>
<style lang="less"> <style lang="less">
.tutorial-modal { .tutorial-modal {
top: 50px; top: 50px;
@@ -15,11 +15,7 @@ type Step = {
import { ref } from "vue"; import { ref } from "vue";
const steps = ref<Step[]>([ const steps = ref<Step[]>([{ title: t("certd.steps.createPipeline") }, { title: t("certd.steps.addTask") }, { title: t("certd.steps.scheduledRun") }]);
{ title: t('certd.steps.createPipeline') },
{ title: t('certd.steps.addTask') },
{ title: t('certd.steps.scheduledRun') }
]);
const router = useRouter(); const router = useRouter();
function goPipeline() { function goPipeline() {
@@ -20,10 +20,9 @@
</div> </div>
<div class="flex-center actions"> <div class="flex-center actions">
<fs-button class="m-10" icon="ion:arrow-back-outline" @click="prev()">{{ t('guide.buttons.prev') }}</fs-button> <fs-button class="m-10" icon="ion:arrow-back-outline" @click="prev()">{{ t("guide.buttons.prev") }}</fs-button>
<fs-button class="m-10" type="primary" icon-right="ion:arrow-forward-outline" @click="next()">{{ t('guide.buttons.next') }}</fs-button> <fs-button class="m-10" type="primary" icon-right="ion:arrow-forward-outline" @click="next()">{{ t("guide.buttons.next") }}</fs-button>
</div> </div>
</div> </div>
</template> </template>
@@ -49,16 +48,13 @@ type StepItems = {
import { computed, nextTick, ref } from "vue"; import { computed, nextTick, ref } from "vue";
const steps = ref<Step[]>([ const steps = ref<Step[]>([
{ {
title: t("guide.createCertPipeline.title"), title: t("guide.createCertPipeline.title"),
description: t("guide.createCertPipeline.description"), description: t("guide.createCertPipeline.description"),
items: [ items: [
{ {
title: t("guide.createCertPipeline.items.tutorialTitle"), title: t("guide.createCertPipeline.items.tutorialTitle"),
descriptions: [ descriptions: [t("guide.createCertPipeline.items.tutorialDesc1"), t("guide.createCertPipeline.items.tutorialDesc2")],
t("guide.createCertPipeline.items.tutorialDesc1"),
t("guide.createCertPipeline.items.tutorialDesc2"),
],
body: () => { body: () => {
return <SimpleSteps></SimpleSteps>; return <SimpleSteps></SimpleSteps>;
}, },
@@ -86,26 +82,17 @@ const steps = ref<Step[]>([
{ {
image: "/static/doc/images/5-1-add-host.png", image: "/static/doc/images/5-1-add-host.png",
title: t("guide.addDeployTask.items.addTaskTitle"), title: t("guide.addDeployTask.items.addTaskTitle"),
descriptions: [ descriptions: [t("guide.addDeployTask.items.addTaskDesc1"), t("guide.addDeployTask.items.addTaskDesc2")],
t("guide.addDeployTask.items.addTaskDesc1"),
t("guide.addDeployTask.items.addTaskDesc2"),
],
}, },
{ {
image: "/static/doc/images/5-2-add-host.png", image: "/static/doc/images/5-2-add-host.png",
title: t("guide.addDeployTask.items.fillParamsTitle"), title: t("guide.addDeployTask.items.fillParamsTitle"),
descriptions: [ descriptions: [t("guide.addDeployTask.items.fillParamsDesc1"), t("guide.addDeployTask.items.fillParamsDesc2")],
t("guide.addDeployTask.items.fillParamsDesc1"),
t("guide.addDeployTask.items.fillParamsDesc2"),
],
}, },
{ {
image: "/static/doc/images/5-3-add-host.png", image: "/static/doc/images/5-3-add-host.png",
title: t("guide.addDeployTask.items.activateCertTitle"), title: t("guide.addDeployTask.items.activateCertTitle"),
descriptions: [ descriptions: [t("guide.addDeployTask.items.activateCertDesc1"), t("guide.addDeployTask.items.activateCertDesc2")],
t("guide.addDeployTask.items.activateCertDesc1"),
t("guide.addDeployTask.items.activateCertDesc2"),
],
}, },
{ {
image: "/static/doc/images/5-4-add-host.png", image: "/static/doc/images/5-4-add-host.png",
@@ -119,81 +106,72 @@ const steps = ref<Step[]>([
}, },
], ],
}, },
{ {
title: t('guide.runAndTestTask.runAndTestTitle'), title: t("guide.runAndTestTask.runAndTestTitle"),
description: t('guide.runAndTestTask.runAndTestDescription'), description: t("guide.runAndTestTask.runAndTestDescription"),
items: [ items: [
{ {
image: "/static/doc/images/9-start.png", image: "/static/doc/images/9-start.png",
title: t('guide.runAndTestTask.runTestOnce'), title: t("guide.runAndTestTask.runTestOnce"),
descriptions: [t('guide.runAndTestTask.clickManualTriggerToTest')], descriptions: [t("guide.runAndTestTask.clickManualTriggerToTest")],
}, },
{ {
image: "/static/doc/images/10-1-log.png", image: "/static/doc/images/10-1-log.png",
title: t('guide.runAndTestTask.viewLogs'), title: t("guide.runAndTestTask.viewLogs"),
descriptions: [t('guide.runAndTestTask.clickTaskToViewStatusAndLogs')], descriptions: [t("guide.runAndTestTask.clickTaskToViewStatusAndLogs")],
}, },
{ {
image: "/static/doc/images/11-1-error.png", image: "/static/doc/images/11-1-error.png",
title: t('guide.runAndTestTask.howToTroubleshootFailure'), title: t("guide.runAndTestTask.howToTroubleshootFailure"),
descriptions: [t('guide.runAndTestTask.viewErrorLogs')], descriptions: [t("guide.runAndTestTask.viewErrorLogs")],
}, },
{ {
image: "/static/doc/images/11-2-error.png", image: "/static/doc/images/11-2-error.png",
title: t('guide.runAndTestTask.howToTroubleshootFailure'), title: t("guide.runAndTestTask.howToTroubleshootFailure"),
descriptions: [ descriptions: [t("guide.runAndTestTask.viewErrorLogs"), t("guide.runAndTestTask.nginxContainerNotExistFix")],
t('guide.runAndTestTask.viewErrorLogs'), },
t('guide.runAndTestTask.nginxContainerNotExistFix'), {
], image: "/static/doc/images/12-1-log-success.png",
}, title: t("guide.runAndTestTask.executionSuccess"),
{ descriptions: [t("guide.runAndTestTask.retryAfterFix")],
image: "/static/doc/images/12-1-log-success.png", },
title: t('guide.runAndTestTask.executionSuccess'), {
descriptions: [t('guide.runAndTestTask.retryAfterFix')], image: "/static/doc/images/12-2-skip-log.png",
}, title: t("guide.runAndTestTask.autoSkipAfterSuccess"),
{ descriptions: [t("guide.runAndTestTask.successSkipExplanation")],
image: "/static/doc/images/12-2-skip-log.png", },
title: t('guide.runAndTestTask.autoSkipAfterSuccess'), {
descriptions: [t('guide.runAndTestTask.successSkipExplanation')], image: "/static/doc/images/13-1-result.png",
}, title: t("guide.runAndTestTask.viewCertDeploymentSuccess"),
{ descriptions: [t("guide.runAndTestTask.visitNginxToSeeCert")],
image: "/static/doc/images/13-1-result.png", },
title: t('guide.runAndTestTask.viewCertDeploymentSuccess'), {
descriptions: [t('guide.runAndTestTask.visitNginxToSeeCert')], image: "/static/doc/images/13-3-download.png",
}, title: t("guide.runAndTestTask.downloadCertManualDeploy"),
{ descriptions: [t("guide.runAndTestTask.downloadIfNoAutoDeployPlugin")],
image: "/static/doc/images/13-3-download.png", },
title: t('guide.runAndTestTask.downloadCertManualDeploy'), ],
descriptions: [t('guide.runAndTestTask.downloadIfNoAutoDeployPlugin')], },
}, {
], title: t("guide.scheduleAndEmailTask.title"),
}, description: t("guide.scheduleAndEmailTask.description"),
{ items: [
title: t('guide.scheduleAndEmailTask.title'), {
description: t('guide.scheduleAndEmailTask.description'), image: "/static/doc/images/14-timer.png",
items: [ title: t("guide.scheduleAndEmailTask.setSchedule"),
{ descriptions: [t("guide.scheduleAndEmailTask.pipelineSuccessThenSchedule"), t("guide.scheduleAndEmailTask.recommendDailyRun")],
image: "/static/doc/images/14-timer.png", },
title: t('guide.scheduleAndEmailTask.setSchedule'), {
descriptions: [ image: "/static/doc/images/15-1-email.png",
t('guide.scheduleAndEmailTask.pipelineSuccessThenSchedule'), title: t("guide.scheduleAndEmailTask.setEmailNotification"),
t('guide.scheduleAndEmailTask.recommendDailyRun'), descriptions: [t("guide.scheduleAndEmailTask.suggestErrorAndRecoveryEmails"), t("guide.scheduleAndEmailTask.basicVersionNeedsMailServer")],
], },
}, {
{ title: t("guide.scheduleAndEmailTask.tutorialEndTitle"),
image: "/static/doc/images/15-1-email.png", descriptions: [t("guide.scheduleAndEmailTask.thanksForWatching")],
title: t('guide.scheduleAndEmailTask.setEmailNotification'), },
descriptions: [ ],
t('guide.scheduleAndEmailTask.suggestErrorAndRecoveryEmails'), },
t('guide.scheduleAndEmailTask.basicVersionNeedsMailServer'),
],
},
{
title: t('guide.scheduleAndEmailTask.tutorialEndTitle'),
descriptions: [t('guide.scheduleAndEmailTask.thanksForWatching')],
},
],
}
]); ]);
const current = ref(0); const current = ref(0);
@@ -10,7 +10,7 @@ export default {
function checkPlus() { function checkPlus() {
// 事件处理代码 // 事件处理代码
notification.warn({ notification.warn({
message: "此为专业版功能,请升级到专业版" message: "此为专业版功能,请升级到专业版",
}); });
} }
el.addEventListener("click", function (event: any) { el.addEventListener("click", function (event: any) {
@@ -20,5 +20,5 @@ export default {
checkPlus(); checkPlus();
}); });
} }
} },
}; };
@@ -1,15 +1,15 @@
<template> <template>
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade"> <div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade">
<contextHolder /> <contextHolder />
<fs-icon icon="mingcute:vip-1-line" :title="text.title" /> <fs-icon icon="mingcute:vip-1-line" :title="text.title" />
<div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5"> <div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5">
<a-tooltip> <a-tooltip>
<template #title> {{ text.title }}</template> <template #title> {{ text.title }}</template>
<span class="">{{ text.name }}</span> <span class="">{{ text.name }}</span>
</a-tooltip> </a-tooltip>
</div> </div>
</div> </div>
</template> </template>
<script lang="tsx" setup> <script lang="tsx" setup>
import { computed, onMounted, reactive } from "vue"; import { computed, onMounted, reactive } from "vue";
@@ -104,7 +104,6 @@ const text = computed<Text>(() => {
} }
}); });
const expireTime = computed(() => { const expireTime = computed(() => {
if (settingStore.isPlus) { if (settingStore.isPlus) {
return dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD"); return dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD");
@@ -157,7 +156,6 @@ async function doActive() {
} }
} }
const computedSiteId = computed(() => settingStore.installInfo?.siteId); const computedSiteId = computed(() => settingStore.installInfo?.siteId);
const [modal, contextHolder] = Modal.useModal(); const [modal, contextHolder] = Modal.useModal();
const userStore = useUserStore(); const userStore = useUserStore();
@@ -169,17 +167,16 @@ function goAccount() {
async function getVipTrial() { async function getVipTrial() {
const res = await api.getVipTrial(); const res = await api.getVipTrial();
message.success(t('vip.congratulations_vip_trial', { duration: res.duration })); message.success(t("vip.congratulations_vip_trial", { duration: res.duration }));
await settingStore.init(); await settingStore.init();
} }
function openTrialModal() { function openTrialModal() {
Modal.destroyAll(); Modal.destroyAll();
modal.confirm({ modal.confirm({
title: t('vip.trial_modal_title'), title: t("vip.trial_modal_title"),
okText: t('vip.trial_modal_ok_text'), okText: t("vip.trial_modal_ok_text"),
onOk() { onOk() {
getVipTrial(); getVipTrial();
}, },
@@ -187,15 +184,14 @@ function openTrialModal() {
content: () => { content: () => {
return ( return (
<div class="flex-col mt-10 mb-10"> <div class="flex-col mt-10 mb-10">
<div>{t('vip.trial_modal_thanks')}</div> <div>{t("vip.trial_modal_thanks")}</div>
<div>{t('vip.trial_modal_click_confirm')}</div> <div>{t("vip.trial_modal_click_confirm")}</div>
</div> </div>
); );
}, },
}); });
} }
function openStarModal() { function openStarModal() {
Modal.destroyAll(); Modal.destroyAll();
const goGithub = () => { const goGithub = () => {
@@ -221,207 +217,176 @@ function openStarModal() {
}); });
} }
function openUpgrade() { function openUpgrade() {
if (!userStore.isAdmin) { if (!userStore.isAdmin) {
message.info(t("vip.admin_only_operation")); message.info(t("vip.admin_only_operation"));
return; return;
} }
const placeholder = t("vip.enter_activation_code"); const placeholder = t("vip.enter_activation_code");
const isPlus = settingStore.isPlus; const isPlus = settingStore.isPlus;
let title = t("vip.activate_pro_business"); let title = t("vip.activate_pro_business");
if (settingStore.isComm) { if (settingStore.isComm) {
title = t("vip.renew_business"); title = t("vip.renew_business");
} else if (settingStore.isPlus) { } else if (settingStore.isPlus) {
title = t("vip.renew_pro_upgrade_business"); title = t("vip.renew_pro_upgrade_business");
} }
const productInfo = settingStore.productInfo;
const productInfo = settingStore.productInfo; const vipTypeDefine = {
const vipTypeDefine = { free: {
free: { title: t("vip.basic_edition"),
title: t("vip.basic_edition"), desc: t("vip.community_free_version"),
desc: t("vip.community_free_version"), type: "free",
type: "free", icon: "lucide:package-open",
icon: "lucide:package-open", privilege: [t("vip.unlimited_certificate_application"), t("vip.unlimited_domain_count"), t("vip.unlimited_certificate_pipelines"), t("vip.common_deployment_plugins"), t("vip.email_webhook_notifications")],
privilege: [ },
t("vip.unlimited_certificate_application"), plus: {
t("vip.unlimited_domain_count"), title: t("vip.professional_edition"),
t("vip.unlimited_certificate_pipelines"), desc: t("vip.open_source_support"),
t("vip.common_deployment_plugins"), type: "plus",
t("vip.email_webhook_notifications"), privilege: [t("vip.vip_group_priority"), t("vip.unlimited_site_certificate_monitoring"), t("vip.more_notification_methods"), t("vip.plugins_fully_open")],
], trial: {
}, title: t("vip.click_to_get_7_day_trial"),
plus: { click: () => {
title: t("vip.professional_edition"), openStarModal();
desc: t("vip.open_source_support"), },
type: "plus", },
privilege: [ icon: "stash:thumb-up",
t("vip.vip_group_priority"), price: productInfo.plus.price,
t("vip.unlimited_site_certificate_monitoring"), price3: `¥${productInfo.plus.price3}/3${t("vip.years")}`,
t("vip.more_notification_methods"), tooltip: productInfo.plus.tooltip,
t("vip.plugins_fully_open"), get() {
], return (
trial: { <a-tooltip title={t("vip.afdian_support_vip")}>
title: t("vip.click_to_get_7_day_trial"), <a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank">
click: () => { {t("vip.get_after_support")}
openStarModal(); </a-button>
</a-tooltip>
);
}, },
}, },
icon: "stash:thumb-up", comm: {
price: productInfo.plus.price, title: t("vip.business_edition"),
price3: `¥${productInfo.plus.price3}/3${t("vip.years")}`, desc: t("vip.commercial_license"),
tooltip: productInfo.plus.tooltip, type: "comm",
get() { icon: "vaadin:handshake",
return ( privilege: [t("vip.all_pro_privileges"), t("vip.allow_commercial_use_modify_logo_title"), t("vip.data_statistics"), t("vip.plugin_management"), t("vip.unlimited_multi_users"), t("vip.support_user_payment")],
<a-tooltip title={t("vip.afdian_support_vip")}> price: productInfo.comm.price,
<a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank"> price3: `¥${productInfo.comm.price3}/3${t("vip.years")}`,
{t("vip.get_after_support")} tooltip: productInfo.comm.tooltip,
</a-button> get() {
</a-tooltip> return <a-button size="small">{t("vip.contact_author_for_trial")}</a-button>;
},
},
};
const modalRef = modal.confirm({
title,
async onOk() {
return await doActive();
},
maskClosable: true,
okText: t("vip.activate"),
width: 1000,
content: () => {
let activationCodeGetWay = (
<span>
<a href="https://afdian.com/a/greper" target="_blank">
{t("vip.get_pro_code_after_support")}
</a>
<span> {t("vip.business_contact_author")}</span>
</span>
); );
}, const vipLabel = settingStore.vipLabel;
}, const slots = [];
comm: { for (const key in vipTypeDefine) {
title: t("vip.business_edition"), // @ts-ignore
desc: t("vip.commercial_license"), const item = vipTypeDefine[key];
type: "comm", const vipBlockClass = `vip-block ${key === settingStore.plusInfo.vipType ? "current" : ""}`;
icon: "vaadin:handshake", slots.push(
privilege: [ <a-col span={8}>
t("vip.all_pro_privileges"), <div class={vipBlockClass}>
t("vip.allow_commercial_use_modify_logo_title"), <h3 class="block-header ">
t("vip.data_statistics"), <span class="flex-o">{item.title}</span>
t("vip.plugin_management"), {item.trial && (
t("vip.unlimited_multi_users"), <span class="trial">
t("vip.support_user_payment"), <a-tooltip title={item.trial.message}>
], <a onClick={item.trial.click}>{item.trial.title}</a>
price: productInfo.comm.price,
price3: `¥${productInfo.comm.price3}/3${t("vip.years")}`,
tooltip: productInfo.comm.tooltip,
get() {
return <a-button size="small">{t("vip.contact_author_for_trial")}</a-button>;
},
},
};
const modalRef = modal.confirm({
title,
async onOk() {
return await doActive();
},
maskClosable: true,
okText: t("vip.activate"),
width: 1000,
content: () => {
let activationCodeGetWay = (
<span>
<a href="https://afdian.com/a/greper" target="_blank">
{t("vip.get_pro_code_after_support")}
</a>
<span> {t("vip.business_contact_author")}</span>
</span>
);
const vipLabel = settingStore.vipLabel;
const slots = [];
for (const key in vipTypeDefine) {
// @ts-ignore
const item = vipTypeDefine[key];
const vipBlockClass = `vip-block ${key === settingStore.plusInfo.vipType ? "current" : ""}`;
slots.push(
<a-col span={8}>
<div class={vipBlockClass}>
<h3 class="block-header ">
<span class="flex-o">{item.title}</span>
{item.trial && (
<span class="trial">
<a-tooltip title={item.trial.message}>
<a onClick={item.trial.click}>{item.trial.title}</a>
</a-tooltip>
</span>
)}
</h3>
<div style="color:green" class="flex-o">
<fs-icon icon={item.icon} class="fs-16 flex-o" />
{item.desc}
</div>
<ul class="flex-1 privilege">
{item.privilege.map((p: string) => (
<li class="flex-baseline">
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
{p}
</li>
))}
</ul>
<div class="footer flex-between flex-vc">
<div class="price-show">
{item.price && (
<span class="flex">
<span class="-text">¥{item.price}</span>
<span>/</span>
{t("vip.year")}
<a-tooltip class="ml-5" title={item.price3}>
<fs-icon class="pointer color-red" icon="ic:outline-discount"></fs-icon>
</a-tooltip> </a-tooltip>
</span> </span>
)} )}
{!item.price && ( </h3>
<span> <div style="color:green" class="flex-o">
<span class="price-text">{t("vip.freee")}</span> <fs-icon icon={item.icon} class="fs-16 flex-o" />
</span> {item.desc}
)}
</div> </div>
<div class="get-show">{item.get && <div>{item.get()}</div>}</div> <ul class="flex-1 privilege">
{item.privilege.map((p: string) => (
<li class="flex-baseline">
<fs-icon class="color-green" icon="ion:checkmark-sharp" />
{p}
</li>
))}
</ul>
<div class="footer flex-between flex-vc">
<div class="price-show">
{item.price && (
<span class="flex">
<span class="-text">¥{item.price}</span>
<span>/</span>
{t("vip.year")}
<a-tooltip class="ml-5" title={item.price3}>
<fs-icon class="pointer color-red" icon="ic:outline-discount"></fs-icon>
</a-tooltip>
</span>
)}
{!item.price && (
<span>
<span class="price-text">{t("vip.freee")}</span>
</span>
)}
</div>
<div class="get-show">{item.get && <div>{item.get()}</div>}</div>
</div>
</div>
</a-col>
);
}
return (
<div class="mt-10 mb-10 vip-active-modal">
{productInfo.notice && (
<div class="mb-10">
<a-alert type="error" message={productInfo.notice}></a-alert>
</div>
)}
<div class="vip-type-vs">
<a-row gutter={20}>{slots}</a-row>
</div>
<div class="mt-10">
<h3 class="block-header">{isPlus ? t("vip.renew") : t("vip.activate_immediately")}</h3>
<div>{isPlus ? `${t("vip.current")} ${vipLabel} ${t("vip.activated_expire_time")}` + dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD") : ""}</div>
<div class="mt-10">
<div class="flex-o w-100">
<span>{t("vip.site_id")}</span>
<fs-copyable class="flex-1" v-model={computedSiteId.value}></fs-copyable>
</div>
<a-input class="mt-10" v-model:value={formState.code} placeholder={placeholder} />
<a-input class="mt-10" v-model:value={formState.inviteCode} placeholder={t("vip.invite_code_optional")} />
</div>
<div class="mt-10">
{t("vip.no_activation_code")}
{activationCodeGetWay}
</div>
<div class="mt-10">
{t("vip.activation_code_one_use")}
<a onClick={goAccount}>{t("vip.bind_account")}</a>{t("vip.transfer_vip")}
</div> </div>
</div> </div>
</a-col> </div>
); );
} },
return ( });
<div class="mt-10 mb-10 vip-active-modal">
{productInfo.notice && (
<div class="mb-10">
<a-alert type="error" message={productInfo.notice}></a-alert>
</div>
)}
<div class="vip-type-vs">
<a-row gutter={20}>{slots}</a-row>
</div>
<div class="mt-10">
<h3 class="block-header">{isPlus ? t("vip.renew") : t("vip.activate_immediately")}</h3>
<div>
{isPlus
? `${t("vip.current")} ${vipLabel} ${t("vip.activated_expire_time")}` +
dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD")
: ""}
</div>
<div class="mt-10">
<div class="flex-o w-100">
<span>{t("vip.site_id")}</span>
<fs-copyable class="flex-1" v-model={computedSiteId.value}></fs-copyable>
</div>
<a-input class="mt-10" v-model:value={formState.code} placeholder={placeholder} />
<a-input
class="mt-10"
v-model:value={formState.inviteCode}
placeholder={t("vip.invite_code_optional")}
/>
</div>
<div class="mt-10">
{t("vip.no_activation_code")}
{activationCodeGetWay}
</div>
<div class="mt-10">
{t("vip.activation_code_one_use")}<a onClick={goAccount}>{t("vip.bind_account")}</a>
{t("vip.transfer_vip")}
</div>
</div>
</div>
);
},
});
} }
onMounted(() => { onMounted(() => {
mitter.on("openVipModal", () => { mitter.on("openVipModal", () => {
@@ -434,75 +399,76 @@ onMounted(() => {
<style lang="less"> <style lang="less">
.layout-vip { .layout-vip {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
&.isPlus { &.isPlus {
color: #c5913f; color: #c5913f;
} }
.text {} .text {
}
} }
.vip-active-modal { .vip-active-modal {
.vip-block { .vip-block {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 10px; padding: 10px;
border: 1px solid #eee; border: 1px solid #eee;
border-radius: 5px; border-radius: 5px;
height: 250px; height: 250px;
//background-color: rgba(250, 237, 167, 0.79); //background-color: rgba(250, 237, 167, 0.79);
&.current { &.current {
border-color: green; border-color: green;
} }
.block-header { .block-header {
padding: 0px; padding: 0px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.trial { .trial {
font-size: 12px; font-size: 12px;
font-wight: 400; font-wight: 400;
} }
} }
.footer { .footer {
padding-top: 5px; padding-top: 5px;
margin-top: 0px; margin-top: 0px;
border-top: 1px solid #eee; border-top: 1px solid #eee;
.price-text { .price-text {
font-size: 18px; font-size: 18px;
color: red; color: red;
} }
} }
} }
ul { ul {
list-style-type: unset; list-style-type: unset;
margin-left: 0px; margin-left: 0px;
padding: 0; padding: 0;
} }
.color-green { .color-green {
color: green; color: green;
} }
.vip-type-vs { .vip-type-vs {
.privilege { .privilege {
.fs-icon { .fs-icon {
color: green; color: green;
} }
} }
.fs-icon { .fs-icon {
margin-right: 5px; margin-right: 5px;
} }
} }
} }
</style> </style>
@@ -35,7 +35,7 @@ export default {
forEach(map, (item, key) => { forEach(map, (item, key) => {
list.push({ list.push({
key, key,
label: item.label label: item.label,
}); });
}); });
return list; return list;
@@ -54,9 +54,9 @@ export default {
return { return {
languages, languages,
current, current,
changeLocale changeLocale,
}; };
} },
}; };
</script> </script>
@@ -1,15 +1,15 @@
.fs-menu-wrapper{ .fs-menu-wrapper {
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
&.fs-menu-better-scroll{ &.fs-menu-better-scroll {
overflow-y: hidden; overflow-y: hidden;
} }
.menu-item-title{ .menu-item-title {
display: flex; display: flex;
align-items: center; align-items: center;
.fs-icon{ .fs-icon {
font-size: 16px !important; font-size: 16px !important;
min-width: 16px !important; min-width: 16px !important;
} }
} }
} }
@@ -10,7 +10,7 @@ import { utils } from "@fast-crud/fast-crud";
import * as _ from "lodash-es"; import * as _ from "lodash-es";
defineOptions({ defineOptions({
name: "FsMenu" name: "FsMenu",
}); });
const props = defineProps<{ const props = defineProps<{
@@ -37,7 +37,7 @@ function buildItemMenus(menus: any) {
title: sub.title, title: sub.title,
icon: () => { icon: () => {
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />; return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
} },
}; };
list.push(item); list.push(item);
@@ -50,7 +50,7 @@ function buildItemMenus(menus: any) {
watch( watch(
() => props.menus, () => props.menus,
(menus) => { menus => {
items.value = buildItemMenus(menus); items.value = buildItemMenus(menus);
}, },
{ immediate: true } { immediate: true }
@@ -77,7 +77,7 @@ function openSelectedParents(fullPath: any) {
return; return;
} }
if (value.path === fullPath) { if (value.path === fullPath) {
_.forEach(context.parents, (item) => { _.forEach(context.parents, item => {
if (item.value instanceof Array) { if (item.value instanceof Array) {
return; return;
} }
@@ -99,7 +99,7 @@ watch(
() => { () => {
return route.fullPath; return route.fullPath;
}, },
(path) => { path => {
// path = route.fullPath; // path = route.fullPath;
selectedKeys.value = [path]; selectedKeys.value = [path];
const changed = openSelectedParents(path); const changed = openSelectedParents(path);
@@ -108,7 +108,7 @@ watch(
} }
}, },
{ {
immediate: true immediate: true,
} }
); );
</script> </script>
@@ -6,7 +6,7 @@ import "./index.less";
import { utils } from "@fast-crud/fast-crud"; import { utils } from "@fast-crud/fast-crud";
import { routerUtils } from "/@/utils/util.router"; import { routerUtils } from "/@/utils/util.router";
defineOptions() defineOptions();
export default defineComponent({ export default defineComponent({
name: "FsMenu", name: "FsMenu",
@@ -14,9 +14,9 @@ export default defineComponent({
props: { props: {
menus: {}, menus: {},
expandSelected: { expandSelected: {
default: false default: false,
}, },
scroll: {} scroll: {},
}, },
setup(props, ctx) { setup(props, ctx) {
async function onSelect(item: any) { async function onSelect(item: any) {
@@ -37,7 +37,7 @@ export default defineComponent({
title: sub.title, title: sub.title,
icon: () => { icon: () => {
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />; return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
} },
}; };
list.push(item); list.push(item);
if (sub.children && sub.children.length > 0) { if (sub.children && sub.children.length > 0) {
@@ -80,7 +80,7 @@ export default defineComponent({
default: () => { default: () => {
return buildMenus(sub.children); return buildMenus(sub.children);
}, },
title title,
}; };
function onTitleClick() { function onTitleClick() {
if (sub.path && ctx.attrs.mode === "horizontal") { if (sub.path && ctx.attrs.mode === "horizontal") {
@@ -101,7 +101,7 @@ export default defineComponent({
const slots = { const slots = {
default() { default() {
return buildMenus(props.menus); return buildMenus(props.menus);
} },
}; };
const selectedKeys = ref([]); const selectedKeys = ref([]);
const openKeys = ref([]); const openKeys = ref([]);
@@ -123,7 +123,7 @@ export default defineComponent({
return; return;
} }
if (value.path === fullPath) { if (value.path === fullPath) {
_.forEach(context.parents, (item) => { _.forEach(context.parents, item => {
if (item.value instanceof Array) { if (item.value instanceof Array) {
return; return;
} }
@@ -148,7 +148,7 @@ export default defineComponent({
() => { () => {
return route.fullPath; return route.fullPath;
}, },
(path) => { path => {
// path = route.fullPath; // path = route.fullPath;
selectedKeys.value = [path]; selectedKeys.value = [path];
const changed = openSelectedParents(path); const changed = openSelectedParents(path);
@@ -157,7 +157,7 @@ export default defineComponent({
} }
}, },
{ {
immediate: true immediate: true,
} }
); );
return () => { return () => {
@@ -170,7 +170,7 @@ export default defineComponent({
// onOpenChange={onOpenChange} // onOpenChange={onOpenChange}
v-models={[ v-models={[
[openKeys.value, "openKeys"], [openKeys.value, "openKeys"],
[selectedKeys.value, "selectedKeys"] [selectedKeys.value, "selectedKeys"],
]} ]}
items={items.value} items={items.value}
inlineCollapsed={!props.expandSelected} inlineCollapsed={!props.expandSelected}
@@ -179,5 +179,5 @@ export default defineComponent({
const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll }; const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll };
return <div>{menu}</div>; return <div>{menu}</div>;
}; };
} },
}); });
@@ -17,7 +17,7 @@ export default defineComponent({
() => { () => {
return router.currentRoute.value.fullPath; return router.currentRoute.value.fullPath;
}, },
(value) => { value => {
showSourceLink.value = value !== "/index"; showSourceLink.value = value !== "/index";
}, },
{ immediate: true } { immediate: true }
@@ -29,9 +29,9 @@ export default defineComponent({
} }
return { return {
goSource, goSource,
showSourceLink showSourceLink,
}; };
} },
}); });
</script> </script>
@@ -2,14 +2,7 @@
<div class="fs-multiple-page-control-group"> <div class="fs-multiple-page-control-group">
<div class="fs-multiple-page-control-content"> <div class="fs-multiple-page-control-content">
<div class="fs-multiple-page-control-content-inner"> <div class="fs-multiple-page-control-content-inner">
<a-tabs <a-tabs class="fs-multiple-page-control fs-multiple-page-sort" :active-key="page.getCurrent" type="editable-card" hide-add @tab-click="handleClick" @edit="handleTabEdit">
class="fs-multiple-page-control fs-multiple-page-sort"
:active-key="page.getCurrent"
type="editable-card"
hide-add
@tab-click="handleClick"
@edit="handleTabEdit"
>
<a-tab-pane v-for="item in page.getOpened" :key="item.fullPath" :name="item.fullPath" :closable="isTabClosable(item)"> <a-tab-pane v-for="item in page.getOpened" :key="item.fullPath" :name="item.fullPath" :closable="isTabClosable(item)">
<template #tab> <template #tab>
<span class="flex-o"> <span class="flex-o">
@@ -75,7 +68,7 @@ export default {
closeRight: pageStore.closeRight, closeRight: pageStore.closeRight,
closeOther: pageStore.closeOther, closeOther: pageStore.closeOther,
closeAll: pageStore.closeAll, closeAll: pageStore.closeAll,
openedSort: pageStore.openedSort openedSort: pageStore.openedSort,
}; };
const computeOpened = computed(() => { const computeOpened = computed(() => {
return pageStore.getOpened; return pageStore.getOpened;
@@ -84,7 +77,7 @@ export default {
return { return {
page: pageStore, page: pageStore,
...actions, ...actions,
computeOpened computeOpened,
}; };
}, },
data() { data() {
@@ -97,9 +90,9 @@ export default {
{ icon: "arrow-left", title: "关闭左侧", value: "left" }, { icon: "arrow-left", title: "关闭左侧", value: "left" },
{ icon: "arrow-right", title: "关闭右侧", value: "right" }, { icon: "arrow-right", title: "关闭右侧", value: "right" },
{ icon: "times", title: "关闭其它", value: "other" }, { icon: "times", title: "关闭其它", value: "other" },
{ icon: "times-circle", title: "关闭全部", value: "all" } { icon: "times-circle", title: "关闭全部", value: "all" },
], ],
tagName: "/index" tagName: "/index",
}; };
}, },
mounted() { mounted() {
@@ -195,8 +188,8 @@ export default {
if (action === "remove") { if (action === "remove") {
this.close({ tagName }); this.close({ tagName });
} }
} },
} as any } as any,
}; };
</script> </script>
<style lang="less"> <style lang="less">
@@ -19,44 +19,44 @@ import { defineComponent, ref } from "vue";
const colorListDefine = [ const colorListDefine = [
{ {
key: "薄暮", key: "薄暮",
color: "#f5222d" color: "#f5222d",
}, },
{ {
key: "火山", key: "火山",
color: "#fa541c" color: "#fa541c",
}, },
{ {
key: "日暮", key: "日暮",
color: "#faad14" color: "#faad14",
}, },
{ {
key: "明青", key: "明青",
color: "#13c2c2" color: "#13c2c2",
}, },
{ {
key: "极光绿", key: "极光绿",
color: "#52c41a" color: "#52c41a",
}, },
{ {
key: "拂晓蓝(默认)", key: "拂晓蓝(默认)",
color: "#1890ff" color: "#1890ff",
}, },
{ {
key: "极客蓝", key: "极客蓝",
color: "#2f54eb" color: "#2f54eb",
}, },
{ {
key: "酱紫", key: "酱紫",
color: "#722ed1" color: "#722ed1",
} },
]; ];
export default defineComponent({ export default defineComponent({
name: "FsThemeColorPicker", name: "FsThemeColorPicker",
props: { props: {
primaryColor: { primaryColor: {
type: String, type: String,
default: "#1890ff" default: "#1890ff",
} },
}, },
emits: ["change"], emits: ["change"],
setup(props, ctx) { setup(props, ctx) {
@@ -66,9 +66,9 @@ export default defineComponent({
} }
return { return {
colorList, colorList,
changeColor changeColor,
}; };
} },
}); });
</script> </script>
<style lang="less"> <style lang="less">
@@ -27,9 +27,9 @@ export default defineComponent({
visible, visible,
show, show,
afterVisibleChange, afterVisibleChange,
setting setting,
}; };
} },
}); });
</script> </script>
@@ -29,9 +29,9 @@ export default defineComponent({
}; };
return { return {
setting, setting,
onChange onChange,
}; };
} },
}); });
</script> </script>
@@ -1,13 +1,13 @@
<template> <template>
<a-dropdown> <a-dropdown>
<div class="fs-user-info">{{ t('user.greeting') }}{{ userStore.getUserInfo?.nickName || userStore.getUserInfo?.username }}</div> <div class="fs-user-info">{{ t("user.greeting") }}{{ userStore.getUserInfo?.nickName || userStore.getUserInfo?.username }}</div>
<template #overlay> <template #overlay>
<a-menu> <a-menu>
<a-menu-item> <a-menu-item>
<div @click="goUserProfile">{{ t('user.profile') }}</div> <div @click="goUserProfile">{{ t("user.profile") }}</div>
</a-menu-item> </a-menu-item>
<a-menu-item> <a-menu-item>
<div @click="doLogout">{{ t('user.logout') }}</div> <div @click="doLogout">{{ t("user.logout") }}</div>
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
</template> </template>
@@ -20,6 +20,7 @@
<!-- <fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />--> <!-- <fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />-->
<div <div
v-for="menu of resourceStore.authedTopMenus" v-for="menu of resourceStore.authedTopMenus"
:key="menu.name"
class="top-menu flex-center header-btn" class="top-menu flex-center header-btn"
:class="{ current: resourceStore.currentTopMenu === menu }" :class="{ current: resourceStore.currentTopMenu === menu }"
:style="{ color: resourceStore.currentTopMenu === menu ? token.colorPrimary : '' }" :style="{ color: resourceStore.currentTopMenu === menu ? token.colorPrimary : '' }"
+10 -10
View File
@@ -3,7 +3,7 @@ import App from "./App.vue";
// import Antd from "ant-design-vue"; // import Antd from "ant-design-vue";
import Antd from "./plugin/antdv-async/index"; import Antd from "./plugin/antdv-async/index";
import "./style/common.less"; import "./style/common.less";
import { i18n, loadLocaleMessages } from "/@/locales" import { i18n, loadLocaleMessages } from "/@/locales";
import components from "./components"; import components from "./components";
import router from "./router"; import router from "./router";
import plugin from "./plugin/"; import plugin from "./plugin/";
@@ -15,15 +15,15 @@ import { initPreferences } from "/@/vben/preferences";
// import "./components/code-editor/import-works"; // import "./components/code-editor/import-works";
// @ts-ignore // @ts-ignore
async function bootstrap() { async function bootstrap() {
const app = createApp(App); const app = createApp(App);
// app.use(Antd); // app.use(Antd);
app.use(Antd); app.use(Antd);
await setupVben(app, { loadLocaleMessages, router }); await setupVben(app, { loadLocaleMessages, router });
app.use(router); app.use(router);
// app.use(i18n); // app.use(i18n);
// app.use(store); // app.use(store);
app.use(components); app.use(components);
app.use(plugin, { i18n }); app.use(plugin, { i18n });
const envMode = util.env.MODE; const envMode = util.env.MODE;
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${envMode}`; const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${envMode}`;
+26 -26
View File
@@ -177,10 +177,10 @@ const mockUtil: any = {
records: records, records: records,
total: data.length, total: data.length,
limit, limit,
offset offset,
} },
}; };
} },
}, },
{ {
path: "/mock/" + name + "/get", path: "/mock/" + name + "/get",
@@ -192,9 +192,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: current data: current,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/byIds", path: "/mock/" + name + "/byIds",
@@ -205,9 +205,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: res data: res,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/add", path: "/mock/" + name + "/add",
@@ -218,9 +218,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: cloneDeep(req.body) data: cloneDeep(req.body),
}; };
} },
}, },
{ {
path: "/mock/" + name + "/update", path: "/mock/" + name + "/update",
@@ -241,9 +241,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: null data: null,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/delete", path: "/mock/" + name + "/delete",
@@ -253,9 +253,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: null data: null,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/batchDelete", path: "/mock/" + name + "/batchDelete",
@@ -271,9 +271,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: null data: null,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/delete", path: "/mock/" + name + "/delete",
@@ -283,9 +283,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: null data: null,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/all", path: "/mock/" + name + "/all",
@@ -294,9 +294,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: list data: list,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/cellUpdate", path: "/mock/" + name + "/cellUpdate",
@@ -317,7 +317,7 @@ const mockUtil: any = {
} else { } else {
item = { item = {
id: ++options.idGenerator, id: ++options.idGenerator,
[req.body.key]: req.body.value [req.body.key]: req.body.value,
}; };
list.unshift(item); list.unshift(item);
} }
@@ -325,9 +325,9 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: item data: item,
}; };
} },
}, },
{ {
path: "/mock/" + name + "/columnUpdate", path: "/mock/" + name + "/columnUpdate",
@@ -350,12 +350,12 @@ const mockUtil: any = {
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: null data: null,
}; };
} },
} },
]; ];
} },
}; };
export default mockUtil; export default mockUtil;
@@ -9,21 +9,21 @@ export default [
children: [ children: [
{ {
value: "yizhi", value: "yizhi",
label: "一致" label: "一致",
}, },
{ {
value: "fankui", value: "fankui",
label: "反馈" label: "反馈",
}, },
{ {
value: "xiaolv", value: "xiaolv",
label: "效率" label: "效率",
}, },
{ {
value: "kekong", value: "kekong",
label: "可控" label: "可控",
} },
] ],
}, },
{ {
value: "daohang", value: "daohang",
@@ -31,15 +31,15 @@ export default [
children: [ children: [
{ {
value: "cexiangdaohang", value: "cexiangdaohang",
label: "侧向导航" label: "侧向导航",
}, },
{ {
value: "dingbudaohang", value: "dingbudaohang",
label: "顶部导航" label: "顶部导航",
} },
] ],
} },
] ],
}, },
{ {
value: "zujian", value: "zujian",
@@ -51,25 +51,25 @@ export default [
children: [ children: [
{ {
value: "layout", value: "layout",
label: "Layout 布局" label: "Layout 布局",
}, },
{ {
value: "color", value: "color",
label: "Color 色彩" label: "Color 色彩",
}, },
{ {
value: "typography", value: "typography",
label: "Typography 字体" label: "Typography 字体",
}, },
{ {
value: "icon", value: "icon",
label: "Icon 图标" label: "Icon 图标",
}, },
{ {
value: "button", value: "button",
label: "Button 按钮" label: "Button 按钮",
} },
] ],
}, },
{ {
value: "form", value: "form",
@@ -77,61 +77,61 @@ export default [
children: [ children: [
{ {
value: "radio", value: "radio",
label: "Radio 单选框" label: "Radio 单选框",
}, },
{ {
value: "checkbox", value: "checkbox",
label: "Checkbox 多选框" label: "Checkbox 多选框",
}, },
{ {
value: "input", value: "input",
label: "Input 输入框" label: "Input 输入框",
}, },
{ {
value: "input-number", value: "input-number",
label: "InputNumber 计数器" label: "InputNumber 计数器",
}, },
{ {
value: "select", value: "select",
label: "Select 选择器" label: "Select 选择器",
}, },
{ {
value: "cascader", value: "cascader",
label: "Cascader 级联选择器" label: "Cascader 级联选择器",
}, },
{ {
value: "switch", value: "switch",
label: "Switch 开关" label: "Switch 开关",
}, },
{ {
value: "slider", value: "slider",
label: "Slider 滑块" label: "Slider 滑块",
}, },
{ {
value: "time-picker", value: "time-picker",
label: "TimePicker 时间选择器" label: "TimePicker 时间选择器",
}, },
{ {
value: "date-picker", value: "date-picker",
label: "DatePicker 日期选择器" label: "DatePicker 日期选择器",
}, },
{ {
value: "datetime-picker", value: "datetime-picker",
label: "DateTimePicker 日期时间选择器" label: "DateTimePicker 日期时间选择器",
}, },
{ {
value: "upload", value: "upload",
label: "Upload 上传" label: "Upload 上传",
}, },
{ {
value: "rate", value: "rate",
label: "Rate 评分" label: "Rate 评分",
}, },
{ {
value: "form1", value: "form1",
label: "Form 表单" label: "Form 表单",
} },
] ],
}, },
{ {
value: "data", value: "data",
@@ -139,29 +139,29 @@ export default [
children: [ children: [
{ {
value: "table", value: "table",
label: "Table 表格" label: "Table 表格",
}, },
{ {
value: "tag", value: "tag",
label: "Tag 标签" label: "Tag 标签",
}, },
{ {
value: "progress", value: "progress",
label: "Progress 进度条" label: "Progress 进度条",
}, },
{ {
value: "tree", value: "tree",
label: "Tree 树形控件" label: "Tree 树形控件",
}, },
{ {
value: "pagination", value: "pagination",
label: "Pagination 分页" label: "Pagination 分页",
}, },
{ {
value: "badge", value: "badge",
label: "Badge 标记" label: "Badge 标记",
} },
] ],
}, },
{ {
value: "notice", value: "notice",
@@ -169,25 +169,25 @@ export default [
children: [ children: [
{ {
value: "alert", value: "alert",
label: "Alert 警告" label: "Alert 警告",
}, },
{ {
value: "loading", value: "loading",
label: "Loading 加载" label: "Loading 加载",
}, },
{ {
value: "message", value: "message",
label: "Message 消息提示" label: "Message 消息提示",
}, },
{ {
value: "message-box", value: "message-box",
label: "MessageBox 弹框" label: "MessageBox 弹框",
}, },
{ {
value: "notification", value: "notification",
label: "Notification 通知" label: "Notification 通知",
} },
] ],
}, },
{ {
value: "navigation", value: "navigation",
@@ -195,25 +195,25 @@ export default [
children: [ children: [
{ {
value: "menu", value: "menu",
label: "NavMenu 导航菜单" label: "NavMenu 导航菜单",
}, },
{ {
value: "tabs", value: "tabs",
label: "Tabs 标签页" label: "Tabs 标签页",
}, },
{ {
value: "breadcrumb", value: "breadcrumb",
label: "Breadcrumb 面包屑" label: "Breadcrumb 面包屑",
}, },
{ {
value: "dropdown", value: "dropdown",
label: "Dropdown 下拉菜单" label: "Dropdown 下拉菜单",
}, },
{ {
value: "steps", value: "steps",
label: "Steps 步骤条" label: "Steps 步骤条",
} },
] ],
}, },
{ {
value: "others", value: "others",
@@ -221,31 +221,31 @@ export default [
children: [ children: [
{ {
value: "dialog", value: "dialog",
label: "Dialog 对话框" label: "Dialog 对话框",
}, },
{ {
value: "tooltip", value: "tooltip",
label: "Tooltip 文字提示" label: "Tooltip 文字提示",
}, },
{ {
value: "popover", value: "popover",
label: "Popover 弹出框" label: "Popover 弹出框",
}, },
{ {
value: "card", value: "card",
label: "Card 卡片" label: "Card 卡片",
}, },
{ {
value: "carousel", value: "carousel",
label: "Carousel 走马灯" label: "Carousel 走马灯",
}, },
{ {
value: "collapse", value: "collapse",
label: "Collapse 折叠面板" label: "Collapse 折叠面板",
} },
] ],
} },
] ],
}, },
{ {
value: "ziyuan", value: "ziyuan",
@@ -253,16 +253,16 @@ export default [
children: [ children: [
{ {
value: "axure", value: "axure",
label: "Axure Components" label: "Axure Components",
}, },
{ {
value: "sketch", value: "sketch",
label: "Sketch Templates" label: "Sketch Templates",
}, },
{ {
value: "jiaohu", value: "jiaohu",
label: "组件交互文档" label: "组件交互文档",
} },
] ],
} },
]; ];
@@ -7,25 +7,25 @@ import { cloneDeep } from "lodash-es";
const openStatus = [ const openStatus = [
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" }, { value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
{ value: "2", label: "停止", color: "cyan" }, { value: "2", label: "停止", color: "cyan" },
{ value: "0", label: "关闭", color: "red", icon: "ion:radio-button-off" } { value: "0", label: "关闭", color: "red", icon: "ion:radio-button-off" },
]; ];
const moreOpenStatus = [ const moreOpenStatus = [
{ value: "1", label: "打开(open)", color: "success" }, { value: "1", label: "打开(open)", color: "success" },
{ value: "2", label: "停止(stop)", color: "cyan" }, { value: "2", label: "停止(stop)", color: "cyan" },
{ value: "0", label: "关闭(close)", color: "red" } { value: "0", label: "关闭(close)", color: "red" },
]; ];
const textStatus = [ const textStatus = [
{ id: "1", text: "打开", color: "success" }, { id: "1", text: "打开", color: "success" },
{ id: "2", text: "停止", color: "cyan" }, { id: "2", text: "停止", color: "cyan" },
{ id: "0", text: "关闭", color: "red" } { id: "0", text: "关闭", color: "red" },
]; ];
let manyStatus = [ let manyStatus = [
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" }, { value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
{ value: "2", label: "停止", color: "cyan" }, { value: "2", label: "停止", color: "cyan" },
{ value: "0", label: "关闭", color: "red", icon: "ion:radio-button-off" } { value: "0", label: "关闭", color: "red", icon: "ion:radio-button-off" },
]; ];
let tempManyStatus: any[] = []; let tempManyStatus: any[] = [];
for (let i = 0; i < 100; i++) { for (let i = 0; i < 100; i++) {
@@ -54,9 +54,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: openStatus data: openStatus,
}; };
} },
}, },
{ {
path: "/mock/dicts/_OpenStatusEnum2", path: "/mock/dicts/_OpenStatusEnum2",
@@ -65,9 +65,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: textStatus data: textStatus,
}; };
} },
}, },
{ {
path: "/mock/dicts/ManyOpenStatusEnum", path: "/mock/dicts/ManyOpenStatusEnum",
@@ -76,9 +76,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: manyStatus data: manyStatus,
}; };
} },
}, },
{ {
path: "/mock/dicts/moreOpenStatusEnum", path: "/mock/dicts/moreOpenStatusEnum",
@@ -87,9 +87,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: moreOpenStatus data: moreOpenStatus,
}; };
} },
}, },
{ {
path: "/mock/dicts/cascaderData", path: "/mock/dicts/cascaderData",
@@ -98,9 +98,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: cascaderData data: cascaderData,
}; };
} },
}, },
{ {
path: "/mock/dicts/pca", path: "/mock/dicts/pca",
@@ -110,9 +110,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: data data: data,
}; };
} },
}, },
{ {
path: "/mock/dicts/littlePca", path: "/mock/dicts/littlePca",
@@ -121,9 +121,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: pcaDataLittle data: pcaDataLittle,
}; };
} },
}, },
{ {
path: "/mock/tree/GetTreeChildrenByParentId", path: "/mock/tree/GetTreeChildrenByParentId",
@@ -133,9 +133,9 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: list data: list,
}; };
} },
}, },
{ {
path: "/mock/tree/GetNodesByValues", path: "/mock/tree/GetNodesByValues",
@@ -145,8 +145,8 @@ export default [
return { return {
code: 0, code: 0,
msg: "success", msg: "success",
data: list data: list,
}; };
} },
} },
]; ];
@@ -9,13 +9,13 @@ export default [
children: [ children: [
{ {
code: "3", code: "3",
name: "海淀" name: "海淀",
}, },
{ {
code: "4", code: "4",
name: "朝阳" name: "朝阳",
} },
] ],
}, },
{ {
code: "5", code: "5",
@@ -23,15 +23,15 @@ export default [
children: [ children: [
{ {
code: "6", code: "6",
name: "海淀郊区" name: "海淀郊区",
}, },
{ {
code: "7", code: "7",
name: "朝阳郊区" name: "朝阳郊区",
} },
] ],
} },
] ],
}, },
{ {
code: "11", code: "11",
@@ -43,13 +43,13 @@ export default [
children: [ children: [
{ {
code: "13", code: "13",
name: "南山" name: "南山",
}, },
{ {
code: "14", code: "14",
name: "福田" name: "福田",
} },
] ],
}, },
{ {
code: "15", code: "15",
@@ -57,14 +57,14 @@ export default [
children: [ children: [
{ {
code: "16", code: "16",
name: "南山郊区" name: "南山郊区",
}, },
{ {
code: "17", code: "17",
name: "福田郊区" name: "福田郊区",
} },
] ],
} },
] ],
} },
]; ];
@@ -17,7 +17,7 @@ export const TreeNodesLazyLoader = {
if (!(values instanceof Array)) { if (!(values instanceof Array)) {
values = [values]; values = [values];
} }
return getPcasData().then((data) => { return getPcasData().then(data => {
const nodes = []; const nodes = [];
for (const value of values) { for (const value of values) {
const found = this.getNode(data, value); const found = this.getNode(data, value);
@@ -44,7 +44,7 @@ export const TreeNodesLazyLoader = {
} }
}, },
getChildren(parent: any) { getChildren(parent: any) {
return getPcasData().then((data) => { return getPcasData().then(data => {
const list = this.getChildrenByParent(parent, data); const list = this.getChildrenByParent(parent, data);
if (list == null) { if (list == null) {
return []; return [];
@@ -85,5 +85,5 @@ export const TreeNodesLazyLoader = {
} }
console.log("found children:", newList); console.log("found children:", newList);
return newList; return newList;
} },
}; };
+1 -1
View File
@@ -38,7 +38,7 @@ list.forEach((apiFile: any) => {
const req = { const req = {
body: data, body: data,
params: params params: params,
}; };
const ret = await item.handle(req); const ret = await item.handle(req);
utils.logger.debug("response:", ret); utils.logger.debug("response:", ret);
+1 -1
View File
@@ -10,5 +10,5 @@ function install(app: App, options: any = {}) {
} }
export default { export default {
install install,
}; };
@@ -2,7 +2,7 @@ import { request } from "/src/api/service";
export async function getPermissions() { export async function getPermissions() {
const ret = await request({ const ret = await request({
url: "/sys/authority/user/permissions", url: "/sys/authority/user/permissions",
method: "post" method: "post",
}); });
// 如果使用你自己的后端,需要在此处将返回结果改造为本模块需要的结构 // 如果使用你自己的后端,需要在此处将返回结果改造为本模块需要的结构
// 结构详情,请参考示例中打印的日志 ”获取权限数据成功:{...}“ (实际上就是“资源管理”页面中列出来的数据) // 结构详情,请参考示例中打印的日志 ”获取权限数据成功:{...}“ (实际上就是“资源管理”页面中列出来的数据)
@@ -7,5 +7,5 @@ const install = function (app: any) {
export default { export default {
install, install,
...permission ...permission,
}; };
@@ -7,5 +7,5 @@ export default {
if (!hasPermission) { if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el); el.parentNode && el.parentNode.removeChild(el);
} }
} },
}; };
@@ -6,7 +6,7 @@ export * from "./errors";
export function usePermission() { export function usePermission() {
return { return {
...util ...util,
}; };
} }
@@ -19,5 +19,5 @@ export default {
// 通过路由守卫,在登录成功后拦截路由,从后台加载权限数据 // 通过路由守卫,在登录成功后拦截路由,从后台加载权限数据
// 然后将权限数据转化为菜单和路由,添加到系统中 // 然后将权限数据转化为菜单和路由,添加到系统中
registerRouterHook(); registerRouterHook();
} },
}; };
@@ -56,7 +56,7 @@ export const usePermissionStore = defineStore({
id: "app.permission", id: "app.permission",
state: (): PermissionState => ({ state: (): PermissionState => ({
permissions: [], permissions: [],
inited: false inited: false,
}), }),
getters: { getters: {
// @ts-ignore // @ts-ignore
@@ -68,7 +68,7 @@ export const usePermissionStore = defineStore({
isInited() { isInited() {
// @ts-ignore // @ts-ignore
return this.inited; return this.inited;
} },
}, },
actions: { actions: {
init({ permissions }: any) { init({ permissions }: any) {
@@ -101,6 +101,6 @@ export const usePermissionStore = defineStore({
} }
} }
this.resolve(permissionTree); this.resolve(permissionTree);
} },
} },
}); });
@@ -47,16 +47,16 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
{ {
actionbar: { actionbar: {
buttons: { buttons: {
add: { show: hasActionPermission("add") } add: { show: hasActionPermission("add") },
} },
}, },
rowHandle: { rowHandle: {
buttons: { buttons: {
edit: { show: hasActionPermission("edit") }, edit: { show: hasActionPermission("edit") },
remove: { show: hasActionPermission("remove") }, remove: { show: hasActionPermission("remove") },
view: { show: hasActionPermission("view") } view: { show: hasActionPermission("view") },
} },
} },
}, },
extra extra
); );
@@ -26,7 +26,7 @@ const util = {
message.error("对不起,您没有权限执行此操作"); message.error("对不起,您没有权限执行此操作");
throw new NoPermissionError(); throw new NoPermissionError();
} }
} },
}; };
export default util; export default util;
+1 -1
View File
@@ -6,7 +6,7 @@ import { createRouterGuard } from "/@/router/guard";
const router = createRouter({ const router = createRouter({
history: createWebHashHistory(), history: createWebHashHistory(),
routes routes,
}); });
/** /**
+24 -29
View File
@@ -1,74 +1,69 @@
.ant-layout .ant-layout-sider{ .ant-layout .ant-layout-sider {
background-color: #ebf1f6;
}
.ant-layout .ant-layout-header{
background-color: #ebf1f6; background-color: #ebf1f6;
} }
.fs-multiple-page-control-group .fs-multiple-page-control-content{ .ant-layout .ant-layout-header {
background-color: #ebf1f6;
}
.fs-multiple-page-control-group .fs-multiple-page-control-content {
overflow-y: hidden; overflow-y: hidden;
} }
.fs-multiple-page-control-group .fs-multiple-page-control-btn .ant-btn{ .fs-multiple-page-control-group .fs-multiple-page-control-btn .ant-btn {
border-bottom-left-radius:0; border-bottom-left-radius: 0;
border-bottom-right-radius:0; border-bottom-right-radius: 0;
} }
.ant-menu-horizontal{ .ant-menu-horizontal {
border-bottom: 0; border-bottom: 0;
} }
.fs-framework .header-menu{ .fs-framework .header-menu {
overflow-y: hidden; overflow-y: hidden;
} }
.ant-btn.ant-btn-icon-only{ .ant-btn.ant-btn-icon-only {
padding-inline:revert; padding-inline: revert;
} }
.fs-form-wrapper .fs-form-header { .fs-form-wrapper .fs-form-header {
padding-right: 30px !important; padding-right: 30px !important;
} }
.fs-values-format .fs-tag {
.fs-values-format .fs-tag{
display: inline-flex; display: inline-flex;
.fs-icon{ .fs-icon {
margin-right: 3px; margin-right: 3px;
} }
} }
.fs-search .ant-row{ .fs-search .ant-row {
} }
//适配手机端 //适配手机端
.ant-tour{ .ant-tour {
max-width: 90vw max-width: 90vw;
} }
.fs-page{ .fs-page {
.fs-page-header{ .fs-page-header {
background-color: hsl(var(--card)); background-color: hsl(var(--card));
} }
.fs-crud-table{ .fs-crud-table {
background-color: hsl(var(--card)); background-color: hsl(var(--card));
} }
} }
footer{ footer {
background-color: hsl(var(--card)) !important; background-color: hsl(var(--card)) !important;
} }
.ant-select-multiple .ant-select-selection-item-remove {
.ant-select-multiple .ant-select-selection-item-remove{
display: flex; display: flex;
align-items: center; align-items: center;
} }
.ant-progress.ant-progress-show-info .ant-progress-outer { .ant-progress.ant-progress-show-info .ant-progress-outer {
margin-inline-end: calc(-3em - 8px); margin-inline-end: calc(-3em - 8px);
padding-inline-end: calc(3em + 8px); padding-inline-end: calc(3em + 8px);
} }
+21 -25
View File
@@ -2,18 +2,17 @@
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
font-size:16px; font-size: 16px;
} }
.fs-icon { .fs-icon {
font-size:16px; font-size: 16px;
} }
.ant-btn { .ant-btn {
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
.fs-iconify{ .fs-iconify {
margin-right: 5px; margin-right: 5px;
} }
} }
@@ -37,7 +36,6 @@
align-items: center; align-items: center;
} }
.ant-drawer-content { .ant-drawer-content {
&.fullscreen { &.fullscreen {
position: fixed; position: fixed;
@@ -51,10 +49,9 @@
} }
} }
.icon-button { .icon-button {
cursor: pointer; cursor: pointer;
font-size: 22px font-size: 22px;
} }
.ant-drawer { .ant-drawer {
@@ -76,7 +73,7 @@
margin: 20px; margin: 20px;
} }
.fs-crud-table{ .fs-crud-table {
.ant-table-body { .ant-table-body {
height: 60vh; height: 60vh;
table { table {
@@ -84,40 +81,39 @@
} }
} }
body a {
body a{ color: #1890ff;
color: #1890ff; &:hover {
&:hover{
color: #40a9ff; color: #40a9ff;
} }
} }
span.fs-icon-svg{ span.fs-icon-svg {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
} }
.ant-btn .fs-icon:last-child{ .ant-btn .fs-icon:last-child {
margin-right:0px margin-right: 0px;
} }
.fs-iconify fs-icon{ .fs-iconify fs-icon {
svg{ svg {
vertical-align:0 !important; vertical-align: 0 !important;
} }
} }
.fs-button{ .fs-button {
span{ span {
&:first-child{ &:first-child {
margin-right: 5px; margin-right: 5px;
} }
&:last-child{ &:last-child {
margin-left: 5px; margin-left: 5px;
} }
} }
.fs-icon,.fs-button-icon{ .fs-icon,
.fs-button-icon {
margin: 0 !important; margin: 0 !important;
} }
} }
+62 -66
View File
@@ -1,12 +1,13 @@
@import './theme/index.less'; @import "./theme/index.less";
@import './theme/default.less'; @import "./theme/default.less";
@import './scroll.less'; @import "./scroll.less";
@import './transition.less'; @import "./transition.less";
@import './fix-windicss.less'; @import "./fix-windicss.less";
@import './antdv4.less'; @import "./antdv4.less";
@import './certd.less'; @import "./certd.less";
html, body { html,
body {
margin: 0; margin: 0;
padding: 0; padding: 0;
height: 100%; height: 100%;
@@ -15,10 +16,15 @@ html, body {
} }
div#app { div#app {
height: 100% height: 100%;
} }
h1, h2, h3, h4, h5, h6 { h1,
h2,
h3,
h4,
h5,
h6 {
margin-bottom: 0; margin-bottom: 0;
margin-top: 0; margin-top: 0;
} }
@@ -30,17 +36,14 @@ h1, h2, h3, h4, h5, h6 {
margin-right: 5px; margin-right: 5px;
} }
.ant-btn-link { .ant-btn-link {
height: 24px; height: 24px;
} }
.ant-input-affix-wrapper { .ant-input-affix-wrapper {
padding: 4px 11px; padding: 4px 11px;
} }
.anticon { .anticon {
vertical-align: 0 !important; vertical-align: 0 !important;
} }
@@ -54,17 +57,17 @@ h1, h2, h3, h4, h5, h6 {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.flex-vc{ .flex-vc {
align-items: center; align-items: center;
} }
.flex-vb{ .flex-vb {
align-items: baseline; align-items: baseline;
} }
.flex-o { .flex-o {
display: flex !important; display: flex !important;
align-items: center; align-items: center;
} }
.flex-baseline{ .flex-baseline {
display: flex !important; display: flex !important;
align-items: baseline; align-items: baseline;
} }
@@ -94,77 +97,76 @@ h1, h2, h3, h4, h5, h6 {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.align-left{ .align-left {
text-align: left; text-align: left;
} }
.align-right{ .align-right {
text-align: right; text-align: right;
} }
.scroll-y { .scroll-y {
overflow-y: auto; overflow-y: auto;
} }
.m-0{ .m-0 {
margin:0 !important; margin: 0 !important;
} }
.m-2{ .m-2 {
margin:2px !important; margin: 2px !important;
} }
.m-3{ .m-3 {
margin:3px !important; margin: 3px !important;
} }
.m-5{ .m-5 {
margin:5px !important; margin: 5px !important;
} }
.m-10 { .m-10 {
margin: 10px !important;; margin: 10px !important;
} }
.m-20{ .m-20 {
margin:20px !important; margin: 20px !important;
} }
.mb-2 { .mb-2 {
margin-bottom: 2px !important;; margin-bottom: 2px !important;
} }
.mb-5 { .mb-5 {
margin-bottom: 5px !important;; margin-bottom: 5px !important;
} }
.ml-5 { .ml-5 {
margin-left: 5px !important;; margin-left: 5px !important;
} }
.ml-10 { .ml-10 {
margin-left: 10px !important;; margin-left: 10px !important;
} }
.ml-20 { .ml-20 {
margin-left: 20px !important;; margin-left: 20px !important;
} }
.ml-15 { .ml-15 {
margin-left: 15px !important;; margin-left: 15px !important;
} }
.mr-5 { .mr-5 {
margin-right: 5px !important;; margin-right: 5px !important;
} }
.mr-10 { .mr-10 {
margin-right: 10px !important;; margin-right: 10px !important;
} }
.mr-20 { .mr-20 {
margin-right: 20px !important;; margin-right: 20px !important;
} }
.mr-15 { .mr-15 {
margin-right: 15px !important;; margin-right: 15px !important;
} }
.mt-5 { .mt-5 {
margin-top: 5px !important;; margin-top: 5px !important;
} }
.mt-10 { .mt-10 {
@@ -172,20 +174,19 @@ h1, h2, h3, h4, h5, h6 {
} }
.mb-10 { .mb-10 {
margin-bottom: 10px !important;; margin-bottom: 10px !important;
} }
.p-5 { .p-5 {
padding: 5px !important;; padding: 5px !important;
} }
.p-10 { .p-10 {
padding: 10px !important;; padding: 10px !important;
} }
.p-20 { .p-20 {
padding: 20px !important;; padding: 20px !important;
} }
.ellipsis { .ellipsis {
white-space: nowrap; white-space: nowrap;
@@ -212,7 +213,7 @@ h1, h2, h3, h4, h5, h6 {
border-bottom: 1px solid #dedede; border-bottom: 1px solid #dedede;
} }
.color-plus{ .color-plus {
color: #c5913f; color: #c5913f;
} }
.color-blue { .color-blue {
@@ -230,8 +231,8 @@ h1, h2, h3, h4, h5, h6 {
color: gray; color: gray;
} }
.iconify{ .iconify {
//font-size: 16px; //font-size: 16px;
} }
.icon-box { .icon-box {
@@ -250,7 +251,6 @@ h1, h2, h3, h4, h5, h6 {
color: #c5913f !important; color: #c5913f !important;
} }
.deleted { .deleted {
color: #c7c7c7; color: #c7c7c7;
//删除线 //删除线
@@ -268,18 +268,17 @@ h1, h2, h3, h4, h5, h6 {
.helper { .helper {
color: #aeaeae; color: #aeaeae;
font-size: 12px; font-size: 12px;
margin-top:3px; margin-top: 3px;
margin-bottom:3px; margin-bottom: 3px;
&.error{ &.error {
color: #ff4d4f; color: #ff4d4f;
} }
} }
.fs-copyable { .fs-copyable {
display: inline-flex; display: inline-flex;
.text { .text {
flex: 1 flex: 1;
} }
.copy-button { .copy-button {
@@ -288,23 +287,20 @@ h1, h2, h3, h4, h5, h6 {
} }
} }
.fs-16 {
.fs-16{ font-size: 16px;
font-size: 16px;
} }
.w-50\%{ .w-50\% {
width: 50%; width: 50%;
} }
.ant-drawer-content-wrapper { .ant-drawer-content-wrapper {
max-width: 90vw; max-width: 90vw;
} }
.block-title {
.block-title{
font-size: 14px; font-size: 14px;
padding:10px; padding: 10px;
color : #6e6e6e; color: #6e6e6e;
} }
@@ -1,3 +1,3 @@
img.ant-image-preview-img{ img.ant-image-preview-img {
display: initial; display: initial;
} }
@@ -5,14 +5,14 @@
::-webkit-scrollbar-track { ::-webkit-scrollbar-track {
width: 8px; width: 8px;
background: rgba(#101F1C, 0.1); background: rgba(#101f1c, 0.1);
-webkit-border-radius: 2em; -webkit-border-radius: 2em;
-moz-border-radius: 2em; -moz-border-radius: 2em;
border-radius: 2em; border-radius: 2em;
} }
::-webkit-scrollbar-thumb { ::-webkit-scrollbar-thumb {
// background-color: rgba(#101F1C, 0.5); // background-color: rgba(#101F1C, 0.5);
background-clip: padding-box; background-clip: padding-box;
min-height: 28px; min-height: 28px;
-webkit-border-radius: 2em; -webkit-border-radius: 2em;
@@ -23,6 +23,5 @@
} }
::-webkit-scrollbar-thumb:hover { ::-webkit-scrollbar-thumb:hover {
//background-color: rgba(#101F1C, 1); //background-color: rgba(#101F1C, 1);
} }
@@ -1,27 +1,27 @@
.ant-layout{ .ant-layout {
background-color: @colorPrimaryBg; background-color: @colorPrimaryBg;
} }
.ant-layout-header { .ant-layout-header {
background-color: @colorPrimaryBg background-color: @colorPrimaryBg;
} }
.ant-layout-sider { .ant-layout-sider {
background-color:@colorPrimaryBg
}
.ant-menu{
background-color: @colorPrimaryBg; background-color: @colorPrimaryBg;
&.ant-menu-submenu-popup{ }
.ant-menu {
background-color: @colorPrimaryBg;
&.ant-menu-submenu-popup {
background-color: transparent; background-color: transparent;
} }
} }
.aside-menu{ .aside-menu {
.ant-menu-submenu > .ant-menu{ .ant-menu-submenu > .ant-menu {
background-color:@colorPrimaryBg background-color: @colorPrimaryBg;
} }
.ant-menu-item-active{ .ant-menu-item-active {
background-color: @bg-menu-item-color; background-color: @bg-menu-item-color;
} }
.ant-menu-item-selected{ .ant-menu-item-selected {
background-color: @bg-menu-item-color !important; background-color: @bg-menu-item-color !important;
} }
} }
@@ -1,3 +1,3 @@
@bg-menu-item-color:hsla(0,0%,100%,.5); @bg-menu-item-color:hsla (0,0%,100%,.5);
@colorPrimaryBg:#ebf1f6; @colorPrimaryBg: #ebf1f6;
@primary-color: #1890ff; @primary-color: #1890ff;
@@ -10,7 +10,7 @@
// 过渡动画 横向渐变 // 过渡动画 横向渐变
.fade-transverse-leave-active, .fade-transverse-leave-active,
.fade-transverse-enter-active { .fade-transverse-enter-active {
transition: all .5s; transition: all 0.5s;
} }
.fade-transverse-enter-from { .fade-transverse-enter-from {
opacity: 0; opacity: 0;
@@ -24,7 +24,7 @@
// 过渡动画 缩放渐变 // 过渡动画 缩放渐变
.fade-scale-leave-active, .fade-scale-leave-active,
.fade-scale-enter-active { .fade-scale-enter-active {
transition: all .3s; transition: all 0.3s;
} }
.fade-scale-enter { .fade-scale-enter {
opacity: 0; opacity: 0;
@@ -13,7 +13,7 @@ export function useReference(formItem: any) {
const ctx = { const ctx = {
compute, compute,
asyncCompute, asyncCompute,
computed computed,
}; };
const script = formItem.mergeScript; const script = formItem.mergeScript;
const func = new Function("ctx", script); const func = new Function("ctx", script);
@@ -30,7 +30,7 @@ export function useReference(formItem: any) {
formItem.helper = { formItem.helper = {
render: () => { render: () => {
return <div innerHTML={helper}></div>; return <div innerHTML={helper}></div>;
} },
}; };
} }
} }
@@ -1,4 +1,4 @@
import {forEach} from "lodash-es"; import { forEach } from "lodash-es";
export function getEnvValue(key: string) { export function getEnvValue(key: string) {
// @ts-ignore // @ts-ignore
return import.meta.env["VITE_APP_" + key]; return import.meta.env["VITE_APP_" + key];
@@ -21,5 +21,5 @@ async function open(path: any) {
} }
export const routerUtils = { export const routerUtils = {
open open,
}; };
@@ -1,5 +1,5 @@
export function eachTree(tree: any[], callback: (item: any) => void) { export function eachTree(tree: any[], callback: (item: any) => void) {
tree.forEach((item) => { tree.forEach(item => {
callback(item); callback(item);
if (item.children) { if (item.children) {
eachTree(item.children, callback); eachTree(item.children, callback);
@@ -19,5 +19,5 @@ export function treeMap(tree: any[], mapFunc: (item: any) => {}) {
export const treeUtils = { export const treeUtils = {
eachTree, eachTree,
treeMap treeMap,
}; };
@@ -25,12 +25,12 @@ interface Props {
} }
defineOptions({ defineOptions({
name: "AccessControl" name: "AccessControl",
}); });
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
codes: () => [], codes: () => [],
type: "role" type: "role",
}); });
const { hasAccessByCodes, hasAccessByRoles } = useAccess(); const { hasAccessByCodes, hasAccessByRoles } = useAccess();
@@ -12,7 +12,7 @@ async function generateAccessible(mode: AccessModeType, options: GenerateMenuAnd
const root = router.getRoutes().find((item: any) => item.path === "/"); const root = router.getRoutes().find((item: any) => item.path === "/");
// 动态添加到router实例内 // 动态添加到router实例内
accessibleRoutes.forEach((route) => { accessibleRoutes.forEach(route => {
if (root && !route.meta?.noBasicLayout) { if (root && !route.meta?.noBasicLayout) {
// 为了兼容之前的版本用法,如果包含子路由,则将component移除,以免出现多层BasicLayout // 为了兼容之前的版本用法,如果包含子路由,则将component移除,以免出现多层BasicLayout
// 如果你的项目已经跟进了本次修改,移除了所有自定义菜单首级的BasicLayout,可以将这段if代码删除 // 如果你的项目已经跟进了本次修改,移除了所有自定义菜单首级的BasicLayout,可以将这段if代码删除
@@ -62,7 +62,7 @@ async function generateRoutes(mode: AccessModeType, options: GenerateMenuAndRout
* 调整路由树,做以下处理: * 调整路由树,做以下处理:
* 1. 对未添加redirect的路由添加redirect * 1. 对未添加redirect的路由添加redirect
*/ */
resultRoutes = mapTree(resultRoutes, (route) => { resultRoutes = mapTree(resultRoutes, route => {
// 如果有redirect或者没有子路由,则直接返回 // 如果有redirect或者没有子路由,则直接返回
if (route.redirect || !route.children || route.children.length === 0) { if (route.redirect || !route.children || route.children.length === 0) {
return route; return route;
@@ -4,23 +4,17 @@
* @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME" * @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME"
* @Example v-access:code="[ROLE_CODE]" or v-access:code="ROLE_CODE" * @Example v-access:code="[ROLE_CODE]" or v-access:code="ROLE_CODE"
*/ */
import type { App, Directive, DirectiveBinding } from 'vue'; import type { App, Directive, DirectiveBinding } from "vue";
import { useAccess } from './use-access'; import { useAccess } from "./use-access";
function isAccessible( function isAccessible(el: Element, binding: DirectiveBinding<string | string[]>) {
el: Element,
binding: DirectiveBinding<string | string[]>,
) {
const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess(); const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess();
const value = binding.value; const value = binding.value;
if (!value) return; if (!value) return;
const authMethod = const authMethod = accessMode.value === "frontend" && binding.arg === "role" ? hasAccessByRoles : hasAccessByCodes;
accessMode.value === 'frontend' && binding.arg === 'role'
? hasAccessByRoles
: hasAccessByCodes;
const values = Array.isArray(value) ? value : [value]; const values = Array.isArray(value) ? value : [value];
@@ -38,5 +32,5 @@ const authDirective: Directive = {
}; };
export function registerAccessDirective(app: App) { export function registerAccessDirective(app: App) {
app.directive('access', authDirective); app.directive("access", authDirective);
} }
@@ -1,4 +1,4 @@
export { default as AccessControl } from './access-control.vue'; export { default as AccessControl } from "./access-control.vue";
export * from './accessible'; export * from "./accessible";
export * from './directive'; export * from "./directive";
export * from './use-access'; export * from "./use-access";
@@ -17,7 +17,7 @@ function useAccess() {
*/ */
function hasAccessByRoles(roles: string[]) { function hasAccessByRoles(roles: string[]) {
const userRoleSet = new Set(userStore.userRoles); const userRoleSet = new Set(userStore.userRoles);
const intersection = roles.filter((item) => userRoleSet.has(item)); const intersection = roles.filter(item => userRoleSet.has(item));
return intersection.length > 0; return intersection.length > 0;
} }
@@ -29,15 +29,15 @@ function useAccess() {
function hasAccessByCodes(codes: string[]) { function hasAccessByCodes(codes: string[]) {
const userCodesSet = new Set(accessStore.accessCodes); const userCodesSet = new Set(accessStore.accessCodes);
const intersection = codes.filter((item) => userCodesSet.has(item)); const intersection = codes.filter(item => userCodesSet.has(item));
return intersection.length > 0; return intersection.length > 0;
} }
async function toggleAccessMode() { async function toggleAccessMode() {
updatePreferences({ updatePreferences({
app: { app: {
accessMode: preferences.app.accessMode === "frontend" ? "backend" : "frontend" accessMode: preferences.app.accessMode === "frontend" ? "backend" : "frontend",
} },
}); });
} }
@@ -45,7 +45,7 @@ function useAccess() {
accessMode, accessMode,
hasAccessByCodes, hasAccessByCodes,
hasAccessByRoles, hasAccessByRoles,
toggleAccessMode toggleAccessMode,
}; };
} }
@@ -74,7 +74,7 @@ const props = withDefaults(defineProps<Props>(), {
afterFetch: undefined, afterFetch: undefined,
modelPropName: "modelValue", modelPropName: "modelValue",
api: undefined, api: undefined,
options: () => [] options: () => [],
}); });
const emit = defineEmits<{ const emit = defineEmits<{
@@ -96,13 +96,13 @@ const getOptions = computed(() => {
const refOptionsData = unref(refOptions); const refOptionsData = unref(refOptions);
function transformData(data: OptionsItem[]): OptionsItem[] { function transformData(data: OptionsItem[]): OptionsItem[] {
return data.map((item) => { return data.map(item => {
const value = get(item, valueField); const value = get(item, valueField);
return { return {
...objectOmit(item, [labelField, valueField, childrenField]), ...objectOmit(item, [labelField, valueField, childrenField]),
label: get(item, labelField), label: get(item, labelField),
value: numberToString ? `${value}` : value, value: numberToString ? `${value}` : value,
...(childrenField && item[childrenField] ? { children: transformData(item[childrenField]) } : {}) ...(childrenField && item[childrenField] ? { children: transformData(item[childrenField]) } : {}),
}; };
}); });
} }
@@ -122,9 +122,9 @@ const bindProps = computed(() => {
...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]), ...objectOmit(attrs, [`onUpdate:${props.modelPropName}`]),
...(props.visibleEvent ...(props.visibleEvent
? { ? {
[props.visibleEvent]: handleFetchForVisible [props.visibleEvent]: handleFetchForVisible,
} }
: {}) : {}),
}; };
}); });
@@ -1 +1 @@
export { default as ApiComponent } from './api-component.vue'; export { default as ApiComponent } from "./api-component.vue";
@@ -1,6 +1,6 @@
import type { CaptchaPoint } from '../types'; import type { CaptchaPoint } from "../types";
import { reactive } from 'vue'; import { reactive } from "vue";
export function useCaptchaPoints() { export function useCaptchaPoints() {
const points = reactive<CaptchaPoint[]>([]); const points = reactive<CaptchaPoint[]>([]);
@@ -1,6 +1,6 @@
export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue'; export { default as PointSelectionCaptcha } from "./point-selection-captcha/index.vue";
export { default as PointSelectionCaptchaCard } from './point-selection-captcha/index.vue'; export { default as PointSelectionCaptchaCard } from "./point-selection-captcha/index.vue";
export { default as SliderCaptcha } from './slider-captcha/index.vue'; export { default as SliderCaptcha } from "./slider-captcha/index.vue";
export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue'; export { default as SliderRotateCaptcha } from "./slider-rotate-captcha/index.vue";
export type * from './types'; export type * from "./types";
@@ -1,23 +1,23 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CaptchaPoint, PointSelectionCaptchaProps } from '../types'; import type { CaptchaPoint, PointSelectionCaptchaProps } from "../types";
import { RotateCw } from '/@/vben/icons'; import { RotateCw } from "/@/vben/icons";
import { $t } from '/@/locales'; import { $t } from "/@/locales";
import { VbenButton, VbenIconButton } from '/@/vben/shadcn-ui'; import { VbenButton, VbenIconButton } from "/@/vben/shadcn-ui";
import { useCaptchaPoints } from '../hooks/useCaptchaPoints'; import { useCaptchaPoints } from "../hooks/useCaptchaPoints";
import CaptchaCard from './point-selection-captcha-card.vue'; import CaptchaCard from "./point-selection-captcha-card.vue";
const props = withDefaults(defineProps<PointSelectionCaptchaProps>(), { const props = withDefaults(defineProps<PointSelectionCaptchaProps>(), {
height: '220px', height: "220px",
hintImage: '', hintImage: "",
hintText: '', hintText: "",
paddingX: '12px', paddingX: "12px",
paddingY: '16px', paddingY: "16px",
showConfirm: false, showConfirm: false,
title: '', title: "",
width: '300px', width: "300px",
}); });
const emit = defineEmits<{ const emit = defineEmits<{
click: [CaptchaPoint]; click: [CaptchaPoint];
@@ -27,7 +27,7 @@ const emit = defineEmits<{
const { addPoint, clearPoints, points } = useCaptchaPoints(); const { addPoint, clearPoints, points } = useCaptchaPoints();
if (!props.hintImage && !props.hintText) { if (!props.hintImage && !props.hintText) {
console.warn('At least one of hint image or hint text must be provided'); console.warn("At least one of hint image or hint text must be provided");
} }
const POINT_OFFSET = 11; const POINT_OFFSET = 11;
@@ -43,15 +43,15 @@ function getElementPosition(element: HTMLElement) {
function handleClick(e: MouseEvent) { function handleClick(e: MouseEvent) {
try { try {
const dom = e.currentTarget as HTMLElement; const dom = e.currentTarget as HTMLElement;
if (!dom) throw new Error('Element not found'); if (!dom) throw new Error("Element not found");
const { x: domX, y: domY } = getElementPosition(dom); const { x: domX, y: domY } = getElementPosition(dom);
const mouseX = e.clientX + window.scrollX; const mouseX = e.clientX + window.scrollX;
const mouseY = e.clientY + window.scrollY; const mouseY = e.clientY + window.scrollY;
if (typeof mouseX !== 'number' || typeof mouseY !== 'number') { if (typeof mouseX !== "number" || typeof mouseY !== "number") {
throw new TypeError('Mouse coordinates not found'); throw new TypeError("Mouse coordinates not found");
} }
const xPos = mouseX - domX; const xPos = mouseX - domX;
@@ -61,7 +61,7 @@ function handleClick(e: MouseEvent) {
// 点击位置边界校验 // 点击位置边界校验
if (xPos < 0 || yPos < 0 || xPos > rect.width || yPos > rect.height) { if (xPos < 0 || yPos < 0 || xPos > rect.width || yPos > rect.height) {
console.warn('Click position is out of the valid range'); console.warn("Click position is out of the valid range");
return; return;
} }
@@ -77,11 +77,11 @@ function handleClick(e: MouseEvent) {
addPoint(point); addPoint(point);
emit('click', point); emit("click", point);
e.stopPropagation(); e.stopPropagation();
e.preventDefault(); e.preventDefault();
} catch (error) { } catch (error) {
console.error('Error in handleClick:', error); console.error("Error in handleClick:", error);
} }
} }
@@ -89,58 +89,40 @@ function clear() {
try { try {
clearPoints(); clearPoints();
} catch (error) { } catch (error) {
console.error('Error in clear:', error); console.error("Error in clear:", error);
} }
} }
function handleRefresh() { function handleRefresh() {
try { try {
clear(); clear();
emit('refresh'); emit("refresh");
} catch (error) { } catch (error) {
console.error('Error in handleRefresh:', error); console.error("Error in handleRefresh:", error);
} }
} }
function handleConfirm() { function handleConfirm() {
if (!props.showConfirm) return; if (!props.showConfirm) return;
try { try {
emit('confirm', points, clear); emit("confirm", points, clear);
} catch (error) { } catch (error) {
console.error('Error in handleConfirm:', error); console.error("Error in handleConfirm:", error);
} }
} }
</script> </script>
<template> <template>
<CaptchaCard <CaptchaCard :captcha-image="captchaImage" :height="height" :padding-x="paddingX" :padding-y="paddingY" :title="title" :width="width" @click="handleClick">
:captcha-image="captchaImage"
:height="height"
:padding-x="paddingX"
:padding-y="paddingY"
:title="title"
:width="width"
@click="handleClick"
>
<template #title> <template #title>
<slot name="title">{{ $t('ui.captcha.title') }}</slot> <slot name="title">{{ $t("ui.captcha.title") }}</slot>
</template> </template>
<template #extra> <template #extra>
<VbenIconButton <VbenIconButton :aria-label="$t('ui.captcha.refreshAriaLabel')" class="ml-1" @click="handleRefresh">
:aria-label="$t('ui.captcha.refreshAriaLabel')"
class="ml-1"
@click="handleRefresh"
>
<RotateCw class="size-5" /> <RotateCw class="size-5" />
</VbenIconButton> </VbenIconButton>
<VbenButton <VbenButton v-if="showConfirm" :aria-label="$t('ui.captcha.confirmAriaLabel')" class="ml-2" size="sm" @click="handleConfirm">
v-if="showConfirm" {{ $t("ui.captcha.confirm") }}
:aria-label="$t('ui.captcha.confirmAriaLabel')"
class="ml-2"
size="sm"
@click="handleConfirm"
>
{{ $t('ui.captcha.confirm') }}
</VbenButton> </VbenButton>
</template> </template>
@@ -159,17 +141,9 @@ function handleConfirm() {
{{ index + 1 }} {{ index + 1 }}
</div> </div>
<template #footer> <template #footer>
<img <img v-if="hintImage" :alt="$t('ui.captcha.alt')" :src="hintImage" class="border-border h-10 w-full rounded border" />
v-if="hintImage" <div v-else-if="hintText" class="border-border flex-center h-10 w-full rounded border">
:alt="$t('ui.captcha.alt')" {{ `${$t("ui.captcha.clickInOrder")}` + `${hintText}` }}
:src="hintImage"
class="border-border h-10 w-full rounded border"
/>
<div
v-else-if="hintText"
class="border-border flex-center h-10 w-full rounded border"
>
{{ `${$t('ui.captcha.clickInOrder')}` + `${hintText}` }}
</div> </div>
</template> </template>
</CaptchaCard> </CaptchaCard>
@@ -1,24 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import type { PointSelectionCaptchaCardProps } from '../types'; import type { PointSelectionCaptchaCardProps } from "../types";
import { computed } from 'vue'; import { computed } from "vue";
import { $t } from '/@/locales'; import { $t } from "/@/locales";
import { import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "/@/vben/shadcn-ui";
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from '/@/vben/shadcn-ui';
const props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), { const props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), {
height: '220px', height: "220px",
paddingX: '12px', paddingX: "12px",
paddingY: '16px', paddingY: "16px",
title: '', title: "",
width: '300px', width: "300px",
}); });
const emit = defineEmits<{ const emit = defineEmits<{
@@ -26,7 +20,7 @@ const emit = defineEmits<{
}>(); }>();
const parseValue = (value: number | string) => { const parseValue = (value: number | string) => {
if (typeof value === 'number') { if (typeof value === "number") {
return value; return value;
} }
const parsed = Number.parseFloat(value); const parsed = Number.parseFloat(value);
@@ -46,7 +40,7 @@ const captchaStyles = computed(() => {
}); });
function handleClick(e: MouseEvent) { function handleClick(e: MouseEvent) {
emit('click', e); emit("click", e);
} }
</script> </script>
<template> <template>
@@ -54,7 +48,7 @@ function handleClick(e: MouseEvent) {
<CardHeader class="p-0"> <CardHeader class="p-0">
<CardTitle id="captcha-title" class="flex items-center justify-between"> <CardTitle id="captcha-title" class="flex items-center justify-between">
<template v-if="$slots.title"> <template v-if="$slots.title">
<slot name="title">{{ $t('ui.captcha.title') }}</slot> <slot name="title">{{ $t("ui.captcha.title") }}</slot>
</template> </template>
<template v-else> <template v-else>
<span>{{ title }}</span> <span>{{ title }}</span>
@@ -65,14 +59,7 @@ function handleClick(e: MouseEvent) {
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent class="relative mt-2 flex w-full overflow-hidden rounded p-0"> <CardContent class="relative mt-2 flex w-full overflow-hidden rounded p-0">
<img <img v-show="captchaImage" :alt="$t('ui.captcha.alt')" :src="captchaImage" :style="captchaStyles" class="relative z-10" @click="handleClick" />
v-show="captchaImage"
:alt="$t('ui.captcha.alt')"
:src="captchaImage"
:style="captchaStyles"
class="relative z-10"
@click="handleClick"
/>
<div class="absolute inset-0"> <div class="absolute inset-0">
<slot></slot> <slot></slot>
</div> </div>
@@ -1,29 +1,25 @@
<script setup lang="ts"> <script setup lang="ts">
import type { import type { CaptchaVerifyPassingData, SliderCaptchaProps, SliderRotateVerifyPassingData } from "../types";
CaptchaVerifyPassingData,
SliderCaptchaProps,
SliderRotateVerifyPassingData,
} from '../types';
import { reactive, unref, useTemplateRef, watch, watchEffect } from 'vue'; import { reactive, unref, useTemplateRef, watch, watchEffect } from "vue";
import { $t } from '/@/locales'; import { $t } from "/@/locales";
import { cn } from '/@/vben/shared/utils'; import { cn } from "/@/vben/shared/utils";
import { useTimeoutFn } from '@vueuse/core'; import { useTimeoutFn } from "@vueuse/core";
import SliderCaptchaAction from './slider-captcha-action.vue'; import SliderCaptchaAction from "./slider-captcha-action.vue";
import SliderCaptchaBar from './slider-captcha-bar.vue'; import SliderCaptchaBar from "./slider-captcha-bar.vue";
import SliderCaptchaContent from './slider-captcha-content.vue'; import SliderCaptchaContent from "./slider-captcha-content.vue";
const props = withDefaults(defineProps<SliderCaptchaProps>(), { const props = withDefaults(defineProps<SliderCaptchaProps>(), {
actionStyle: () => ({}), actionStyle: () => ({}),
barStyle: () => ({}), barStyle: () => ({}),
contentStyle: () => ({}), contentStyle: () => ({}),
isSlot: false, isSlot: false,
successText: '', successText: "",
text: '', text: "",
wrapperStyle: () => ({}), wrapperStyle: () => ({}),
}); });
@@ -49,21 +45,21 @@ defineExpose({
resume, resume,
}); });
const wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef'); const wrapperRef = useTemplateRef<HTMLDivElement>("wrapperRef");
const barRef = useTemplateRef<typeof SliderCaptchaBar>('barRef'); const barRef = useTemplateRef<typeof SliderCaptchaBar>("barRef");
const contentRef = useTemplateRef<typeof SliderCaptchaContent>('contentRef'); const contentRef = useTemplateRef<typeof SliderCaptchaContent>("contentRef");
const actionRef = useTemplateRef<typeof SliderCaptchaAction>('actionRef'); const actionRef = useTemplateRef<typeof SliderCaptchaAction>("actionRef");
watch( watch(
() => state.isPassing, () => state.isPassing,
(isPassing) => { isPassing => {
if (isPassing) { if (isPassing) {
const { endTime, startTime } = state; const { endTime, startTime } = state;
const time = (endTime - startTime) / 1000; const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) }); emit("success", { isPassing, time: time.toFixed(1) });
modelValue.value = isPassing; modelValue.value = isPassing;
} }
}, }
); );
watchEffect(() => { watchEffect(() => {
@@ -71,9 +67,9 @@ watchEffect(() => {
}); });
function getEventPageX(e: MouseEvent | TouchEvent): number { function getEventPageX(e: MouseEvent | TouchEvent): number {
if ('pageX' in e) { if ("pageX" in e) {
return e.pageX; return e.pageX;
} else if ('touches' in e && e.touches[0]) { } else if ("touches" in e && e.touches[0]) {
return e.touches[0].pageX; return e.touches[0].pageX;
} }
return 0; return 0;
@@ -84,14 +80,9 @@ function handleDragStart(e: MouseEvent | TouchEvent) {
return; return;
} }
if (!actionRef.value) return; if (!actionRef.value) return;
emit('start', e); emit("start", e);
state.moveDistance = state.moveDistance = getEventPageX(e) - Number.parseInt(actionRef.value.getStyle().left.replace("px", "") || "0", 10);
getEventPageX(e) -
Number.parseInt(
actionRef.value.getStyle().left.replace('px', '') || '0',
10,
);
state.startTime = Date.now(); state.startTime = Date.now();
state.isMoving = true; state.isMoving = true;
} }
@@ -112,7 +103,7 @@ function handleDragMoving(e: MouseEvent | TouchEvent) {
const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl()); const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());
const moveX = getEventPageX(e) - moveDistance; const moveX = getEventPageX(e) - moveDistance;
emit('move', { emit("move", {
event: e, event: e,
moveDistance, moveDistance,
moveX, moveX,
@@ -133,7 +124,7 @@ function handleDragMoving(e: MouseEvent | TouchEvent) {
function handleDragOver(e: MouseEvent | TouchEvent) { function handleDragOver(e: MouseEvent | TouchEvent) {
const { isMoving, isPassing, moveDistance } = state; const { isMoving, isPassing, moveDistance } = state;
if (isMoving && !isPassing) { if (isMoving && !isPassing) {
emit('end', e); emit("end", e);
const actionEl = actionRef.value; const actionEl = actionRef.value;
const barEl = unref(barRef); const barEl = unref(barRef);
if (!actionEl || !barEl) return; if (!actionEl || !barEl) return;
@@ -185,12 +176,12 @@ function resume() {
const contentEl = unref(contentRef); const contentEl = unref(contentRef);
if (!actionEl || !barEl || !contentEl) return; if (!actionEl || !barEl || !contentEl) return;
contentEl.getEl().style.width = '100%'; contentEl.getEl().style.width = "100%";
state.toLeft = true; state.toLeft = true;
useTimeoutFn(() => { useTimeoutFn(() => {
state.toLeft = false; state.toLeft = false;
actionEl.setLeft('0'); actionEl.setLeft("0");
barEl.setWidth('0'); barEl.setWidth("0");
}, 300); }, 300);
} }
</script> </script>
@@ -198,12 +189,7 @@ function resume() {
<template> <template>
<div <div
ref="wrapperRef" ref="wrapperRef"
:class=" :class="cn('border-border bg-background-deep relative flex h-10 w-full items-center overflow-hidden rounded-md border text-center', props.class)"
cn(
'border-border bg-background-deep relative flex h-10 w-full items-center overflow-hidden rounded-md border text-center',
props.class,
)
"
:style="wrapperStyle" :style="wrapperStyle"
@mouseleave="handleDragOver" @mouseleave="handleDragOver"
@mousemove="handleDragMoving" @mousemove="handleDragMoving"
@@ -211,31 +197,14 @@ function resume() {
@touchend="handleDragOver" @touchend="handleDragOver"
@touchmove="handleDragMoving" @touchmove="handleDragMoving"
> >
<SliderCaptchaBar <SliderCaptchaBar ref="barRef" :bar-style="barStyle" :to-left="state.toLeft" />
ref="barRef" <SliderCaptchaContent ref="contentRef" :content-style="contentStyle" :is-passing="state.isPassing" :success-text="successText || $t('ui.captcha.sliderSuccessText')" :text="text || $t('ui.captcha.sliderDefaultText')">
:bar-style="barStyle"
:to-left="state.toLeft"
/>
<SliderCaptchaContent
ref="contentRef"
:content-style="contentStyle"
:is-passing="state.isPassing"
:success-text="successText || $t('ui.captcha.sliderSuccessText')"
:text="text || $t('ui.captcha.sliderDefaultText')"
>
<template v-if="$slots.text" #text> <template v-if="$slots.text" #text>
<slot :is-passing="state.isPassing" name="text"></slot> <slot :is-passing="state.isPassing" name="text"></slot>
</template> </template>
</SliderCaptchaContent> </SliderCaptchaContent>
<SliderCaptchaAction <SliderCaptchaAction ref="actionRef" :action-style="actionStyle" :is-passing="state.isPassing" :to-left="state.toLeft" @mousedown="handleDragStart" @touchstart="handleDragStart">
ref="actionRef"
:action-style="actionStyle"
:is-passing="state.isPassing"
:to-left="state.toLeft"
@mousedown="handleDragStart"
@touchstart="handleDragStart"
>
<template v-if="$slots.actionIcon" #icon> <template v-if="$slots.actionIcon" #icon>
<slot :is-passing="state.isPassing" name="actionIcon"></slot> <slot :is-passing="state.isPassing" name="actionIcon"></slot>
</template> </template>
@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CSSProperties } from 'vue'; import type { CSSProperties } from "vue";
import { computed, ref, useTemplateRef } from 'vue'; import { computed, ref, useTemplateRef } from "vue";
import { Check, ChevronsRight } from '/@/vben/icons'; import { Check, ChevronsRight } from "/@/vben/icons";
import { Slot } from '/@/vben/shadcn-ui'; import { Slot } from "/@/vben/shadcn-ui";
const props = defineProps<{ const props = defineProps<{
actionStyle: CSSProperties; actionStyle: CSSProperties;
@@ -13,9 +13,9 @@ const props = defineProps<{
toLeft: boolean; toLeft: boolean;
}>(); }>();
const actionRef = useTemplateRef<HTMLDivElement>('actionRef'); const actionRef = useTemplateRef<HTMLDivElement>("actionRef");
const left = ref('0'); const left = ref("0");
const style = computed(() => { const style = computed(() => {
const { actionStyle } = props; const { actionStyle } = props;
@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CSSProperties } from 'vue'; import type { CSSProperties } from "vue";
import { computed, ref, useTemplateRef } from 'vue'; import { computed, ref, useTemplateRef } from "vue";
const props = defineProps<{ const props = defineProps<{
barStyle: CSSProperties; barStyle: CSSProperties;
toLeft: boolean; toLeft: boolean;
}>(); }>();
const barRef = useTemplateRef<HTMLDivElement>('barRef'); const barRef = useTemplateRef<HTMLDivElement>("barRef");
const width = ref('0'); const width = ref("0");
const style = computed(() => { const style = computed(() => {
const { barStyle } = props; const { barStyle } = props;
@@ -31,10 +31,5 @@ defineExpose({
</script> </script>
<template> <template>
<div <div ref="barRef" :class="toLeft && 'transition-width !w-0 duration-300'" :style="style" class="bg-success absolute h-full"></div>
ref="barRef"
:class="toLeft && 'transition-width !w-0 duration-300'"
:style="style"
class="bg-success absolute h-full"
></div>
</template> </template>
@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CSSProperties } from 'vue'; import type { CSSProperties } from "vue";
import { computed, useTemplateRef } from 'vue'; import { computed, useTemplateRef } from "vue";
import { VbenSpineText } from '/@/vben/shadcn-ui'; import { VbenSpineText } from "/@/vben/shadcn-ui";
const props = defineProps<{ const props = defineProps<{
contentStyle: CSSProperties; contentStyle: CSSProperties;
@@ -12,7 +12,7 @@ const props = defineProps<{
text: string; text: string;
}>(); }>();
const contentRef = useTemplateRef<HTMLDivElement>('contentRef'); const contentRef = useTemplateRef<HTMLDivElement>("contentRef");
const style = computed(() => { const style = computed(() => {
const { contentStyle } = props; const { contentStyle } = props;
@@ -1,33 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import type { import type { CaptchaVerifyPassingData, SliderCaptchaActionType, SliderRotateCaptchaProps, SliderRotateVerifyPassingData } from "../types";
CaptchaVerifyPassingData,
SliderCaptchaActionType,
SliderRotateCaptchaProps,
SliderRotateVerifyPassingData,
} from '../types';
import { computed, reactive, unref, useTemplateRef, watch } from 'vue'; import { computed, reactive, unref, useTemplateRef, watch } from "vue";
import { $t } from '/@/locales'; import { $t } from "/@/locales";
import { useTimeoutFn } from '@vueuse/core'; import { useTimeoutFn } from "@vueuse/core";
import SliderCaptcha from '../slider-captcha/index.vue'; import SliderCaptcha from "../slider-captcha/index.vue";
const props = withDefaults(defineProps<SliderRotateCaptchaProps>(), { const props = withDefaults(defineProps<SliderRotateCaptchaProps>(), {
defaultTip: '', defaultTip: "",
diffDegree: 20, diffDegree: 20,
imageSize: 260, imageSize: 260,
maxDegree: 300, maxDegree: 300,
minDegree: 120, minDegree: 120,
src: '', src: "",
}); });
const emit = defineEmits<{ const emit = defineEmits<{
success: [CaptchaVerifyPassingData]; success: [CaptchaVerifyPassingData];
}>(); }>();
const slideBarRef = useTemplateRef<SliderCaptchaActionType>('slideBarRef'); const slideBarRef = useTemplateRef<SliderCaptchaActionType>("slideBarRef");
const state = reactive({ const state = reactive({
currentRotate: 0, currentRotate: 0,
@@ -45,14 +40,14 @@ const modalValue = defineModel<boolean>({ default: false });
watch( watch(
() => state.isPassing, () => state.isPassing,
(isPassing) => { isPassing => {
if (isPassing) { if (isPassing) {
const { endTime, startTime } = state; const { endTime, startTime } = state;
const time = (endTime - startTime) / 1000; const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) }); emit("success", { isPassing, time: time.toFixed(1) });
} }
modalValue.value = isPassing; modalValue.value = isPassing;
}, }
); );
const getImgWrapStyleRef = computed(() => { const getImgWrapStyleRef = computed(() => {
@@ -67,7 +62,7 @@ const getImgWrapStyleRef = computed(() => {
const getFactorRef = computed(() => { const getFactorRef = computed(() => {
const { maxDegree, minDegree } = props; const { maxDegree, minDegree } = props;
if (minDegree > maxDegree) { if (minDegree > maxDegree) {
console.warn('minDegree should not be greater than maxDegree'); console.warn("minDegree should not be greater than maxDegree");
} }
if (minDegree === maxDegree) { if (minDegree === maxDegree) {
@@ -88,18 +83,14 @@ function handleDragBarMove(data: SliderRotateVerifyPassingData) {
if (denominator === 0) { if (denominator === 0) {
return; return;
} }
const currentRotate = Math.ceil( const currentRotate = Math.ceil((moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef));
(moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef),
);
state.currentRotate = currentRotate; state.currentRotate = currentRotate;
setImgRotate(state.randomRotate - currentRotate); setImgRotate(state.randomRotate - currentRotate);
} }
function handleImgOnLoad() { function handleImgOnLoad() {
const { maxDegree, minDegree } = props; const { maxDegree, minDegree } = props;
const ranRotate = Math.floor( const ranRotate = Math.floor(minDegree! + Math.random() * (maxDegree! - minDegree!)); // 生成随机角度
minDegree! + Math.random() * (maxDegree! - minDegree!),
); // 生成随机角度
state.randomRotate = ranRotate; state.randomRotate = ranRotate;
setImgRotate(ranRotate); setImgRotate(ranRotate);
} }
@@ -147,15 +138,11 @@ function resume() {
} }
const imgCls = computed(() => { const imgCls = computed(() => {
return state.toOrigin ? ['transition-transform duration-300'] : []; return state.toOrigin ? ["transition-transform duration-300"] : [];
}); });
const verifyTip = computed(() => { const verifyTip = computed(() => {
return state.isPassing return state.isPassing ? $t("ui.captcha.sliderRotateSuccessTip", [((state.endTime - state.startTime) / 1000).toFixed(1)]) : $t("ui.captcha.sliderRotateFailTip");
? $t('ui.captcha.sliderRotateSuccessTip', [
((state.endTime - state.startTime) / 1000).toFixed(1),
])
: $t('ui.captcha.sliderRotateFailTip');
}); });
defineExpose({ defineExpose({
@@ -165,22 +152,9 @@ defineExpose({
<template> <template>
<div class="relative flex flex-col items-center"> <div class="relative flex flex-col items-center">
<div <div :style="getImgWrapStyleRef" class="border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md">
:style="getImgWrapStyleRef" <img :class="imgCls" :src="src" :style="state.imgStyle" alt="verify" class="w-full rounded-full" @click="resume" @load="handleImgOnLoad" />
class="border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md" <div class="absolute bottom-3 left-0 z-10 block h-7 w-full text-center text-xs leading-[30px] text-white">
>
<img
:class="imgCls"
:src="src"
:style="state.imgStyle"
alt="verify"
class="w-full rounded-full"
@click="resume"
@load="handleImgOnLoad"
/>
<div
class="absolute bottom-3 left-0 z-10 block h-7 w-full text-center text-xs leading-[30px] text-white"
>
<div <div
v-if="state.showTip" v-if="state.showTip"
:class="{ :class="{
@@ -191,20 +165,12 @@ defineExpose({
{{ verifyTip }} {{ verifyTip }}
</div> </div>
<div v-if="!state.dragging" class="bg-black/30"> <div v-if="!state.dragging" class="bg-black/30">
{{ defaultTip || $t('ui.captcha.sliderRotateDefaultTip') }} {{ defaultTip || $t("ui.captcha.sliderRotateDefaultTip") }}
</div> </div>
</div> </div>
</div> </div>
<SliderCaptcha <SliderCaptcha ref="slideBarRef" v-model="modalValue" class="mt-5" is-slot @end="handleDragEnd" @move="handleDragBarMove" @start="handleStart">
ref="slideBarRef"
v-model="modalValue"
class="mt-5"
is-slot
@end="handleDragEnd"
@move="handleDragBarMove"
@start="handleStart"
>
<template v-for="(_, key) in $slots" :key="key" #[key]="slotProps"> <template v-for="(_, key) in $slots" :key="key" #[key]="slotProps">
<slot :name="key" v-bind="slotProps"></slot> <slot :name="key" v-bind="slotProps"></slot>
</template> </template>
@@ -1,6 +1,6 @@
import type { CSSProperties } from 'vue'; import type { CSSProperties } from "vue";
import type { ClassType } from '/@/vben/types'; import type { ClassType } from "/@/vben/types";
export interface CaptchaData { export interface CaptchaData {
/** /**
@@ -54,8 +54,7 @@ export interface PointSelectionCaptchaCardProps {
width?: number | string; width?: number | string;
} }
export interface PointSelectionCaptchaProps export interface PointSelectionCaptchaProps extends PointSelectionCaptchaCardProps {
extends PointSelectionCaptchaCardProps {
/** /**
* 是否展示确定按钮 * 是否展示确定按钮
* @default false * @default false
@@ -1,18 +1,14 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { ColPageProps } from './types'; import type { ColPageProps } from "./types";
import { computed, ref, useSlots } from 'vue'; import { computed, ref, useSlots } from "vue";
import { import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "/@/vben/shadcn-ui";
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from '/@/vben/shadcn-ui';
import Page from '../page/page.vue'; import Page from "../page/page.vue";
defineOptions({ defineOptions({
name: 'ColPage', name: "ColPage",
inheritAttrs: false, inheritAttrs: false,
}); });
@@ -33,7 +29,7 @@ const delegatedSlots = computed(() => {
const resultSlots: string[] = []; const resultSlots: string[] = [];
for (const key of Object.keys(slots)) { for (const key of Object.keys(slots)) {
if (!['default', 'left'].includes(key)) { if (!["default", "left"].includes(key)) {
resultSlots.push(key); resultSlots.push(key);
} }
} }
@@ -58,23 +54,12 @@ defineExpose({
<template> <template>
<Page v-bind="delegatedProps"> <Page v-bind="delegatedProps">
<!-- 继承默认的slot --> <!-- 继承默认的slot -->
<template <template v-for="slotName in delegatedSlots" :key="slotName" #[slotName]="slotProps">
v-for="slotName in delegatedSlots"
:key="slotName"
#[slotName]="slotProps"
>
<slot :name="slotName" v-bind="slotProps"></slot> <slot :name="slotName" v-bind="slotProps"></slot>
</template> </template>
<ResizablePanelGroup class="w-full" direction="horizontal"> <ResizablePanelGroup class="w-full" direction="horizontal">
<ResizablePanel <ResizablePanel ref="leftPanelRef" :collapsed-size="leftCollapsedWidth" :collapsible="leftCollapsible" :default-size="leftWidth" :max-size="leftMaxWidth" :min-size="leftMinWidth">
ref="leftPanelRef"
:collapsed-size="leftCollapsedWidth"
:collapsible="leftCollapsible"
:default-size="leftWidth"
:max-size="leftMaxWidth"
:min-size="leftMinWidth"
>
<template #default="slotProps"> <template #default="slotProps">
<slot <slot
name="left" name="left"
@@ -86,18 +71,8 @@ defineExpose({
></slot> ></slot>
</template> </template>
</ResizablePanel> </ResizablePanel>
<ResizableHandle <ResizableHandle v-if="resizable" :style="{ backgroundColor: splitLine ? undefined : 'transparent' }" :with-handle="splitHandle" />
v-if="resizable" <ResizablePanel :collapsed-size="rightCollapsedWidth" :collapsible="rightCollapsible" :default-size="rightWidth" :max-size="rightMaxWidth" :min-size="rightMinWidth">
:style="{ backgroundColor: splitLine ? undefined : 'transparent' }"
:with-handle="splitHandle"
/>
<ResizablePanel
:collapsed-size="rightCollapsedWidth"
:collapsible="rightCollapsible"
:default-size="rightWidth"
:max-size="rightMaxWidth"
:min-size="rightMinWidth"
>
<template #default> <template #default>
<slot></slot> <slot></slot>
</template> </template>
@@ -1,2 +1,2 @@
export { default as ColPage } from './col-page.vue'; export { default as ColPage } from "./col-page.vue";
export * from './types'; export * from "./types";
@@ -1,4 +1,4 @@
import type { PageProps } from '../page/types'; import type { PageProps } from "../page/types";
export interface ColPageProps extends PageProps { export interface ColPageProps extends PageProps {
/** /**
@@ -1,23 +1,23 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { CountToProps } from './types'; import type { CountToProps } from "./types";
import { computed, onMounted, ref, watch } from 'vue'; import { computed, onMounted, ref, watch } from "vue";
import { isString } from '/@/vben/shared/utils'; import { isString } from "/@/vben/shared/utils";
import { TransitionPresets, useTransition } from '@vueuse/core'; import { TransitionPresets, useTransition } from "@vueuse/core";
const props = withDefaults(defineProps<CountToProps>(), { const props = withDefaults(defineProps<CountToProps>(), {
startVal: 0, startVal: 0,
duration: 2000, duration: 2000,
separator: ',', separator: ",",
decimal: '.', decimal: ".",
decimals: 0, decimals: 0,
delay: 0, delay: 0,
transition: () => TransitionPresets.easeOutExpo, transition: () => TransitionPresets.easeOutExpo,
}); });
const emit = defineEmits(['started', 'finished']); const emit = defineEmits(["started", "finished"]);
const lastValue = ref(props.startVal); const lastValue = ref(props.startVal);
@@ -27,9 +27,9 @@ onMounted(() => {
watch( watch(
() => props.endVal, () => props.endVal,
(val) => { val => {
lastValue.value = val; lastValue.value = val;
}, }
); );
const currentValue = useTransition(lastValue, { const currentValue = useTransition(lastValue, {
@@ -37,62 +37,43 @@ const currentValue = useTransition(lastValue, {
duration: computed(() => props.duration), duration: computed(() => props.duration),
disabled: computed(() => props.disabled), disabled: computed(() => props.disabled),
transition: computed(() => { transition: computed(() => {
return isString(props.transition) return isString(props.transition) ? TransitionPresets[props.transition] : props.transition;
? TransitionPresets[props.transition]
: props.transition;
}), }),
onStarted() { onStarted() {
emit('started'); emit("started");
}, },
onFinished() { onFinished() {
emit('finished'); emit("finished");
}, },
}); });
const numMain = computed(() => { const numMain = computed(() => {
const result = currentValue.value const result = currentValue.value
.toFixed(props.decimals) .toFixed(props.decimals)
.split('.')[0] .split(".")[0]
?.replaceAll(/\B(?=(\d{3})+(?!\d))/g, props.separator); ?.replaceAll(/\B(?=(\d{3})+(?!\d))/g, props.separator);
return result; return result;
}); });
const numDec = computed(() => { const numDec = computed(() => {
return ( return props.decimal + currentValue.value.toFixed(props.decimals).split(".")[1];
props.decimal + currentValue.value.toFixed(props.decimals).split('.')[1]
);
}); });
</script> </script>
<template> <template>
<div class="count-to" v-bind="$attrs"> <div class="count-to" v-bind="$attrs">
<slot name="prefix"> <slot name="prefix">
<div <div v-if="prefix" class="count-to-prefix" :style="prefixStyle" :class="prefixClass">
class="count-to-prefix"
:style="prefixStyle"
:class="prefixClass"
v-if="prefix"
>
{{ prefix }} {{ prefix }}
</div> </div>
</slot> </slot>
<div class="count-to-main" :class="mainClass" :style="mainStyle"> <div class="count-to-main" :class="mainClass" :style="mainStyle">
<span>{{ numMain }}</span> <span>{{ numMain }}</span>
<span <span v-if="decimals > 0" class="count-to-main-decimal" :class="decimalClass" :style="decimalStyle">
class="count-to-main-decimal"
v-if="decimals > 0"
:class="decimalClass"
:style="decimalStyle"
>
{{ numDec }} {{ numDec }}
</span> </span>
</div> </div>
<slot name="suffix"> <slot name="suffix">
<div <div v-if="suffix" class="count-to-suffix" :style="suffixStyle" :class="suffixClass">
class="count-to-suffix"
:style="suffixStyle"
:class="suffixClass"
v-if="suffix"
>
{{ suffix }} {{ suffix }}
</div> </div>
</slot> </slot>
@@ -112,7 +93,7 @@ const numDec = computed(() => {
} }
&-main { &-main {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
// font-size: 1.5rem; // font-size: 1.5rem;
&-decimal { &-decimal {

Some files were not shown because too many files have changed in this diff Show More