chore: code format

pull/453/head
xiaojunnuo 2025-06-29 14:09:09 +08:00
parent 04422a4637
commit 4fcfd089d8
644 changed files with 10845 additions and 13184 deletions

View File

@ -15,7 +15,8 @@
"serve": "vite preview",
"preview": "vite preview",
"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",
"tsc": "vue-tsc --noEmit --skipLibCheck",
"circle:check": "pnpm dependency-cruise --validate --output-type err-html -f dependency-report.html src",

View File

@ -10,6 +10,10 @@ import { cloneDeep, debounce as lodashDebounce } from "lodash-es";
import { initWorkers } from "./workers";
import { importJavascriptContribution, importJsonContribution, importMonacoYaml, importYamlContribution } from "./async-import";
defineOptions({
name: "CodeEditor",
});
/**
* config:
* value: '', //

View File

@ -18,7 +18,7 @@
<script>
export default {
name: "PiContainer"
name: "PiContainer",
};
</script>

View File

@ -1,21 +1,17 @@
<template>
<div class="cron-editor">
<div class="flex-o">
<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" />
</div>
<div class="mt-5 flex">
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
<fs-icon icon="ion:close-circle" class="pointer fs-16 ml-5 color-gray" :title="t('certd.cron.clearTip')"
@click="onClear"></fs-icon>
</div>
<div class="helper">{{ t('certd.cron.nextTrigger') }}{{ nextTime }}</div>
<div class="fs-helper">{{ errorMessage }}</div>
</div>
<div class="cron-editor">
<div class="flex-o">
<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" />
</div>
<div class="mt-5 flex">
<a-input :disabled="true" :readonly="readonly" :value="modelValue" @change="onChange"></a-input>
<fs-icon icon="ion:close-circle" class="pointer fs-16 ml-5 color-gray" :title="t('certd.cron.clearTip')" @click="onClear"></fs-icon>
</div>
<div class="helper">{{ t("certd.cron.nextTrigger") }}{{ nextTime }}</div>
<div class="fs-helper">{{ errorMessage }}</div>
</div>
</template>
<script lang="ts" setup>
import parser from "cron-parser";
import { computed, ref } from "vue";
@ -25,108 +21,107 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n();
import { getCronNextTimes } from "/@/components/cron-editor/utils";
defineOptions({
name: "CronEditor",
name: "CronEditor",
});
const props = defineProps<{
modelValue?: string;
disabled?: boolean;
readonly?: boolean;
allowEveryMin?: boolean;
modelValue?: string;
disabled?: boolean;
readonly?: boolean;
allowEveryMin?: boolean;
}>();
const period = ref<string>("");
if (props.modelValue == null || props.modelValue.endsWith("* * *")) {
period.value = "day";
period.value = "day";
} else if (props.modelValue.endsWith("* *")) {
period.value = "month";
period.value = "month";
} else if (props.modelValue.endsWith("*")) {
period.value = "year";
period.value = "year";
}
const emit = defineEmits<{
"update:modelValue": any;
change: any;
"update:modelValue": any;
change: any;
}>();
const errorMessage = ref<string | null>(null);
const onUpdate = (value: string) => {
if (value === props.modelValue) {
return;
}
const arr: string[] = value.split(" ");
if (arr[0] === "*") {
arr[0] = "0";
}
if (!props.allowEveryMin) {
if (arr[1] === "*") {
arr[1] = "0";
}
}
if (value === props.modelValue) {
return;
}
const arr: string[] = value.split(" ");
if (arr[0] === "*") {
arr[0] = "0";
}
if (!props.allowEveryMin) {
if (arr[1] === "*") {
arr[1] = "0";
}
}
value = arr.join(" ");
value = arr.join(" ");
emit("update:modelValue", value);
errorMessage.value = undefined;
emit("update:modelValue", value);
errorMessage.value = undefined;
};
const onPeriod = (value: string) => {
period.value = value;
period.value = value;
};
const onChange = (e: any) => {
const value = e.target.value;
onUpdate(value);
const value = e.target.value;
onUpdate(value);
};
const onError = (error: any) => {
errorMessage.value = error;
errorMessage.value = error;
};
const onClear = () => {
if (props.disabled) {
return;
}
onUpdate("");
if (props.disabled) {
return;
}
onUpdate("");
};
const nextTime = computed(() => {
if (props.modelValue == null) {
return t("certd.cron.tip");
}
if (props.modelValue == null) {
return t("certd.cron.tip");
}
try {
const nextTimes = getCronNextTimes(props.modelValue, 2);
return nextTimes.join("");
} catch (e) {
console.log(e);
return t("certd.cron.tip");
}
try {
const nextTimes = getCronNextTimes(props.modelValue, 2);
return nextTimes.join("");
} catch (e) {
console.log(e);
return t("certd.cron.tip");
}
});
</script>
<style lang="less">
.cron-editor {
.cron-ant {
flex-wrap: wrap;
.cron-ant {
flex-wrap: wrap;
&*> {
margin-bottom: 2px;
display: flex;
align-items: center;
}
&* > {
margin-bottom: 2px;
display: flex;
align-items: center;
}
.vcron-select-list {
min-width: 56px;
}
.vcron-select-list {
min-width: 56px;
}
.vcron-select-input {
min-height: 22px;
background-color: #fff;
}
.vcron-select-input {
min-height: 22px;
background-color: #fff;
}
.vcron-select-container {
display: flex;
align-items: center;
}
}
.vcron-select-container {
display: flex;
align-items: center;
}
}
}
</style>

View File

@ -26,7 +26,9 @@
import { defineComponent, onMounted, ref } from "vue";
import * as api from "./api";
import { Modal, notification } from "ant-design-vue";
defineOptions({
name: "EmailEditor",
});
const props = defineProps<{}>();
const VNodes = defineComponent({
props: {

View File

@ -16,7 +16,7 @@ import dayjs from "dayjs";
import { computed } from "vue";
defineOptions({
name: "ExpiresTimeText"
name: "ExpiresTimeText",
});
const props = defineProps<{

View File

@ -15,7 +15,7 @@ Author: Pedro Oliveira <kanytu@gmail . com>
.hljs-literal,
.hljs-symbol,
.hljs-bullet {
color: #6897BB;
color: #6897bb;
}
.hljs-keyword,
@ -42,7 +42,7 @@ Author: Pedro Oliveira <kanytu@gmail . com>
.hljs-string,
.hljs-attribute,
.hljs-addition {
color: #6A8759;
color: #6a8759;
}
.hljs-section,

View File

@ -8,7 +8,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
display: block;
overflow-x: auto;
padding: 0.5em;
background: #FFFFFF;
background: #ffffff;
}
.hljs,
@ -21,7 +21,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-selector-tag,
.hljs-doctag,
.hljs-name {
color: #00979D;
color: #00979d;
}
.hljs-built_in,
@ -29,7 +29,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #D35400;
color: #d35400;
}
.hljs-regexp,
@ -39,7 +39,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #00979D;
color: #00979d;
}
.hljs-type,
@ -49,7 +49,7 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
.hljs-quote,
.hljs-template-tag,
.hljs-deletion {
color: #005C5F;
color: #005c5f;
}
.hljs-title,
@ -59,15 +59,15 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
}
.hljs-comment {
color: rgba(149,165,166,.8);
color: rgba(149, 165, 166, 0.8);
}
.hljs-meta-keyword {
color: #728E00;
color: #728e00;
}
.hljs-meta {
color: #728E00;
color: #728e00;
color: #434f54;
}
@ -80,9 +80,9 @@ Arduino® Light Theme - Stefania Mellai <s.mellai@arduino.cc>
}
.hljs-function {
color: #728E00;
color: #728e00;
}
.hljs-number {
color: #8A7B52;
color: #8a7b52;
}

View File

@ -8,14 +8,14 @@ Brown Paper style from goldblog.com.ua (c) Zaripov Yura <yur4ik7@ukr.net>
display: block;
overflow-x: auto;
padding: 0.5em;
background:#b7a68e url(./brown-papersq.png);
background: #b7a68e url(./brown-papersq.png);
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal {
color:#005599;
font-weight:bold;
color: #005599;
font-weight: bold;
}
.hljs,

View File

@ -45,8 +45,6 @@ Ported by Fabrício Tavares de Oliveira
color: #88f;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-title,

View File

@ -4,7 +4,6 @@ Darcula color scheme from the JetBrains family of IDEs
*/
.hljs {
display: block;
overflow-x: auto;

View File

@ -3,4 +3,4 @@
Please use darcula.css instead.
*/
@import url('darcula.css');
@import url("darcula.css");

View File

@ -8,10 +8,9 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
display: block;
overflow-x: auto;
padding: 0.5em;
background: #F0F0F0;
background: #f0f0f0;
}
/* Base color: saturation 0; */
.hljs,
@ -32,7 +31,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
font-weight: bold;
}
/* User color: hue: 0 */
.hljs-type,
@ -59,14 +57,13 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #BC6060;
color: #bc6060;
}
/* Language color: hue: 90; */
.hljs-literal {
color: #78A960;
color: #78a960;
}
.hljs-built_in,
@ -76,7 +73,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
color: #397300;
}
/* Meta color: hue: 200 */
.hljs-meta {
@ -87,7 +83,6 @@ Original highlight.js style (c) Ivan Sagalaev <maniac@softwaremaniacs.org>
color: #4d99bf;
}
/* Misc effects */
.hljs-emphasis {

View File

@ -10,7 +10,8 @@ Date: 2013-04-02
display: block;
overflow-x: auto;
padding: 0.5em;
background: #eee; color: black;
background: #eee;
color: black;
}
.hljs-link,

View File

@ -68,7 +68,7 @@ Google Code style (c) Aahan Krish <geekpanth3r@gmail.com>
.hljs-selector-id,
.hljs-selector-class {
color: #9B703F
color: #9b703f;
}
.hljs-addition {

View File

@ -60,8 +60,8 @@ grayscale style (c) MY Sun <simonmysun@gmail.com>
}
.hljs-regexp {
color: #333;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat;
color: #333;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat;
}
.hljs-symbol,
@ -84,7 +84,7 @@ grayscale style (c) MY Sun <simonmysun@gmail.com>
.hljs-deletion {
color: #fff;
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat;
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat;
}
.hljs-addition {

View File

@ -47,7 +47,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-literal,
.hljs-deletion,
.hljs-link {
color: #cc6666
color: #cc6666;
}
/*color: fg_green*/
@ -64,7 +64,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-attribute,
.hljs-code,
.hljs-selector-id {
color: #b294bb;
color: #b294bb;
}
/*color: fg_blue*/
@ -72,7 +72,7 @@ vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid)
.hljs-selector-tag,
.hljs-bullet,
.hljs-tag {
color: #81a2be;
color: #81a2be;
}
/*color: fg_aqua*/

View File

@ -61,7 +61,7 @@
.hljs-number,
.hljs-deletion {
color:#ff73fd;
color: #ff73fd;
}
.hljs-emphasis {

View File

@ -6,7 +6,8 @@ Monokai style - ported by Luigi Maselli - http://grigio.org
display: block;
overflow-x: auto;
padding: 0.5em;
background: #272822; color: #ddd;
background: #272822;
color: #ddd;
}
.hljs-tag,

View File

@ -72,7 +72,7 @@
}
.hljs-selector-class {
color: #A082BD
color: #a082bd;
}
.hljs-keyword,

View File

