fix: 修复管理端前端 lint 与构建问题

- 收敛 easyflow-ui-admin 的 lint、格式和类型问题

- 修正 demo 页面与管理端前端构建失败点

- 验证 pnpm lint 与 pnpm build 均已通过
This commit is contained in:
2026-04-05 21:39:13 +08:00
parent bb72e19c84
commit 7e7c236c2a
240 changed files with 5151 additions and 4701 deletions

View File

@@ -7,7 +7,12 @@ import { computed, nextTick, ref, unref, useAttrs, watch } from 'vue';
import { LoaderCircle } from '@easyflow/icons';
import { cloneDeep, get, isEqual, isFunction } from '@easyflow-core/shared/utils';
import {
cloneDeep,
get,
isEqual,
isFunction,
} from '@easyflow-core/shared/utils';
import { objectOmit } from '@vueuse/core';

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { computed } from 'vue';
import type { ChatThinkingBlockProps } from './types';
import { computed } from 'vue';
defineOptions({
name: 'ChatThinkingBlock',
});
@@ -24,8 +24,8 @@ const emit = defineEmits<{
const normalizedContent = computed(() =>
String(props.content || '')
.replace(/\r\n/g, '\n')
.replace(/^\s*\n+/, '')
.replaceAll('\r\n', '\n')
.replace(/^\s*\n/, '')
.trimEnd(),
);
@@ -131,27 +131,26 @@ function toggleExpanded() {
<style scoped>
.chat-thinking-block {
border: 1px solid hsl(var(--divider-faint) / 0.18);
background: linear-gradient(
180deg,
hsl(var(--glass-tint) / 48%) 0%,
hsl(var(--surface-panel) / 74%) 100%
);
border: 1px solid hsl(var(--divider-faint) / 18%);
border-radius: 16px;
background:
linear-gradient(
180deg,
hsl(var(--glass-tint) / 0.48) 0%,
hsl(var(--surface-panel) / 0.74) 100%
);
box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.24),
0 10px 24px -24px hsl(var(--foreground) / 0.18);
inset 0 1px 0 hsl(var(--glass-border) / 24%),
0 10px 24px -24px hsl(var(--foreground) / 18%);
backdrop-filter: blur(12px);
}
.chat-thinking-block__trigger {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
width: 100%;
min-width: 0;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 10px;
padding: 9px 12px;
color: inherit;
text-align: left;
@@ -166,7 +165,7 @@ function toggleExpanded() {
}
.chat-thinking-block__trigger:not(:disabled):hover {
background: hsl(var(--surface-contrast-soft) / 0.34);
background: hsl(var(--surface-contrast-soft) / 34%);
}
.chat-thinking-block__trigger:disabled {
@@ -175,9 +174,9 @@ function toggleExpanded() {
.chat-thinking-block__leading {
display: inline-flex;
min-width: 0;
align-items: center;
gap: 8px;
align-items: center;
min-width: 0;
}
.chat-thinking-block__indicator {
@@ -185,19 +184,19 @@ function toggleExpanded() {
flex: 0 0 auto;
width: 8px;
height: 8px;
background: hsl(var(--text-muted) / 74%);
border-radius: 999px;
background: hsl(var(--text-muted) / 0.74);
}
.chat-thinking-block.is-thinking .chat-thinking-block__indicator {
background: hsl(var(--primary) / 0.82);
box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12);
background: hsl(var(--primary) / 82%);
box-shadow: 0 0 0 4px hsl(var(--primary) / 12%);
animation: chat-thinking-pulse 1.8s ease-in-out infinite;
}
.chat-thinking-block.is-error .chat-thinking-block__indicator {
background: hsl(var(--destructive) / 0.86);
box-shadow: 0 0 0 4px hsl(var(--destructive) / 0.1);
background: hsl(var(--destructive) / 86%);
box-shadow: 0 0 0 4px hsl(var(--destructive) / 10%);
}
.chat-thinking-block__label {
@@ -211,10 +210,10 @@ function toggleExpanded() {
.chat-thinking-block__summary {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
font-size: 12px;
line-height: 1.3;
color: hsl(var(--text-muted));
text-overflow: ellipsis;
white-space: nowrap;
}
@@ -236,15 +235,15 @@ function toggleExpanded() {
}
.chat-thinking-block__content {
margin: 0;
padding: 10px 12px;
border-radius: 12px;
background: hsl(var(--surface-panel) / 0.72);
margin: 0;
font-size: 12px;
line-height: 1.68;
color: hsl(var(--text-secondary));
overflow-wrap: anywhere;
white-space: pre-wrap;
word-break: break-word;
background: hsl(var(--surface-panel) / 72%);
border-radius: 12px;
}
.chat-thinking-block.is-disabled {
@@ -267,12 +266,12 @@ function toggleExpanded() {
@keyframes chat-thinking-pulse {
0%,
100% {
box-shadow: 0 0 0 4px hsl(var(--primary) / 0.12);
box-shadow: 0 0 0 4px hsl(var(--primary) / 12%);
opacity: 0.92;
}
50% {
box-shadow: 0 0 0 7px hsl(var(--primary) / 0.04);
box-shadow: 0 0 0 7px hsl(var(--primary) / 4%);
opacity: 1;
}
}

View File

@@ -1,5 +1,2 @@
export { default as ChatThinkingBlock } from './ChatThinkingBlock.vue';
export type {
ChatThinkingBlockProps,
ChatThinkingBlockStatus,
} from './types';
export type { ChatThinkingBlockProps, ChatThinkingBlockStatus } from './types';

View File

@@ -8,10 +8,10 @@ import { EmptyIcon, Grip, listIcons } from '@easyflow/icons';
import { $t } from '@easyflow/locales';
import {
Button,
EasyFlowIcon,
EasyFlowIconButton,
EasyFlowPopover,
Button,
Input,
Pagination,
PaginationEllipsis,

View File

@@ -4,7 +4,7 @@ import type { TreeProps } from '@easyflow-core/shadcn-ui';
import { Inbox } from '@easyflow/icons';
import { $t } from '@easyflow/locales';
import { treePropsDefaults, EasyFlowTree } from '@easyflow-core/shadcn-ui';
import { EasyFlowTree, treePropsDefaults } from '@easyflow-core/shadcn-ui';
const props = withDefaults(defineProps<TreeProps>(), treePropsDefaults());
</script>

View File

@@ -1,7 +1,8 @@
import {mount} from '@vue/test-utils';
import {nextTick} from 'vue';
import { mount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import {beforeEach, describe, expect, it, vi} from 'vitest';
import AuthenticationLogin from '../login.vue';
const { formApi, routerPush } = vi.hoisted(() => ({
@@ -41,7 +42,8 @@ vi.mock('@easyflow-core/form-ui', async () => {
vi.mock('@easyflow-core/shadcn-ui', async (importOriginal) => {
const vue = await import('vue');
const actual = await importOriginal<typeof import('@easyflow-core/shadcn-ui')>();
const actual =
await importOriginal<typeof import('@easyflow-core/shadcn-ui')>();
return {
...actual,
@@ -102,7 +104,7 @@ vi.mock('@easyflow-core/shadcn-ui', async (importOriginal) => {
};
});
describe('AuthenticationLogin', () => {
describe('authenticationLogin', () => {
const rememberKey = `REMEMBER_ME_ACCOUNT_${location.hostname}`;
beforeEach(() => {

View File

@@ -6,7 +6,9 @@
<slot></slot>
</h2>
<p class="text-muted-foreground max-w-[34rem] text-[0.97rem] leading-7 sm:text-[1rem]">
<p
class="text-muted-foreground max-w-[34rem] text-[0.97rem] leading-7 sm:text-[1rem]"
>
<slot name="desc"></slot>
</p>
</div>

View File

@@ -1,14 +1,15 @@
<script setup lang="ts">
import type {Recordable} from '@easyflow/types';
import type { Recordable } from '@easyflow/types';
import type {EasyFlowFormSchema} from '@easyflow-core/form-ui';
import {useEasyFlowForm} from '@easyflow-core/form-ui';
import type { EasyFlowFormSchema } from '@easyflow-core/form-ui';
import {computed, reactive} from 'vue';
import {useRouter} from 'vue-router';
import { computed, reactive } from 'vue';
import { useRouter } from 'vue-router';
import {$t} from '@easyflow/locales';
import {EasyFlowButton} from '@easyflow-core/shadcn-ui';
import { $t } from '@easyflow/locales';
import { useEasyFlowForm } from '@easyflow-core/form-ui';
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
import Title from './auth-title.vue';

View File

@@ -1,12 +1,13 @@
<script setup lang="ts">
import type {EasyFlowFormSchema} from '@easyflow-core/form-ui';
import {useEasyFlowForm} from '@easyflow-core/form-ui';
import type { EasyFlowFormSchema } from '@easyflow-core/form-ui';
import {computed, reactive} from 'vue';
import {useRouter} from 'vue-router';
import { computed, reactive } from 'vue';
import { useRouter } from 'vue-router';
import {$t} from '@easyflow/locales';
import {EasyFlowButton} from '@easyflow-core/shadcn-ui';
import { $t } from '@easyflow/locales';
import { useEasyFlowForm } from '@easyflow-core/form-ui';
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
import Title from './auth-title.vue';

View File

@@ -6,7 +6,7 @@ import { computed, watch } from 'vue';
import { $t } from '@easyflow/locales';
import { useEasyFlowModal } from '@easyflow-core/popup-ui';
import { Slot, EasyFlowAvatar } from '@easyflow-core/shadcn-ui';
import { EasyFlowAvatar, Slot } from '@easyflow-core/shadcn-ui';
interface Props extends AuthenticationProps {
avatar?: string;

View File

@@ -1,16 +1,17 @@
<script setup lang="ts">
import type {Recordable} from '@easyflow/types';
import type { Recordable } from '@easyflow/types';
import type {EasyFlowFormSchema} from '@easyflow-core/form-ui';
import {useEasyFlowForm} from '@easyflow-core/form-ui';
import type { EasyFlowFormSchema } from '@easyflow-core/form-ui';
import type {AuthenticationProps} from './types';
import type { AuthenticationProps } from './types';
import {computed, onMounted, reactive, ref} from 'vue';
import {useRouter} from 'vue-router';
import { computed, onMounted, reactive, ref } from 'vue';
import { useRouter } from 'vue-router';
import {$t} from '@easyflow/locales';
import {EasyFlowButton, EasyFlowCheckbox} from '@easyflow-core/shadcn-ui';
import { $t } from '@easyflow/locales';
import { useEasyFlowForm } from '@easyflow-core/form-ui';
import { EasyFlowButton, EasyFlowCheckbox } from '@easyflow-core/shadcn-ui';
import Title from './auth-title.vue';
import ThirdPartyLogin from './third-party-login.vue';
@@ -174,7 +175,10 @@ defineExpose({
</slot>
<slot name="to-register">
<div v-if="showRegister" class="auth-footer-copy mt-5 text-center text-sm">
<div
v-if="showRegister"
class="auth-footer-copy mt-5 text-center text-sm"
>
{{ $t('authentication.accountTip') }}
<button
class="auth-inline-action"
@@ -198,8 +202,8 @@ defineExpose({
}
.auth-form-group :deep(.easyflow-form-ui .text-destructive) {
font-size: 0.84rem;
margin-top: 0.45rem;
font-size: 0.84rem;
}
.auth-login-options {
@@ -207,14 +211,14 @@ defineExpose({
}
.auth-checkbox {
color: hsl(var(--text-muted));
font-size: 0.92rem;
color: hsl(var(--text-muted));
}
.auth-inline-action {
color: hsl(var(--nav-item-active-foreground));
font-size: 0.92rem;
font-weight: 500;
color: hsl(var(--nav-item-active-foreground));
transition: opacity 0.18s ease;
}
@@ -228,20 +232,19 @@ defineExpose({
}
.auth-brand-submit {
background:
linear-gradient(
120deg,
rgb(11 111 211) 0%,
rgb(22 159 200) 38%,
rgb(38 199 193) 62%,
rgb(11 111 211) 100%
);
color: rgb(255 255 255);
background: linear-gradient(
120deg,
rgb(11 111 211) 0%,
rgb(22 159 200) 38%,
rgb(38 199 193) 62%,
rgb(11 111 211) 100%
);
background-size: 200% 200%;
border: none;
box-shadow:
0 22px 34px -22px rgb(11 111 211 / 0.56),
inset 0 1px 0 rgb(255 255 255 / 0.24);
color: rgb(255 255 255);
0 22px 34px -22px rgb(11 111 211 / 56%),
inset 0 1px 0 rgb(255 255 255 / 24%);
transition:
transform 180ms ease,
box-shadow 180ms ease,
@@ -251,8 +254,8 @@ defineExpose({
.auth-brand-submit:hover {
box-shadow:
0 24px 38px -22px rgb(11 111 211 / 0.62),
inset 0 1px 0 rgb(255 255 255 / 0.28);
0 24px 38px -22px rgb(11 111 211 / 62%),
inset 0 1px 0 rgb(255 255 255 / 28%);
filter: saturate(1.04);
transform: translateY(-1px);
}
@@ -262,7 +265,7 @@ defineExpose({
}
.auth-brand-submit:focus-visible {
outline: 2px solid rgb(78 176 255 / 0.8);
outline: 2px solid rgb(78 176 255 / 80%);
outline-offset: 2px;
}

View File

@@ -1,12 +1,12 @@
<script setup lang="ts">
import {ref} from 'vue';
import {useRouter} from 'vue-router';
import { ref } from 'vue';
import { useRouter } from 'vue-router';
import {$t} from '@easyflow/locales';
import { $t } from '@easyflow/locales';
import {EasyFlowButton} from '@easyflow-core/shadcn-ui';
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
import {useQRCode} from '@vueuse/integrations/useQRCode';
import { useQRCode } from '@vueuse/integrations/useQRCode';
import Title from './auth-title.vue';
@@ -112,25 +112,29 @@ function goToLogin() {
}
.auth-qrcode-frame {
align-items: center;
background: linear-gradient(180deg, rgb(255 255 255 / 0.92), rgb(244 249 255 / 0.96));
border: 1px solid hsl(var(--line-subtle));
border-radius: 1.5rem;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.6);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
max-width: 17rem;
padding: 1rem;
margin: 0 auto;
background: linear-gradient(
180deg,
rgb(255 255 255 / 92%),
rgb(244 249 255 / 96%)
);
border: 1px solid hsl(var(--line-subtle));
border-radius: 1.5rem;
box-shadow: inset 0 1px 0 rgb(255 255 255 / 60%);
}
.auth-qrcode-image {
width: min(100%, 13rem);
aspect-ratio: 1;
border-radius: 1rem;
width: min(100%, 13rem);
}
.dark .auth-qrcode-frame {
background: linear-gradient(180deg, rgb(14 22 36 / 0.92), rgb(11 19 31 / 0.96));
background: linear-gradient(180deg, rgb(14 22 36 / 92%), rgb(11 19 31 / 96%));
}
</style>

View File

@@ -1,14 +1,15 @@
<script setup lang="ts">
import type {Recordable} from '@easyflow/types';
import type { Recordable } from '@easyflow/types';
import type {EasyFlowFormSchema} from '@easyflow-core/form-ui';
import {useEasyFlowForm} from '@easyflow-core/form-ui';
import type { EasyFlowFormSchema } from '@easyflow-core/form-ui';
import {computed, reactive} from 'vue';
import {useRouter} from 'vue-router';
import { computed, reactive } from 'vue';
import { useRouter } from 'vue-router';
import {$t} from '@easyflow/locales';
import {EasyFlowButton} from '@easyflow-core/shadcn-ui';
import { $t } from '@easyflow/locales';
import { useEasyFlowForm } from '@easyflow-core/form-ui';
import { EasyFlowButton } from '@easyflow-core/shadcn-ui';
import Title from './auth-title.vue';
@@ -127,9 +128,9 @@ defineExpose({
}
.auth-inline-action {
color: hsl(var(--nav-item-active-foreground));
font-size: 0.92rem;
font-weight: 500;
color: hsl(var(--nav-item-active-foreground));
transition: opacity 0.18s ease;
}

View File

@@ -1,5 +1,10 @@
<script setup lang="ts">
import { Card, CardContent, CardHeader, CardTitle } from '@easyflow-core/shadcn-ui';
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from '@easyflow-core/shadcn-ui';
interface Props {
title: string;

View File

@@ -3,7 +3,12 @@ import type { TabOption } from '@easyflow/types';
import { computed } from 'vue';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@easyflow-core/shadcn-ui';
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from '@easyflow-core/shadcn-ui';
interface Props {
tabs?: TabOption[];