Files
dbmgr-hmos/data/src/main/ets/grid/FormViewModel.ets
T
2026-10-19 00:11:38 +08:00

129 lines
3.6 KiB
Plaintext

/**
* 表单视图模型(1.7.2)。
*
* 单行记录的表单编辑:字段定义(可编辑/只读/必填),值的脏检测与回滚,
* 提交时产出 CellChange 交给 TableEditor 生成 UPDATE。
*/
import { CellChange } from './TableEditor';
export interface FieldSpec {
column: string;
label: string;
editable: boolean;
required: boolean;
}
export class FormViewModel {
private readonly fields: FieldSpec[];
private original: Map<string, string> = new Map<string, string>();
private current: Map<string, string> = new Map<string, string>();
constructor(fields: FieldSpec[]) {
this.fields = fields.slice();
}
fields_(): FieldSpec[] {
return this.fields.slice();
}
/** 载入一行数据(重置脏状态)。 */
load(values: Map<string, string>): void {
this.original = new Map<string, string>();
this.current = new Map<string, string>();
for (let i = 0; i < this.fields.length; i++) {
const column: string = this.fields[i].column;
const value: string | undefined = values.get(column);
this.original.set(column, value === undefined ? '' : value);
this.current.set(column, value === undefined ? '' : value);
}
}
get(column: string): string {
const value: string | undefined = this.current.get(column);
return value === undefined ? '' : value;
}
/** 修改值;只读列或未知列忽略。 */
set(column: string, value: string): boolean {
const field: FieldSpec | undefined = this.fieldOf(column);
if (field === undefined || !field.editable) {
return false;
}
this.current.set(column, value);
return true;
}
isEditable(column: string): boolean {
const field: FieldSpec | undefined = this.fieldOf(column);
return field !== undefined && field.editable;
}
/** 脏字段(值发生过变化)。 */
dirtyFields(): string[] {
const out: string[] = [];
for (let i = 0; i < this.fields.length; i++) {
const column: string = this.fields[i].column;
if (this.get(column) !== this.originalOf(column)) {
out.push(column);
}
}
return out;
}
isDirty(): boolean {
return this.dirtyFields().length > 0;
}
/** 回滚到载入时的值。 */
revert(): void {
this.current = new Map<string, string>();
this.original.forEach((value: string, column: string) => {
this.current.set(column, value);
});
}
/** 必填校验;返回错误列与消息。 */
validate(): string[] {
const errors: string[] = [];
for (let i = 0; i < this.fields.length; i++) {
const field: FieldSpec = this.fields[i];
if (field.required && this.get(field.column).trim().length === 0) {
errors.push(field.column + ' is required');
}
}
return errors;
}
/** 产出变更(供 TableEditor 提交);必填不通过时返回空数组。 */
changes(): CellChange[] {
if (this.validate().length > 0) {
return [];
}
const out: CellChange[] = [];
const dirty: string[] = this.dirtyFields();
for (let i = 0; i < dirty.length; i++) {
out.push({
rowIndex: 0,
column: dirty[i],
oldValue: this.originalOf(dirty[i]),
newValue: this.get(dirty[i])
});
}
return out;
}
private originalOf(column: string): string {
const value: string | undefined = this.original.get(column);
return value === undefined ? '' : value;
}
private fieldOf(column: string): FieldSpec | undefined {
for (let i = 0; i < this.fields.length; i++) {
if (this.fields[i].column === column) {
return this.fields[i];
}
}
return undefined;
}
}