Compare commits
5 Commits
d403891446
...
safe-form
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96728d87fd | ||
|
|
66419d22d4 | ||
|
|
18cb623730 | ||
|
|
4c7f052ea1 | ||
|
|
13b535c530 |
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@@ -266,6 +266,7 @@ declare global {
|
|||||||
const useRoute: typeof import('vue-router')['useRoute']
|
const useRoute: typeof import('vue-router')['useRoute']
|
||||||
const useRouter: typeof import('vue-router')['useRouter']
|
const useRouter: typeof import('vue-router')['useRouter']
|
||||||
const useSSRWidth: typeof import('@vueuse/core')['useSSRWidth']
|
const useSSRWidth: typeof import('@vueuse/core')['useSSRWidth']
|
||||||
|
const useSafeNForm: typeof import('./src/utils/use-safe-n-form-auto-imports')['useSafeNForm']
|
||||||
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
const useScreenOrientation: typeof import('@vueuse/core')['useScreenOrientation']
|
||||||
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
const useScreenSafeArea: typeof import('@vueuse/core')['useScreenSafeArea']
|
||||||
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
const useScriptTag: typeof import('@vueuse/core')['useScriptTag']
|
||||||
@@ -608,6 +609,7 @@ declare module 'vue' {
|
|||||||
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
|
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
|
||||||
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
|
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
|
||||||
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
|
readonly useSSRWidth: UnwrapRef<typeof import('@vueuse/core')['useSSRWidth']>
|
||||||
|
readonly useSafeNForm: UnwrapRef<typeof import('./src/utils/use-safe-n-form-auto-imports')['useSafeNForm']>
|
||||||
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
readonly useScreenOrientation: UnwrapRef<typeof import('@vueuse/core')['useScreenOrientation']>
|
||||||
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
readonly useScreenSafeArea: UnwrapRef<typeof import('@vueuse/core')['useScreenSafeArea']>
|
||||||
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
|
readonly useScriptTag: UnwrapRef<typeof import('@vueuse/core')['useScriptTag']>
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
"@unhead/vue": "^2.0.14",
|
"@unhead/vue": "^2.0.14",
|
||||||
"@vueuse/core": "^13.9.0",
|
"@vueuse/core": "^13.9.0",
|
||||||
"highlight.js": "^11.11.1",
|
"highlight.js": "^11.11.1",
|
||||||
|
"lodash-es": "^4.17.21",
|
||||||
"naive-ui": "^2.43.1",
|
"naive-ui": "^2.43.1",
|
||||||
"pinia": "^3.0.3",
|
"pinia": "^3.0.3",
|
||||||
"primeicons": "^7.0.0",
|
"primeicons": "^7.0.0",
|
||||||
@@ -89,6 +90,7 @@
|
|||||||
"@tsconfig/node22": "^22.0.2",
|
"@tsconfig/node22": "^22.0.2",
|
||||||
"@types/html-minifier-terser": "^7.0.2",
|
"@types/html-minifier-terser": "^7.0.2",
|
||||||
"@types/jsdom": "^27.0.0",
|
"@types/jsdom": "^27.0.0",
|
||||||
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^22.18.1",
|
"@types/node": "^22.18.1",
|
||||||
"@vant/auto-import-resolver": "^1.3.0",
|
"@vant/auto-import-resolver": "^1.3.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
@@ -124,6 +126,7 @@
|
|||||||
"stylelint-define-config": "^16.24.0",
|
"stylelint-define-config": "^16.24.0",
|
||||||
"svgo": "^4.0.0",
|
"svgo": "^4.0.0",
|
||||||
"tinyglobby": "^0.2.15",
|
"tinyglobby": "^0.2.15",
|
||||||
|
"type-fest": "^5.1.0",
|
||||||
"typescript": "~5.9.2",
|
"typescript": "~5.9.2",
|
||||||
"unocss": "^66.5.1",
|
"unocss": "^66.5.1",
|
||||||
"unocss-preset-animations": "^1.2.1",
|
"unocss-preset-animations": "^1.2.1",
|
||||||
|
|||||||
23
pnpm-lock.yaml
generated
23
pnpm-lock.yaml
generated
@@ -38,6 +38,9 @@ importers:
|
|||||||
highlight.js:
|
highlight.js:
|
||||||
specifier: ^11.11.1
|
specifier: ^11.11.1
|
||||||
version: 11.11.1
|
version: 11.11.1
|
||||||
|
lodash-es:
|
||||||
|
specifier: ^4.17.21
|
||||||
|
version: 4.17.21
|
||||||
naive-ui:
|
naive-ui:
|
||||||
specifier: ^2.43.1
|
specifier: ^2.43.1
|
||||||
version: 2.43.1(vue@3.5.22(typescript@5.9.2))
|
version: 2.43.1(vue@3.5.22(typescript@5.9.2))
|
||||||
@@ -120,6 +123,9 @@ importers:
|
|||||||
'@types/jsdom':
|
'@types/jsdom':
|
||||||
specifier: ^27.0.0
|
specifier: ^27.0.0
|
||||||
version: 27.0.0
|
version: 27.0.0
|
||||||
|
'@types/lodash-es':
|
||||||
|
specifier: ^4.17.12
|
||||||
|
version: 4.17.12
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^22.18.1
|
specifier: ^22.18.1
|
||||||
version: 22.18.11
|
version: 22.18.11
|
||||||
@@ -225,6 +231,9 @@ importers:
|
|||||||
tinyglobby:
|
tinyglobby:
|
||||||
specifier: ^0.2.15
|
specifier: ^0.2.15
|
||||||
version: 0.2.15
|
version: 0.2.15
|
||||||
|
type-fest:
|
||||||
|
specifier: ^5.1.0
|
||||||
|
version: 5.1.0
|
||||||
typescript:
|
typescript:
|
||||||
specifier: ~5.9.2
|
specifier: ~5.9.2
|
||||||
version: 5.9.2
|
version: 5.9.2
|
||||||
@@ -5167,6 +5176,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
|
resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
|
|
||||||
|
tagged-tag@1.0.0:
|
||||||
|
resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
terser@5.44.0:
|
terser@5.44.0:
|
||||||
resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==}
|
resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
@@ -5259,6 +5272,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
|
resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
type-fest@5.1.0:
|
||||||
|
resolution: {integrity: sha512-wQ531tuWvB6oK+pchHIu5lHe5f5wpSCqB8Kf4dWQRbOYc9HTge7JL0G4Qd44bh6QuJCccIzL3bugb8GI0MwHrg==}
|
||||||
|
engines: {node: '>=20'}
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@@ -11011,6 +11028,8 @@ snapshots:
|
|||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
strip-ansi: 6.0.1
|
strip-ansi: 6.0.1
|
||||||
|
|
||||||
|
tagged-tag@1.0.0: {}
|
||||||
|
|
||||||
terser@5.44.0:
|
terser@5.44.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/source-map': 0.3.11
|
'@jridgewell/source-map': 0.3.11
|
||||||
@@ -11088,6 +11107,10 @@ snapshots:
|
|||||||
|
|
||||||
type-fest@0.20.2: {}
|
type-fest@0.20.2: {}
|
||||||
|
|
||||||
|
type-fest@5.1.0:
|
||||||
|
dependencies:
|
||||||
|
tagged-tag: 1.0.0
|
||||||
|
|
||||||
typed-array-buffer@1.0.3:
|
typed-array-buffer@1.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bound: 1.0.4
|
call-bound: 1.0.4
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { RouterView } from 'vue-router';
|
|
||||||
import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
||||||
|
import A2use from './utils/a2use.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -9,6 +9,8 @@ import AppNaiveUIProvider from './AppNaiveUIProvider.vue';
|
|||||||
<Toast />
|
<Toast />
|
||||||
|
|
||||||
<AppNaiveUIProvider>
|
<AppNaiveUIProvider>
|
||||||
<RouterView />
|
<!-- <RouterView /> -->
|
||||||
|
|
||||||
|
<A2use></A2use>
|
||||||
</AppNaiveUIProvider>
|
</AppNaiveUIProvider>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
90
src/utils/a2use.vue
Normal file
90
src/utils/a2use.vue
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { get, set } from 'lodash-es';
|
||||||
|
|
||||||
|
const { formValue, SafeNForm, SafeNFormItem, formRef } = useSafeNForm({
|
||||||
|
initialFormValue: {
|
||||||
|
/* ⚠️:
|
||||||
|
如果没使用`SafeNFormItem`,
|
||||||
|
这里`user`对象没有手动初始化的话,将会报错:
|
||||||
|
`can't access property "name", $setup.formValue.user is undefined`
|
||||||
|
*/
|
||||||
|
user: {
|
||||||
|
name: '',
|
||||||
|
age: 0,
|
||||||
|
},
|
||||||
|
phone: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSetUserName() {
|
||||||
|
set(formValue.value, 'user.name', 'Alice');
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleValidateClick() {
|
||||||
|
formRef.value?.validate((errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
window.$nMessage!.success('Valid');
|
||||||
|
} else {
|
||||||
|
console.log(errors);
|
||||||
|
window.$nMessage!.error('Invalid');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div p-4>
|
||||||
|
<div border>
|
||||||
|
<div>
|
||||||
|
<pre>formValue: {{ JSON.stringify(formValue, null, 2) }}</pre>
|
||||||
|
</div>
|
||||||
|
<div>get(formValue, 'user.name'): {{ get(formValue, 'user.name') }}</div>
|
||||||
|
</div>
|
||||||
|
<n-space mt-4>
|
||||||
|
<n-button @click="handleSetUserName">Set user.name</n-button>
|
||||||
|
</n-space>
|
||||||
|
|
||||||
|
<n-space item-class="flex-1">
|
||||||
|
<n-card title="SafeForm" mt-4>
|
||||||
|
<SafeNForm label-placement="left" label-width="auto">
|
||||||
|
<n-form-item
|
||||||
|
label="姓名"
|
||||||
|
path="user.name"
|
||||||
|
:rule="{ required: true, message: '请输入姓名', trigger: ['input'] }"
|
||||||
|
>
|
||||||
|
<n-input v-model:value="formValue.user.name" placeholder="输入姓名" />
|
||||||
|
</n-form-item>
|
||||||
|
|
||||||
|
<SafeNFormItem
|
||||||
|
#default="{ value, setValue }"
|
||||||
|
:rule="{ required: true, message: '请输入姓名', trigger: ['input'] }"
|
||||||
|
label="姓名"
|
||||||
|
path="user.name"
|
||||||
|
>
|
||||||
|
<NInput :value="value" placeholder="SafeNFormItem" @update:value="setValue" />
|
||||||
|
</SafeNFormItem>
|
||||||
|
|
||||||
|
<n-form-item
|
||||||
|
label="电话号码"
|
||||||
|
path="phone"
|
||||||
|
:rule="{ required: true, message: '请输入电话号码', trigger: ['blur'] }"
|
||||||
|
>
|
||||||
|
<n-input v-model:value="formValue.phone" placeholder="电话号码" />
|
||||||
|
</n-form-item>
|
||||||
|
|
||||||
|
<SafeNFormItem
|
||||||
|
label="电话号码"
|
||||||
|
path="phone"
|
||||||
|
:rule="{ required: true, message: '请输入电话号码', trigger: ['blur'] }"
|
||||||
|
>
|
||||||
|
<!-- 如果没有提供插槽,会默认渲染一个`<NInput>` -->
|
||||||
|
</SafeNFormItem>
|
||||||
|
|
||||||
|
<n-form-item>
|
||||||
|
<n-button attr-type="button" @click="handleValidateClick"> 验证 </n-button>
|
||||||
|
</n-form-item>
|
||||||
|
</SafeNForm>
|
||||||
|
</n-card>
|
||||||
|
</n-space>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
121
src/utils/use-safe-n-form-auto-imports.tsx
Normal file
121
src/utils/use-safe-n-form-auto-imports.tsx
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
/**
|
||||||
|
* https://www.naiveui.com/zh-CN/os-theme/components/form
|
||||||
|
*
|
||||||
|
* FIXME: `NForm` 和 `NFormItem` 的 slots 还没有实现。`NFormItemGi`组件。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { get, set } from 'lodash-es';
|
||||||
|
import type { FormInst, FormItemProps, FormProps } from 'naive-ui';
|
||||||
|
import { NForm, NFormItem, formItemProps, NInput, formProps } from 'naive-ui';
|
||||||
|
import type { Get, Paths } from 'type-fest';
|
||||||
|
import type { SlotsType } from 'vue';
|
||||||
|
import { Comment } from 'vue';
|
||||||
|
|
||||||
|
type UseSafeNFormOptions<FormValue> = {
|
||||||
|
initialFormValue?: FormValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function useSafeNForm<T extends Record<string, any> = Record<string, unknown>>(
|
||||||
|
options: UseSafeNFormOptions<T> = {},
|
||||||
|
) {
|
||||||
|
const formRef = ref<FormInst | null>(null);
|
||||||
|
const formValue = ref<T>(structuredClone(toRaw(options.initialFormValue)) || ({} as T));
|
||||||
|
|
||||||
|
// 创建类型安全的 Form 组件
|
||||||
|
type SafeNFormProps = FormProps;
|
||||||
|
|
||||||
|
type SafeNFormSlots = SlotsType<{
|
||||||
|
default?: { count?: number };
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const SafeNForm = defineComponent<SafeNFormProps, /* Emits */ [], /* EE */ never, SafeNFormSlots>(
|
||||||
|
(props, ctx) => {
|
||||||
|
return () => (
|
||||||
|
<NForm
|
||||||
|
{...props}
|
||||||
|
model={formValue.value}
|
||||||
|
ref={(inst) => {
|
||||||
|
formRef.value = inst as unknown as FormInst;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{ctx.slots.default?.({})}
|
||||||
|
</NForm>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'SafeNForm',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: formProps,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// <<<<<
|
||||||
|
|
||||||
|
// >>>>> 创建类型安全的 FormItem 组件
|
||||||
|
type SafeNFormItemProps<P extends Paths<T> & string> = FormItemProps & {
|
||||||
|
path: P;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SafeNFormItemDefaultSlot<P extends Paths<T> & string> = {
|
||||||
|
value: Get<T, P>;
|
||||||
|
setValue: (val: Get<T, P>) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const SafeNFormItemImpl = defineComponent<
|
||||||
|
SafeNFormItemProps<Paths<T> & string>,
|
||||||
|
/* Emits */ [],
|
||||||
|
/* EE */ never,
|
||||||
|
SlotsType<{ default: SafeNFormItemDefaultSlot<Paths<T> & string> }>
|
||||||
|
>(
|
||||||
|
(props, ctx) => {
|
||||||
|
return () => {
|
||||||
|
const value = get(formValue.value, props.path);
|
||||||
|
function setValue(val: typeof value) {
|
||||||
|
set(formValue.value, props.path, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultSlotContent = ctx.slots.default?.({
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 如果没有提供默认 slot 内容,则渲染一个 NInput 作为默认输入组件
|
||||||
|
const renderDefaultNInput = defaultSlotContent?.some((v) => v.type !== Comment) ? null : (
|
||||||
|
<NInput value={value} onUpdate:value={setValue} />
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NFormItem {...props} path={props.path}>
|
||||||
|
{defaultSlotContent}
|
||||||
|
{renderDefaultNInput}
|
||||||
|
</NFormItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'SafeNFormItem',
|
||||||
|
inheritAttrs: false,
|
||||||
|
props: Object.keys(formItemProps) as unknown as [keyof FormItemProps],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Expose a generic constructor so template literals narrow `path`.
|
||||||
|
type SafeNFormItemComponent = {
|
||||||
|
new <P extends Paths<T> & string>(
|
||||||
|
props: SafeNFormItemProps<P>,
|
||||||
|
): {
|
||||||
|
$props: SafeNFormItemProps<P>;
|
||||||
|
$slots: {
|
||||||
|
default?: (scope: SafeNFormItemDefaultSlot<P>) => VNode[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
const SafeNFormItem = SafeNFormItemImpl as SafeNFormItemComponent;
|
||||||
|
// <<<<<
|
||||||
|
|
||||||
|
return {
|
||||||
|
formValue,
|
||||||
|
SafeNForm,
|
||||||
|
SafeNFormItem,
|
||||||
|
formRef,
|
||||||
|
};
|
||||||
|
}
|
||||||
6
worker-configuration.d.ts
vendored
6
worker-configuration.d.ts
vendored
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
// Generated by Wrangler by running `wrangler types` (hash: b18d7aec4937222767b077e627f9f927)
|
// Generated by Wrangler by running `wrangler types` (hash: 0003c1b3cd56e3cc5549efef6b4c6d3d)
|
||||||
// Runtime types generated with workerd@1.20251008.0 2025-09-09
|
// Runtime types generated with workerd@1.20251008.0 2025-09-09
|
||||||
declare namespace Cloudflare {
|
declare namespace Cloudflare {
|
||||||
interface GlobalProps {
|
interface GlobalProps {
|
||||||
@@ -7,13 +7,13 @@ declare namespace Cloudflare {
|
|||||||
}
|
}
|
||||||
interface Env {
|
interface Env {
|
||||||
KV: KVNamespace;
|
KV: KVNamespace;
|
||||||
|
VITE_APP_BUILD_TIME: string;
|
||||||
|
VITE_APP_BUILD_COMMIT: string;
|
||||||
VITE_BUILD_SOURCE_MAP: string;
|
VITE_BUILD_SOURCE_MAP: string;
|
||||||
VITE_BUILD_MINIFY: string;
|
VITE_BUILD_MINIFY: string;
|
||||||
VITE_CLOUDFLARE_SERVER_ENABLED: string;
|
VITE_CLOUDFLARE_SERVER_ENABLED: string;
|
||||||
VITE_APP_TITLE: string;
|
VITE_APP_TITLE: string;
|
||||||
VITE_APP_BASE: string;
|
VITE_APP_BASE: string;
|
||||||
VITE_APP_BUILD_COMMIT: string;
|
|
||||||
VITE_APP_BUILD_TIME: string;
|
|
||||||
VITE_APP_ENABLE_VUE_DEVTOOLS: string;
|
VITE_APP_ENABLE_VUE_DEVTOOLS: string;
|
||||||
VITE_APP_MENU_SHOW_DEMOS: string;
|
VITE_APP_MENU_SHOW_DEMOS: string;
|
||||||
VITE_APP_MENU_SHOW_ORDER: string;
|
VITE_APP_MENU_SHOW_ORDER: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user