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

@@ -1,272 +1,292 @@
export interface ParameterLike {
name?: string;
ref?: string;
refType?: string;
children?: ParameterLike[];
name?: string;
ref?: string;
refType?: string;
children?: ParameterLike[];
}
export interface TokenRange {
start: number;
end: number;
text: string;
key: string;
start: number;
end: number;
text: string;
key: string;
}
export type TokenPart =
| {
type: 'text';
text: string;
}
| {
type: 'token';
text: string;
key: string;
valid: boolean;
};
| {
type: 'text';
text: string;
}
| {
type: 'token';
text: string;
key: string;
valid: boolean;
};
export interface ParameterCandidate {
name: string;
resolved: boolean;
name: string;
resolved: boolean;
}
const TOKEN_PATTERN = /\{\{\s*([^{}]+?)\s*}}/g;
export function normalizeTokenKey(tokenKey: string): string {
return tokenKey.trim();
return tokenKey.trim();
}
export function flattenParameterNames(parameters?: ParameterLike[] | null): string[] {
return flattenParameterCandidates(parameters).map((item) => item.name);
export function flattenParameterNames(
parameters?: ParameterLike[] | null,
): string[] {
return flattenParameterCandidates(parameters).map((item) => item.name);
}
function isParameterResolved(parameter?: ParameterLike): boolean {
if (!parameter) {
return false;
}
if (!parameter) {
return false;
}
const refType = (parameter.refType || '').trim();
if (refType === 'fixed' || refType === 'input') {
return true;
}
const refType = (parameter.refType || '').trim();
if (refType === 'fixed' || refType === 'input') {
return true;
}
const ref = (parameter.ref || '').trim();
return !!ref;
const ref = (parameter.ref || '').trim();
return !!ref;
}
export function flattenParameterCandidates(parameters?: ParameterLike[] | null): ParameterCandidate[] {
if (!parameters || parameters.length === 0) {
return [];
export function flattenParameterCandidates(
parameters?: ParameterLike[] | null,
): ParameterCandidate[] {
if (!parameters || parameters.length === 0) {
return [];
}
const candidates: ParameterCandidate[] = [];
const indexMap = new Map<string, number>();
const addCandidate = (name: string, resolved: boolean) => {
const normalized = name.trim();
if (!normalized) {
return;
}
const exists = indexMap.get(normalized);
if (exists === undefined) {
indexMap.set(normalized, candidates.length);
candidates.push({
name: normalized,
resolved,
});
return;
}
const candidates: ParameterCandidate[] = [];
const indexMap = new Map<string, number>();
// 同名参数只要有一个可解析,就视为可解析
if (resolved) {
candidates[exists].resolved = true;
}
};
const addCandidate = (name: string, resolved: boolean) => {
const normalized = name.trim();
if (!normalized) {
return;
}
const exists = indexMap.get(normalized);
if (exists === undefined) {
indexMap.set(normalized, candidates.length);
candidates.push({
name: normalized,
resolved
});
return;
}
const walk = (
items: ParameterLike[],
parentPath = '',
inheritedResolved = true,
) => {
for (const item of items) {
const rawName = item?.name?.trim();
if (!rawName) {
continue;
}
// 同名参数只要有一个可解析,就视为可解析
if (resolved) {
candidates[exists].resolved = true;
}
};
const currentPath = parentPath ? `${parentPath}.${rawName}` : rawName;
const currentResolved = inheritedResolved && isParameterResolved(item);
addCandidate(currentPath, currentResolved);
const walk = (items: ParameterLike[], parentPath = '', inheritedResolved = true) => {
for (const item of items) {
const rawName = item?.name?.trim();
if (!rawName) {
continue;
}
if (item.children && item.children.length > 0) {
walk(item.children, currentPath, currentResolved);
}
}
};
const currentPath = parentPath ? `${parentPath}.${rawName}` : rawName;
const currentResolved = inheritedResolved && isParameterResolved(item);
addCandidate(currentPath, currentResolved);
if (item.children && item.children.length > 0) {
walk(item.children, currentPath, currentResolved);
}
}
};
walk(parameters);
return candidates;
walk(parameters);
return candidates;
}
export function parseTokenParts(content: string, validParams: string[] = []): TokenPart[] {
const source = content ?? '';
const validSet = new Set(validParams.map(normalizeTokenKey));
const parts: TokenPart[] = [];
export function parseTokenParts(
content: string,
validParams: string[] = [],
): TokenPart[] {
const source = content ?? '';
const validSet = new Set(validParams.map(normalizeTokenKey));
const parts: TokenPart[] = [];
let lastIndex = 0;
TOKEN_PATTERN.lastIndex = 0;
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
let lastIndex = 0;
TOKEN_PATTERN.lastIndex = 0;
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
while (match) {
if (match.index > lastIndex) {
parts.push({
type: 'text',
text: source.slice(lastIndex, match.index)
});
}
const rawToken = match[0];
const tokenKey = normalizeTokenKey(match[1] || '');
parts.push({
type: 'token',
text: rawToken,
key: tokenKey,
valid: validSet.has(tokenKey)
});
lastIndex = match.index + rawToken.length;
match = TOKEN_PATTERN.exec(source);
while (match) {
if (match.index > lastIndex) {
parts.push({
type: 'text',
text: source.slice(lastIndex, match.index),
});
}
if (lastIndex < source.length) {
parts.push({
type: 'text',
text: source.slice(lastIndex)
});
}
const rawToken = match[0];
const tokenKey = normalizeTokenKey(match[1] || '');
parts.push({
type: 'token',
text: rawToken,
key: tokenKey,
valid: validSet.has(tokenKey),
});
if (parts.length === 0) {
parts.push({
type: 'text',
text: source
});
}
lastIndex = match.index + rawToken.length;
match = TOKEN_PATTERN.exec(source);
}
return parts;
if (lastIndex < source.length) {
parts.push({
type: 'text',
text: source.slice(lastIndex),
});
}
if (parts.length === 0) {
parts.push({
type: 'text',
text: source,
});
}
return parts;
}
export function getTokenRanges(content: string): TokenRange[] {
const source = content ?? '';
const ranges: TokenRange[] = [];
TOKEN_PATTERN.lastIndex = 0;
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
const source = content ?? '';
const ranges: TokenRange[] = [];
TOKEN_PATTERN.lastIndex = 0;
let match: RegExpExecArray | null = TOKEN_PATTERN.exec(source);
while (match) {
const rawToken = match[0];
ranges.push({
start: match.index,
end: match.index + rawToken.length,
text: rawToken,
key: normalizeTokenKey(match[1] || '')
});
match = TOKEN_PATTERN.exec(source);
}
while (match) {
const rawToken = match[0];
ranges.push({
start: match.index,
end: match.index + rawToken.length,
text: rawToken,
key: normalizeTokenKey(match[1] || ''),
});
match = TOKEN_PATTERN.exec(source);
}
return ranges;
return ranges;
}
export function findTokenRangeAtCursor(
content: string,
cursor: number,
options?: {
includeStart?: boolean;
includeEnd?: boolean;
}
content: string,
cursor: number,
options?: {
includeStart?: boolean;
includeEnd?: boolean;
},
): TokenRange | null {
if (!Number.isInteger(cursor) || cursor < 0) {
return null;
}
const includeStart = options?.includeStart ?? false;
const includeEnd = options?.includeEnd ?? false;
const ranges = getTokenRanges(content);
for (const range of ranges) {
const leftValid = includeStart ? cursor >= range.start : cursor > range.start;
const rightValid = includeEnd ? cursor <= range.end : cursor < range.end;
if (leftValid && rightValid) {
return range;
}
}
if (!Number.isInteger(cursor) || cursor < 0) {
return null;
}
const includeStart = options?.includeStart ?? false;
const includeEnd = options?.includeEnd ?? false;
const ranges = getTokenRanges(content);
for (const range of ranges) {
const leftValid = includeStart
? cursor >= range.start
: cursor > range.start;
const rightValid = includeEnd ? cursor <= range.end : cursor < range.end;
if (leftValid && rightValid) {
return range;
}
}
return null;
}
export function findBackspaceTokenRange(content: string, cursor: number): TokenRange | null {
return findTokenRangeAtCursor(content, cursor, {
includeStart: false,
includeEnd: true
});
export function findBackspaceTokenRange(
content: string,
cursor: number,
): TokenRange | null {
return findTokenRangeAtCursor(content, cursor, {
includeStart: false,
includeEnd: true,
});
}
export function splitTokenDisplay(rawToken: string, normalizedKey?: string): {
hiddenPrefix: string;
visibleText: string;
hiddenSuffix: string;
export function splitTokenDisplay(
rawToken: string,
normalizedKey?: string,
): {
hiddenPrefix: string;
visibleText: string;
hiddenSuffix: string;
} {
const source = rawToken ?? '';
if (!source.startsWith('{{') || !source.endsWith('}}')) {
return {
hiddenPrefix: '',
visibleText: normalizedKey || source,
hiddenSuffix: ''
};
}
const inner = source.slice(2, -2);
const visibleText = normalizeTokenKey(normalizedKey || inner);
if (!visibleText) {
return {
hiddenPrefix: '',
visibleText: source,
hiddenSuffix: ''
};
}
const innerStart = inner.indexOf(visibleText);
const leading = innerStart >= 0 ? inner.slice(0, innerStart) : '';
const trailing = innerStart >= 0 ? inner.slice(innerStart + visibleText.length) : '';
const source = rawToken ?? '';
if (!source.startsWith('{{') || !source.endsWith('}}')) {
return {
hiddenPrefix: `{{${leading}`,
visibleText,
hiddenSuffix: `${trailing}}}`
hiddenPrefix: '',
visibleText: normalizedKey || source,
hiddenSuffix: '',
};
}
const inner = source.slice(2, -2);
const visibleText = normalizeTokenKey(normalizedKey || inner);
if (!visibleText) {
return {
hiddenPrefix: '',
visibleText: source,
hiddenSuffix: '',
};
}
const innerStart = inner.indexOf(visibleText);
const leading = innerStart >= 0 ? inner.slice(0, innerStart) : '';
const trailing =
innerStart >= 0 ? inner.slice(innerStart + visibleText.length) : '';
return {
hiddenPrefix: `{{${leading}`,
visibleText,
hiddenSuffix: `${trailing}}}`,
};
}
export function insertTextAtCursor(
content: string,
insertedText: string,
selectionStart?: number | null,
selectionEnd?: number | null
content: string,
insertedText: string,
selectionStart?: number | null,
selectionEnd?: number | null,
): {
value: string;
cursor: number;
value: string;
cursor: number;
} {
const source = content ?? '';
const start = Number.isInteger(selectionStart)
? Math.max(0, Math.min(selectionStart as number, source.length))
: source.length;
const end = Number.isInteger(selectionEnd)
? Math.max(start, Math.min(selectionEnd as number, source.length))
: start;
const source = content ?? '';
const start = Number.isInteger(selectionStart)
? Math.max(0, Math.min(selectionStart as number, source.length))
: source.length;
const end = Number.isInteger(selectionEnd)
? Math.max(start, Math.min(selectionEnd as number, source.length))
: start;
const nextValue = source.slice(0, start) + insertedText + source.slice(end);
return {
value: nextValue,
cursor: start + insertedText.length
};
const nextValue = source.slice(0, start) + insertedText + source.slice(end);
return {
value: nextValue,
cursor: start + insertedText.length,
};
}
export function escapeHtml(text: string): string {
return text
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;');
return text
.replaceAll('&', '&amp;')
.replaceAll('<', '&lt;')
.replaceAll('>', '&gt;')
.replaceAll('"', '&quot;')
.replaceAll("'", '&#39;');
}