@ -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
*/
.hljs { /* Common set of rules required by highlight.js (don'r remove!) */
display: block;
overflow-x: auto;
padding: 0.5em;
background: #FFFFDF; /* Half and Half (approx.) */
/* --- Uncomment to add PureBASIC native IDE styled font!
.hljs {
/* Common set of rules required by highlight.js (don'r remove!) */
display: block;
overflow-x: auto;
padding: 0.5em;
background: #ffffdf; /* Half and Half (approx.) */
/* --- Uncomment to add PureBASIC native IDE styled font!
font-family: Consolas;
*/
}
@ -39,7 +40,7 @@ NOTE_2: Color names provided in comments were derived using "Name that Color" on
.hljs-attr,
.hljs-params,
.hljs-subst {
color: #000000; /* Black */
color: #000000; /* Black */
}
.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-selector-pseudo,
.hljs-addition {
color: #00AAAA; /* Persian Green (approx.) */
color: #00aaaa; /* Persian Green (approx.) */
}
.hljs-title, /* --- used for PureBASIC Procedures Names --- */
.hljs-tag,
.hljs-variable,
.hljs-code {
color: #006666; /* Blue Stone (approx.) */
.hljs-code {
color: #006666; /* Blue Stone (approx.) */
}
.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-built_in,
.hljs-builtin-name {
color: #006666; /* Blue Stone (approx.) */
font-weight: bold;
color: #006666; /* Blue Stone (approx.) */
font-weight: bold;
}
.hljs-string, /* --- used for PureBASIC Strings --- */
.hljs-selector-attr {
color: #0080FF; /* Azure Radiance (approx.) */
color: #0080ff; /* Azure Radiance (approx.) */
}
.hljs-symbol, /* --- used for PureBASIC Constants --- */
.hljs-link,
.hljs-deletion,
.hljs-attribute {
color: #924B72; /* Cannon Pink (approx.) */
color: #924b72; /* Cannon Pink (approx.) */
}
.hljs-meta,
.hljs-literal,
.hljs-selector-id {
color: #924B72; /* Cannon Pink (approx.) */
font-weight: bold;
color: #924b72; /* Cannon Pink (approx.) */
font-weight: bold;
}
.hljs-strong,
.hljs-name {
font-weight: bold;
font-weight: bold;
}
.hljs-emphasis {
font-style: italic;
font-style: italic;
}

View File

@ -4,7 +4,6 @@ Qt Creator dark color scheme
*/
.hljs {
display: block;
overflow-x: auto;
@ -32,8 +31,7 @@ Qt Creator dark color scheme
color: #ff55ff;
}
.hljs-code
.hljs-selector-class {
.hljs-code .hljs-selector-class {
color: #aaaaff;
}

View File

@ -4,7 +4,6 @@ Qt Creator light color scheme
*/
.hljs {
display: block;
overflow-x: auto;
@ -32,8 +31,7 @@ Qt Creator light color scheme
color: #000080;
}
.hljs-code
.hljs-selector-class {
.hljs-code .hljs-selector-class {
color: #800080;
}
@ -59,7 +57,7 @@ Qt Creator light color scheme
.hljs-variable,
.hljs-params,
.hljs-class .hljs-title {
color: #0055AF;
color: #0055af;
}
.hljs-string,

View File

@ -44,7 +44,6 @@ Railscasts-like style (c) Visoft, Inc. (Damien White)
color: #da4939;
}
.hljs-symbol,
.hljs-bullet,
.hljs-built_in,

View File

@ -12,7 +12,6 @@ Style with support for rainbow parens
color: #d1d9e1;
}
.hljs-comment,
.hljs-quote {
color: #969896;
@ -50,7 +49,7 @@ Style with support for rainbow parens
.hljs-template-variable,
.hljs-selector-id,
.hljs-class .hljs-title {
color: #ffcc66;
color: #ffcc66;
}
.hljs-section,

View File

@ -8,7 +8,7 @@
display: block;
overflow-x: auto;
padding: 0.5em;
background: #F0F0F0;
background: #f0f0f0;
}
/* Base color: saturation 0; */
@ -31,15 +31,15 @@
}
.hljs-attribute {
color: #0E9A00;
}
color: #0e9a00;
}
.hljs-function {
color: #99069A;
color: #99069a;
}
.hljs-builtin-name {
color: #99069A;
color: #99069a;
}
/* User color: hue: 0 */
@ -68,24 +68,22 @@
.hljs-link,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #BC6060;
color: #bc6060;
}
/* Language color: hue: 90; */
.hljs-literal {
color: #78A960;
color: #78a960;
}
.hljs-built_in,
.hljs-bullet,
.hljs-code,
.hljs-addition {
color: #0C9A9A;
color: #0c9a9a;
}
/* Meta color: hue: 200 */
.hljs-meta {
@ -96,7 +94,6 @@
color: #4d99bf;
}
/* Misc effects */
.hljs-emphasis {

View File

@ -9,11 +9,11 @@ School Book style from goldblog.com.ua (c) Zaripov Yura <yur4ik7@ukr.net>
overflow-x: auto;
padding: 15px 0.5em 0.5em 30px;
font-size: 11px;
line-height:16px;
line-height: 16px;
}
pre{
background:#f6f6ae url(./school-book.png);
pre {
background: #f6f6ae url(./school-book.png);
border-top: solid 2px #d2e8b9;
border-bottom: solid 1px #d2e8b9;
}
@ -21,8 +21,8 @@ pre{
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal {
color:#005599;
font-weight:bold;
color: #005599;
font-weight: bold;
}
.hljs,

View File

@ -58,7 +58,6 @@ Visual Studio-like style based on original C# coloring by Jason Diamond <jason@d
color: #00b0e8;
}
.hljs-emphasis {
font-style: italic;
}

View File

@ -7,39 +7,39 @@
display: block;
overflow-x: auto;
padding: 0.5em;
background: #1E1E1E;
color: #DCDCDC;
background: #1e1e1e;
color: #dcdcdc;
}
.hljs-keyword,
.hljs-literal,
.hljs-symbol,
.hljs-name {
color: #569CD6;
color: #569cd6;
}
.hljs-link {
color: #569CD6;
color: #569cd6;
text-decoration: underline;
}
.hljs-built_in,
.hljs-type {
color: #4EC9B0;
color: #4ec9b0;
}
.hljs-number,
.hljs-class {
color: #B8D7A3;
color: #b8d7a3;
}
.hljs-string,
.hljs-meta-string {
color: #D69D85;
color: #d69d85;
}
.hljs-regexp,
.hljs-template-tag {
color: #9A5334;
color: #9a5334;
}
.hljs-subst,
@ -47,34 +47,34 @@
.hljs-title,
.hljs-params,
.hljs-formula {
color: #DCDCDC;
color: #dcdcdc;
}
.hljs-comment,
.hljs-quote {
color: #57A64A;
color: #57a64a;
font-style: italic;
}
.hljs-doctag {
color: #608B4E;
color: #608b4e;
}
.hljs-meta,
.hljs-meta-keyword,
.hljs-tag {
color: #9B9B9B;
color: #9b9b9b;
}
.hljs-variable,
.hljs-template-variable {
color: #BD63C5;
color: #bd63c5;
}
.hljs-attr,
.hljs-attribute,
.hljs-builtin-name {
color: #9CDCFE;
color: #9cdcfe;
}
.hljs-section {
@ -99,7 +99,7 @@
.hljs-selector-class,
.hljs-selector-attr,
.hljs-selector-pseudo {
color: #D7BA7D;
color: #d7ba7d;
}
.hljs-addition {

View File

@ -70,7 +70,6 @@ based on dark.css by Ivan Sagalaev
color: #7f9f7f;
}
.hljs-emphasis {
font-style: italic;
}

View File

@ -18,18 +18,18 @@ export default defineComponent({
code: {
type: String,
required: false,
default: ""
default: "",
},
formatHtml: {
type: Boolean,
required: false,
default: false
default: false,
},
lang: {
type: String,
required: false,
default: ""
}
default: "",
},
},
setup(props: any, ctx: any) {
const highlightHTMLRef: Ref = ref("");
@ -42,7 +42,7 @@ export default defineComponent({
doHighlight();
},
{
immediate: true
immediate: true,
}
);
@ -52,9 +52,9 @@ export default defineComponent({
}
return {
highlightHTMLRef,
doHighlight
doHighlight,
};
}
},
});
</script>

View File

