feat: add Flutter schema-driven form cards
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
enum JsonValueType { string, number, boolean }
|
||||
|
||||
enum FormControlType { text, textArea, select, dateTime }
|
||||
|
||||
class DynamicFormDefinition {
|
||||
const DynamicFormDefinition({
|
||||
required this.dataSchema,
|
||||
required this.uiSchema,
|
||||
});
|
||||
|
||||
final JsonFormSchema dataSchema;
|
||||
final FormUiSchema uiSchema;
|
||||
}
|
||||
|
||||
class JsonFormSchema {
|
||||
const JsonFormSchema({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.properties,
|
||||
this.required = const {},
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String title;
|
||||
final Map<String, JsonFieldSchema> properties;
|
||||
final Set<String> required;
|
||||
}
|
||||
|
||||
class JsonFieldSchema {
|
||||
const JsonFieldSchema({
|
||||
required this.type,
|
||||
this.format,
|
||||
this.enumValues = const [],
|
||||
this.minLength,
|
||||
this.maxLength,
|
||||
});
|
||||
|
||||
final JsonValueType type;
|
||||
final String? format;
|
||||
final List<String> enumValues;
|
||||
final int? minLength;
|
||||
final int? maxLength;
|
||||
}
|
||||
|
||||
class FormUiSchema {
|
||||
const FormUiSchema({required this.description, required this.sections});
|
||||
|
||||
final String description;
|
||||
final List<FormSectionSchema> sections;
|
||||
}
|
||||
|
||||
class FormSectionSchema {
|
||||
const FormSectionSchema({required this.title, required this.controls});
|
||||
|
||||
final String title;
|
||||
final List<FormControlSchema> controls;
|
||||
}
|
||||
|
||||
class FormControlSchema {
|
||||
const FormControlSchema({
|
||||
required this.field,
|
||||
required this.label,
|
||||
required this.control,
|
||||
this.placeholder,
|
||||
this.helperText,
|
||||
this.optionLabels = const {},
|
||||
});
|
||||
|
||||
final String field;
|
||||
final String label;
|
||||
final FormControlType control;
|
||||
final String? placeholder;
|
||||
final String? helperText;
|
||||
final Map<String, String> optionLabels;
|
||||
}
|
||||
|
||||
class DynamicFormState {
|
||||
const DynamicFormState({this.values = const {}, this.errors = const {}});
|
||||
|
||||
final Map<String, Object?> values;
|
||||
final Map<String, String> errors;
|
||||
|
||||
DynamicFormState copyWith({
|
||||
Map<String, Object?>? values,
|
||||
Map<String, String>? errors,
|
||||
}) {
|
||||
return DynamicFormState(
|
||||
values: values ?? this.values,
|
||||
errors: errors ?? this.errors,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:aioa_mobile/core/forms/schema/form_schema.dart';
|
||||
|
||||
Map<String, String> validateDynamicForm(
|
||||
JsonFormSchema schema,
|
||||
Map<String, Object?> values,
|
||||
) {
|
||||
final errors = <String, String>{};
|
||||
for (final entry in schema.properties.entries) {
|
||||
final key = entry.key;
|
||||
final value = values[key];
|
||||
final field = entry.value;
|
||||
final empty = value == null || (value is String && value.trim().isEmpty);
|
||||
if (schema.required.contains(key) && empty) {
|
||||
errors[key] = '此项为必填项';
|
||||
continue;
|
||||
}
|
||||
if (empty) continue;
|
||||
if (value is String) {
|
||||
if (field.minLength != null && value.trim().length < field.minLength!) {
|
||||
errors[key] = '至少输入 ${field.minLength} 个字符';
|
||||
} else if (field.maxLength != null && value.length > field.maxLength!) {
|
||||
errors[key] = '最多输入 ${field.maxLength} 个字符';
|
||||
} else if (field.enumValues.isNotEmpty &&
|
||||
!field.enumValues.contains(value)) {
|
||||
errors[key] = '选项无效';
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
Reference in New Issue
Block a user