You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kev/Drawer/AI/Models/SpecialMessages/FormRequestMessage.cs

127 lines
5.2 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using AI.Models.Form;
namespace AI.Models.SpecialMessages
{
/// <summary>
/// 表单请求特殊消息 - 在聊天流中显示可填写的表单
/// </summary>
public class FormRequestMessage : ISpecialMessage, INotifyPropertyChanged
{
private string _submitLabel = "提交";
/// <summary>消息唯一标识符</summary>
public string Id { get; set; } = Guid.NewGuid().ToString();
/// <summary>类型名称</summary>
public string TypeName => "Form";
/// <summary>不需要实时更新</summary>
public bool IsLive => false;
/// <summary>表单定义(只读)</summary>
public FormDefinition Definition { get; }
/// <summary>带当前值的字段列表,用于绑定与提交</summary>
public ObservableCollection<FormFieldEntry> FieldsWithValues { get; } = new ObservableCollection<FormFieldEntry>();
/// <summary>提交按钮文案(可从 Definition 覆盖)</summary>
public string SubmitLabel
{
get => _submitLabel;
set => SetProperty(ref _submitLabel, value);
}
public FormRequestMessage(FormDefinition definition)
{
Definition = definition ?? throw new ArgumentNullException(nameof(definition));
_submitLabel = definition.SubmitLabel;
foreach (var f in definition.Fields)
{
var entry = new FormFieldEntry
{
Id = f.Id,
Label = f.Label,
Description = f.Description,
Type = f.Type,
Required = f.Required,
DefaultValue = f.DefaultValue,
Options = f.Options,
Min = f.Min,
Max = f.Max,
Step = f.Step,
MaxLength = f.MaxLength,
Placeholder = f.Placeholder,
DefaultValues = f.DefaultValues != null ? new List<string>(f.DefaultValues) : null,
CurrentValue = f.DefaultValue?.ToString() ?? string.Empty,
};
if (f.Type == FormFieldType.MultiSelect)
{
if (f.DefaultValues != null && f.DefaultValues.Count > 0)
{
foreach (var v in f.DefaultValues)
entry.SelectedValues.Add(v);
}
else if (f.DefaultValue is System.Collections.IEnumerable en && f.DefaultValue is not string)
{
foreach (var v in en)
entry.SelectedValues.Add(v?.ToString() ?? string.Empty);
}
else if (f.DefaultValue is string defStr && !string.IsNullOrEmpty(defStr))
{
foreach (var v in defStr.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
entry.SelectedValues.Add(v);
}
if (f.Options != null)
{
foreach (var opt in f.Options)
entry.MultiSelectOptions.Add(new MultiSelectOptionItem(entry, opt, entry.SelectedValues.Contains(opt)));
}
}
FieldsWithValues.Add(entry);
}
}
/// <summary>收集当前值用于提交。Key 为字段 IdValue 为对象(按 Type 转换)</summary>
public Dictionary<string, object> GetValues()
{
var dict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
foreach (var entry in FieldsWithValues)
{
var raw = entry.CurrentValue?.Trim() ?? string.Empty;
object value = entry.Type switch
{
FormFieldType.Number => double.TryParse(raw, out var n) ? n : 0d,
FormFieldType.Boolean => raw is "1" or "true" or "True" or "yes" or "是",
FormFieldType.Json => raw,
FormFieldType.MultiSelect => entry.SelectedValues.Count > 0
? new List<string>(entry.SelectedValues)
: (object)raw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries).ToList(),
_ => raw,
};
dict[entry.Id] = value;
}
return dict;
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string? propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}
}