@ -3,40 +3,40 @@
// 功能
// 将HTML字符串格式化
const format = (function() {
const format = (function () {
function style_html(html_source, indent_size, indent_character, max_char) {
var Parser, multi_parser;
function Parser() {
this.pos = 0;
this.token = '';
this.current_mode = 'CONTENT';
this.token = "";
this.current_mode = "CONTENT";
this.tags = {
parent: 'parent1',
parent: "parent1",
parentcount: 1,
parent1: ''
parent1: "",
};
this.tag_type = '';
this.token_text = this.last_token = this.last_text = this.token_type = '';
this.tag_type = "";
this.token_text = this.last_token = this.last_text = this.token_type = "";
this.Utils = {
whitespace: "\n\r\t ".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(','),
in_array: function(what, arr) {
whitespace: "\n\r\t ".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(","),
in_array: function (what, arr) {
for (var i = 0; i < arr.length; i++) {
if (what === arr[i]) {
return true;
}
}
return false;
}
}
this.get_content = function() {
var char = '';
},
};
this.get_content = function () {
var char = "";
var content = [];
var space = false;
while (this.input.charAt(this.pos) !== '<') {
while (this.input.charAt(this.pos) !== "<") {
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);
this.pos++;
@ -49,78 +49,78 @@ const format = (function() {
continue;
} else if (space) {
if (this.line_char_count >= this.max_char) {
content.push('\n');
content.push("\n");
for (var i = 0; i < this.indent_level; i++) {
content.push(this.indent_string);
}
this.line_char_count = 0;
} else {
content.push(' ');
content.push(" ");
this.line_char_count++;
}
space = false;
}
content.push(char);
}
return content.length ? content.join('') : '';
}
this.get_script = function() {
var char = '';
return content.length ? content.join("") : "";
};
this.get_script = function () {
var char = "";
var content = [];
var reg_match = new RegExp('\<\/script' + '\>', 'igm');
var reg_match = new RegExp("</script" + ">", "igm");
reg_match.lastIndex = this.pos;
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) {
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);
this.pos++;
content.push(char);
}
return content.length ? content.join('') : '';
}
this.record_tag = function(tag) {
if (this.tags[tag + 'count']) {
this.tags[tag + 'count']++;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level;
return content.length ? content.join("") : "";
};
this.record_tag = function (tag) {
if (this.tags[tag + "count"]) {
this.tags[tag + "count"]++;
this.tags[tag + this.tags[tag + "count"]] = this.indent_level;
} else {
this.tags[tag + 'count'] = 1;
this.tags[tag + this.tags[tag + 'count']] = this.indent_level;
this.tags[tag + "count"] = 1;
this.tags[tag + this.tags[tag + "count"]] = this.indent_level;
}
this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent;
this.tags.parent = tag + this.tags[tag + 'count'];
}
this.retrieve_tag = function(tag) {
if (this.tags[tag + 'count']) {
this.tags[tag + this.tags[tag + "count"] + "parent"] = this.tags.parent;
this.tags.parent = tag + this.tags[tag + "count"];
};
this.retrieve_tag = function (tag) {
if (this.tags[tag + "count"]) {
var temp_parent = this.tags.parent;
while (temp_parent) {
if (tag + this.tags[tag + 'count'] === temp_parent) {
if (tag + this.tags[tag + "count"] === temp_parent) {
break;
}
temp_parent = this.tags[temp_parent + 'parent'];
temp_parent = this.tags[temp_parent + "parent"];
}
if (temp_parent) {
this.indent_level = this.tags[tag + this.tags[tag + 'count']];
this.tags.parent = this.tags[temp_parent + 'parent'];
this.indent_level = this.tags[tag + this.tags[tag + "count"]];
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']];
if (this.tags[tag + 'count'] == 1) {
delete this.tags[tag + 'count'];
delete this.tags[tag + this.tags[tag + "count"] + "parent"];
delete this.tags[tag + this.tags[tag + "count"]];
if (this.tags[tag + "count"] == 1) {
delete this.tags[tag + "count"];
} else {
this.tags[tag + 'count']--;
this.tags[tag + "count"]--;
}
}
}
this.get_tag = function() {
var char = '';
};
this.get_tag = function () {
var char = "";
var content = [];
var space = false;
do {
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);
this.pos++;
@ -131,92 +131,92 @@ const format = (function() {
continue;
}
if (char === "'" || char === '"') {
if (!content[1] || content[1] !== '!') {
if (!content[1] || content[1] !== "!") {
char += this.get_unformatted(char);
space = true;
}
}
if (char === '=') {
if (char === "=") {
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) {
this.print_newline(false, content);
this.line_char_count = 0;
} else {
content.push(' ');
content.push(" ");
this.line_char_count++;
}
space = false;
}
content.push(char);
} while ( char !== '>');
var tag_complete = content.join('');
} while (char !== ">");
var tag_complete = content.join("");
var tag_index;
if (tag_complete.indexOf(' ') != -1) {
tag_index = tag_complete.indexOf(' ');
if (tag_complete.indexOf(" ") != -1) {
tag_index = tag_complete.indexOf(" ");
} else {
tag_index = tag_complete.indexOf('>');
tag_index = tag_complete.indexOf(">");
}
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)) {
this.tag_type = 'SINGLE';
} else if (tag_check === 'script') {
if (tag_complete.charAt(tag_complete.length - 2) === "/" || this.Utils.in_array(tag_check, this.Utils.single_token)) {
this.tag_type = "SINGLE";
} else if (tag_check === "script") {
this.record_tag(tag_check);
this.tag_type = 'SCRIPT';
} else if (tag_check === 'style') {
this.tag_type = "SCRIPT";
} else if (tag_check === "style") {
this.record_tag(tag_check);
this.tag_type = 'STYLE';
} else if (tag_check.charAt(0) === '!') {
if (tag_check.indexOf('[if') != -1) {
if (tag_complete.indexOf('!IE') != -1) {
var comment = this.get_unformatted('-->', tag_complete);
this.tag_type = "STYLE";
} else if (tag_check.charAt(0) === "!") {
if (tag_check.indexOf("[if") != -1) {
if (tag_complete.indexOf("!IE") != -1) {
var comment = this.get_unformatted("-->", tag_complete);
content.push(comment);
}
this.tag_type = 'START';
} else if (tag_check.indexOf('[endif') != -1) {
this.tag_type = 'END';
this.tag_type = "START";
} else if (tag_check.indexOf("[endif") != -1) {
this.tag_type = "END";
this.unindent();
} else if (tag_check.indexOf('[cdata[') != -1) {
var comment = this.get_unformatted(']]>', tag_complete);
} else if (tag_check.indexOf("[cdata[") != -1) {
var comment = this.get_unformatted("]]>", tag_complete);
content.push(comment);
this.tag_type = 'SINGLE';
this.tag_type = "SINGLE";
} else {
var comment = this.get_unformatted('-->', tag_complete);
var comment = this.get_unformatted("-->", tag_complete);
content.push(comment);
this.tag_type = 'SINGLE';
this.tag_type = "SINGLE";
}
} else {
if (tag_check.charAt(0) === '/') {
if (tag_check.charAt(0) === "/") {
this.retrieve_tag(tag_check.substring(1));
this.tag_type = 'END';
this.tag_type = "END";
} else {
this.record_tag(tag_check);
this.tag_type = 'START';
this.tag_type = "START";
}
if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) {
this.print_newline(true, this.output);
}
}
return content.join('');
}
this.get_unformatted = function(delimiter, orig_tag) {
return content.join("");
};
this.get_unformatted = function (delimiter, orig_tag) {
if (orig_tag && orig_tag.indexOf(delimiter) != -1) {
return '';
return "";
}
var char = '';
var content = '';
var char = "";
var content = "";
var space = true;
do {
char = this.input.charAt(this.pos);
this.pos++
this.pos++;
if (this.Utils.in_array(char, this.Utils.whitespace)) {
if (!space) {
this.line_char_count--;
continue;
}
if (char === '\n' || char === '\r') {
content += '\n';
if (char === "\n" || char === "\r") {
content += "\n";
for (var i = 0; i < this.indent_level; i++) {
content += this.indent_string;
}
@ -228,44 +228,43 @@ const format = (function() {
content += char;
this.line_char_count++;
space = true;
} while ( content . indexOf ( delimiter ) == -1);
} while (content.indexOf(delimiter) == -1);
return content;
}
this.get_token = function() {
};
this.get_token = function () {
var token;
if (this.last_token === 'TK_TAG_SCRIPT') {
if (this.last_token === "TK_TAG_SCRIPT") {
var temp_token = this.get_script();
if (typeof temp_token !== 'string') {
if (typeof temp_token !== "string") {
return temp_token;
}
//token = js_beautify(temp_token, this.indent_size, this.indent_character, this.indent_level);
//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();
if (typeof token !== 'string') {
if (typeof token !== "string") {
return token;
} else {
return [token, 'TK_CONTENT'];
return [token, "TK_CONTENT"];
}
}
if (this.current_mode === 'TAG') {
if (this.current_mode === "TAG") {
token = this.get_tag();
if (typeof token !== 'string') {
if (typeof token !== "string") {
return token;
} else {
var tag_name_type = 'TK_TAG_' + this.tag_type;
var tag_name_type = "TK_TAG_" + this.tag_type;
return [token, tag_name_type];
}
}
}
this.printer = function(js_source, indent_character, indent_size, max_char) {
this.input = js_source || '';
};
this.printer = function (js_source, indent_character, indent_size, max_char) {
this.input = js_source || "";
this.output = [];
this.indent_character = indent_character || ' ';
this.indent_string = '';
this.indent_character = indent_character || " ";
this.indent_string = "";
this.indent_size = indent_size || 2;
this.indent_level = 0;
this.max_char = max_char || 70;
@ -273,7 +272,7 @@ const format = (function() {
for (var i = 0; i < this.indent_size; i++) {
this.indent_string += this.indent_character;
}
this.print_newline = function(ignore, arr) {
this.print_newline = function (ignore, arr) {
this.line_char_count = 0;
if (!arr || !arr.length) {
return;
@ -283,23 +282,23 @@ const format = (function() {
arr.pop();
}
}
arr.push('\n');
arr.push("\n");
for (var i = 0; i < this.indent_level; i++) {
arr.push(this.indent_string);
}
}
this.print_token = function(text) {
};
this.print_token = function (text) {
this.output.push(text);
}
this.indent = function() {
};
this.indent = function () {
this.indent_level++;
}
this.unindent = function() {
};
this.unindent = function () {
if (this.indent_level > 0) {
this.indent_level--;
}
}
}
};
};
return this;
}
multi_parser = new Parser();
@ -308,58 +307,56 @@ const format = (function() {
var t = multi_parser.get_token();
multi_parser.token_text = t[0];
multi_parser.token_type = t[1];
if (multi_parser.token_type === 'TK_EOF') {
if (multi_parser.token_type === "TK_EOF") {
break;
}
switch (multi_parser.token_type) {
case 'TK_TAG_START':
case 'TK_TAG_SCRIPT':
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 !== '') {
case "TK_TAG_START":
case "TK_TAG_SCRIPT":
case "TK_TAG_STYLE":
multi_parser.print_newline(false, multi_parser.output);
multi_parser.print_token(multi_parser.token_text);
}
multi_parser.current_mode = 'TAG';
break;
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_token(multi_parser.token_text);
}
multi_parser.current_mode = "TAG";
break;
}
multi_parser.last_token = multi_parser.token_type;
multi_parser.last_text = multi_parser.token_text;
}
return multi_parser.output.join('');
return multi_parser.output.join("");
}
return function(data) {
var dataHolder = ['__dataHolder_', [Math.random(), Math.random(), Math.random(), Math.random()].join('_').replace(/[^0-9]/g, '_'), '_'].join('_');
return function (data) {
var dataHolder = ["__dataHolder_", [Math.random(), Math.random(), Math.random(), Math.random()].join("_").replace(/[^0-9]/g, "_"), "_"].join("_");
var dataHolders = {};
var index = 0;
data = data.replace(/(\")(data:[^\"]*)(\")/g,
function($0, $1, $2, $3) {
data = data.replace(/(\")(data:[^\"]*)(\")/g, function ($0, $1, $2, $3) {
var name = dataHolder + index++;
dataHolders[name] = $2;
return $1 + name + $3;
})
data = style_html(data, 2, ' ', 0x10000000);
data = data.replace(new RegExp(dataHolder + '[0-9]+', 'g'),
function($0) {
});
data = style_html(data, 2, " ", 0x10000000);
data = data.replace(new RegExp(dataHolder + "[0-9]+", "g"), function ($0) {
return dataHolders[$0];
});
return data;
}
};
})();
export default format
export default format;

View File

@ -1,6 +1,6 @@
<template>
<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">
<fs-icon :icon="item.icon" class="fs-16 color-blue mr-5" />
{{ item.label }}

View File

@ -10,12 +10,12 @@ export default {
props: {
modelValue: {
type: String,
default: undefined
default: undefined,
},
// eslint-disable-next-line vue/require-default-prop
from: {
type: [String, Array]
}
type: [String, Array],
},
},
emits: ["update:modelValue"],
setup(props: any, ctx: any) {
@ -35,7 +35,7 @@ export default {
currentStageIndex: currentStageIndex.value,
currentTaskIndex: currentTaskIndex.value,
currentStepIndex: currentStepIndex.value,
currentTask: currentTask.value
currentTask: currentTask.value,
});
if (props.from) {
if (typeof props.from === "string") {
@ -73,9 +73,9 @@ export default {
}
return {
options,
onChanged
onChanged,
};
}
},
};
</script>

View File

@ -2,6 +2,10 @@
import { ref } from "vue";
import TutorialSteps from "/@/components/tutorial/tutorial-steps.vue";
defineOptions({
name: "TutorialModal",
});
const props = defineProps<{
showIcon?: boolean;
}>();
@ -16,23 +20,18 @@ const slots = defineSlots();
<template>
<div class="tutorial-button pointer" @click="open">
<template v-if="!slots.default">
<fs-icon
v-if="showIcon === false"
icon="ant-design:question-circle-outlined"
class="mr-0.5"
></fs-icon>
<div class="hidden md:block">{{$t('tutorial.title')}}</div>
<fs-icon v-if="showIcon === false" icon="ant-design:question-circle-outlined" class="mr-0.5"></fs-icon>
<div class="hidden md:block">{{ $t("tutorial.title") }}</div>
</template>
<slot></slot>
<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" />
<template #footer></template>
</a-modal>
</div>
</template>
<style lang="less">
.tutorial-modal {
top: 50px;

View File

@ -15,11 +15,7 @@ type Step = {
import { ref } from "vue";
const steps = ref<Step[]>([
{ title: t('certd.steps.createPipeline') },
{ title: t('certd.steps.addTask') },
{ title: t('certd.steps.scheduledRun') }
]);
const steps = ref<Step[]>([{ title: t("certd.steps.createPipeline") }, { title: t("certd.steps.addTask") }, { title: t("certd.steps.scheduledRun") }]);
const router = useRouter();
function goPipeline() {

View File

@ -20,10 +20,9 @@
</div>
<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" type="primary" icon-right="ion:arrow-forward-outline" @click="next()">{{ t('guide.buttons.next') }}</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>
</div>
</div>
</template>
@ -49,16 +48,13 @@ type StepItems = {
import { computed, nextTick, ref } from "vue";
const steps = ref<Step[]>([
{
{
title: t("guide.createCertPipeline.title"),
description: t("guide.createCertPipeline.description"),
items: [
{
title: t("guide.createCertPipeline.items.tutorialTitle"),
descriptions: [
t("guide.createCertPipeline.items.tutorialDesc1"),
t("guide.createCertPipeline.items.tutorialDesc2"),
],
descriptions: [t("guide.createCertPipeline.items.tutorialDesc1"), t("guide.createCertPipeline.items.tutorialDesc2")],
body: () => {
return <SimpleSteps></SimpleSteps>;
},
@ -86,26 +82,17 @@ const steps = ref<Step[]>([
{
image: "/static/doc/images/5-1-add-host.png",
title: t("guide.addDeployTask.items.addTaskTitle"),
descriptions: [
t("guide.addDeployTask.items.addTaskDesc1"),
t("guide.addDeployTask.items.addTaskDesc2"),
],
descriptions: [t("guide.addDeployTask.items.addTaskDesc1"), t("guide.addDeployTask.items.addTaskDesc2")],
},
{
image: "/static/doc/images/5-2-add-host.png",
title: t("guide.addDeployTask.items.fillParamsTitle"),
descriptions: [
t("guide.addDeployTask.items.fillParamsDesc1"),
t("guide.addDeployTask.items.fillParamsDesc2"),
],
descriptions: [t("guide.addDeployTask.items.fillParamsDesc1"), t("guide.addDeployTask.items.fillParamsDesc2")],
},
{
image: "/static/doc/images/5-3-add-host.png",
title: t("guide.addDeployTask.items.activateCertTitle"),
descriptions: [
t("guide.addDeployTask.items.activateCertDesc1"),
t("guide.addDeployTask.items.activateCertDesc2"),
],
descriptions: [t("guide.addDeployTask.items.activateCertDesc1"), t("guide.addDeployTask.items.activateCertDesc2")],
},
{
image: "/static/doc/images/5-4-add-host.png",
@ -119,81 +106,72 @@ const steps = ref<Step[]>([
},
],
},
{
title: t('guide.runAndTestTask.runAndTestTitle'),
description: t('guide.runAndTestTask.runAndTestDescription'),
items: [
{
image: "/static/doc/images/9-start.png",
title: t('guide.runAndTestTask.runTestOnce'),
descriptions: [t('guide.runAndTestTask.clickManualTriggerToTest')],
},
{
image: "/static/doc/images/10-1-log.png",
title: t('guide.runAndTestTask.viewLogs'),
descriptions: [t('guide.runAndTestTask.clickTaskToViewStatusAndLogs')],
},
{
image: "/static/doc/images/11-1-error.png",
title: t('guide.runAndTestTask.howToTroubleshootFailure'),
descriptions: [t('guide.runAndTestTask.viewErrorLogs')],
},
{
image: "/static/doc/images/11-2-error.png",
title: t('guide.runAndTestTask.howToTroubleshootFailure'),
descriptions: [
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-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-3-download.png",
title: t('guide.runAndTestTask.downloadCertManualDeploy'),
descriptions: [t('guide.runAndTestTask.downloadIfNoAutoDeployPlugin')],
},
],
},
{
title: t('guide.scheduleAndEmailTask.title'),
description: t('guide.scheduleAndEmailTask.description'),
items: [
{
image: "/static/doc/images/14-timer.png",
title: t('guide.scheduleAndEmailTask.setSchedule'),
descriptions: [
t('guide.scheduleAndEmailTask.pipelineSuccessThenSchedule'),
t('guide.scheduleAndEmailTask.recommendDailyRun'),
],
},
{
image: "/static/doc/images/15-1-email.png",
title: t('guide.scheduleAndEmailTask.setEmailNotification'),
descriptions: [
t('guide.scheduleAndEmailTask.suggestErrorAndRecoveryEmails'),
t('guide.scheduleAndEmailTask.basicVersionNeedsMailServer'),
],
},
{
title: t('guide.scheduleAndEmailTask.tutorialEndTitle'),
descriptions: [t('guide.scheduleAndEmailTask.thanksForWatching')],
},
],
}
{
title: t("guide.runAndTestTask.runAndTestTitle"),
description: t("guide.runAndTestTask.runAndTestDescription"),
items: [
{
image: "/static/doc/images/9-start.png",
title: t("guide.runAndTestTask.runTestOnce"),
descriptions: [t("guide.runAndTestTask.clickManualTriggerToTest")],
},
{
image: "/static/doc/images/10-1-log.png",
title: t("guide.runAndTestTask.viewLogs"),
descriptions: [t("guide.runAndTestTask.clickTaskToViewStatusAndLogs")],
},
{
image: "/static/doc/images/11-1-error.png",
title: t("guide.runAndTestTask.howToTroubleshootFailure"),
descriptions: [t("guide.runAndTestTask.viewErrorLogs")],
},
{
image: "/static/doc/images/11-2-error.png",
title: t("guide.runAndTestTask.howToTroubleshootFailure"),
descriptions: [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-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-3-download.png",
title: t("guide.runAndTestTask.downloadCertManualDeploy"),
descriptions: [t("guide.runAndTestTask.downloadIfNoAutoDeployPlugin")],
},
],
},
{
title: t("guide.scheduleAndEmailTask.title"),
description: t("guide.scheduleAndEmailTask.description"),
items: [
{
image: "/static/doc/images/14-timer.png",
title: t("guide.scheduleAndEmailTask.setSchedule"),
descriptions: [t("guide.scheduleAndEmailTask.pipelineSuccessThenSchedule"), t("guide.scheduleAndEmailTask.recommendDailyRun")],
},
{
image: "/static/doc/images/15-1-email.png",
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);

View File

@ -10,7 +10,7 @@ export default {
function checkPlus() {
// 事件处理代码
notification.warn({
message: "此为专业版功能,请升级到专业版"
message: "此为专业版功能,请升级到专业版",
});
}
el.addEventListener("click", function (event: any) {
@ -20,5 +20,5 @@ export default {
checkPlus();
});
}
}
},
};

View File

@ -1,15 +1,15 @@
<template>
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade">
<contextHolder />
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
<div v-if="!settingStore.isComm || userStore.isAdmin" class="layout-vip isPlus" @click="openUpgrade">
<contextHolder />
<fs-icon icon="mingcute:vip-1-line" :title="text.title" />
<div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5">
<a-tooltip>
<template #title> {{ text.title }}</template>
<span class="">{{ text.name }}</span>
</a-tooltip>
</div>
</div>
<div v-if="mode !== 'icon'" class="text hidden md:block ml-0.5">
<a-tooltip>
<template #title> {{ text.title }}</template>
<span class="">{{ text.name }}</span>
</a-tooltip>
</div>
</div>
</template>
<script lang="tsx" setup>
import { computed, onMounted, reactive } from "vue";
@ -104,7 +104,6 @@ const text = computed<Text>(() => {
}
});
const expireTime = computed(() => {
if (settingStore.isPlus) {
return dayjs(settingStore.plusInfo.expireTime).format("YYYY-MM-DD");
@ -157,7 +156,6 @@ async function doActive() {
}
}
const computedSiteId = computed(() => settingStore.installInfo?.siteId);
const [modal, contextHolder] = Modal.useModal();
const userStore = useUserStore();
@ -169,17 +167,16 @@ function goAccount() {
async function 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();
}
function openTrialModal() {
Modal.destroyAll();
modal.confirm({
title: t('vip.trial_modal_title'),
okText: t('vip.trial_modal_ok_text'),
title: t("vip.trial_modal_title"),
okText: t("vip.trial_modal_ok_text"),
onOk() {
getVipTrial();
},
@ -187,15 +184,14 @@ function openTrialModal() {
content: () => {
return (
<div class="flex-col mt-10 mb-10">
<div>{t('vip.trial_modal_thanks')}</div>
<div>{t('vip.trial_modal_click_confirm')}</div>
<div>{t("vip.trial_modal_thanks")}</div>
<div>{t("vip.trial_modal_click_confirm")}</div>
</div>
);
},
});
}
function openStarModal() {
Modal.destroyAll();
const goGithub = () => {
@ -221,207 +217,176 @@ function openStarModal() {
});
}
function openUpgrade() {
if (!userStore.isAdmin) {
message.info(t("vip.admin_only_operation"));
return;
}
const placeholder = t("vip.enter_activation_code");
const isPlus = settingStore.isPlus;
let title = t("vip.activate_pro_business");
if (settingStore.isComm) {
title = t("vip.renew_business");
} else if (settingStore.isPlus) {
title = t("vip.renew_pro_upgrade_business");
}
if (!userStore.isAdmin) {
message.info(t("vip.admin_only_operation"));
return;
}
const placeholder = t("vip.enter_activation_code");
const isPlus = settingStore.isPlus;
let title = t("vip.activate_pro_business");
if (settingStore.isComm) {
title = t("vip.renew_business");
} else if (settingStore.isPlus) {
title = t("vip.renew_pro_upgrade_business");
}
const productInfo = settingStore.productInfo;
const vipTypeDefine = {
free: {
title: t("vip.basic_edition"),
desc: t("vip.community_free_version"),
type: "free",
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"),
],
},
plus: {
title: t("vip.professional_edition"),
desc: t("vip.open_source_support"),
type: "plus",
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"),
click: () => {
openStarModal();
const productInfo = settingStore.productInfo;
const vipTypeDefine = {
free: {
title: t("vip.basic_edition"),
desc: t("vip.community_free_version"),
type: "free",
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")],
},
plus: {
title: t("vip.professional_edition"),
desc: t("vip.open_source_support"),
type: "plus",
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"),
click: () => {
openStarModal();
},
},
icon: "stash:thumb-up",
price: productInfo.plus.price,
price3: `¥${productInfo.plus.price3}/3${t("vip.years")}`,
tooltip: productInfo.plus.tooltip,
get() {
return (
<a-tooltip title={t("vip.afdian_support_vip")}>
<a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank">
{t("vip.get_after_support")}
</a-button>
</a-tooltip>
);
},
},
icon: "stash:thumb-up",
price: productInfo.plus.price,
price3: `¥${productInfo.plus.price3}/3${t("vip.years")}`,
tooltip: productInfo.plus.tooltip,
get() {
return (
<a-tooltip title={t("vip.afdian_support_vip")}>
<a-button size="small" type="primary" href="https://afdian.com/a/greper" target="_blank">
{t("vip.get_after_support")}
</a-button>
</a-tooltip>
comm: {
title: t("vip.business_edition"),
desc: t("vip.commercial_license"),
type: "comm",
icon: "vaadin:handshake",
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")],
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>
);
},
},
comm: {
title: t("vip.business_edition"),
desc: t("vip.commercial_license"),
type: "comm",
icon: "vaadin:handshake",
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"),
],
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>
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>
)}
{!item.price && (
<span>
<span class="price-text">{t("vip.freee")}</span>
</span>
)}
</h3>
<div style="color:green" class="flex-o">
<fs-icon icon={item.icon} class="fs-16 flex-o" />
{item.desc}
</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>
</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(() => {
mitter.on("openVipModal", () => {
@ -434,75 +399,76 @@ onMounted(() => {
<style lang="less">
.layout-vip {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&.isPlus {
color: #c5913f;
}
&.isPlus {
color: #c5913f;
}
.text {}
.text {
}
}
.vip-active-modal {
.vip-block {
display: flex;
flex-direction: column;
padding: 10px;
border: 1px solid #eee;
border-radius: 5px;
height: 250px;
.vip-block {
display: flex;
flex-direction: column;
padding: 10px;
border: 1px solid #eee;
border-radius: 5px;
height: 250px;
//background-color: rgba(250, 237, 167, 0.79);
&.current {
border-color: green;
}
//background-color: rgba(250, 237, 167, 0.79);
&.current {
border-color: green;
}
.block-header {
padding: 0px;
display: flex;
justify-content: space-between;
.block-header {
padding: 0px;
display: flex;
justify-content: space-between;
.trial {
font-size: 12px;
font-wight: 400;
}
}
.trial {
font-size: 12px;
font-wight: 400;
}
}
.footer {
padding-top: 5px;
margin-top: 0px;
border-top: 1px solid #eee;
.footer {
padding-top: 5px;
margin-top: 0px;
border-top: 1px solid #eee;
.price-text {
font-size: 18px;
color: red;
}
}
}
.price-text {
font-size: 18px;
color: red;
}
}
}
ul {
list-style-type: unset;
margin-left: 0px;
padding: 0;
}
ul {
list-style-type: unset;
margin-left: 0px;
padding: 0;
}
.color-green {
color: green;
}
.color-green {
color: green;
}
.vip-type-vs {
.privilege {
.fs-icon {
color: green;
}
}
.vip-type-vs {
.privilege {
.fs-icon {
color: green;
}
}
.fs-icon {
margin-right: 5px;
}
}
.fs-icon {
margin-right: 5px;
}
}
}
</style>

View File

@ -35,7 +35,7 @@ export default {
forEach(map, (item, key) => {
list.push({
key,
label: item.label
label: item.label,
});
});
return list;
@ -54,9 +54,9 @@ export default {
return {
languages,
current,
changeLocale
changeLocale,
};
}
},
};
</script>

View File

@ -1,15 +1,15 @@
.fs-menu-wrapper{
.fs-menu-wrapper {
height: 100%;
overflow-y: auto;
&.fs-menu-better-scroll{
&.fs-menu-better-scroll {
overflow-y: hidden;
}
.menu-item-title{
.menu-item-title {
display: flex;
align-items: center;
.fs-icon{
font-size: 16px !important;
min-width: 16px !important;
.fs-icon {
font-size: 16px !important;
min-width: 16px !important;
}
}
}

View File

@ -10,7 +10,7 @@ import { utils } from "@fast-crud/fast-crud";
import * as _ from "lodash-es";
defineOptions({
name: "FsMenu"
name: "FsMenu",
});
const props = defineProps<{
@ -37,7 +37,7 @@ function buildItemMenus(menus: any) {
title: sub.title,
icon: () => {
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
}
},
};
list.push(item);
@ -50,7 +50,7 @@ function buildItemMenus(menus: any) {
watch(
() => props.menus,
(menus) => {
menus => {
items.value = buildItemMenus(menus);
},
{ immediate: true }
@ -77,7 +77,7 @@ function openSelectedParents(fullPath: any) {
return;
}
if (value.path === fullPath) {
_.forEach(context.parents, (item) => {
_.forEach(context.parents, item => {
if (item.value instanceof Array) {
return;
}
@ -99,7 +99,7 @@ watch(
() => {
return route.fullPath;
},
(path) => {
path => {
// path = route.fullPath;
selectedKeys.value = [path];
const changed = openSelectedParents(path);
@ -108,7 +108,7 @@ watch(
}
},
{
immediate: true
immediate: true,
}
);
</script>

View File

@ -6,7 +6,7 @@ import "./index.less";
import { utils } from "@fast-crud/fast-crud";
import { routerUtils } from "/@/utils/util.router";
defineOptions()
defineOptions();
export default defineComponent({
name: "FsMenu",
@ -14,9 +14,9 @@ export default defineComponent({
props: {
menus: {},
expandSelected: {
default: false
default: false,
},
scroll: {}
scroll: {},
},
setup(props, ctx) {
async function onSelect(item: any) {
@ -37,7 +37,7 @@ export default defineComponent({
title: sub.title,
icon: () => {
return <fsIcon icon={sub.icon ?? sub.meta?.icon} />;
}
},
};
list.push(item);
if (sub.children && sub.children.length > 0) {
@ -80,7 +80,7 @@ export default defineComponent({
default: () => {
return buildMenus(sub.children);
},
title
title,
};
function onTitleClick() {
if (sub.path && ctx.attrs.mode === "horizontal") {
@ -101,7 +101,7 @@ export default defineComponent({
const slots = {
default() {
return buildMenus(props.menus);
}
},
};
const selectedKeys = ref([]);
const openKeys = ref([]);
@ -123,7 +123,7 @@ export default defineComponent({
return;
}
if (value.path === fullPath) {
_.forEach(context.parents, (item) => {
_.forEach(context.parents, item => {
if (item.value instanceof Array) {
return;
}
@ -148,7 +148,7 @@ export default defineComponent({
() => {
return route.fullPath;
},
(path) => {
path => {
// path = route.fullPath;
selectedKeys.value = [path];
const changed = openSelectedParents(path);
@ -157,7 +157,7 @@ export default defineComponent({
}
},
{
immediate: true
immediate: true,
}
);
return () => {
@ -170,7 +170,7 @@ export default defineComponent({
// onOpenChange={onOpenChange}
v-models={[
[openKeys.value, "openKeys"],
[selectedKeys.value, "selectedKeys"]
[selectedKeys.value, "selectedKeys"],
]}
items={items.value}
inlineCollapsed={!props.expandSelected}
@ -179,5 +179,5 @@ export default defineComponent({
const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll };
return <div>{menu}</div>;
};
}
},
});

View File

@ -17,7 +17,7 @@ export default defineComponent({
() => {
return router.currentRoute.value.fullPath;
},
(value) => {
value => {
showSourceLink.value = value !== "/index";
},
{ immediate: true }
@ -29,9 +29,9 @@ export default defineComponent({
}
return {
goSource,
showSourceLink
showSourceLink,
};
}
},
});
</script>

View File

@ -2,14 +2,7 @@
<div class="fs-multiple-page-control-group">
<div class="fs-multiple-page-control-content">
<div class="fs-multiple-page-control-content-inner">
<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"
>
<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">
<a-tab-pane v-for="item in page.getOpened" :key="item.fullPath" :name="item.fullPath" :closable="isTabClosable(item)">
<template #tab>
<span class="flex-o">
@ -75,7 +68,7 @@ export default {
closeRight: pageStore.closeRight,
closeOther: pageStore.closeOther,
closeAll: pageStore.closeAll,
openedSort: pageStore.openedSort
openedSort: pageStore.openedSort,
};
const computeOpened = computed(() => {
return pageStore.getOpened;
@ -84,7 +77,7 @@ export default {
return {
page: pageStore,
...actions,
computeOpened
computeOpened,
};
},
data() {
@ -97,9 +90,9 @@ export default {
{ icon: "arrow-left", title: "关闭左侧", value: "left" },
{ icon: "arrow-right", title: "关闭右侧", value: "right" },
{ icon: "times", title: "关闭其它", value: "other" },
{ icon: "times-circle", title: "关闭全部", value: "all" }
{ icon: "times-circle", title: "关闭全部", value: "all" },
],
tagName: "/index"
tagName: "/index",
};
},
mounted() {
@ -195,8 +188,8 @@ export default {
if (action === "remove") {
this.close({ tagName });
}
}
} as any
},
} as any,
};
</script>
<style lang="less">

View File

@ -19,44 +19,44 @@ import { defineComponent, ref } from "vue";
const colorListDefine = [
{
key: "薄暮",
color: "#f5222d"
color: "#f5222d",
},
{
key: "火山",
color: "#fa541c"
color: "#fa541c",
},
{
key: "日暮",
color: "#faad14"
color: "#faad14",
},
{
key: "明青",
color: "#13c2c2"
color: "#13c2c2",
},
{
key: "极光绿",
color: "#52c41a"
color: "#52c41a",
},
{
key: "拂晓蓝(默认)",
color: "#1890ff"
color: "#1890ff",
},
{
key: "极客蓝",
color: "#2f54eb"
color: "#2f54eb",
},
{
key: "酱紫",
color: "#722ed1"
}
color: "#722ed1",
},
];
export default defineComponent({
name: "FsThemeColorPicker",
props: {
primaryColor: {
type: String,
default: "#1890ff"
}
default: "#1890ff",
},
},
emits: ["change"],
setup(props, ctx) {
@ -66,9 +66,9 @@ export default defineComponent({
}
return {
colorList,
changeColor
changeColor,
};
}
},
});
</script>
<style lang="less">

View File

@ -27,9 +27,9 @@ export default defineComponent({
visible,
show,
afterVisibleChange,
setting
setting,
};
}
},
});
</script>

View File

@ -29,9 +29,9 @@ export default defineComponent({
};
return {
setting,
onChange
onChange,
};
}
},
});
</script>

View File

@ -1,13 +1,13 @@
<template>
<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>
<a-menu>
<a-menu-item>
<div @click="goUserProfile">{{ t('user.profile') }}</div>
<div @click="goUserProfile">{{ t("user.profile") }}</div>
</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>
</template>

View File

@ -20,6 +20,7 @@
<!-- <fs-menu class="header-menu" mode="horizontal" :expand-selected="false" :selectable="false" :menus="frameworkMenus" />-->
<div
v-for="menu of resourceStore.authedTopMenus"
:key="menu.name"
class="top-menu flex-center header-btn"
:class="{ current: resourceStore.currentTopMenu === menu }"
:style="{ color: resourceStore.currentTopMenu === menu ? token.colorPrimary : '' }"

View File

@ -3,7 +3,7 @@ import App from "./App.vue";
// import Antd from "ant-design-vue";
import Antd from "./plugin/antdv-async/index";
import "./style/common.less";
import { i18n, loadLocaleMessages } from "/@/locales"
import { i18n, loadLocaleMessages } from "/@/locales";
import components from "./components";
import router from "./router";
import plugin from "./plugin/";
@ -15,15 +15,15 @@ import { initPreferences } from "/@/vben/preferences";
// import "./components/code-editor/import-works";
// @ts-ignore
async function bootstrap() {
const app = createApp(App);
// app.use(Antd);
app.use(Antd);
await setupVben(app, { loadLocaleMessages, router });
app.use(router);
// app.use(i18n);
// app.use(store);
app.use(components);
app.use(plugin, { i18n });
const app = createApp(App);
// app.use(Antd);
app.use(Antd);
await setupVben(app, { loadLocaleMessages, router });
app.use(router);
// app.use(i18n);
// app.use(store);
app.use(components);
app.use(plugin, { i18n });
const envMode = util.env.MODE;
const namespace = `${import.meta.env.VITE_APP_NAMESPACE}-${envMode}`;

View File

@ -177,10 +177,10 @@ const mockUtil: any = {
records: records,
total: data.length,
limit,
offset
}
offset,
},
};
}
},
},
{
path: "/mock/" + name + "/get",
@ -192,9 +192,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: current
data: current,
};
}
},
},
{
path: "/mock/" + name + "/byIds",
@ -205,9 +205,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: res
data: res,
};
}
},
},
{
path: "/mock/" + name + "/add",
@ -218,9 +218,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: cloneDeep(req.body)
data: cloneDeep(req.body),
};
}
},
},
{
path: "/mock/" + name + "/update",
@ -241,9 +241,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: null
data: null,
};
}
},
},
{
path: "/mock/" + name + "/delete",
@ -253,9 +253,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: null
data: null,
};
}
},
},
{
path: "/mock/" + name + "/batchDelete",
@ -271,9 +271,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: null
data: null,
};
}
},
},
{
path: "/mock/" + name + "/delete",
@ -283,9 +283,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: null
data: null,
};
}
},
},
{
path: "/mock/" + name + "/all",
@ -294,9 +294,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: list
data: list,
};
}
},
},
{
path: "/mock/" + name + "/cellUpdate",
@ -317,7 +317,7 @@ const mockUtil: any = {
} else {
item = {
id: ++options.idGenerator,
[req.body.key]: req.body.value
[req.body.key]: req.body.value,
};
list.unshift(item);
}
@ -325,9 +325,9 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: item
data: item,
};
}
},
},
{
path: "/mock/" + name + "/columnUpdate",
@ -350,12 +350,12 @@ const mockUtil: any = {
return {
code: 0,
msg: "success",
data: null
data: null,
};
}
}
},
},
];
}
},
};
export default mockUtil;

View File

@ -9,21 +9,21 @@ export default [
children: [
{
value: "yizhi",
label: "一致"
label: "一致",
},
{
value: "fankui",
label: "反馈"
label: "反馈",
},
{
value: "xiaolv",
label: "效率"
label: "效率",
},
{
value: "kekong",
label: "可控"
}
]
label: "可控",
},
],
},
{
value: "daohang",
@ -31,15 +31,15 @@ export default [
children: [
{
value: "cexiangdaohang",
label: "侧向导航"
label: "侧向导航",
},
{
value: "dingbudaohang",
label: "顶部导航"
}
]
}
]
label: "顶部导航",
},
],
},
],
},
{
value: "zujian",
@ -51,25 +51,25 @@ export default [
children: [
{
value: "layout",
label: "Layout 布局"
label: "Layout 布局",
},
{
value: "color",
label: "Color 色彩"
label: "Color 色彩",
},
{
value: "typography",
label: "Typography 字体"
label: "Typography 字体",
},
{
value: "icon",
label: "Icon 图标"
label: "Icon 图标",
},
{
value: "button",
label: "Button 按钮"
}
]
label: "Button 按钮",
},
],
},
{
value: "form",
@ -77,61 +77,61 @@ export default [
children: [
{
value: "radio",
label: "Radio 单选框"
label: "Radio 单选框",
},
{
value: "checkbox",
label: "Checkbox 多选框"
label: "Checkbox 多选框",
},
{
value: "input",
label: "Input 输入框"
label: "Input 输入框",
},
{
value: "input-number",
label: "InputNumber 计数器"
label: "InputNumber 计数器",
},
{
value: "select",
label: "Select 选择器"
label: "Select 选择器",
},
{
value: "cascader",
label: "Cascader 级联选择器"
label: "Cascader 级联选择器",
},
{
value: "switch",
label: "Switch 开关"
label: "Switch 开关",
},
{
value: "slider",
label: "Slider 滑块"
label: "Slider 滑块",
},
{
value: "time-picker",
label: "TimePicker 时间选择器"
label: "TimePicker 时间选择器",
},
{
value: "date-picker",
label: "DatePicker 日期选择器"
label: "DatePicker 日期选择器",
},
{
value: "datetime-picker",
label: "DateTimePicker 日期时间选择器"
label: "DateTimePicker 日期时间选择器",
},
{
value: "upload",
label: "Upload 上传"
label: "Upload 上传",
},
{
value: "rate",
label: "Rate 评分"
label: "Rate 评分",
},
{
value: "form1",
label: "Form 表单"
}
]
label: "Form 表单",
},
],
},
{
value: "data",
@ -139,29 +139,29 @@ export default [
children: [
{
value: "table",
label: "Table 表格"
label: "Table 表格",
},
{
value: "tag",
label: "Tag 标签"
label: "Tag 标签",
},
{
value: "progress",
label: "Progress 进度条"
label: "Progress 进度条",
},
{
value: "tree",
label: "Tree 树形控件"
label: "Tree 树形控件",
},
{
value: "pagination",
label: "Pagination 分页"
label: "Pagination 分页",
},
{
value: "badge",
label: "Badge 标记"
}
]
label: "Badge 标记",
},
],
},
{
value: "notice",
@ -169,25 +169,25 @@ export default [
children: [
{
value: "alert",
label: "Alert 警告"
label: "Alert 警告",
},
{
value: "loading",
label: "Loading 加载"
label: "Loading 加载",
},
{
value: "message",
label: "Message 消息提示"
label: "Message 消息提示",
},
{
value: "message-box",
label: "MessageBox 弹框"
label: "MessageBox 弹框",
},
{
value: "notification",
label: "Notification 通知"
}
]
label: "Notification 通知",
},
],
},
{
value: "navigation",
@ -195,25 +195,25 @@ export default [
children: [
{
value: "menu",
label: "NavMenu 导航菜单"
label: "NavMenu 导航菜单",
},
{
value: "tabs",
label: "Tabs 标签页"
label: "Tabs 标签页",
},
{
value: "breadcrumb",
label: "Breadcrumb 面包屑"
label: "Breadcrumb 面包屑",
},
{
value: "dropdown",
label: "Dropdown 下拉菜单"
label: "Dropdown 下拉菜单",
},
{
value: "steps",
label: "Steps 步骤条"
}
]
label: "Steps 步骤条",
},
],
},
{
value: "others",
@ -221,31 +221,31 @@ export default [
children: [
{
value: "dialog",
label: "Dialog 对话框"
label: "Dialog 对话框",
},
{
value: "tooltip",
label: "Tooltip 文字提示"
label: "Tooltip 文字提示",
},
{
value: "popover",
label: "Popover 弹出框"
label: "Popover 弹出框",
},
{
value: "card",
label: "Card 卡片"
label: "Card 卡片",
},
{
value: "carousel",
label: "Carousel 走马灯"
label: "Carousel 走马灯",
},
{
value: "collapse",
label: "Collapse 折叠面板"
}
]
}
]
label: "Collapse 折叠面板",
},
],
},
],
},
{
value: "ziyuan",
@ -253,16 +253,16 @@ export default [
children: [
{
value: "axure",
label: "Axure Components"
label: "Axure Components",
},
{
value: "sketch",
label: "Sketch Templates"
label: "Sketch Templates",
},
{
value: "jiaohu",
label: "组件交互文档"
}
]
}
label: "组件交互文档",
},
],
},
];

View File

@ -7,25 +7,25 @@ import { cloneDeep } from "lodash-es";
const openStatus = [
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
{ 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 = [
{ value: "1", label: "打开(open)", color: "success" },
{ value: "2", label: "停止(stop)", color: "cyan" },
{ value: "0", label: "关闭(close)", color: "red" }
{ value: "0", label: "关闭(close)", color: "red" },
];
const textStatus = [
{ id: "1", text: "打开", color: "success" },
{ id: "2", text: "停止", color: "cyan" },
{ id: "0", text: "关闭", color: "red" }
{ id: "0", text: "关闭", color: "red" },
];
let manyStatus = [
{ value: "1", label: "打开", color: "success", icon: "ion:radio-button-on" },
{ 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[] = [];
for (let i = 0; i < 100; i++) {
@ -54,9 +54,9 @@ export default [
return {
code: 0,
msg: "success",
data: openStatus
data: openStatus,
};
}
},
},
{
path: "/mock/dicts/_OpenStatusEnum2",
@ -65,9 +65,9 @@ export default [
return {
code: 0,
msg: "success",
data: textStatus
data: textStatus,
};
}
},
},
{
path: "/mock/dicts/ManyOpenStatusEnum",
@ -76,9 +76,9 @@ export default [
return {
code: 0,
msg: "success",
data: manyStatus
data: manyStatus,
};
}
},
},
{
path: "/mock/dicts/moreOpenStatusEnum",
@ -87,9 +87,9 @@ export default [
return {
code: 0,
msg: "success",
data: moreOpenStatus
data: moreOpenStatus,
};
}
},
},
{
path: "/mock/dicts/cascaderData",
@ -98,9 +98,9 @@ export default [
return {
code: 0,
msg: "success",
data: cascaderData
data: cascaderData,
};
}
},
},
{
path: "/mock/dicts/pca",
@ -110,9 +110,9 @@ export default [
return {
code: 0,
msg: "success",
data: data
data: data,
};
}
},
},
{
path: "/mock/dicts/littlePca",
@ -121,9 +121,9 @@ export default [
return {
code: 0,
msg: "success",
data: pcaDataLittle
data: pcaDataLittle,
};
}
},
},
{
path: "/mock/tree/GetTreeChildrenByParentId",
@ -133,9 +133,9 @@ export default [
return {
code: 0,
msg: "success",
data: list
data: list,
};
}
},
},
{
path: "/mock/tree/GetNodesByValues",
@ -145,8 +145,8 @@ export default [
return {
code: 0,
msg: "success",
data: list
data: list,
};
}
}
},
},
];

View File

@ -9,13 +9,13 @@ export default [
children: [
{
code: "3",
name: "海淀"
name: "海淀",
},
{
code: "4",
name: "朝阳"
}
]
name: "朝阳",
},
],
},
{
code: "5",
@ -23,15 +23,15 @@ export default [
children: [
{
code: "6",
name: "海淀郊区"
name: "海淀郊区",
},
{
code: "7",
name: "朝阳郊区"
}
]
}
]
name: "朝阳郊区",
},
],
},
],
},
{
code: "11",
@ -43,13 +43,13 @@ export default [
children: [
{
code: "13",
name: "南山"
name: "南山",
},
{
code: "14",
name: "福田"
}
]
name: "福田",
},
],
},
{
code: "15",
@ -57,14 +57,14 @@ export default [
children: [
{
code: "16",
name: "南山郊区"
name: "南山郊区",
},
{
code: "17",
name: "福田郊区"
}
]
}
]
}
name: "福田郊区",
},
],
},
],
},
];

