Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
This commit is contained in:
commit
fbb0d641db
@ -1,4 +1,8 @@
|
||||
export default defineEventHandler((event) => {
|
||||
event.node.res.setHeader(
|
||||
'Access-Control-Allow-Origin',
|
||||
event.headers.get('Origin') ?? '*',
|
||||
);
|
||||
if (event.method === 'OPTIONS') {
|
||||
event.node.res.statusCode = 204;
|
||||
event.node.res.statusMessage = 'No Content.';
|
||||
|
@ -9,7 +9,8 @@ export default defineNitroConfig({
|
||||
cors: true,
|
||||
headers: {
|
||||
'Access-Control-Allow-Credentials': 'true',
|
||||
'Access-Control-Allow-Headers': '*',
|
||||
'Access-Control-Allow-Headers':
|
||||
'Accept, Authorization, Content-Length, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With',
|
||||
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Expose-Headers': '*',
|
||||
|
@ -2,6 +2,7 @@ import { createApp, watchEffect } from 'vue';
|
||||
|
||||
import { registerAccessDirective } from '@vben/access';
|
||||
import { initTippy } from '@vben/common-ui';
|
||||
import { MotionPlugin } from '@vben/plugins/motion';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { initStores } from '@vben/stores';
|
||||
import '@vben/styles';
|
||||
@ -49,6 +50,9 @@ async function bootstrap(namespace: string) {
|
||||
// 配置路由及路由守卫
|
||||
app.use(router);
|
||||
|
||||
// 配置Motion插件
|
||||
app.use(MotionPlugin);
|
||||
|
||||
// 动态更新标题
|
||||
watchEffect(() => {
|
||||
if (preferences.app.dynamicTitle) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
社区交流群主要是为了方便大家交流,提问,解答问题,分享经验等。偏自助方式,如果你有问题,可以通过以下方式加入社区交流群:
|
||||
|
||||
- [QQ频道](https://pd.qq.com/s/16p8lvvob):推荐!!!主要提供问题解答,分享经验等。
|
||||
- QQ群:[大群](https://qm.qq.com/q/MEmHoCLbG0),[1群](https://qm.qq.com/q/YacMHPYAMu)、[2群](https://qm.qq.com/q/ajVKZvFICk)、[3群](https://qm.qq.com/q/36zdwThP2E),[4群](https://qm.qq.com/q/sCzSlm3504),主要使用者的交流群。
|
||||
- QQ群:[大群](https://qm.qq.com/q/MEmHoCLbG0),[1群](https://qm.qq.com/q/YacMHPYAMu)、[2群](https://qm.qq.com/q/ajVKZvFICk)、[3群](https://qm.qq.com/q/36zdwThP2E),[4群](https://qm.qq.com/q/sCzSlm3504),[5群](https://qm.qq.com/q/ya9XrtbS6s),主要的使用者交流群。
|
||||
- [Discord](https://discord.com/invite/VU62jTecad): 主要提供问题解答,分享经验等。
|
||||
|
||||
::: tip
|
||||
|
@ -336,7 +336,7 @@ function autofocus() {
|
||||
>
|
||||
<VbenRenderContent
|
||||
:content="customContentRender[name]"
|
||||
v-bind="{ ...renderSlotProps, $formContext: slotProps }"
|
||||
v-bind="{ ...renderSlotProps, formContext: slotProps }"
|
||||
/>
|
||||
</template>
|
||||
<!-- <slot></slot> -->
|
||||
|
@ -47,6 +47,7 @@
|
||||
"vue": "catalog:",
|
||||
"vue-codemirror6": "1.3.4",
|
||||
"vue-json-pretty": "^2.4.0",
|
||||
"vue-json-viewer": "catalog:",
|
||||
"vue-router": "catalog:",
|
||||
"vue-tippy": "catalog:"
|
||||
},
|
||||
|
123
packages/effects/common-ui/src/components/count-to/count-to.vue
Normal file
123
packages/effects/common-ui/src/components/count-to/count-to.vue
Normal file
@ -0,0 +1,123 @@
|
||||
<script lang="ts" setup>
|
||||
import type { CountToProps } from './types';
|
||||
|
||||
import { computed, onMounted, ref, watch } from 'vue';
|
||||
|
||||
import { isString } from '@vben-core/shared/utils';
|
||||
|
||||
import { TransitionPresets, useTransition } from '@vueuse/core';
|
||||
|
||||
const props = withDefaults(defineProps<CountToProps>(), {
|
||||
startVal: 0,
|
||||
duration: 2000,
|
||||
separator: ',',
|
||||
decimal: '.',
|
||||
decimals: 0,
|
||||
delay: 0,
|
||||
transition: () => TransitionPresets.easeOutExpo,
|
||||
});
|
||||
|
||||
const emit = defineEmits(['started', 'finished']);
|
||||
|
||||
const lastValue = ref(props.startVal);
|
||||
|
||||
onMounted(() => {
|
||||
lastValue.value = props.endVal;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.endVal,
|
||||
(val) => {
|
||||
lastValue.value = val;
|
||||
},
|
||||
);
|
||||
|
||||
const currentValue = useTransition(lastValue, {
|
||||
delay: computed(() => props.delay),
|
||||
duration: computed(() => props.duration),
|
||||
disabled: computed(() => props.disabled),
|
||||
transition: computed(() => {
|
||||
return isString(props.transition)
|
||||
? TransitionPresets[props.transition]
|
||||
: props.transition;
|
||||
}),
|
||||
onStarted() {
|
||||
emit('started');
|
||||
},
|
||||
onFinished() {
|
||||
emit('finished');
|
||||
},
|
||||
});
|
||||
|
||||
const numMain = computed(() => {
|
||||
const result = currentValue.value
|
||||
.toFixed(props.decimals)
|
||||
.split('.')[0]
|
||||
?.replaceAll(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
return result;
|
||||
});
|
||||
|
||||
const numDec = computed(() => {
|
||||
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"
|
||||
>
|
||||
{{ 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"
|
||||
>
|
||||
{{ numDec }}
|
||||
</span>
|
||||
</div>
|
||||
<slot name="suffix">
|
||||
<div
|
||||
class="count-to-suffix"
|
||||
:style="suffixStyle"
|
||||
:class="suffixClass"
|
||||
v-if="suffix"
|
||||
>
|
||||
{{ suffix }}
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.count-to {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
&-prefix {
|
||||
// font-size: 1rem;
|
||||
}
|
||||
|
||||
&-suffix {
|
||||
// font-size: 1rem;
|
||||
}
|
||||
|
||||
&-main {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
// font-size: 1.5rem;
|
||||
|
||||
&-decimal {
|
||||
// font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,2 @@
|
||||
export { default as CountTo } from './count-to.vue';
|
||||
export * from './types';
|
53
packages/effects/common-ui/src/components/count-to/types.ts
Normal file
53
packages/effects/common-ui/src/components/count-to/types.ts
Normal file
@ -0,0 +1,53 @@
|
||||
import type { CubicBezierPoints, EasingFunction } from '@vueuse/core';
|
||||
|
||||
import type { StyleValue } from 'vue';
|
||||
|
||||
import { TransitionPresets as TransitionPresetsData } from '@vueuse/core';
|
||||
|
||||
export type TransitionPresets = keyof typeof TransitionPresetsData;
|
||||
|
||||
export const TransitionPresetsKeys = Object.keys(
|
||||
TransitionPresetsData,
|
||||
) as TransitionPresets[];
|
||||
|
||||
export interface CountToProps {
|
||||
/** 初始值 */
|
||||
startVal?: number;
|
||||
/** 当前值 */
|
||||
endVal: number;
|
||||
/** 是否禁用动画 */
|
||||
disabled?: boolean;
|
||||
/** 延迟动画开始的时间 */
|
||||
delay?: number;
|
||||
/** 持续时间 */
|
||||
duration?: number;
|
||||
/** 小数位数 */
|
||||
decimals?: number;
|
||||
/** 小数点 */
|
||||
decimal?: string;
|
||||
/** 分隔符 */
|
||||
separator?: string;
|
||||
/** 前缀 */
|
||||
prefix?: string;
|
||||
/** 后缀 */
|
||||
suffix?: string;
|
||||
/** 过渡效果 */
|
||||
transition?: CubicBezierPoints | EasingFunction | TransitionPresets;
|
||||
/** 整数部分的类名 */
|
||||
mainClass?: string;
|
||||
/** 小数部分的类名 */
|
||||
decimalClass?: string;
|
||||
/** 前缀部分的类名 */
|
||||
prefixClass?: string;
|
||||
/** 后缀部分的类名 */
|
||||
suffixClass?: string;
|
||||
|
||||
/** 整数部分的样式 */
|
||||
mainStyle?: StyleValue;
|
||||
/** 小数部分的样式 */
|
||||
decimalStyle?: StyleValue;
|
||||
/** 前缀部分的样式 */
|
||||
prefixStyle?: StyleValue;
|
||||
/** 后缀部分的样式 */
|
||||
suffixStyle?: StyleValue;
|
||||
}
|
@ -2,9 +2,11 @@ export * from './api-component';
|
||||
export * from './captcha';
|
||||
export * from './code-mirror';
|
||||
export * from './col-page';
|
||||
export * from './count-to';
|
||||
export * from './ellipsis-text';
|
||||
export * from './icon-picker';
|
||||
export * from './json-preview';
|
||||
export * from './json-viewer';
|
||||
export * from './markdown';
|
||||
export * from './page';
|
||||
export * from './resize';
|
||||
|
@ -0,0 +1,3 @@
|
||||
export { default as JsonViewer } from './index.vue';
|
||||
|
||||
export * from './types';
|
@ -0,0 +1,98 @@
|
||||
<script lang="ts" setup>
|
||||
import type { SetupContext } from 'vue';
|
||||
|
||||
import type { Recordable } from '@vben/types';
|
||||
|
||||
import type {
|
||||
JsonViewerAction,
|
||||
JsonViewerProps,
|
||||
JsonViewerToggle,
|
||||
JsonViewerValue,
|
||||
} from './types';
|
||||
|
||||
import { computed, useAttrs } from 'vue';
|
||||
// @ts-ignore
|
||||
import VueJsonViewer from 'vue-json-viewer';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import { isBoolean } from '@vben-core/shared/utils';
|
||||
|
||||
defineOptions({ name: 'JsonViewer' });
|
||||
|
||||
const props = withDefaults(defineProps<JsonViewerProps>(), {
|
||||
expandDepth: 1,
|
||||
copyable: false,
|
||||
sort: false,
|
||||
boxed: false,
|
||||
theme: 'default-json-theme',
|
||||
expanded: false,
|
||||
previewMode: false,
|
||||
showArrayIndex: true,
|
||||
showDoubleQuotes: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
click: [event: MouseEvent];
|
||||
copied: [event: JsonViewerAction];
|
||||
keyClick: [key: string];
|
||||
toggle: [param: JsonViewerToggle];
|
||||
valueClick: [value: JsonViewerValue];
|
||||
}>();
|
||||
|
||||
const attrs: SetupContext['attrs'] = useAttrs();
|
||||
|
||||
function handleClick(event: MouseEvent) {
|
||||
if (
|
||||
event.target instanceof HTMLElement &&
|
||||
event.target.classList.contains('jv-item')
|
||||
) {
|
||||
const pathNode = event.target.closest('.jv-push');
|
||||
if (!pathNode || !pathNode.hasAttribute('path')) {
|
||||
return;
|
||||
}
|
||||
const param: JsonViewerValue = {
|
||||
path: '',
|
||||
value: '',
|
||||
depth: 0,
|
||||
el: event.target,
|
||||
};
|
||||
|
||||
param.path = pathNode.getAttribute('path') || '';
|
||||
param.depth = Number(pathNode.getAttribute('depth')) || 0;
|
||||
|
||||
param.value = event.target.textContent || undefined;
|
||||
param.value = JSON.parse(param.value);
|
||||
emit('valueClick', param);
|
||||
}
|
||||
emit('click', event);
|
||||
}
|
||||
|
||||
const bindProps = computed<Recordable<any>>(() => {
|
||||
const copyable = {
|
||||
copyText: $t('ui.jsonViewer.copy'),
|
||||
copiedText: $t('ui.jsonViewer.copied'),
|
||||
timeout: 2000,
|
||||
...(isBoolean(props.copyable) ? {} : props.copyable),
|
||||
};
|
||||
|
||||
return {
|
||||
...props,
|
||||
...attrs,
|
||||
onCopied: (event: JsonViewerAction) => emit('copied', event),
|
||||
onKeyclick: (key: string) => emit('keyClick', key),
|
||||
onClick: (event: MouseEvent) => handleClick(event),
|
||||
copyable: props.copyable ? copyable : false,
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<VueJsonViewer v-bind="bindProps">
|
||||
<template #copy="slotProps">
|
||||
<slot name="copy" v-bind="slotProps"></slot>
|
||||
</template>
|
||||
</VueJsonViewer>
|
||||
</template>
|
||||
<style lang="scss">
|
||||
@use './style.scss';
|
||||
</style>
|
@ -0,0 +1,98 @@
|
||||
.default-json-theme {
|
||||
font-family: Consolas, Menlo, Courier, monospace;
|
||||
font-size: 14px;
|
||||
color: hsl(var(--foreground));
|
||||
white-space: nowrap;
|
||||
background: hsl(var(--background));
|
||||
|
||||
&.jv-container.boxed {
|
||||
border: 1px solid hsl(var(--border));
|
||||
}
|
||||
|
||||
.jv-ellipsis {
|
||||
display: inline-block;
|
||||
padding: 0 4px 2px;
|
||||
font-size: 0.9em;
|
||||
line-height: 0.9;
|
||||
color: hsl(var(--secondary-foreground));
|
||||
vertical-align: 2px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background-color: hsl(var(--secondary));
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.jv-button {
|
||||
color: hsl(var(--primary));
|
||||
}
|
||||
|
||||
.jv-key {
|
||||
color: hsl(var(--heavy-foreground));
|
||||
}
|
||||
|
||||
.jv-item {
|
||||
&.jv-array {
|
||||
color: hsl(var(--heavy-foreground));
|
||||
}
|
||||
|
||||
&.jv-boolean {
|
||||
color: hsl(var(--red-400));
|
||||
}
|
||||
|
||||
&.jv-function {
|
||||
color: hsl(var(--destructive-foreground));
|
||||
}
|
||||
|
||||
&.jv-number {
|
||||
color: hsl(var(--info-foreground));
|
||||
}
|
||||
|
||||
&.jv-number-float {
|
||||
color: hsl(var(--info-foreground));
|
||||
}
|
||||
|
||||
&.jv-number-integer {
|
||||
color: hsl(var(--info-foreground));
|
||||
}
|
||||
|
||||
&.jv-object {
|
||||
color: hsl(var(--accent-darker));
|
||||
}
|
||||
|
||||
&.jv-undefined {
|
||||
color: hsl(var(--secondary-foreground));
|
||||
}
|
||||
|
||||
&.jv-string {
|
||||
color: hsl(var(--primary));
|
||||
word-break: break-word;
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
&.jv-container .jv-code {
|
||||
padding: 10px;
|
||||
|
||||
&.boxed:not(.open) {
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&.open {
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.jv-toggle {
|
||||
&::before {
|
||||
padding: 0 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&::before {
|
||||
background: hsl(var(--accent-foreground));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
export interface JsonViewerProps {
|
||||
/** 要展示的结构数据 */
|
||||
value: any;
|
||||
/** 展开深度 */
|
||||
expandDepth?: number;
|
||||
/** 是否可复制 */
|
||||
copyable?: boolean;
|
||||
/** 是否排序 */
|
||||
sort?: boolean;
|
||||
/** 显示边框 */
|
||||
boxed?: boolean;
|
||||
/** 主题 */
|
||||
theme?: string;
|
||||
/** 是否展开 */
|
||||
expanded?: boolean;
|
||||
/** 时间格式化函数 */
|
||||
timeformat?: (time: Date | number | string) => string;
|
||||
/** 预览模式 */
|
||||
previewMode?: boolean;
|
||||
/** 显示数组索引 */
|
||||
showArrayIndex?: boolean;
|
||||
/** 显示双引号 */
|
||||
showDoubleQuotes?: boolean;
|
||||
}
|
||||
|
||||
export interface JsonViewerAction {
|
||||
action: string;
|
||||
text: string;
|
||||
trigger: HTMLElement;
|
||||
}
|
||||
|
||||
export interface JsonViewerValue {
|
||||
value: any;
|
||||
path: string;
|
||||
depth: number;
|
||||
el: HTMLElement;
|
||||
}
|
||||
|
||||
export interface JsonViewerToggle {
|
||||
/** 鼠标事件 */
|
||||
event: MouseEvent;
|
||||
/** 当前展开状态 */
|
||||
open: boolean;
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
import type { Arrayable, MaybeElementRef } from '@vueuse/core';
|
||||
|
||||
import type { Ref } from 'vue';
|
||||
|
||||
import { computed, onUnmounted, ref, unref, watch } from 'vue';
|
||||
|
||||
import { isFunction } from '@vben/utils';
|
||||
import { useMouseInElement } from '@vueuse/core';
|
||||
import { computed, onUnmounted, ref, watch } from 'vue';
|
||||
|
||||
import { useElementHover } from '@vueuse/core';
|
||||
|
||||
/**
|
||||
* 监测鼠标是否在元素内部,如果在元素内部则返回 true,否则返回 false
|
||||
@ -15,15 +18,19 @@ export function useHoverToggle(
|
||||
refElement: Arrayable<MaybeElementRef>,
|
||||
delay: (() => number) | number = 500,
|
||||
) {
|
||||
const isOutsides: Array<Ref<boolean>> = [];
|
||||
const isHovers: Array<Ref<boolean>> = [];
|
||||
const value = ref(false);
|
||||
const timer = ref<ReturnType<typeof setTimeout> | undefined>();
|
||||
const refs = Array.isArray(refElement) ? refElement : [refElement];
|
||||
refs.forEach((refEle) => {
|
||||
const listener = useMouseInElement(refEle, { handleOutside: true });
|
||||
isOutsides.push(listener.isOutside);
|
||||
const eleRef = computed(() => {
|
||||
const ele = unref(refEle);
|
||||
return ele instanceof Element ? ele : (ele?.$el as Element);
|
||||
});
|
||||
const isHover = useElementHover(eleRef);
|
||||
isHovers.push(isHover);
|
||||
});
|
||||
const isOutsideAll = computed(() => isOutsides.every((v) => v.value));
|
||||
const isOutsideAll = computed(() => isHovers.every((v) => !v.value));
|
||||
|
||||
function setValueDelay(val: boolean) {
|
||||
timer.value && clearTimeout(timer.value);
|
||||
|
@ -21,6 +21,10 @@
|
||||
"./vxe-table": {
|
||||
"types": "./src/vxe-table/index.ts",
|
||||
"default": "./src/vxe-table/index.ts"
|
||||
},
|
||||
"./motion": {
|
||||
"types": "./src/motion/index.ts",
|
||||
"default": "./src/motion/index.ts"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -34,6 +38,7 @@
|
||||
"@vben/types": "workspace:*",
|
||||
"@vben/utils": "workspace:*",
|
||||
"@vueuse/core": "catalog:",
|
||||
"@vueuse/motion": "catalog:",
|
||||
"echarts": "catalog:",
|
||||
"vue": "catalog:",
|
||||
"vxe-pc-ui": "catalog:",
|
||||
|
8
packages/effects/plugins/src/motion/index.ts
Normal file
8
packages/effects/plugins/src/motion/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export * from './types';
|
||||
|
||||
export {
|
||||
MotionComponent as Motion,
|
||||
MotionDirective,
|
||||
MotionGroupComponent as MotionGroup,
|
||||
MotionPlugin,
|
||||
} from '@vueuse/motion';
|
26
packages/effects/plugins/src/motion/types.ts
Normal file
26
packages/effects/plugins/src/motion/types.ts
Normal file
@ -0,0 +1,26 @@
|
||||
export const MotionPresets = [
|
||||
'fade',
|
||||
'fadeVisible',
|
||||
'fadeVisibleOnce',
|
||||
'rollBottom',
|
||||
'rollLeft',
|
||||
'rollRight',
|
||||
'rollTop',
|
||||
'rollVisibleBottom',
|
||||
'rollVisibleLeft',
|
||||
'rollVisibleRight',
|
||||
'rollVisibleTop',
|
||||
'pop',
|
||||
'popVisible',
|
||||
'popVisibleOnce',
|
||||
'slideBottom',
|
||||
'slideLeft',
|
||||
'slideRight',
|
||||
'slideTop',
|
||||
'slideVisibleBottom',
|
||||
'slideVisibleLeft',
|
||||
'slideVisibleRight',
|
||||
'slideVisibleTop',
|
||||
] as const;
|
||||
|
||||
export type MotionPreset = (typeof MotionPresets)[number];
|
@ -25,6 +25,10 @@
|
||||
"placeholder": "Select an icon",
|
||||
"search": "Search icon..."
|
||||
},
|
||||
"jsonViewer": {
|
||||
"copy": "Copy",
|
||||
"copied": "Copied"
|
||||
},
|
||||
"fallback": {
|
||||
"pageNotFound": "Oops! Page Not Found",
|
||||
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",
|
||||
|
@ -25,6 +25,10 @@
|
||||
"placeholder": "选择一个图标",
|
||||
"search": "搜索图标..."
|
||||
},
|
||||
"jsonViewer": {
|
||||
"copy": "复制",
|
||||
"copied": "已复制"
|
||||
},
|
||||
"fallback": {
|
||||
"pageNotFound": "哎呀!未找到页面",
|
||||
"pageNotFoundDesc": "抱歉,我们无法找到您要找的页面。",
|
||||
|
@ -22,23 +22,29 @@ export namespace AuthApi {
|
||||
* 登录
|
||||
*/
|
||||
export async function loginApi(data: AuthApi.LoginParams) {
|
||||
return requestClient.post<AuthApi.LoginResult>('/auth/login', data);
|
||||
return requestClient.post<AuthApi.LoginResult>('/auth/login', data, {
|
||||
withCredentials: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新accessToken
|
||||
*/
|
||||
export async function refreshTokenApi() {
|
||||
return baseRequestClient.post<AuthApi.RefreshTokenResult>('/auth/refresh', {
|
||||
withCredentials: true,
|
||||
});
|
||||
return baseRequestClient.post<AuthApi.RefreshTokenResult>(
|
||||
'/auth/refresh',
|
||||
null,
|
||||
{
|
||||
withCredentials: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
export async function logoutApi() {
|
||||
return baseRequestClient.post('/auth/logout', {
|
||||
return baseRequestClient.post('/auth/logout', null, {
|
||||
withCredentials: true,
|
||||
});
|
||||
}
|
||||
|
@ -111,3 +111,9 @@ export const requestClient = createRequestClient(apiURL, {
|
||||
});
|
||||
|
||||
export const baseRequestClient = new RequestClient({ baseURL: apiURL });
|
||||
|
||||
export interface PageFetchParams {
|
||||
[key: string]: any;
|
||||
pageNo?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import { createApp, watchEffect } from 'vue';
|
||||
|
||||
import { registerAccessDirective } from '@vben/access';
|
||||
import { initTippy } from '@vben/common-ui';
|
||||
import { MotionPlugin } from '@vben/plugins/motion';
|
||||
import { preferences } from '@vben/preferences';
|
||||
import { initStores } from '@vben/stores';
|
||||
import '@vben/styles';
|
||||
@ -49,6 +50,9 @@ async function bootstrap(namespace: string) {
|
||||
// 配置@tanstack/vue-query
|
||||
app.use(VueQueryPlugin);
|
||||
|
||||
// 配置Motion插件
|
||||
app.use(MotionPlugin);
|
||||
|
||||
// 动态更新标题
|
||||
watchEffect(() => {
|
||||
if (preferences.app.dynamicTitle) {
|
||||
|
@ -255,6 +255,33 @@ const routes: RouteRecordRaw[] = [
|
||||
title: 'Tippy',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'JsonViewer',
|
||||
path: '/examples/json-viewer',
|
||||
component: () => import('#/views/examples/json-viewer/index.vue'),
|
||||
meta: {
|
||||
icon: 'tabler:json',
|
||||
title: 'JsonViewer',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Motion',
|
||||
path: '/examples/motion',
|
||||
component: () => import('#/views/examples/motion/index.vue'),
|
||||
meta: {
|
||||
icon: 'mdi:animation-play',
|
||||
title: 'Motion',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'CountTo',
|
||||
path: '/examples/count-to',
|
||||
component: () => import('#/views/examples/count-to/index.vue'),
|
||||
meta: {
|
||||
icon: 'mdi:animation-play',
|
||||
title: 'CountTo',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
178
playground/src/views/examples/count-to/index.vue
Normal file
178
playground/src/views/examples/count-to/index.vue
Normal file
@ -0,0 +1,178 @@
|
||||
<script lang="ts" setup>
|
||||
import type { CountToProps, TransitionPresets } from '@vben/common-ui';
|
||||
|
||||
import { reactive } from 'vue';
|
||||
|
||||
import { CountTo, Page, TransitionPresetsKeys } from '@vben/common-ui';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
Row,
|
||||
Select,
|
||||
Switch,
|
||||
} from 'ant-design-vue';
|
||||
|
||||
const props = reactive<CountToProps & { transition: TransitionPresets }>({
|
||||
decimal: '.',
|
||||
decimals: 2,
|
||||
decimalStyle: {
|
||||
fontSize: 'small',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
delay: 0,
|
||||
disabled: false,
|
||||
duration: 2000,
|
||||
endVal: 100_000,
|
||||
mainStyle: {
|
||||
color: 'hsl(var(--primary))',
|
||||
fontSize: 'xx-large',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
prefix: '¥',
|
||||
prefixStyle: {
|
||||
paddingRight: '0.5rem',
|
||||
},
|
||||
separator: ',',
|
||||
startVal: 0,
|
||||
suffix: '元',
|
||||
suffixStyle: {
|
||||
paddingLeft: '0.5rem',
|
||||
},
|
||||
transition: 'easeOutQuart',
|
||||
});
|
||||
|
||||
function changeNumber() {
|
||||
props.endVal =
|
||||
Math.floor(Math.random() * 100_000_000) / 10 ** (props.decimals || 0);
|
||||
}
|
||||
|
||||
function openDocumentation() {
|
||||
window.open('https://vueuse.org/core/useTransition/', '_blank');
|
||||
}
|
||||
|
||||
function onStarted() {
|
||||
message.loading({
|
||||
content: '动画已开始',
|
||||
duration: 0,
|
||||
key: 'animator-info',
|
||||
});
|
||||
}
|
||||
|
||||
function onFinished() {
|
||||
message.success({
|
||||
content: '动画已结束',
|
||||
duration: 2,
|
||||
key: 'animator-info',
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Page title="CountTo" description="数字滚动动画组件。使用">
|
||||
<template #description>
|
||||
<span>
|
||||
使用useTransition封装的数字滚动动画组件,每次改变当前值都会产生过渡动画。
|
||||
</span>
|
||||
<Button type="link" @click="openDocumentation">
|
||||
查看useTransition文档
|
||||
</Button>
|
||||
</template>
|
||||
<Card title="基本用法">
|
||||
<div class="flex w-full items-center justify-center pb-4">
|
||||
<CountTo v-bind="props" @started="onStarted" @finished="onFinished" />
|
||||
</div>
|
||||
<Form :model="props">
|
||||
<Row :gutter="20">
|
||||
<Col :span="8">
|
||||
<FormItem label="初始值" name="startVal">
|
||||
<InputNumber v-model:value="props.startVal" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="当前值" name="endVal">
|
||||
<InputNumber
|
||||
v-model:value="props.endVal"
|
||||
class="w-full"
|
||||
:precision="props.decimals"
|
||||
>
|
||||
<template #addonAfter>
|
||||
<IconifyIcon
|
||||
v-tippy="`设置一个随机值`"
|
||||
class="size-5 cursor-pointer outline-none"
|
||||
icon="ix:random-filled"
|
||||
@click="changeNumber"
|
||||
/>
|
||||
</template>
|
||||
</InputNumber>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="禁用动画" name="disabled">
|
||||
<Switch v-model:checked="props.disabled" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="延迟动画" name="delay">
|
||||
<InputNumber v-model:value="props.delay" :min="0" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="持续时间" name="duration">
|
||||
<InputNumber v-model:value="props.duration" :min="0" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
|
||||
<Col :span="8">
|
||||
<FormItem label="小数位数" name="decimals">
|
||||
<InputNumber
|
||||
v-model:value="props.decimals"
|
||||
:min="0"
|
||||
:precision="0"
|
||||
/>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="分隔符" name="separator">
|
||||
<Input v-model:value="props.separator" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="小数点" name="decimal">
|
||||
<Input v-model:value="props.decimal" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="动画" name="transition">
|
||||
<Select v-model:value="props.transition">
|
||||
<Select.Option
|
||||
v-for="preset in TransitionPresetsKeys"
|
||||
:key="preset"
|
||||
:value="preset"
|
||||
>
|
||||
{{ preset }}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="前缀" name="prefix">
|
||||
<Input v-model:value="props.prefix" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem label="后缀" name="suffix">
|
||||
<Input v-model:value="props.suffix" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
66
playground/src/views/examples/json-viewer/data.ts
Normal file
66
playground/src/views/examples/json-viewer/data.ts
Normal file
@ -0,0 +1,66 @@
|
||||
export const json1 = {
|
||||
additionalInfo: {
|
||||
author: 'Your Name',
|
||||
debug: true,
|
||||
version: '1.3.10',
|
||||
versionCode: 132,
|
||||
},
|
||||
additionalNotes: 'This JSON is used for demonstration purposes',
|
||||
tools: [
|
||||
{
|
||||
description: 'Description of Tool 1',
|
||||
name: 'Tool 1',
|
||||
},
|
||||
{
|
||||
description: 'Description of Tool 2',
|
||||
name: 'Tool 2',
|
||||
},
|
||||
{
|
||||
description: 'Description of Tool 3',
|
||||
name: 'Tool 3',
|
||||
},
|
||||
{
|
||||
description: 'Description of Tool 4',
|
||||
name: 'Tool 4',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const json2 = JSON.parse(`
|
||||
{
|
||||
"id": "chatcmpl-123",
|
||||
"object": "chat.completion",
|
||||
"created": 1677652288,
|
||||
"model": "gpt-3.5-turbo-0613",
|
||||
"system_fingerprint": "fp_44709d6fcb",
|
||||
"choices": [{
|
||||
"index": 0,
|
||||
"message": {
|
||||
"role": "assistant",
|
||||
"content": "Hello there, how may I assist you today?"
|
||||
},
|
||||
"finish_reason": "stop"
|
||||
}],
|
||||
"usage": {
|
||||
"prompt_tokens": 9,
|
||||
"completion_tokens": 12,
|
||||
"total_tokens": 21,
|
||||
"debug_mode": true
|
||||
},
|
||||
"debug": {
|
||||
"startAt": "2021-08-01T00:00:00Z",
|
||||
"logs": [
|
||||
{
|
||||
"timestamp": "2021-08-01T00:00:00Z",
|
||||
"message": "This is a debug message",
|
||||
"extra":[ "extra1", "extra2" ]
|
||||
},
|
||||
{
|
||||
"timestamp": "2021-08-01T00:00:01Z",
|
||||
"message": "This is another debug message",
|
||||
"extra":[ "extra3", "extra4" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
`);
|
51
playground/src/views/examples/json-viewer/index.vue
Normal file
51
playground/src/views/examples/json-viewer/index.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<script lang="ts" setup>
|
||||
import type { JsonViewerAction, JsonViewerValue } from '@vben/common-ui';
|
||||
|
||||
import { JsonViewer, Page } from '@vben/common-ui';
|
||||
|
||||
import { Card, message } from 'ant-design-vue';
|
||||
|
||||
import { json1, json2 } from './data';
|
||||
|
||||
function handleKeyClick(key: string) {
|
||||
message.info(`点击了Key ${key}`);
|
||||
}
|
||||
|
||||
function handleValueClick(value: JsonViewerValue) {
|
||||
message.info(`点击了Value ${JSON.stringify(value)}`);
|
||||
}
|
||||
|
||||
function handleCopied(_event: JsonViewerAction) {
|
||||
message.success('已复制JSON');
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Page
|
||||
title="Json Viewer"
|
||||
description="一个渲染 JSON 结构数据的组件,支持复制、展开等,简单易用"
|
||||
>
|
||||
<Card title="默认配置">
|
||||
<JsonViewer :value="json1" />
|
||||
</Card>
|
||||
<Card title="可复制、默认展开3层、显示边框、事件处理" class="mt-4">
|
||||
<JsonViewer
|
||||
:value="json2"
|
||||
:expand-depth="3"
|
||||
copyable
|
||||
:sort="false"
|
||||
@key-click="handleKeyClick"
|
||||
@value-click="handleValueClick"
|
||||
@copied="handleCopied"
|
||||
boxed
|
||||
/>
|
||||
</Card>
|
||||
<Card title="预览模式" class="mt-4">
|
||||
<JsonViewer
|
||||
:value="json2"
|
||||
copyable
|
||||
preview-mode
|
||||
:show-array-index="false"
|
||||
/>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
213
playground/src/views/examples/motion/index.vue
Normal file
213
playground/src/views/examples/motion/index.vue
Normal file
@ -0,0 +1,213 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { Motion, MotionGroup, MotionPresets } from '@vben/plugins/motion';
|
||||
|
||||
import { refAutoReset, watchDebounced } from '@vueuse/core';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Form,
|
||||
FormItem,
|
||||
InputNumber,
|
||||
Row,
|
||||
Select,
|
||||
} from 'ant-design-vue';
|
||||
// 本例子用不到visible类型的动画。带有VisibleOnce和Visible的类型会在组件进入视口被显示时执行动画,
|
||||
const presets = MotionPresets.filter((v) => !v.includes('Visible'));
|
||||
const showCard1 = refAutoReset(true, 100);
|
||||
const showCard2 = refAutoReset(true, 100);
|
||||
const showCard3 = refAutoReset(true, 100);
|
||||
const motionProps = reactive({
|
||||
delay: 0,
|
||||
duration: 300,
|
||||
enter: { scale: 1 },
|
||||
hovered: { scale: 1.1, transition: { delay: 0, duration: 50 } },
|
||||
preset: 'fade',
|
||||
tapped: { scale: 0.9, transition: { delay: 0, duration: 50 } },
|
||||
});
|
||||
|
||||
const motionGroupProps = reactive({
|
||||
delay: 0,
|
||||
duration: 300,
|
||||
enter: { scale: 1 },
|
||||
hovered: { scale: 1.1, transition: { delay: 0, duration: 50 } },
|
||||
preset: 'fade',
|
||||
tapped: { scale: 0.9, transition: { delay: 0, duration: 50 } },
|
||||
});
|
||||
|
||||
watchDebounced(
|
||||
motionProps,
|
||||
() => {
|
||||
showCard2.value = false;
|
||||
},
|
||||
{ debounce: 200, deep: true },
|
||||
);
|
||||
|
||||
watchDebounced(
|
||||
motionGroupProps,
|
||||
() => {
|
||||
showCard3.value = false;
|
||||
},
|
||||
{ debounce: 200, deep: true },
|
||||
);
|
||||
|
||||
function openDocPage() {
|
||||
window.open('https://motion.vueuse.org/', '_blank');
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Page title="Motion">
|
||||
<template #description>
|
||||
<span>一个易于使用的为其它组件赋予动画效果的组件。</span>
|
||||
<Button type="link" @click="openDocPage">查看文档</Button>
|
||||
</template>
|
||||
<Card title="使用指令" :body-style="{ minHeight: '5rem' }">
|
||||
<template #extra>
|
||||
<Button type="primary" @click="showCard1 = false">重载</Button>
|
||||
</template>
|
||||
<div>
|
||||
<div class="relative flex gap-2 overflow-hidden" v-if="showCard1">
|
||||
<Button v-motion-fade-visible>fade</Button>
|
||||
<Button v-motion-pop-visible :duration="500">pop</Button>
|
||||
<Button v-motion-slide-left>slide-left</Button>
|
||||
<Button v-motion-slide-right>slide-right</Button>
|
||||
<Button v-motion-slide-bottom>slide-bottom</Button>
|
||||
<Button v-motion-slide-top>slide-top</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<Card
|
||||
class="mt-2"
|
||||
title="使用组件(将内部作为一个整体添加动画)"
|
||||
:body-style="{ padding: 0 }"
|
||||
>
|
||||
<div
|
||||
class="relative flex min-h-32 items-center justify-center gap-2 overflow-hidden"
|
||||
>
|
||||
<Motion
|
||||
v-bind="motionProps"
|
||||
v-if="showCard2"
|
||||
class="flex items-center gap-2"
|
||||
>
|
||||
<Button size="large">这个按钮在显示时会有动画效果</Button>
|
||||
<span>附属组件,会作为整体处理动画</span>
|
||||
</Motion>
|
||||
</div>
|
||||
<div
|
||||
class="relative flex min-h-32 items-center justify-center gap-2 overflow-hidden"
|
||||
>
|
||||
<div v-if="showCard2" class="flex items-center gap-2">
|
||||
<span>顺序延迟</span>
|
||||
<Motion
|
||||
v-bind="{
|
||||
...motionProps,
|
||||
delay: motionProps.delay + 100 * i,
|
||||
}"
|
||||
v-for="i in 5"
|
||||
:key="i"
|
||||
>
|
||||
<Button size="large">按钮{{ i }}</Button>
|
||||
</Motion>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Form :model="motionProps" :label-col="{ span: 10 }">
|
||||
<Row>
|
||||
<Col :span="8">
|
||||
<FormItem prop="preset" label="动画效果">
|
||||
<Select v-model:value="motionProps.preset">
|
||||
<Select.Option
|
||||
:value="preset"
|
||||
v-for="preset in presets"
|
||||
:key="preset"
|
||||
>
|
||||
{{ preset }}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="duration" label="持续时间">
|
||||
<InputNumber v-model:value="motionProps.duration" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="delay" label="延迟动画">
|
||||
<InputNumber v-model:value="motionProps.delay" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="hovered.scale" label="Hover缩放">
|
||||
<InputNumber v-model:value="motionProps.hovered.scale" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="hovered.tapped" label="按下时缩放">
|
||||
<InputNumber v-model:value="motionProps.tapped.scale" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
<Card
|
||||
class="mt-2"
|
||||
title="分组动画(每个子元素都会应用相同的独立动画)"
|
||||
:body-style="{ padding: 0 }"
|
||||
>
|
||||
<div
|
||||
class="relative flex min-h-32 items-center justify-center gap-2 overflow-hidden"
|
||||
>
|
||||
<MotionGroup v-bind="motionGroupProps" v-if="showCard3">
|
||||
<Button size="large">按钮1</Button>
|
||||
<Button size="large">按钮2</Button>
|
||||
<Button size="large">按钮3</Button>
|
||||
<Button size="large">按钮4</Button>
|
||||
<Button size="large">按钮5</Button>
|
||||
</MotionGroup>
|
||||
</div>
|
||||
<div>
|
||||
<Form :model="motionGroupProps" :label-col="{ span: 10 }">
|
||||
<Row>
|
||||
<Col :span="8">
|
||||
<FormItem prop="preset" label="动画效果">
|
||||
<Select v-model:value="motionGroupProps.preset">
|
||||
<Select.Option
|
||||
:value="preset"
|
||||
v-for="preset in presets"
|
||||
:key="preset"
|
||||
>
|
||||
{{ preset }}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="duration" label="持续时间">
|
||||
<InputNumber v-model:value="motionGroupProps.duration" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="delay" label="延迟动画">
|
||||
<InputNumber v-model:value="motionGroupProps.delay" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="hovered.scale" label="Hover缩放">
|
||||
<InputNumber v-model:value="motionGroupProps.hovered.scale" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
<Col :span="8">
|
||||
<FormItem prop="hovered.tapped" label="按下时缩放">
|
||||
<InputNumber v-model:value="motionGroupProps.tapped.scale" />
|
||||
</FormItem>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
@ -21,22 +21,22 @@ catalog:
|
||||
'@commitlint/cli': ^19.7.1
|
||||
'@commitlint/config-conventional': ^19.7.1
|
||||
'@ctrl/tinycolor': ^4.1.0
|
||||
'@eslint/js': ^9.19.0
|
||||
'@faker-js/faker': ^9.4.0
|
||||
'@iconify/json': ^2.2.302
|
||||
'@eslint/js': ^9.20.0
|
||||
'@faker-js/faker': ^9.5.0
|
||||
'@iconify/json': ^2.2.307
|
||||
'@iconify/tailwind': ^1.2.0
|
||||
'@iconify/vue': ^4.3.0
|
||||
'@intlify/core-base': ^11.1.0
|
||||
'@intlify/core-base': ^11.1.1
|
||||
'@intlify/unplugin-vue-i18n': ^6.0.3
|
||||
'@jspm/generator': ^2.4.2
|
||||
'@jspm/generator': ^2.5.0
|
||||
'@manypkg/get-packages': ^2.2.2
|
||||
'@nolebase/vitepress-plugin-git-changelog': ^2.12.1
|
||||
'@nolebase/vitepress-plugin-git-changelog': ^2.14.0
|
||||
'@playwright/test': ^1.50.1
|
||||
'@pnpm/workspace.read-manifest': ^1000.0.2
|
||||
'@stylistic/stylelint-plugin': ^3.1.1
|
||||
'@tailwindcss/nesting': 0.0.0-insiders.565cd3e
|
||||
'@tailwindcss/typography': ^0.5.16
|
||||
'@tanstack/vue-query': ^5.65.0
|
||||
'@tanstack/vue-query': ^5.66.3
|
||||
'@tanstack/vue-store': ^0.7.0
|
||||
'@types/archiver': ^6.0.3
|
||||
'@types/eslint': ^9.6.1
|
||||
@ -45,13 +45,13 @@ catalog:
|
||||
'@types/lodash.clonedeep': ^4.5.9
|
||||
'@types/lodash.get': ^4.4.9
|
||||
'@types/lodash.isequal': ^4.5.8
|
||||
'@types/node': ^22.13.1
|
||||
'@types/node': ^22.13.4
|
||||
'@types/nprogress': ^0.2.3
|
||||
'@types/postcss-import': ^14.0.3
|
||||
'@types/qrcode': ^1.5.5
|
||||
'@types/sortablejs': ^1.15.8
|
||||
'@typescript-eslint/eslint-plugin': ^8.23.0
|
||||
'@typescript-eslint/parser': ^8.23.0
|
||||
'@typescript-eslint/eslint-plugin': ^8.24.0
|
||||
'@typescript-eslint/parser': ^8.24.0
|
||||
'@vee-validate/zod': ^4.15.0
|
||||
'@vite-pwa/vitepress': ^0.5.3
|
||||
'@vitejs/plugin-vue': ^5.2.1
|
||||
@ -59,8 +59,9 @@ catalog:
|
||||
'@vue/reactivity': ^3.5.13
|
||||
'@vue/shared': ^3.5.13
|
||||
'@vue/test-utils': ^2.4.6
|
||||
'@vueuse/core': ^12.5.0
|
||||
'@vueuse/integrations': ^12.5.0
|
||||
'@vueuse/core': ^12.7.0
|
||||
'@vueuse/motion': ^2.2.6
|
||||
'@vueuse/integrations': ^12.7.0
|
||||
ant-design-vue: ^4.2.6
|
||||
archiver: ^7.0.1
|
||||
autoprefixer: ^10.4.20
|
||||
@ -84,9 +85,9 @@ catalog:
|
||||
depcheck: ^1.4.7
|
||||
dotenv: ^16.4.7
|
||||
echarts: ^5.6.0
|
||||
element-plus: ^2.9.3
|
||||
eslint: ^9.19.0
|
||||
eslint-config-turbo: ^2.4.0
|
||||
element-plus: ^2.9.4
|
||||
eslint: ^9.20.1
|
||||
eslint-config-turbo: ^2.4.2
|
||||
eslint-plugin-command: ^0.2.7
|
||||
eslint-plugin-eslint-comments: ^3.2.0
|
||||
eslint-plugin-import-x: ^4.6.1
|
||||
@ -94,7 +95,7 @@ catalog:
|
||||
eslint-plugin-jsonc: ^2.19.1
|
||||
eslint-plugin-n: ^17.15.1
|
||||
eslint-plugin-no-only-tests: ^3.3.0
|
||||
eslint-plugin-perfectionist: ^4.8.0
|
||||
eslint-plugin-perfectionist: ^4.9.0
|
||||
eslint-plugin-prettier: ^5.2.3
|
||||
eslint-plugin-regexp: ^2.7.0
|
||||
eslint-plugin-unicorn: ^56.0.1
|
||||
@ -104,8 +105,8 @@ catalog:
|
||||
execa: ^9.5.2
|
||||
find-up: ^7.0.0
|
||||
get-port: ^7.1.0
|
||||
globals: ^15.14.0
|
||||
h3: ^1.14.0
|
||||
globals: ^15.15.0
|
||||
h3: ^1.15.0
|
||||
happy-dom: ^16.8.1
|
||||
html-minifier-terser: ^7.2.0
|
||||
husky: ^9.1.7
|
||||
@ -126,22 +127,22 @@ catalog:
|
||||
pinia-plugin-persistedstate: ^4.2.0
|
||||
pkg-types: ^1.3.1
|
||||
playwright: ^1.50.1
|
||||
postcss: ^8.5.1
|
||||
postcss: ^8.5.2
|
||||
postcss-antd-fixes: ^0.2.0
|
||||
postcss-html: ^1.8.0
|
||||
postcss-import: ^16.1.0
|
||||
postcss-preset-env: ^10.1.3
|
||||
postcss-preset-env: ^10.1.4
|
||||
postcss-scss: ^4.0.9
|
||||
prettier: ^3.4.2
|
||||
prettier: ^3.5.1
|
||||
prettier-plugin-tailwindcss: ^0.6.11
|
||||
publint: ^0.2.12
|
||||
qrcode: ^1.5.4
|
||||
radix-vue: ^1.9.13
|
||||
radix-vue: ^1.9.14
|
||||
resolve.exports: ^2.0.3
|
||||
rimraf: ^6.0.1
|
||||
rollup: ^4.34.2
|
||||
rollup: ^4.34.7
|
||||
rollup-plugin-visualizer: ^5.14.0
|
||||
sass: ^1.83.4
|
||||
sass: ^1.85.0
|
||||
sortablejs: ^1.15.6
|
||||
stylelint: ^16.14.1
|
||||
stylelint-config-recess-order: ^5.1.1
|
||||
@ -157,29 +158,30 @@ catalog:
|
||||
tailwindcss-animate: ^1.0.7
|
||||
theme-colors: ^0.1.0
|
||||
tippy.js: ^6.2.5
|
||||
turbo: ^2.4.0
|
||||
turbo: ^2.4.2
|
||||
typescript: ^5.7.3
|
||||
unbuild: ^3.3.1
|
||||
unplugin-element-plus: ^0.9.0
|
||||
unplugin-element-plus: ^0.9.1
|
||||
vee-validate: ^4.15.0
|
||||
vite: ^6.0.11
|
||||
vite: ^6.1.0
|
||||
vite-plugin-compression: ^0.5.1
|
||||
vite-plugin-dts: ^4.5.0
|
||||
vite-plugin-html: ^3.2.2
|
||||
vite-plugin-lazy-import: ^1.0.7
|
||||
vite-plugin-pwa: ^0.21.1
|
||||
vite-plugin-vue-devtools: ^7.7.1
|
||||
vite-plugin-vue-devtools: ^7.7.2
|
||||
vitepress: ^1.6.3
|
||||
vitepress-plugin-group-icons: ^1.3.5
|
||||
vitest: ^2.1.9
|
||||
vue: ^3.5.13
|
||||
vue-eslint-parser: ^9.4.3
|
||||
vue-i18n: ^11.1.0
|
||||
vue-i18n: ^11.1.1
|
||||
vue-json-viewer: ^3.0.4
|
||||
vue-router: ^4.5.0
|
||||
vue-tippy: ^6.6.0
|
||||
vue-tsc: 2.1.10
|
||||
vxe-pc-ui: ^4.3.79
|
||||
vxe-pc-ui: ^4.3.87
|
||||
vxe-table: 4.10.0
|
||||
watermark-js-plus: ^1.5.7
|
||||
zod: ^3.24.1
|
||||
watermark-js-plus: ^1.5.8
|
||||
zod: ^3.24.2
|
||||
zod-defaults: ^0.1.3
|
||||
|
Loading…
Reference in New Issue
Block a user