2023-11-07 22:32:38 +08:00
|
|
|
|
using System.Collections.Generic;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.Linq;
|
2023-03-24 22:32:42 +08:00
|
|
|
|
using System.Windows.Input;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
using System.Windows.Media;
|
2023-04-26 22:53:44 +08:00
|
|
|
|
using AIStudio.Wpf.DiagramDesigner.Enums;
|
2023-01-25 11:11:27 +08:00
|
|
|
|
using AIStudio.Wpf.DiagramDesigner.Models;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2022-10-28 22:45:39 +08:00
|
|
|
|
namespace AIStudio.Wpf.DiagramDesigner
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-01-27 14:54:03 +08:00
|
|
|
|
public abstract class LogicalGateItemViewModelBase : DesignerItemViewModelBase
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-04-15 23:32:29 +08:00
|
|
|
|
public ICommand AddInputCommand
|
|
|
|
|
|
{
|
|
|
|
|
|
get; private set;
|
|
|
|
|
|
}
|
|
|
|
|
|
public ICommand AddOutputCommand
|
|
|
|
|
|
{
|
|
|
|
|
|
get; private set;
|
|
|
|
|
|
}
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-04-22 21:06:52 +08:00
|
|
|
|
public virtual bool EnableAddInput
|
|
|
|
|
|
{
|
|
|
|
|
|
get;
|
|
|
|
|
|
} = false;
|
|
|
|
|
|
|
|
|
|
|
|
public virtual bool EnableAddOutput
|
|
|
|
|
|
{
|
|
|
|
|
|
get;
|
|
|
|
|
|
} = false;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-01-27 14:54:03 +08:00
|
|
|
|
public LogicalGateItemViewModelBase(LogicalType logicalType) : this(null, logicalType)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public LogicalGateItemViewModelBase(IDiagramViewModel root, LogicalType logicalType) : base(root)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-04-23 22:44:15 +08:00
|
|
|
|
this.LogicalType = logicalType;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-24 17:53:04 +08:00
|
|
|
|
public LogicalGateItemViewModelBase(IDiagramViewModel root, SelectableItemBase designer) : base(root, designer)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-04-23 22:44:15 +08:00
|
|
|
|
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-25 11:11:27 +08:00
|
|
|
|
public LogicalGateItemViewModelBase(IDiagramViewModel root, SerializableItem serializableItem, string serializableType) : base(root, serializableItem, serializableType)
|
2022-12-08 20:54:45 +08:00
|
|
|
|
{
|
2023-04-23 22:44:15 +08:00
|
|
|
|
|
2022-12-08 20:54:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-24 23:10:57 +08:00
|
|
|
|
public override SelectableItemBase GetSerializableObject()
|
2022-12-08 20:54:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
return new LogicalGateDesignerItemBase(this);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-25 11:59:31 +08:00
|
|
|
|
protected override void Init(IDiagramViewModel root, bool initNew)
|
2023-04-15 23:32:29 +08:00
|
|
|
|
{
|
2021-07-23 09:42:22 +08:00
|
|
|
|
ShowRotate = false;
|
2021-08-01 22:30:12 +08:00
|
|
|
|
ShowArrow = false;
|
2023-01-25 23:55:30 +08:00
|
|
|
|
AddInputCommand = new SimpleCommand(Command_Enable, para => ExecuteAddInput(para));
|
|
|
|
|
|
AddOutputCommand = new SimpleCommand(Command_Enable, para => ExecuteAddOutput(para));
|
2023-04-22 21:06:52 +08:00
|
|
|
|
BuildMenuOptions();
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-03-25 11:59:31 +08:00
|
|
|
|
base.Init(root, initNew);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override void InitNew()
|
|
|
|
|
|
{
|
2023-05-21 22:06:59 +08:00
|
|
|
|
ExecuteAddInput(null);
|
|
|
|
|
|
ExecuteAddInput(null);
|
|
|
|
|
|
ExecuteAddOutput(null);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void BuildMenuOptions()
|
|
|
|
|
|
{
|
|
|
|
|
|
menuOptions = new ObservableCollection<CinchMenuItem>();
|
2023-04-22 21:06:52 +08:00
|
|
|
|
if (EnableAddInput == true)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
CinchMenuItem menuItem = new CinchMenuItem();
|
|
|
|
|
|
menuItem.Text = "添加输入";
|
|
|
|
|
|
menuItem.Command = AddInputCommand;
|
|
|
|
|
|
menuItem.CommandParameter = menuItem;
|
|
|
|
|
|
menuOptions.Add(menuItem);
|
|
|
|
|
|
}
|
2023-04-22 21:06:52 +08:00
|
|
|
|
if (EnableAddOutput == true)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
CinchMenuItem menuItem = new CinchMenuItem();
|
|
|
|
|
|
menuItem.Text = "添加输出";
|
|
|
|
|
|
menuItem.Command = AddOutputCommand;
|
|
|
|
|
|
menuItem.CommandParameter = menuItem;
|
|
|
|
|
|
menuOptions.Add(menuItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-27 14:54:03 +08:00
|
|
|
|
protected override void LoadDesignerItemViewModel(SelectableItemBase designerbase)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-01-27 14:54:03 +08:00
|
|
|
|
base.LoadDesignerItemViewModel(designerbase);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-01-24 17:53:04 +08:00
|
|
|
|
if (designerbase is LogicalGateDesignerItemBase designer)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.LogicalType = designer.LogicalType;
|
|
|
|
|
|
this.OrderNumber = designer.OrderNumber;
|
|
|
|
|
|
this.Value = designer.Value;
|
|
|
|
|
|
this.IsEnabled = designer.IsEnabled;
|
|
|
|
|
|
|
|
|
|
|
|
ClearConnectors();
|
|
|
|
|
|
Input.Clear();
|
|
|
|
|
|
Output.Clear();
|
|
|
|
|
|
|
2023-04-16 12:21:51 +08:00
|
|
|
|
if (designer.LogicalConnectors != null)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-04-16 12:21:51 +08:00
|
|
|
|
foreach (var connector in designer.LogicalConnectors)
|
2023-01-24 17:53:04 +08:00
|
|
|
|
{
|
2023-04-16 12:21:51 +08:00
|
|
|
|
LogicalConnectorInfo fullyCreatedConnectorInfo = new LogicalConnectorInfo(this.Root, this, connector);
|
|
|
|
|
|
|
|
|
|
|
|
if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
Input.Add(Input.Count, fullyCreatedConnectorInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (fullyCreatedConnectorInfo.Orientation == ConnectorOrientation.Right)
|
|
|
|
|
|
{
|
|
|
|
|
|
Output.Add(Output.Count, fullyCreatedConnectorInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
AddConnector(fullyCreatedConnectorInfo);
|
2023-01-24 17:53:04 +08:00
|
|
|
|
}
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private int _orderNumber;
|
|
|
|
|
|
public int OrderNumber
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return _orderNumber;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
SetProperty(ref _orderNumber, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool _isEnabled;
|
|
|
|
|
|
public bool IsEnabled
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return _isEnabled;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
SetProperty(ref _isEnabled, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private double _value;
|
|
|
|
|
|
public double Value
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return _value;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
SetProperty(ref _value, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-15 23:32:29 +08:00
|
|
|
|
public LogicalType LogicalType
|
|
|
|
|
|
{
|
|
|
|
|
|
get; set;
|
|
|
|
|
|
}
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
|
|
|
|
|
|
2023-01-31 22:45:50 +08:00
|
|
|
|
public Dictionary<int, LogicalConnectorInfo> Input { get; set; } = new Dictionary<int, LogicalConnectorInfo>();
|
|
|
|
|
|
public Dictionary<int, LogicalConnectorInfo> Output { get; set; } = new Dictionary<int, LogicalConnectorInfo>();
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-04-23 22:44:15 +08:00
|
|
|
|
public override void ClearConnectors()
|
|
|
|
|
|
{
|
2023-05-21 22:06:59 +08:00
|
|
|
|
Connectors.Clear();
|
2023-04-23 22:44:15 +08:00
|
|
|
|
Input.Clear();
|
|
|
|
|
|
Output.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual LogicalConnectorInfo ExecuteAddInput(object parameter, int index = 0, string name = null)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (Input.Values.Count >= 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.ItemHeight = this.ItemHeight * (Input.Values.Count + 1) / Input.Values.Count;
|
|
|
|
|
|
}
|
2023-01-31 22:45:50 +08:00
|
|
|
|
LogicalConnectorInfo connector = new LogicalConnectorInfo(this, ConnectorOrientation.Left, true, false, ValueTypeInput.Count > index ? ValueTypeInput[index] : ValueTypeInput[0]);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
connector.XRatio = 0;
|
2023-04-23 22:44:15 +08:00
|
|
|
|
connector.Name = name ?? $"Input{index}";
|
2021-07-23 09:42:22 +08:00
|
|
|
|
Input.Add(Input.Count, connector);
|
|
|
|
|
|
for (int i = 0; i < Input.Values.Count; i++)
|
|
|
|
|
|
{
|
2021-08-01 22:30:12 +08:00
|
|
|
|
Input[i].YRatio = (i + 1.0) / (Input.Values.Count + 1.0);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
AddConnector(connector);
|
2023-04-22 22:40:41 +08:00
|
|
|
|
|
|
|
|
|
|
return connector;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-23 22:44:15 +08:00
|
|
|
|
public virtual LogicalConnectorInfo ExecuteAddOutput(object parameter, int index = 0, string name = null)
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
2023-01-31 22:45:50 +08:00
|
|
|
|
LogicalConnectorInfo connector = new LogicalConnectorInfo(this, ConnectorOrientation.Right, true, false, ValueTypeOutput.Count > index ? ValueTypeOutput[index] : ValueTypeInput[0]);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
connector.XRatio = 1;
|
2023-04-23 22:44:15 +08:00
|
|
|
|
connector.Name = name ?? $"Output{index}";
|
2021-07-23 09:42:22 +08:00
|
|
|
|
Output.Add(Output.Count, connector);
|
|
|
|
|
|
for (int i = 0; i < Output.Values.Count; i++)
|
|
|
|
|
|
{
|
2021-08-01 22:30:12 +08:00
|
|
|
|
Output[i].YRatio = (i + 1.0) / (Output.Values.Count + 1.0);
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
AddConnector(connector);
|
2023-04-22 22:40:41 +08:00
|
|
|
|
|
|
|
|
|
|
return connector;
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-29 18:36:50 +08:00
|
|
|
|
public virtual List<ConnectorValueType> ValueTypeInput
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2023-04-29 18:36:50 +08:00
|
|
|
|
return new List<ConnectorValueType>() { ConnectorValueType.Real };
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-29 18:36:50 +08:00
|
|
|
|
public virtual List<ConnectorValueType> ValueTypeOutput
|
2021-07-23 09:42:22 +08:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
2023-04-29 18:36:50 +08:00
|
|
|
|
return new List<ConnectorValueType>() { ConnectorValueType.Real };
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-04-15 23:32:29 +08:00
|
|
|
|
|
2023-04-16 10:10:12 +08:00
|
|
|
|
public void Execute()
|
|
|
|
|
|
{
|
|
|
|
|
|
GetInput();
|
|
|
|
|
|
CalculateOutput();
|
|
|
|
|
|
}
|
2023-04-29 18:36:50 +08:00
|
|
|
|
|
2023-04-15 23:32:29 +08:00
|
|
|
|
public virtual void GetInput()
|
|
|
|
|
|
{
|
2023-04-16 20:11:40 +08:00
|
|
|
|
foreach (var input in Input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var connector = GetSourceItem(input.Value);
|
|
|
|
|
|
if (connector == null)
|
|
|
|
|
|
{
|
2023-04-26 22:53:44 +08:00
|
|
|
|
input.Value.ErrorCode = ConnectorErrorCode.None;
|
2023-04-16 20:11:40 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-05-03 09:59:46 +08:00
|
|
|
|
if (connector.SourceConnectorInfoFully?.DataItem is LogicalGateItemViewModelBase sourceItem)
|
2023-04-16 20:11:40 +08:00
|
|
|
|
{
|
2023-05-03 09:59:46 +08:00
|
|
|
|
var output = (connector.SourceConnectorInfoFully as LogicalConnectorInfo);
|
2023-04-16 20:11:40 +08:00
|
|
|
|
|
2023-05-01 00:10:55 +08:00
|
|
|
|
if (EnableInputValue(connector, input.Value, output))
|
2023-04-16 20:11:40 +08:00
|
|
|
|
{
|
2023-05-01 00:10:55 +08:00
|
|
|
|
connector.ColorViewModel.LineColor.Color = output.ColorViewModel.FillColor.Color;
|
|
|
|
|
|
connector.ColorViewModel.FillColor.Color = output.ColorViewModel.FillColor.Color;
|
|
|
|
|
|
connector.AnimationViewModel.Color = output.ColorViewModel.FillColor.Color;
|
|
|
|
|
|
|
2023-04-25 23:07:25 +08:00
|
|
|
|
input.Value.ConnectorValue = output.ConnectorValue;
|
|
|
|
|
|
input.Value.ConnectorString = output.ConnectorString;
|
2023-05-03 09:59:46 +08:00
|
|
|
|
input.Value.ColorViewModel.FillColor.Color = connector.SourceConnectorInfoFully.ColorViewModel.FillColor.Color;
|
2023-04-25 23:07:25 +08:00
|
|
|
|
if (LogicalType == LogicalType.Output)
|
|
|
|
|
|
{
|
2023-05-03 09:59:46 +08:00
|
|
|
|
input.Value.ConnectorValueType = (connector.SourceConnectorInfoFully as LogicalConnectorInfo).ConnectorValueType;
|
2023-04-25 23:07:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (LogicalType == LogicalType.NOT)
|
|
|
|
|
|
{
|
2023-05-03 09:59:46 +08:00
|
|
|
|
input.Value.ConnectorValueType = ((connector.SourceConnectorInfoFully as LogicalConnectorInfo).ConnectorValueType == ConnectorValueType.Bool) ? ConnectorValueType.Bool : ConnectorValueType.Int;
|
2023-04-25 23:07:25 +08:00
|
|
|
|
}
|
2023-05-01 00:10:55 +08:00
|
|
|
|
|
|
|
|
|
|
sourceItem.ClearOutputValue(connector, output);
|
2023-04-16 20:11:40 +08:00
|
|
|
|
}
|
2023-05-01 00:10:55 +08:00
|
|
|
|
sourceItem.StartAnimation(output);
|
2023-04-16 20:11:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-04-15 23:32:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void CalculateOutput()
|
|
|
|
|
|
{
|
2023-04-16 20:11:40 +08:00
|
|
|
|
foreach (var output in Output)
|
|
|
|
|
|
{
|
2023-04-26 22:53:44 +08:00
|
|
|
|
if (output.Value.ErrorCode != ConnectorErrorCode.None)
|
2023-04-24 22:43:56 +08:00
|
|
|
|
{
|
2023-04-26 22:53:44 +08:00
|
|
|
|
output.Value.ColorViewModel.FillColor.Color = Colors.DarkRed;
|
2023-04-24 22:43:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (output.Value.ConnectorValueType == ConnectorValueType.Bool)
|
2023-04-16 20:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (output.Value.ConnectorValue == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
output.Value.ColorViewModel.FillColor.Color = Colors.Red;
|
|
|
|
|
|
if (LogicalType == LogicalType.Output)
|
|
|
|
|
|
{
|
|
|
|
|
|
ColorViewModel.FillColor.Color = Colors.Red;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
|
|
|
|
|
|
if (LogicalType == LogicalType.Output)
|
|
|
|
|
|
{
|
|
|
|
|
|
ColorViewModel.FillColor.Color = Colors.Green;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-05-01 00:10:55 +08:00
|
|
|
|
else if (output.Value.ConnectorValueType <= ConnectorValueType.ValueType)
|
2023-04-16 20:11:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
output.Value.ColorViewModel.FillColor.Color = Colors.Green;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2021-07-23 09:42:22 +08:00
|
|
|
|
|
2023-05-01 00:10:55 +08:00
|
|
|
|
public virtual bool EnableInputValue(ConnectionViewModel connector, LogicalConnectorInfo input, LogicalConnectorInfo output)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!input.CanAttachTo(output))
|
|
|
|
|
|
{
|
|
|
|
|
|
input.ErrorCode = ConnectorErrorCode.ConnErr;
|
|
|
|
|
|
input.ErrorMessage = "连接类型不匹配";
|
|
|
|
|
|
input.ColorViewModel.FillColor.Color = Colors.DarkRed;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void ClearOutputValue(ConnectionViewModel connector, LogicalConnectorInfo output)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public virtual void StartAnimation(LogicalConnectorInfo output)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-16 20:11:40 +08:00
|
|
|
|
protected ConnectionViewModel GetSourceItem(FullyCreatedConnectorInfo sinkConnector)
|
|
|
|
|
|
{
|
2023-04-24 20:10:17 +08:00
|
|
|
|
return Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SinkConnectorInfo == sinkConnector);
|
2023-04-16 20:11:40 +08:00
|
|
|
|
}
|
2023-05-01 00:10:55 +08:00
|
|
|
|
|
|
|
|
|
|
protected ConnectionViewModel GetSinkItem(FullyCreatedConnectorInfo sourceConnector)
|
|
|
|
|
|
{
|
2023-05-03 09:59:46 +08:00
|
|
|
|
return Root?.Items.OfType<ConnectionViewModel>().FirstOrDefault(p => p.SourceConnectorInfoFully == sourceConnector);
|
2023-05-01 00:10:55 +08:00
|
|
|
|
}
|
2023-04-16 20:11:40 +08:00
|
|
|
|
}
|
2021-07-23 09:42:22 +08:00
|
|
|
|
}
|