View File

@ -17,7 +17,7 @@ export const TreeNodesLazyLoader = {
if (!(values instanceof Array)) {
values = [values];
}
return getPcasData().then((data) => {
return getPcasData().then(data => {
const nodes = [];
for (const value of values) {
const found = this.getNode(data, value);
@ -44,7 +44,7 @@ export const TreeNodesLazyLoader = {
}
},
getChildren(parent: any) {
return getPcasData().then((data) => {
return getPcasData().then(data => {
const list = this.getChildrenByParent(parent, data);
if (list == null) {
return [];
@ -85,5 +85,5 @@ export const TreeNodesLazyLoader = {
}
console.log("found children:", newList);
return newList;
}
},
};

View File

@ -38,7 +38,7 @@ list.forEach((apiFile: any) => {
const req = {
body: data,
params: params
params: params,
};
const ret = await item.handle(req);
utils.logger.debug("response:", ret);

View File

@ -10,5 +10,5 @@ function install(app: App, options: any = {}) {
}
export default {
install
install,
};

View File

@ -2,7 +2,7 @@ import { request } from "/src/api/service";
export async function getPermissions() {
const ret = await request({
url: "/sys/authority/user/permissions",
method: "post"
method: "post",
});
// 如果使用你自己的后端,需要在此处将返回结果改造为本模块需要的结构
// 结构详情,请参考示例中打印的日志 ”获取权限数据成功:{...}“ (实际上就是“资源管理”页面中列出来的数据)

View File

@ -7,5 +7,5 @@ const install = function (app: any) {
export default {
install,
...permission
...permission,
};

View File

@ -7,5 +7,5 @@ export default {
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el);
}
}
},
};

View File

@ -6,7 +6,7 @@ export * from "./errors";
export function usePermission() {
return {
...util
...util,
};
}
@ -19,5 +19,5 @@ export default {
// 通过路由守卫,在登录成功后拦截路由,从后台加载权限数据
// 然后将权限数据转化为菜单和路由,添加到系统中
registerRouterHook();
}
},
};

View File

@ -56,7 +56,7 @@ export const usePermissionStore = defineStore({
id: "app.permission",
state: (): PermissionState => ({
permissions: [],
inited: false
inited: false,
}),
getters: {
// @ts-ignore
@ -68,7 +68,7 @@ export const usePermissionStore = defineStore({
isInited() {
// @ts-ignore
return this.inited;
}
},
},
actions: {
init({ permissions }: any) {
@ -101,6 +101,6 @@ export const usePermissionStore = defineStore({
}
}
this.resolve(permissionTree);
}
}
},
},
});

View File

@ -47,16 +47,16 @@ export function useCrudPermission({ permission }: UseCrudPermissionProps) {
{
actionbar: {
buttons: {
add: { show: hasActionPermission("add") }
}
add: { show: hasActionPermission("add") },
},
},
rowHandle: {
buttons: {
edit: { show: hasActionPermission("edit") },
remove: { show: hasActionPermission("remove") },
view: { show: hasActionPermission("view") }
}
}
view: { show: hasActionPermission("view") },
},
},
},
extra
);

View File

@ -26,7 +26,7 @@ const util = {
message.error("对不起,您没有权限执行此操作");
throw new NoPermissionError();
}
}
},
};
export default util;

