feat: 更新为 1.2.0 构建产物(内核重构版)
- 产物替换为 funjiaui.es.js / funjiaui.cjs.js / funjiaui.umd.js - style.css 更新,新增 index.d.ts 与各组件类型声明目录 - 移除旧产物 um_table.es.js(1.0.0 的 ES 包,历史与 v1.0.0 标签仍可回溯) - package.json 补齐 module / types / unpkg / jsdelivr / files 字段, 并将 vue、element-plus、@element-plus/icons-vue 声明为 peerDependencies - 新增 README 说明产物清单与用法
This commit is contained in:
Vendored
+80
@@ -0,0 +1,80 @@
|
||||
import type { VNode } from "vue";
|
||||
import type { IToolbar, TDecoratorKey, TEvent, TOperateType } from "../types";
|
||||
import { type IEventTask, type TFireHook } from "./events";
|
||||
/**
|
||||
* 列 / 操作列 / 工具栏的装配逻辑。
|
||||
*
|
||||
* 改造前这段"扫描类元数据 -> 拼 h() 节点 -> 造事件闭包"的代码
|
||||
* 全写在 UmByClass.vue 的 render() 里(200+ 行),
|
||||
* 每次渲染都要重建一遍,且无法复用、无法单测。这里抽成纯函数。
|
||||
*/
|
||||
/** 收集数据列 VNode(按 sort 升序) */
|
||||
export declare const collectDataColumns: (target: any) => VNode[];
|
||||
/** 操作列分组:同一 id(缺省用 type)的多个方法会聚合到同一个按钮上 */
|
||||
export interface IOperateGroup {
|
||||
type: TOperateType;
|
||||
sort: number;
|
||||
title?: any;
|
||||
isShow?: (rowData: any) => boolean;
|
||||
tasks: IEventTask[];
|
||||
}
|
||||
/**
|
||||
* 按 id(缺省用 type)聚合操作列配置。
|
||||
*
|
||||
* 说明:`@TableColumnMethodDecorator` 允许给多个方法配同一个 `type`,
|
||||
* 分别声明 `es: "onBefore" / "onNow" / "onAfter"`,运行时串成一条链,
|
||||
* 从而做到"先取详情 -> 再弹窗 -> 最后提交"。
|
||||
*/
|
||||
export declare const collectOperateGroups: (target: any) => IOperateGroup[];
|
||||
/**
|
||||
* 是否需要渲染操作列。
|
||||
*
|
||||
* 原判断:`(operates.length > 0 && !targetInstance.isShowOperate) || targetInstance?.isShowOperate?.()`
|
||||
* - 存在操作按钮但 `isShowOperate()` 返回 false 时,因为 `!undefined` 为真仍会渲染出空操作列;
|
||||
* - 没有操作按钮但 `isShowOperate()` 返回 true 时会渲染出一个空列。
|
||||
* 这里改成明确的语义:有按钮 && (未配置 isShowOperate 或其为真)。
|
||||
*/
|
||||
export declare const resolveShowOperate: (target: any, hasOperate: boolean) => boolean;
|
||||
/** 解析操作列宽度(支持实例属性与类静态属性两种写法) */
|
||||
export declare const resolveOperateWidth: (target: any, fallback?: number | string) => number | string;
|
||||
export interface IBuildOperateColumnOptions {
|
||||
fire: TFireHook;
|
||||
/** 透传给操作事件的行数据集合 */
|
||||
tableData?: any[];
|
||||
width?: number | string;
|
||||
/** 需要延后执行 onAfter 的按钮类型,见 IDeferOptions */
|
||||
deferAfterTypes?: string[];
|
||||
}
|
||||
/**
|
||||
* 默认的"弹窗确认型"按钮类型。
|
||||
*
|
||||
* 这些按钮的 `onAfter` 会被摘出主事件链,由组件在弹窗给出结果后补跑。
|
||||
* 单独抽成常量是为了让配置体检(`./diagnose`)和组件用同一份清单判断
|
||||
* "这个按钮是不是应该有 onAfter" —— 两边各写一份字符串迟早会对不上。
|
||||
*/
|
||||
export declare const DEFAULT_DEFER_TYPES: string[];
|
||||
/** 生成操作列 VNode;没有操作按钮时返回 null */
|
||||
export declare const buildOperateColumn: (groups: IOperateGroup[], options: IBuildOperateColumnOptions) => VNode | null;
|
||||
/** 工具栏收集结果 */
|
||||
export interface IToolbarCollectResult {
|
||||
toolbars: IToolbar[];
|
||||
events: TEvent[];
|
||||
}
|
||||
/**
|
||||
* 收集某个装饰器下、指定 `type` 的全部方法,按优先级降序返回。
|
||||
*
|
||||
* 用于"弹窗确定后补跑 onAfter"这类只需要部分阶段的场景:
|
||||
* 同一个按钮的多个方法(不同 `es`)都要收进来,但只执行其中某几个阶段。
|
||||
*/
|
||||
export declare const collectTypedTasks: (target: any, decoratorKey: TDecoratorKey, type: string) => IEventTask[];
|
||||
/**
|
||||
* 收集工具栏按钮与对应事件。
|
||||
*
|
||||
* 关于 `rerunOnAfterFalsy`:原实现靠它实现"弹窗被取消 / 接口失败后重来一轮",
|
||||
* 但事件链在 onAfter 返回假值时会用 `i -= 2` 回到第一阶段,若业务方法持续返回假值
|
||||
* 就会把弹窗反复重开。改造后弹窗改为"挂起事件链、确认后再继续"(见 deferAfterTypes),
|
||||
* 不再需要这个重跑机制,这里默认关闭,只在显式要求时启用。
|
||||
*/
|
||||
export declare const collectToolbar: (target: any, fire: TFireHook, options?: {
|
||||
deferAfterTypes?: string[];
|
||||
}) => IToolbarCollectResult;
|
||||
Vendored
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 配置体检。
|
||||
*
|
||||
* 装饰器驱动这套写法的最大代价是"错误是静默的":字符串写错、装饰器挂错位置、
|
||||
* 少写一个阶段,编译不报错、运行也不抛异常,只是功能没生效。使用方看到的现象
|
||||
* 永远是"点了没反应",然后去找组件的 bug —— 而问题在他的配置类里。
|
||||
*
|
||||
* 这个模块把常见的配置失误在组件挂载时一次性报出来,让静默的失败变成一条
|
||||
* 指得出位置的警告。它只读元数据、不改行为,报错也不阻断渲染。
|
||||
*/
|
||||
export type TDiagnosticLevel = "error" | "warn";
|
||||
export interface IDiagnostic {
|
||||
level: TDiagnosticLevel;
|
||||
/** 规则名,便于单测断言与按需忽略 */
|
||||
code: string;
|
||||
/** 出问题的成员(属性名 / 方法名 / 按钮类型),用于定位 */
|
||||
member?: string;
|
||||
/** 一句话结论 */
|
||||
message: string;
|
||||
/** 具体怎么改 */
|
||||
hint?: string;
|
||||
}
|
||||
export interface IDiagnoseOptions {
|
||||
/**
|
||||
* 需要"弹窗确认后才提交"的按钮类型,缺省用 `DEFAULT_DEFER_TYPES`。
|
||||
* 传了就以传入的为准(组件会把自己的 `defer-after-types` 传进来)。
|
||||
*/
|
||||
deferAfterTypes?: string[];
|
||||
/** 是否要求存在 `getList`(`UmByClassEnhance` 场景传 true) */
|
||||
requireGetList?: boolean;
|
||||
}
|
||||
/**
|
||||
* 检查一个配置类,返回全部发现的问题(按 error -> warn、再按成员名排序)。
|
||||
* 只读,不产生任何副作用。
|
||||
*/
|
||||
export declare const diagnoseTarget: (target: any, options?: IDiagnoseOptions) => IDiagnostic[];
|
||||
export declare const setDiagnosticsEnabled: (enabled: boolean) => void;
|
||||
export declare const isDiagnosticsEnabled: () => boolean;
|
||||
export interface IReportOptions extends IDiagnoseOptions {
|
||||
/** 本次是否上报(组件会把 `:diagnose="false"` 传进来) */
|
||||
enabled?: boolean;
|
||||
}
|
||||
/** 把诊断结果打到控制台,并原样返回,便于使用方自行处理 */
|
||||
export declare const reportDiagnostics: (target: any, options?: IReportOptions) => IDiagnostic[];
|
||||
export declare const reportDiagnosticsOnce: (target: any, options?: IReportOptions) => IDiagnostic[];
|
||||
Vendored
+68
@@ -0,0 +1,68 @@
|
||||
import type { TExecutionSequence, TMethodMetaValue } from "../types";
|
||||
/**
|
||||
* 事件链执行器。
|
||||
*
|
||||
* 改造前"按 priority 排序 -> 按 es 分阶段 -> 依次 await"这套逻辑
|
||||
* 在 UmByClass(操作列 / 工具栏)和 UmByClassEnhance(弹窗确认)里被复制了 3 份,
|
||||
* 参数顺序、是否透传行数据、是否支持重跑都各不相同。这里统一。
|
||||
*/
|
||||
/** 一个待执行的事件 */
|
||||
export interface IEventTask {
|
||||
event: (...args: any[]) => any;
|
||||
meta: TMethodMetaValue;
|
||||
}
|
||||
/** 阶段顺序 */
|
||||
export declare const EVENT_PHASES: TExecutionSequence[];
|
||||
/** 按优先级排序(数字越大越先执行),不修改入参数组 */
|
||||
export declare const sortTasksByPriority: (tasks: IEventTask[]) => IEventTask[];
|
||||
/**
|
||||
* 阶段之间的钩子,把控制权交回业务组件(弹窗、消息提示等都挂在这里)。
|
||||
* - `data`:当前累积的数据
|
||||
* - `type`:按钮类型("添加" / "edit" / "del" / "批量删除" ...),业务侧据此分支
|
||||
* - `phase`:当前阶段
|
||||
* - `meta`:该阶段第一个事件的元数据
|
||||
* @returns 处理后的数据,作为下一阶段的输入
|
||||
*/
|
||||
export type TFireHook = (data: any, type: string, phase: TExecutionSequence, meta?: TMethodMetaValue) => Promise<any> | any;
|
||||
export interface IRunEventPipelineOptions {
|
||||
tasks: IEventTask[];
|
||||
/** 原始入参,恒作为每个事件的第一个参数 */
|
||||
rowId: any;
|
||||
/**
|
||||
* "当前数据"(第二个参数,也是 fire 钩子拿到的 `data`)的初始值,
|
||||
* 缺省等于 `rowId`。
|
||||
*
|
||||
* 操作列会把整行数据作为初始值传进来:行数据通常已经是完整的,
|
||||
* 组件不应该强迫使用方再写一个 `es: "onBefore"` 的方法去查一遍详情,
|
||||
* 否则一旦漏写,`edit` 拿到的就只有一个行 id,表单会静默变成空的。
|
||||
*/
|
||||
initial?: any;
|
||||
/** 按钮类型,透传给 fire 钩子 */
|
||||
type: string;
|
||||
/** 阶段间的钩子 */
|
||||
fire: TFireHook;
|
||||
/** 透传给事件的额外参数(如整表数据) */
|
||||
extra?: any[];
|
||||
/**
|
||||
* 只执行指定阶段(默认按 onBefore -> onNow -> onAfter 全跑)。
|
||||
* 弹窗"确定"时只需要补跑 onAfter,用这个参数收窄。
|
||||
*/
|
||||
phases?: TExecutionSequence[];
|
||||
/**
|
||||
* onAfter 返回假值时是否回到第一阶段重跑。
|
||||
* 原 UmByClass 工具栏分支用 `i -= 2` 实现,一旦事件始终返回假值会死循环卡死页面,
|
||||
* 这里保留该行为但加上最大重跑次数保护。
|
||||
*/
|
||||
rerunOnAfterFalsy?: boolean;
|
||||
maxRerun?: number;
|
||||
}
|
||||
/**
|
||||
* 依次执行 onBefore -> onNow -> onAfter。
|
||||
*
|
||||
* 事件签名固定为 `(rowId, currentData, meta, ...extra)`:
|
||||
* - `rowId`:原始入参(行 id / 选中项),恒定不变;
|
||||
* - `currentData`:上一个事件的返回值,同阶段多个事件形成"责任链";
|
||||
* - `meta`:该事件的元数据;
|
||||
* - `...extra`:组件透传的额外数据(如整表数据)。
|
||||
*/
|
||||
export declare function runEventPipeline(options: IRunEventPipelineOptions): Promise<any>;
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* UmTable 组件族的内核:类元数据读取 / 事件链执行 / 列装配 / 配置体检。
|
||||
* 供有定制需求的使用方复用,无需重复实现反射扫描逻辑。
|
||||
*/
|
||||
export * from "./meta";
|
||||
export * from "./events";
|
||||
export * from "./columns";
|
||||
export * from "./diagnose";
|
||||
Vendored
+73
@@ -0,0 +1,73 @@
|
||||
import type { TDecoratorKey } from "../types";
|
||||
/**
|
||||
* 类元数据访问层。
|
||||
*
|
||||
* 改造前,"实例化 target -> for...in 遍历 -> Reflect.getMetadata"
|
||||
* 这套逻辑在 UmByClass / UmByClassEnhance / UmSearchForm / UmSearchFormEnhance /
|
||||
* UmTableForm 里被复制了 8 次,每次细节还都略有出入(有的漏了 hasOwnProperty 判断,
|
||||
* 有的用归一化名查、有的用原始名查),导致同一份配置在不同组件里表现不一致。
|
||||
*
|
||||
* 这里收口成唯一实现。
|
||||
*/
|
||||
/** 类实例上的一个成员 */
|
||||
export interface IClassMember {
|
||||
/** 类上的原始属性名(可能带 `_` 前缀) */
|
||||
key: string;
|
||||
/** 归一化名称:去掉 `_` 前缀,与后端字段名一致 */
|
||||
fieldName: string;
|
||||
/** 成员的值 */
|
||||
value: any;
|
||||
/** 是否为函数成员 */
|
||||
isMethod: boolean;
|
||||
}
|
||||
/** 带元数据的成员 */
|
||||
export type IDecoratedMember<M> = IClassMember & {
|
||||
meta: M;
|
||||
};
|
||||
/** 去掉 `_` 前缀:`_foo` -> `foo` */
|
||||
export declare const normalizeFieldName: (key: string) => string;
|
||||
/**
|
||||
* 构造实例,用于读取"实例字段"上的装饰器元数据。
|
||||
* target 为空或不是构造函数时返回原值 / 空对象,避免抛错。
|
||||
*/
|
||||
export declare const createTargetInstance: (target: any) => any;
|
||||
/**
|
||||
* 收集类实例上的全部成员(含原型链上的方法)。
|
||||
*
|
||||
* 为什么要扫原型链:当 `useDefineForClassFields = false` 时,
|
||||
* 无初始值的字段(如 `birthday: any;`)不会出现在实例上,
|
||||
* 只靠 `for...in` 会漏掉这些字段对应的列。
|
||||
*/
|
||||
export declare const collectClassMembers: (target: any) => IClassMember[];
|
||||
/**
|
||||
* 读取某个成员上的装饰器元数据。
|
||||
* 先按归一化名查,再按原始名查,兼容两种书写习惯。
|
||||
*/
|
||||
export declare const getMemberMeta: <M>(target: any, decoratorKey: TDecoratorKey, member: Pick<IClassMember, "key" | "fieldName">) => M | undefined;
|
||||
/**
|
||||
* 扫描出所有挂载了指定装饰器元数据的成员。
|
||||
* @param options.methods 是否是方法成员(默认 false,即取普通字段)
|
||||
*/
|
||||
export declare const scanDecoratedMembers: <M>(target: any, decoratorKey: TDecoratorKey, options?: {
|
||||
methods?: boolean;
|
||||
}) => IDecoratedMember<M>[];
|
||||
/**
|
||||
* 在"接口原始数据"与"表单展示数据"之间做双向字段转换。
|
||||
*
|
||||
* 约定:类上用 `_field` 存原始值,再通过 getter/setter `field` 暴露格式化后的值
|
||||
* (金额、日期、字典等)。原实现把这段转换在 UmByClassEnhance 里写了两遍
|
||||
* (打开弹窗时一遍、提交时一遍),且两遍取的属性名还不一致(一处取 `field`、
|
||||
* 一处取 `_field`),行为难以预期。这里统一为单一实现:
|
||||
* - `in` :接口原始值 -> 表单展示值(走 getter)
|
||||
* - `out`:表单展示值 -> 接口原始值(走 `_field`)
|
||||
*
|
||||
* @returns 转换后的同一份 data(便于链式调用)
|
||||
*/
|
||||
export declare const transformFields: (target: any, data: any, direction: "in" | "out") => any;
|
||||
/**
|
||||
* 按类型取出某个方法元数据(早退版本,避免每次全量扫描后才 return)
|
||||
*/
|
||||
export declare const findMethodMeta: (target: any, decoratorKey: TDecoratorKey, type: string) => {
|
||||
meta: any;
|
||||
member: IDecoratedMember<any>;
|
||||
} | null;
|
||||
Reference in New Issue
Block a user