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

95 lines
3.2 KiB
Plaintext

/**
* 数据校验与冲突提示(1.7.11)。
*
* 两层:
* - RowValidator:按列规则(必填/长度/正则)校验单元格与整行;
* - ConflictDetector:乐观并发——提交前比对「读取时版本」与「当前库中版本」,
* 不一致即判定冲突,UI 提示用户重新加载或覆盖。
*/
export interface ColumnRule {
column: string;
required: boolean;
minLength: number;
maxLength: number;
/** 正则;为空表示不校验。 */
pattern: string;
}
export interface ValidationIssue {
column: string;
message: string;
}
export class RowValidator {
/** 校验单元格,返回错误消息(空数组通过)。 */
static validateCell(rule: ColumnRule, value: string): string[] {
const errors: string[] = [];
const text: string = value === undefined || value === null ? '' : value;
if (rule.required && text.trim().length === 0) {
errors.push(rule.column + ' is required');
return errors;
}
if (text.length > 0 && rule.maxLength > 0 && text.length > rule.maxLength) {
errors.push(rule.column + ' exceeds max length ' + rule.maxLength);
}
if (text.length > 0 && rule.minLength > 0 && text.length < rule.minLength) {
errors.push(rule.column + ' is shorter than min length ' + rule.minLength);
}
if (text.length > 0 && rule.pattern.length > 0 && !new RegExp(rule.pattern).test(text)) {
errors.push(rule.column + ' does not match pattern ' + rule.pattern);
}
return errors;
}
/** 校验整行(values: 列 → 值)。 */
static validateRow(values: Map<string, string>, rules: ColumnRule[]): ValidationIssue[] {
const issues: ValidationIssue[] = [];
for (let i = 0; i < rules.length; i++) {
const rule: ColumnRule = rules[i];
const value: string | undefined = values.get(rule.column);
const errors: string[] = RowValidator.validateCell(rule, value === undefined ? '' : value);
for (let j = 0; j < errors.length; j++) {
issues.push({ column: rule.column, message: errors[j] });
}
}
return issues;
}
/** 便捷:无错误为 true。 */
static isValid(values: Map<string, string>, rules: ColumnRule[]): boolean {
return RowValidator.validateRow(values, rules).length === 0;
}
}
export interface ConflictInfo {
conflict: boolean;
reason: string;
}
export class ConflictDetector {
/**
* 乐观并发检测:读取时版本与提交时版本不同即冲突。
* 版本可以是时间戳、行版本号或 updated_at 字符串。
*/
static detect(fetchedVersion: string, currentVersion: string): ConflictInfo {
if (fetchedVersion === currentVersion) {
return { conflict: false, reason: '' };
}
return {
conflict: true,
reason: 'row changed since load: fetched=' + fetchedVersion + ', current=' + currentVersion
};
}
/** 批量检测(行号 → {fetched, current})。 */
static detectBatch(pairs: Map<number, string[]>): Map<number, ConflictInfo> {
const out: Map<number, ConflictInfo> = new Map<number, ConflictInfo>();
pairs.forEach((versions: string[], row: number) => {
if (versions.length >= 2) {
out.set(row, ConflictDetector.detect(versions[0], versions[1]));
}
});
return out;
}
}