View File

@ -6,7 +6,7 @@ import { createRouterGuard } from "/@/router/guard";
const router = createRouter({
history: createWebHashHistory(),
routes
routes,
});
/**

View File

@ -1,74 +1,69 @@
.ant-layout .ant-layout-sider{
background-color: #ebf1f6;
}
.ant-layout .ant-layout-header{
.ant-layout .ant-layout-sider {
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;
}
.fs-multiple-page-control-group .fs-multiple-page-control-btn .ant-btn{
border-bottom-left-radius:0;
border-bottom-right-radius:0;
.fs-multiple-page-control-group .fs-multiple-page-control-btn .ant-btn {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ant-menu-horizontal{
.ant-menu-horizontal {
border-bottom: 0;
}
.fs-framework .header-menu{
.fs-framework .header-menu {
overflow-y: hidden;
}
.ant-btn.ant-btn-icon-only{
padding-inline:revert;
.ant-btn.ant-btn-icon-only {
padding-inline: revert;
}
.fs-form-wrapper .fs-form-header {
padding-right: 30px !important;
}
.fs-values-format .fs-tag{
.fs-values-format .fs-tag {
display: inline-flex;
.fs-icon{
.fs-icon {
margin-right: 3px;
}
}
.fs-search .ant-row{
.fs-search .ant-row {
}
//适配手机端
.ant-tour{
max-width: 90vw
.ant-tour {
max-width: 90vw;
}
.fs-page{
.fs-page-header{
.fs-page {
.fs-page-header {
background-color: hsl(var(--card));
}
.fs-crud-table{
.fs-crud-table {
background-color: hsl(var(--card));
}
}
footer{
footer {
background-color: hsl(var(--card)) !important;
}
.ant-select-multiple .ant-select-selection-item-remove{
.ant-select-multiple .ant-select-selection-item-remove {
display: flex;
align-items: center;
}
.ant-progress.ant-progress-show-info .ant-progress-outer {
margin-inline-end: calc(-3em - 8px);
padding-inline-end: calc(3em + 8px);
}
}

View File

@ -2,18 +2,17 @@
display: inline-flex;
justify-content: center;
align-items: center;
font-size:16px;
font-size: 16px;
}
.fs-icon {
font-size:16px;
font-size: 16px;
}
.ant-btn {
display: inline-flex;
justify-content: center;
align-items: center;
.fs-iconify{
.fs-iconify {
margin-right: 5px;
}
}
@ -37,7 +36,6 @@
align-items: center;
}
.ant-drawer-content {
&.fullscreen {
position: fixed;
@ -51,10 +49,9 @@
}
}
.icon-button {
cursor: pointer;
font-size: 22px
font-size: 22px;
}
.ant-drawer {
@ -76,7 +73,7 @@
margin: 20px;
}
.fs-crud-table{
.fs-crud-table {
.ant-table-body {
height: 60vh;
table {
@ -84,40 +81,39 @@
}
}
body a{
color: #1890ff;
&:hover{
body a {
color: #1890ff;
&:hover {
color: #40a9ff;
}
}
span.fs-icon-svg{
span.fs-icon-svg {
display: inline-flex;
align-items: center;
}
.ant-btn .fs-icon:last-child{
margin-right:0px
.ant-btn .fs-icon:last-child {
margin-right: 0px;
}
.fs-iconify fs-icon{
svg{
vertical-align:0 !important;
.fs-iconify fs-icon {
svg {
vertical-align: 0 !important;
}
}
.fs-button{
span{
&:first-child{
.fs-button {
span {
&:first-child {
margin-right: 5px;
}
&:last-child{
&:last-child {
margin-left: 5px;
}
}
.fs-icon,.fs-button-icon{
.fs-icon,
.fs-button-icon {
margin: 0 !important;
}
}
}

View File

@ -1,12 +1,13 @@
@import './theme/index.less';
@import './theme/default.less';
@import './scroll.less';
@import './transition.less';
@import './fix-windicss.less';
@import './antdv4.less';
@import './certd.less';
@import "./theme/index.less";
@import "./theme/default.less";
@import "./scroll.less";
@import "./transition.less";
@import "./fix-windicss.less";
@import "./antdv4.less";
@import "./certd.less";
html, body {
html,
body {
margin: 0;
padding: 0;
height: 100%;
@ -15,10 +16,15 @@ html, body {
}
div#app {
height: 100%
height: 100%;
}
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
margin-bottom: 0;
margin-top: 0;
}
@ -30,17 +36,14 @@ h1, h2, h3, h4, h5, h6 {
margin-right: 5px;
}
.ant-btn-link {
height: 24px;
}
.ant-input-affix-wrapper {
padding: 4px 11px;
}
.anticon {
vertical-align: 0 !important;
}
@ -54,17 +57,17 @@ h1, h2, h3, h4, h5, h6 {
justify-content: center;
align-items: center;
}
.flex-vc{
.flex-vc {
align-items: center;
}
.flex-vb{
.flex-vb {
align-items: baseline;
}
.flex-o {
display: flex !important;
align-items: center;
}
.flex-baseline{
.flex-baseline {
display: flex !important;
align-items: baseline;
}
@ -94,77 +97,76 @@ h1, h2, h3, h4, h5, h6 {
display: flex;
flex-direction: column;
}
.align-left{
.align-left {
text-align: left;
}
.align-right{
.align-right {
text-align: right;
}
.scroll-y {
overflow-y: auto;
}
.m-0{
margin:0 !important;
.m-0 {
margin: 0 !important;
}
.m-2{
margin:2px !important;
.m-2 {
margin: 2px !important;
}
.m-3{
margin:3px !important;
.m-3 {
margin: 3px !important;
}
.m-5{
margin:5px !important;
.m-5 {
margin: 5px !important;
}
.m-10 {
margin: 10px !important;;
margin: 10px !important;
}
.m-20{
margin:20px !important;
.m-20 {
margin: 20px !important;
}
.mb-2 {
margin-bottom: 2px !important;;
margin-bottom: 2px !important;
}
.mb-5 {
margin-bottom: 5px !important;;
margin-bottom: 5px !important;
}
.ml-5 {
margin-left: 5px !important;;
margin-left: 5px !important;
}
.ml-10 {
margin-left: 10px !important;;
margin-left: 10px !important;
}
.ml-20 {
margin-left: 20px !important;;
margin-left: 20px !important;
}
.ml-15 {
margin-left: 15px !important;;
margin-left: 15px !important;
}
.mr-5 {
margin-right: 5px !important;;
margin-right: 5px !important;
}
.mr-10 {
margin-right: 10px !important;;
margin-right: 10px !important;
}
.mr-20 {
margin-right: 20px !important;;
margin-right: 20px !important;
}
.mr-15 {
margin-right: 15px !important;;
margin-right: 15px !important;
}
.mt-5 {
margin-top: 5px !important;;
margin-top: 5px !important;
}
.mt-10 {
@ -172,20 +174,19 @@ h1, h2, h3, h4, h5, h6 {
}
.mb-10 {
margin-bottom: 10px !important;;
margin-bottom: 10px !important;
}
.p-5 {
padding: 5px !important;;
padding: 5px !important;
}
.p-10 {
padding: 10px !important;;
padding: 10px !important;
}
.p-20 {
padding: 20px !important;;
padding: 20px !important;
}
.ellipsis {
white-space: nowrap;
@ -212,7 +213,7 @@ h1, h2, h3, h4, h5, h6 {
border-bottom: 1px solid #dedede;
}
.color-plus{
.color-plus {
color: #c5913f;
}
.color-blue {
@ -230,8 +231,8 @@ h1, h2, h3, h4, h5, h6 {
color: gray;
}
.iconify{
//font-size: 16px;
.iconify {
//font-size: 16px;
}
.icon-box {
@ -250,7 +251,6 @@ h1, h2, h3, h4, h5, h6 {
color: #c5913f !important;
}
.deleted {
color: #c7c7c7;
//删除线
@ -268,18 +268,17 @@ h1, h2, h3, h4, h5, h6 {
.helper {
color: #aeaeae;
font-size: 12px;
margin-top:3px;
margin-bottom:3px;
&.error{
margin-top: 3px;
margin-bottom: 3px;
&.error {
color: #ff4d4f;
}
}
.fs-copyable {
display: inline-flex;
.text {
flex: 1
flex: 1;
}
.copy-button {
@ -288,23 +287,20 @@ h1, h2, h3, h4, h5, h6 {
}
}
.fs-16{
font-size: 16px;
.fs-16 {
font-size: 16px;
}
.w-50\%{
width: 50%;
.w-50\% {
width: 50%;
}
.ant-drawer-content-wrapper {
max-width: 90vw;
}
.block-title{
.block-title {
font-size: 14px;
padding:10px;
color : #6e6e6e;
}
padding: 10px;
color: #6e6e6e;
}

View File

@ -1,3 +1,3 @@
img.ant-image-preview-img{
img.ant-image-preview-img {
display: initial;
}

View File

@ -5,14 +5,14 @@
::-webkit-scrollbar-track {
width: 8px;
background: rgba(#101F1C, 0.1);
background: rgba(#101f1c, 0.1);
-webkit-border-radius: 2em;
-moz-border-radius: 2em;
border-radius: 2em;
}
::-webkit-scrollbar-thumb {
// background-color: rgba(#101F1C, 0.5);
// background-color: rgba(#101F1C, 0.5);
background-clip: padding-box;
min-height: 28px;
-webkit-border-radius: 2em;
@ -23,6 +23,5 @@
}
::-webkit-scrollbar-thumb:hover {
//background-color: rgba(#101F1C, 1);
}

View File

@ -1,27 +1,27 @@
.ant-layout{
.ant-layout {
background-color: @colorPrimaryBg;
}
.ant-layout-header {
background-color: @colorPrimaryBg
background-color: @colorPrimaryBg;
}
.ant-layout-sider {
background-color:@colorPrimaryBg
}
.ant-menu{
background-color: @colorPrimaryBg;
&.ant-menu-submenu-popup{
}
.ant-menu {
background-color: @colorPrimaryBg;
&.ant-menu-submenu-popup {
background-color: transparent;
}
}
.aside-menu{
.ant-menu-submenu > .ant-menu{
background-color:@colorPrimaryBg
.aside-menu {
.ant-menu-submenu > .ant-menu {
background-color: @colorPrimaryBg;
}
.ant-menu-item-active{
.ant-menu-item-active {
background-color: @bg-menu-item-color;
}
.ant-menu-item-selected{
.ant-menu-item-selected {
background-color: @bg-menu-item-color !important;
}
}

View File

@ -1,3 +1,3 @@
@bg-menu-item-color:hsla(0,0%,100%,.5);
@colorPrimaryBg:#ebf1f6;
@primary-color: #1890ff;
@bg-menu-item-color:hsla (0,0%,100%,.5);
@colorPrimaryBg: #ebf1f6;
@primary-color: #1890ff;

View File

@ -10,7 +10,7 @@
// 过渡动画 横向渐变
.fade-transverse-leave-active,
.fade-transverse-enter-active {
transition: all .5s;
transition: all 0.5s;
}
.fade-transverse-enter-from {
opacity: 0;
@ -24,7 +24,7 @@
// 过渡动画 缩放渐变
.fade-scale-leave-active,
.fade-scale-enter-active {
transition: all .3s;
transition: all 0.3s;
}
.fade-scale-enter {
opacity: 0;

View File

@ -13,7 +13,7 @@ export function useReference(formItem: any) {
const ctx = {
compute,
asyncCompute,
computed
computed,
};
const script = formItem.mergeScript;
const func = new Function("ctx", script);
@ -30,7 +30,7 @@ export function useReference(formItem: any) {
formItem.helper = {
render: () => {
return <div innerHTML={helper}></div>;
}
},
};
}
}

View File

@ -1,4 +1,4 @@
import {forEach} from "lodash-es";
import { forEach } from "lodash-es";
export function getEnvValue(key: string) {
// @ts-ignore
return import.meta.env["VITE_APP_" + key];

View File

@ -21,5 +21,5 @@ async function open(path: any) {
}
export const routerUtils = {
open
open,
};

View File

@ -1,5 +1,5 @@
export function eachTree(tree: any[], callback: (item: any) => void) {
tree.forEach((item) => {
tree.forEach(item => {
callback(item);
if (item.children) {
eachTree(item.children, callback);
@ -19,5 +19,5 @@ export function treeMap(tree: any[], mapFunc: (item: any) => {}) {
export const treeUtils = {
eachTree,
treeMap
treeMap,
};

View File

@ -25,12 +25,12 @@ interface Props {
}
defineOptions({
name: "AccessControl"
name: "AccessControl",
});
const props = withDefaults(defineProps<Props>(), {
codes: () => [],
type: "role"
type: "role",
});
const { hasAccessByCodes, hasAccessByRoles } = useAccess();

View File

@ -12,7 +12,7 @@ async function generateAccessible(mode: AccessModeType, options: GenerateMenuAnd
const root = router.getRoutes().find((item: any) => item.path === "/");
// 动态添加到router实例内
accessibleRoutes.forEach((route) => {
accessibleRoutes.forEach(route => {
if (root && !route.meta?.noBasicLayout) {
// 为了兼容之前的版本用法如果包含子路由则将component移除以免出现多层BasicLayout
// 如果你的项目已经跟进了本次修改移除了所有自定义菜单首级的BasicLayout可以将这段if代码删除
@ -62,7 +62,7 @@ async function generateRoutes(mode: AccessModeType, options: GenerateMenuAndRout
*
* 1. redirectredirect
*/
resultRoutes = mapTree(resultRoutes, (route) => {
resultRoutes = mapTree(resultRoutes, route => {
// 如果有redirect或者没有子路由则直接返回
if (route.redirect || !route.children || route.children.length === 0) {
return route;

View File

@ -4,23 +4,17 @@
* @Example v-access:role="[ROLE_NAME]" or v-access:role="ROLE_NAME"
* @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(
el: Element,
binding: DirectiveBinding<string | string[]>,
) {
function isAccessible(el: Element, binding: DirectiveBinding<string | string[]>) {
const { accessMode, hasAccessByCodes, hasAccessByRoles } = useAccess();
const value = binding.value;
if (!value) return;
const authMethod =
accessMode.value === 'frontend' && binding.arg === 'role'
? hasAccessByRoles
: hasAccessByCodes;
const authMethod = accessMode.value === "frontend" && binding.arg === "role" ? hasAccessByRoles : hasAccessByCodes;
const values = Array.isArray(value) ? value : [value];
@ -38,5 +32,5 @@ const authDirective: Directive = {
};
export function registerAccessDirective(app: App) {
app.directive('access', authDirective);
app.directive("access", authDirective);
}

View File

@ -1,4 +1,4 @@
export { default as AccessControl } from './access-control.vue';
export * from './accessible';
export * from './directive';
export * from './use-access';
export { default as AccessControl } from "./access-control.vue";
export * from "./accessible";
export * from "./directive";
export * from "./use-access";

View File

@ -17,7 +17,7 @@ function useAccess() {
*/
function hasAccessByRoles(roles: string[]) {
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;
}
@ -29,15 +29,15 @@ function useAccess() {
function hasAccessByCodes(codes: string[]) {
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;
}
async function toggleAccessMode() {
updatePreferences({
app: {
accessMode: preferences.app.accessMode === "frontend" ? "backend" : "frontend"
}
accessMode: preferences.app.accessMode === "frontend" ? "backend" : "frontend",
},
});
}
@ -45,7 +45,7 @@ function useAccess() {
accessMode,
hasAccessByCodes,
hasAccessByRoles,
toggleAccessMode
toggleAccessMode,
};
}

View File

@ -74,7 +74,7 @@ const props = withDefaults(defineProps<Props>(), {
afterFetch: undefined,
modelPropName: "modelValue",
api: undefined,
options: () => []
options: () => [],
});
const emit = defineEmits<{
@ -96,13 +96,13 @@ const getOptions = computed(() => {
const refOptionsData = unref(refOptions);
function transformData(data: OptionsItem[]): OptionsItem[] {
return data.map((item) => {
return data.map(item => {
const value = get(item, valueField);
return {
...objectOmit(item, [labelField, valueField, childrenField]),
label: get(item, labelField),
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}`]),
...(props.visibleEvent
? {
[props.visibleEvent]: handleFetchForVisible
[props.visibleEvent]: handleFetchForVisible,
}
: {})
: {}),
};
});

View File

@ -1 +1 @@
export { default as ApiComponent } from './api-component.vue';
export { default as ApiComponent } from "./api-component.vue";

View File

@ -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() {
const points = reactive<CaptchaPoint[]>([]);

View File

@ -1,6 +1,6 @@
export { default as PointSelectionCaptcha } from './point-selection-captcha/index.vue';
export { default as PointSelectionCaptchaCard } 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 SliderCaptcha } from './slider-captcha/index.vue';
export { default as SliderRotateCaptcha } from './slider-rotate-captcha/index.vue';
export type * from './types';
export { default as SliderCaptcha } from "./slider-captcha/index.vue";
export { default as SliderRotateCaptcha } from "./slider-rotate-captcha/index.vue";
export type * from "./types";

View File

@ -1,23 +1,23 @@
<script setup lang="ts">
import type { CaptchaPoint, PointSelectionCaptchaProps } from '../types';
import type { CaptchaPoint, PointSelectionCaptchaProps } from "../types";
import { RotateCw } from '/@/vben/icons';
import { $t } from '/@/locales';
import { RotateCw } from "/@/vben/icons";
import { $t } from "/@/locales";
import { VbenButton, VbenIconButton } from '/@/vben/shadcn-ui';
import { VbenButton, VbenIconButton } from "/@/vben/shadcn-ui";
import { useCaptchaPoints } from '../hooks/useCaptchaPoints';
import CaptchaCard from './point-selection-captcha-card.vue';
import { useCaptchaPoints } from "../hooks/useCaptchaPoints";
import CaptchaCard from "./point-selection-captcha-card.vue";
const props = withDefaults(defineProps<PointSelectionCaptchaProps>(), {
height: '220px',
hintImage: '',
hintText: '',
paddingX: '12px',
paddingY: '16px',
height: "220px",
hintImage: "",
hintText: "",
paddingX: "12px",
paddingY: "16px",
showConfirm: false,
title: '',
width: '300px',
title: "",
width: "300px",
});
const emit = defineEmits<{
click: [CaptchaPoint];
@ -27,7 +27,7 @@ const emit = defineEmits<{
const { addPoint, clearPoints, points } = useCaptchaPoints();
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;
@ -43,15 +43,15 @@ function getElementPosition(element: HTMLElement) {
function handleClick(e: MouseEvent) {
try {
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 mouseX = e.clientX + window.scrollX;
const mouseY = e.clientY + window.scrollY;
if (typeof mouseX !== 'number' || typeof mouseY !== 'number') {
throw new TypeError('Mouse coordinates not found');
if (typeof mouseX !== "number" || typeof mouseY !== "number") {
throw new TypeError("Mouse coordinates not found");
}
const xPos = mouseX - domX;
@ -61,7 +61,7 @@ function handleClick(e: MouseEvent) {
//
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;
}
@ -77,11 +77,11 @@ function handleClick(e: MouseEvent) {
addPoint(point);
emit('click', point);
emit("click", point);
e.stopPropagation();
e.preventDefault();
} catch (error) {
console.error('Error in handleClick:', error);
console.error("Error in handleClick:", error);
}
}
@ -89,58 +89,40 @@ function clear() {
try {
clearPoints();
} catch (error) {
console.error('Error in clear:', error);
console.error("Error in clear:", error);
}
}
function handleRefresh() {
try {
clear();
emit('refresh');
emit("refresh");
} catch (error) {
console.error('Error in handleRefresh:', error);
console.error("Error in handleRefresh:", error);
}
}
function handleConfirm() {
if (!props.showConfirm) return;
try {
emit('confirm', points, clear);
emit("confirm", points, clear);
} catch (error) {
console.error('Error in handleConfirm:', error);
console.error("Error in handleConfirm:", error);
}
}
</script>
<template>
<CaptchaCard
:captcha-image="captchaImage"
:height="height"
:padding-x="paddingX"
:padding-y="paddingY"
:title="title"
:width="width"
@click="handleClick"
>
<CaptchaCard :captcha-image="captchaImage" :height="height" :padding-x="paddingX" :padding-y="paddingY" :title="title" :width="width" @click="handleClick">
<template #title>
<slot name="title">{{ $t('ui.captcha.title') }}</slot>
<slot name="title">{{ $t("ui.captcha.title") }}</slot>
</template>
<template #extra>
<VbenIconButton
:aria-label="$t('ui.captcha.refreshAriaLabel')"
class="ml-1"
@click="handleRefresh"
>
<VbenIconButton :aria-label="$t('ui.captcha.refreshAriaLabel')" class="ml-1" @click="handleRefresh">
<RotateCw class="size-5" />
</VbenIconButton>
<VbenButton
v-if="showConfirm"
:aria-label="$t('ui.captcha.confirmAriaLabel')"
class="ml-2"
size="sm"
@click="handleConfirm"
>
{{ $t('ui.captcha.confirm') }}
<VbenButton v-if="showConfirm" :aria-label="$t('ui.captcha.confirmAriaLabel')" class="ml-2" size="sm" @click="handleConfirm">
{{ $t("ui.captcha.confirm") }}
</VbenButton>
</template>
@ -159,17 +141,9 @@ function handleConfirm() {
{{ index + 1 }}
</div>
<template #footer>
<img
v-if="hintImage"
:alt="$t('ui.captcha.alt')"
: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}` }}
<img v-if="hintImage" :alt="$t('ui.captcha.alt')" :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>
</template>
</CaptchaCard>

View File

@ -1,24 +1,18 @@
<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 {
Card,
CardContent,
CardFooter,
CardHeader,
CardTitle,
} from '/@/vben/shadcn-ui';
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "/@/vben/shadcn-ui";
const props = withDefaults(defineProps<PointSelectionCaptchaCardProps>(), {
height: '220px',
paddingX: '12px',
paddingY: '16px',
title: '',
width: '300px',
height: "220px",
paddingX: "12px",
paddingY: "16px",
title: "",
width: "300px",
});
const emit = defineEmits<{
@ -26,7 +20,7 @@ const emit = defineEmits<{
}>();
const parseValue = (value: number | string) => {
if (typeof value === 'number') {
if (typeof value === "number") {
return value;
}
const parsed = Number.parseFloat(value);
@ -46,7 +40,7 @@ const captchaStyles = computed(() => {
});
function handleClick(e: MouseEvent) {
emit('click', e);
emit("click", e);
}
</script>
<template>
@ -54,7 +48,7 @@ function handleClick(e: MouseEvent) {
<CardHeader class="p-0">
<CardTitle id="captcha-title" class="flex items-center justify-between">
<template v-if="$slots.title">
<slot name="title">{{ $t('ui.captcha.title') }}</slot>
<slot name="title">{{ $t("ui.captcha.title") }}</slot>
</template>
<template v-else>
<span>{{ title }}</span>
@ -65,14 +59,7 @@ function handleClick(e: MouseEvent) {
</CardTitle>
</CardHeader>
<CardContent class="relative mt-2 flex w-full overflow-hidden rounded p-0">
<img
v-show="captchaImage"
:alt="$t('ui.captcha.alt')"
:src="captchaImage"
:style="captchaStyles"
class="relative z-10"
@click="handleClick"
/>
<img v-show="captchaImage" :alt="$t('ui.captcha.alt')" :src="captchaImage" :style="captchaStyles" class="relative z-10" @click="handleClick" />
<div class="absolute inset-0">
<slot></slot>
</div>

View File

@ -1,29 +1,25 @@
<script setup lang="ts">
import type {
CaptchaVerifyPassingData,
SliderCaptchaProps,
SliderRotateVerifyPassingData,
} from '../types';
import type { 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 SliderCaptchaBar from './slider-captcha-bar.vue';
import SliderCaptchaContent from './slider-captcha-content.vue';
import SliderCaptchaAction from "./slider-captcha-action.vue";
import SliderCaptchaBar from "./slider-captcha-bar.vue";
import SliderCaptchaContent from "./slider-captcha-content.vue";
const props = withDefaults(defineProps<SliderCaptchaProps>(), {
actionStyle: () => ({}),
barStyle: () => ({}),
contentStyle: () => ({}),
isSlot: false,
successText: '',
text: '',
successText: "",
text: "",
wrapperStyle: () => ({}),
});
@ -49,21 +45,21 @@ defineExpose({
resume,
});
const wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef');
const barRef = useTemplateRef<typeof SliderCaptchaBar>('barRef');
const contentRef = useTemplateRef<typeof SliderCaptchaContent>('contentRef');
const actionRef = useTemplateRef<typeof SliderCaptchaAction>('actionRef');
const wrapperRef = useTemplateRef<HTMLDivElement>("wrapperRef");
const barRef = useTemplateRef<typeof SliderCaptchaBar>("barRef");
const contentRef = useTemplateRef<typeof SliderCaptchaContent>("contentRef");
const actionRef = useTemplateRef<typeof SliderCaptchaAction>("actionRef");
watch(
() => state.isPassing,
(isPassing) => {
isPassing => {
if (isPassing) {
const { endTime, startTime } = state;
const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) });
emit("success", { isPassing, time: time.toFixed(1) });
modelValue.value = isPassing;
}
},
}
);
watchEffect(() => {
@ -71,9 +67,9 @@ watchEffect(() => {
});
function getEventPageX(e: MouseEvent | TouchEvent): number {
if ('pageX' in e) {
if ("pageX" in e) {
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 0;
@ -84,14 +80,9 @@ function handleDragStart(e: MouseEvent | TouchEvent) {
return;
}
if (!actionRef.value) return;
emit('start', e);
emit("start", e);
state.moveDistance =
getEventPageX(e) -
Number.parseInt(
actionRef.value.getStyle().left.replace('px', '') || '0',
10,
);
state.moveDistance = getEventPageX(e) - Number.parseInt(actionRef.value.getStyle().left.replace("px", "") || "0", 10);
state.startTime = Date.now();
state.isMoving = true;
}
@ -112,7 +103,7 @@ function handleDragMoving(e: MouseEvent | TouchEvent) {
const { actionWidth, offset, wrapperWidth } = getOffset(actionEl.getEl());
const moveX = getEventPageX(e) - moveDistance;
emit('move', {
emit("move", {
event: e,
moveDistance,
moveX,
@ -133,7 +124,7 @@ function handleDragMoving(e: MouseEvent | TouchEvent) {
function handleDragOver(e: MouseEvent | TouchEvent) {
const { isMoving, isPassing, moveDistance } = state;
if (isMoving && !isPassing) {
emit('end', e);
emit("end", e);
const actionEl = actionRef.value;
const barEl = unref(barRef);
if (!actionEl || !barEl) return;
@ -185,12 +176,12 @@ function resume() {
const contentEl = unref(contentRef);
if (!actionEl || !barEl || !contentEl) return;
contentEl.getEl().style.width = '100%';
contentEl.getEl().style.width = "100%";
state.toLeft = true;
useTimeoutFn(() => {
state.toLeft = false;
actionEl.setLeft('0');
barEl.setWidth('0');
actionEl.setLeft("0");
barEl.setWidth("0");
}, 300);
}
</script>
@ -198,12 +189,7 @@ function resume() {
<template>
<div
ref="wrapperRef"
:class="
cn(
'border-border bg-background-deep relative flex h-10 w-full items-center overflow-hidden rounded-md border text-center',
props.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)"
:style="wrapperStyle"
@mouseleave="handleDragOver"
@mousemove="handleDragMoving"
@ -211,31 +197,14 @@ function resume() {
@touchend="handleDragOver"
@touchmove="handleDragMoving"
>
<SliderCaptchaBar
ref="barRef"
: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')"
>
<SliderCaptchaBar ref="barRef" :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>
<slot :is-passing="state.isPassing" name="text"></slot>
</template>
</SliderCaptchaContent>
<SliderCaptchaAction
ref="actionRef"
:action-style="actionStyle"
:is-passing="state.isPassing"
:to-left="state.toLeft"
@mousedown="handleDragStart"
@touchstart="handleDragStart"
>
<SliderCaptchaAction ref="actionRef" :action-style="actionStyle" :is-passing="state.isPassing" :to-left="state.toLeft" @mousedown="handleDragStart" @touchstart="handleDragStart">
<template v-if="$slots.actionIcon" #icon>
<slot :is-passing="state.isPassing" name="actionIcon"></slot>
</template>

View File

@ -1,11 +1,11 @@
<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<{
actionStyle: CSSProperties;
@ -13,9 +13,9 @@ const props = defineProps<{
toLeft: boolean;
}>();
const actionRef = useTemplateRef<HTMLDivElement>('actionRef');
const actionRef = useTemplateRef<HTMLDivElement>("actionRef");
const left = ref('0');
const left = ref("0");
const style = computed(() => {
const { actionStyle } = props;

View File

@ -1,16 +1,16 @@
<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<{
barStyle: CSSProperties;
toLeft: boolean;
}>();
const barRef = useTemplateRef<HTMLDivElement>('barRef');
const barRef = useTemplateRef<HTMLDivElement>("barRef");
const width = ref('0');
const width = ref("0");
const style = computed(() => {
const { barStyle } = props;
@ -31,10 +31,5 @@ defineExpose({
</script>
<template>
<div
ref="barRef"
:class="toLeft && 'transition-width !w-0 duration-300'"
:style="style"
class="bg-success absolute h-full"
></div>
<div ref="barRef" :class="toLeft && 'transition-width !w-0 duration-300'" :style="style" class="bg-success absolute h-full"></div>
</template>

View File

@ -1,9 +1,9 @@
<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<{
contentStyle: CSSProperties;
@ -12,7 +12,7 @@ const props = defineProps<{
text: string;
}>();
const contentRef = useTemplateRef<HTMLDivElement>('contentRef');
const contentRef = useTemplateRef<HTMLDivElement>("contentRef");
const style = computed(() => {
const { contentStyle } = props;

View File

@ -1,33 +1,28 @@
<script setup lang="ts">
import type {
CaptchaVerifyPassingData,
SliderCaptchaActionType,
SliderRotateCaptchaProps,
SliderRotateVerifyPassingData,
} from '../types';
import type { 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>(), {
defaultTip: '',
defaultTip: "",
diffDegree: 20,
imageSize: 260,
maxDegree: 300,
minDegree: 120,
src: '',
src: "",
});
const emit = defineEmits<{
success: [CaptchaVerifyPassingData];
}>();
const slideBarRef = useTemplateRef<SliderCaptchaActionType>('slideBarRef');
const slideBarRef = useTemplateRef<SliderCaptchaActionType>("slideBarRef");
const state = reactive({
currentRotate: 0,
@ -45,14 +40,14 @@ const modalValue = defineModel<boolean>({ default: false });
watch(
() => state.isPassing,
(isPassing) => {
isPassing => {
if (isPassing) {
const { endTime, startTime } = state;
const time = (endTime - startTime) / 1000;
emit('success', { isPassing, time: time.toFixed(1) });
emit("success", { isPassing, time: time.toFixed(1) });
}
modalValue.value = isPassing;
},
}
);
const getImgWrapStyleRef = computed(() => {
@ -67,7 +62,7 @@ const getImgWrapStyleRef = computed(() => {
const getFactorRef = computed(() => {
const { maxDegree, minDegree } = props;
if (minDegree > maxDegree) {
console.warn('minDegree should not be greater than maxDegree');
console.warn("minDegree should not be greater than maxDegree");
}
if (minDegree === maxDegree) {
@ -88,18 +83,14 @@ function handleDragBarMove(data: SliderRotateVerifyPassingData) {
if (denominator === 0) {
return;
}
const currentRotate = Math.ceil(
(moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef),
);
const currentRotate = Math.ceil((moveX / denominator) * 1.5 * maxDegree! * unref(getFactorRef));
state.currentRotate = currentRotate;
setImgRotate(state.randomRotate - currentRotate);
}
function handleImgOnLoad() {
const { maxDegree, minDegree } = props;
const ranRotate = Math.floor(
minDegree! + Math.random() * (maxDegree! - minDegree!),
); //
const ranRotate = Math.floor(minDegree! + Math.random() * (maxDegree! - minDegree!)); //
state.randomRotate = ranRotate;
setImgRotate(ranRotate);
}
@ -147,15 +138,11 @@ function resume() {
}
const imgCls = computed(() => {
return state.toOrigin ? ['transition-transform duration-300'] : [];
return state.toOrigin ? ["transition-transform duration-300"] : [];
});
const verifyTip = computed(() => {
return state.isPassing
? $t('ui.captcha.sliderRotateSuccessTip', [
((state.endTime - state.startTime) / 1000).toFixed(1),
])
: $t('ui.captcha.sliderRotateFailTip');
return state.isPassing ? $t("ui.captcha.sliderRotateSuccessTip", [((state.endTime - state.startTime) / 1000).toFixed(1)]) : $t("ui.captcha.sliderRotateFailTip");
});
defineExpose({
@ -165,22 +152,9 @@ defineExpose({
<template>
<div class="relative flex flex-col items-center">
<div
:style="getImgWrapStyleRef"
class="border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md"
>
<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 :style="getImgWrapStyleRef" class="border-border relative cursor-pointer overflow-hidden rounded-full border shadow-md">
<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
v-if="state.showTip"
:class="{
@ -191,20 +165,12 @@ defineExpose({
{{ verifyTip }}
</div>
<div v-if="!state.dragging" class="bg-black/30">
{{ defaultTip || $t('ui.captcha.sliderRotateDefaultTip') }}
{{ defaultTip || $t("ui.captcha.sliderRotateDefaultTip") }}
</div>
</div>
</div>
<SliderCaptcha
ref="slideBarRef"
v-model="modalValue"
class="mt-5"
is-slot
@end="handleDragEnd"
@move="handleDragBarMove"
@start="handleStart"
>
<SliderCaptcha 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">
<slot :name="key" v-bind="slotProps"></slot>
</template>

View File

@ -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 {
/**
@ -54,8 +54,7 @@ export interface PointSelectionCaptchaCardProps {
width?: number | string;
}
export interface PointSelectionCaptchaProps
extends PointSelectionCaptchaCardProps {
export interface PointSelectionCaptchaProps extends PointSelectionCaptchaCardProps {
/**
*
* @default false

View File

@ -1,18 +1,14 @@
<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 {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from '/@/vben/shadcn-ui';
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "/@/vben/shadcn-ui";
import Page from '../page/page.vue';
import Page from "../page/page.vue";
defineOptions({
name: 'ColPage',
name: "ColPage",
inheritAttrs: false,
});
@ -33,7 +29,7 @@ const delegatedSlots = computed(() => {
const resultSlots: string[] = [];
for (const key of Object.keys(slots)) {
if (!['default', 'left'].includes(key)) {
if (!["default", "left"].includes(key)) {
resultSlots.push(key);
}
}
@ -58,23 +54,12 @@ defineExpose({
<template>
<Page v-bind="delegatedProps">
<!-- 继承默认的slot -->
<template
v-for="slotName in delegatedSlots"
:key="slotName"
#[slotName]="slotProps"
>
<template v-for="slotName in delegatedSlots" :key="slotName" #[slotName]="slotProps">
<slot :name="slotName" v-bind="slotProps"></slot>
</template>
<ResizablePanelGroup class="w-full" direction="horizontal">
<ResizablePanel
ref="leftPanelRef"
:collapsed-size="leftCollapsedWidth"
:collapsible="leftCollapsible"
:default-size="leftWidth"
:max-size="leftMaxWidth"
:min-size="leftMinWidth"
>
<ResizablePanel ref="leftPanelRef" :collapsed-size="leftCollapsedWidth" :collapsible="leftCollapsible" :default-size="leftWidth" :max-size="leftMaxWidth" :min-size="leftMinWidth">
<template #default="slotProps">
<slot
name="left"
@ -86,18 +71,8 @@ defineExpose({
></slot>
</template>
</ResizablePanel>
<ResizableHandle
v-if="resizable"
:style="{ backgroundColor: splitLine ? undefined : 'transparent' }"
:with-handle="splitHandle"
/>
<ResizablePanel
:collapsed-size="rightCollapsedWidth"
:collapsible="rightCollapsible"
:default-size="rightWidth"
:max-size="rightMaxWidth"
:min-size="rightMinWidth"
>
<ResizableHandle v-if="resizable" :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>
<slot></slot>
</template>

View File

@ -1,2 +1,2 @@
export { default as ColPage } from './col-page.vue';
export * from './types';
export { default as ColPage } from "./col-page.vue";
export * from "./types";

View File

@ -1,4 +1,4 @@
import type { PageProps } from '../page/types';
import type { PageProps } from "../page/types";
export interface ColPageProps extends PageProps {
/**

View File

@ -1,23 +1,23 @@
<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>(), {
startVal: 0,
duration: 2000,
separator: ',',
decimal: '.',
separator: ",",
decimal: ".",
decimals: 0,
delay: 0,
transition: () => TransitionPresets.easeOutExpo,
});
const emit = defineEmits(['started', 'finished']);
const emit = defineEmits(["started", "finished"]);
const lastValue = ref(props.startVal);
@ -27,9 +27,9 @@ onMounted(() => {
watch(
() => props.endVal,
(val) => {
val => {
lastValue.value = val;
},
}
);
const currentValue = useTransition(lastValue, {
@ -37,62 +37,43 @@ const currentValue = useTransition(lastValue, {
duration: computed(() => props.duration),
disabled: computed(() => props.disabled),
transition: computed(() => {
return isString(props.transition)
? TransitionPresets[props.transition]
: props.transition;
return isString(props.transition) ? TransitionPresets[props.transition] : props.transition;
}),
onStarted() {
emit('started');
emit("started");
},
onFinished() {
emit('finished');
emit("finished");
},
});
const numMain = computed(() => {
const result = currentValue.value
.toFixed(props.decimals)
.split('.')[0]
.split(".")[0]
?.replaceAll(/\B(?=(\d{3})+(?!\d))/g, props.separator);
return result;
});
const numDec = computed(() => {
return (
props.decimal + currentValue.value.toFixed(props.decimals).split('.')[1]
);
return props.decimal + currentValue.value.toFixed(props.decimals).split(".")[1];
});
</script>
<template>
<div class="count-to" v-bind="$attrs">
<slot name="prefix">
<div
class="count-to-prefix"
:style="prefixStyle"
:class="prefixClass"
v-if="prefix"
>
<div v-if="prefix" class="count-to-prefix" :style="prefixStyle" :class="prefixClass">
{{ prefix }}
</div>
</slot>
<div class="count-to-main" :class="mainClass" :style="mainStyle">
<span>{{ numMain }}</span>
<span
class="count-to-main-decimal"
v-if="decimals > 0"
:class="decimalClass"
:style="decimalStyle"
>
<span v-if="decimals > 0" class="count-to-main-decimal" :class="decimalClass" :style="decimalStyle">
{{ numDec }}
</span>
</div>
<slot name="suffix">
<div
class="count-to-suffix"
:style="suffixStyle"
:class="suffixClass"
v-if="suffix"
>
<div v-if="suffix" class="count-to-suffix" :style="suffixStyle" :class="suffixClass">
{{ suffix }}
</div>
</slot>
@ -112,7 +93,7 @@ const numDec = computed(() => {
}
&-main {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
// font-size: 1.5rem;
&-decimal {

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