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

@@ -84,14 +84,25 @@ const resolvedPrimaryAction = computed(() => {
return props.primaryAction;
});
function resolveActionPlacement(
action: ActionButton,
index: number,
): ActionPlacement {
if (action.placement) {
return action.placement;
}
if (resolvedPrimaryAction.value) {
return 'menu';
}
return index < 3 ? 'inline' : 'menu';
}
const resolvedActions = computed<ResolvedActionButton[]>(() => {
return props.actions
.filter((action) => hasPermission(action.permission))
.map((action, index) => ({
...action,
placement:
action.placement ||
(resolvedPrimaryAction.value ? 'menu' : index < 3 ? 'inline' : 'menu'),
placement: resolveActionPlacement(action, index),
tone:
action.tone ||
(action.className?.includes('danger') ? 'danger' : 'default'),
@@ -111,8 +122,8 @@ const menuActions = computed(() => {
const showFooter = computed(() => {
return Boolean(
resolvedPrimaryAction.value ||
inlineActions.value.length ||
menuActions.value.length,
inlineActions.value.length > 0 ||
menuActions.value.length > 0,
);
});
@@ -132,10 +143,8 @@ function handleActionClick(event: Event, action: ActionButton, item: any) {
v-for="(item, index) in props.data"
:key="item.id ?? index"
shadow="never"
:class="[
'card-item',
{ 'card-item--interactive': resolvedPrimaryAction },
]"
class="card-item"
:class="[{ 'card-item--interactive': resolvedPrimaryAction }]"
:role="resolvedPrimaryAction ? 'button' : undefined"
:tabindex="resolvedPrimaryAction ? 0 : undefined"
@click="handlePrimaryAction(item)"
@@ -201,7 +210,7 @@ function handleActionClick(event: Event, action: ActionButton, item: any) {
</div>
<div
v-if="inlineActions.length || menuActions.length"
v-if="inlineActions.length > 0 || menuActions.length > 0"
class="card-actions"
@click.stop
>

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import type {CSSProperties} from 'vue';
import {computed, useSlots} from 'vue';
import type { CSSProperties } from 'vue';
import { computed, useSlots } from 'vue';
interface Props {
contentPadding?: number | string;
@@ -67,8 +68,8 @@ const contentStyle = computed((): CSSProperties => {
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
gap: 16px;
min-height: 0;
}
.list-page-shell.is-dense {
@@ -78,9 +79,9 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__toolbar {
position: relative;
display: flex;
gap: 16px;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
padding: 8px 6px 2px;
background: transparent;
border: none;
@@ -92,8 +93,8 @@ const contentStyle = computed((): CSSProperties => {
top: 12px;
z-index: 5;
padding: 10px 10px 6px;
background: hsl(var(--glass-tint) / 0.7);
border: 1px solid hsl(var(--glass-border) / 0.44);
background: hsl(var(--glass-tint) / 70%);
border: 1px solid hsl(var(--glass-border) / 44%);
border-radius: 20px;
box-shadow: var(--shadow-toolbar);
backdrop-filter: blur(var(--glass-blur)) saturate(155%);
@@ -110,40 +111,41 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__content {
--list-page-shell-content-padding: 0px;
position: relative;
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
position: relative;
overflow: hidden;
padding: var(--list-page-shell-content-padding);
overflow: hidden;
background: linear-gradient(
180deg,
hsl(var(--glass-border) / 0.84) 0%,
hsl(var(--surface-panel) / 0.94) 28%,
hsl(var(--surface-panel) / 0.97) 100%
hsl(var(--glass-border) / 84%) 0%,
hsl(var(--surface-panel) / 94%) 28%,
hsl(var(--surface-panel) / 97%) 100%
);
border: 1px solid hsl(var(--glass-border) / 0.58);
border: 1px solid hsl(var(--glass-border) / 58%);
border-radius: 24px;
box-shadow:
inset 0 1px 0 hsl(var(--glass-border) / 0.72),
0 24px 54px -42px hsl(var(--primary) / 0.22),
0 18px 42px -34px hsl(var(--foreground) / 0.1);
inset 0 1px 0 hsl(var(--glass-border) / 72%),
0 24px 54px -42px hsl(var(--primary) / 22%),
0 18px 42px -34px hsl(var(--foreground) / 10%);
backdrop-filter: blur(calc(var(--glass-blur) * 0.7)) saturate(145%);
}
.list-page-shell.is-subtle .list-page-shell__content {
background: linear-gradient(
180deg,
hsl(var(--glass-tint) / 0.84) 0%,
hsl(var(--surface-contrast-soft) / 0.94) 100%
hsl(var(--glass-tint) / 84%) 0%,
hsl(var(--surface-contrast-soft) / 94%) 100%
);
box-shadow: none;
}
.list-page-shell.is-plain .list-page-shell__content {
background: hsl(var(--surface-panel) / 0.96);
border: 1px solid hsl(var(--divider-faint) / 0.58);
background: hsl(var(--surface-panel) / 96%);
border: 1px solid hsl(var(--divider-faint) / 58%);
border-radius: 20px;
box-shadow: none;
backdrop-filter: none;
@@ -162,14 +164,10 @@ const contentStyle = computed((): CSSProperties => {
background:
radial-gradient(
ellipse 84% 72% at 10% 0%,
hsl(var(--nav-ambient) / 0.18) 0%,
hsl(var(--nav-ambient) / 18%) 0%,
transparent 68%
),
linear-gradient(
180deg,
hsl(var(--nav-flow-trace) / 0.08) 0%,
transparent 78%
);
linear-gradient(180deg, hsl(var(--nav-flow-trace) / 8%) 0%, transparent 78%);
}
.list-page-shell__content > * {
@@ -195,6 +193,7 @@ const contentStyle = computed((): CSSProperties => {
--el-table-border-color: hsl(var(--table-row-border));
--el-table-current-row-bg-color: hsl(var(--table-row-hover));
--el-fill-color-blank: transparent;
background: transparent;
}
@@ -216,8 +215,8 @@ const contentStyle = computed((): CSSProperties => {
font-size: 13px;
font-weight: 600;
color: hsl(var(--text-strong));
background: hsl(var(--table-header-bg) / 0.86);
border-bottom: 1px solid hsl(var(--divider-faint) / 0.38);
background: hsl(var(--table-header-bg) / 86%);
border-bottom: 1px solid hsl(var(--divider-faint) / 38%);
}
.list-page-shell__content :deep(.el-table th.el-table__cell:first-child) {
@@ -232,7 +231,7 @@ const contentStyle = computed((): CSSProperties => {
.list-page-shell__content :deep(.el-table--border .el-table__cell) {
padding: 14px 0;
border-right: none;
border-bottom: 1px solid hsl(var(--divider-faint) / 0.46);
border-bottom: 1px solid hsl(var(--divider-faint) / 46%);
}
.list-page-shell__content :deep(.el-table__row:hover > td.el-table__cell) {

View File

@@ -138,7 +138,7 @@ onMounted(() => {
flex: 1;
flex-direction: column;
min-height: 0;
padding: 18px 20px 18px;
padding: 18px 20px;
}
.page-data-container__body {

View File

@@ -114,6 +114,7 @@ const isSvgString = (icon: any) => {
v-if="item.icon"
class="ml-[-3px] flex items-center justify-center"
>
<!-- eslint-disable vue/no-v-html -->
<div
v-if="isSvgString(item.icon)"
v-html="item.icon"
@@ -127,6 +128,7 @@ const isSvgString = (icon: any) => {
}"
class="svg-container"
></div>
<!-- eslint-enable vue/no-v-html -->
<img
v-else-if="
typeof item.icon === 'string' && !isComponent(item.icon)

View File

@@ -1,6 +1,7 @@
import {mount} from '@vue/test-utils';
import { mount } from '@vue/test-utils';
import { describe, expect, it, vi } from 'vitest';
import {describe, expect, it, vi} from 'vitest';
import CardList from '../CardList.vue';
const { hasAccessByCodes } = vi.hoisted(() => ({
@@ -13,7 +14,7 @@ vi.mock('@easyflow/access', () => ({
}),
}));
describe('CardList', () => {
describe('cardList', () => {
function mountCardList(props: Record<string, unknown>) {
return mount(CardList, {
props: {