初始化项目
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* 表单视图模型(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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user