- 新增模块抽象与 manifest/版本范围、安装/启用/停用/回滚\n- 模块管理页面:上传 .tpm/.zip、状态与冲突提示\n- 任务中心/新建任务改为基于模块贡献动态展示(system 不出现在新建列表)\n- API 管理改为基于模块贡献动态创建与通用配置编辑\n- 支持模块扩展任务执行器与扩展页面入口 /ext/{moduleId}/{pageKey}\n\n内置模块:builtin.kick-api、builtin.tasks
97 lines
3.2 KiB
Plaintext
97 lines
3.2 KiB
Plaintext
@namespace TelegramPanel.Web.Components.Dialogs
|
||
@inject ISnackbar Snackbar
|
||
@using System.Security.Cryptography
|
||
@using TelegramPanel.Modules
|
||
@using TelegramPanel.Web.ExternalApi
|
||
|
||
<MudDialog>
|
||
<DialogContent>
|
||
<MudStack Spacing="2">
|
||
<MudAlert Severity="Severity.Info" Variant="Variant.Outlined" Dense="true">
|
||
新建一个外部 API 配置项(可在同一个接口下创建多个配置,使用不同的 `X-API-Key` 区分)。
|
||
</MudAlert>
|
||
|
||
<MudTextField @bind-Value="name" Label="API 名称" Variant="Variant.Outlined" Required="true"
|
||
HelperText="用于在面板中区分不同的 API 配置项" />
|
||
|
||
<MudSelect @bind-Value="type" Label="API 类型" Variant="Variant.Outlined" Dense="true">
|
||
@foreach (var t in AvailableTypes)
|
||
{
|
||
<MudSelectItem Value="@t.Type">@t.DisplayName(@t.Route)</MudSelectItem>
|
||
}
|
||
</MudSelect>
|
||
|
||
<MudSwitch @bind-Value="enabled" Label="立即启用" Color="Color.Primary" />
|
||
</MudStack>
|
||
</DialogContent>
|
||
<DialogActions>
|
||
<MudButton Variant="Variant.Text" Color="Color.Default" OnClick="Cancel">取消</MudButton>
|
||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="Confirm">创建</MudButton>
|
||
</DialogActions>
|
||
</MudDialog>
|
||
|
||
@code
|
||
{
|
||
[CascadingParameter] private MudDialogInstance MudDialog { get; set; } = default!;
|
||
[Parameter] public IReadOnlyList<ModuleApiTypeDefinition> AvailableTypes { get; set; } = Array.Empty<ModuleApiTypeDefinition>();
|
||
|
||
private string name = "";
|
||
private string type = "";
|
||
private bool enabled;
|
||
|
||
protected override void OnInitialized()
|
||
{
|
||
if (string.IsNullOrWhiteSpace(type))
|
||
type = AvailableTypes.FirstOrDefault()?.Type ?? "";
|
||
}
|
||
|
||
private void Cancel() => MudDialog.Cancel();
|
||
|
||
private void Confirm()
|
||
{
|
||
var n = (name ?? "").Trim();
|
||
if (string.IsNullOrWhiteSpace(n))
|
||
{
|
||
Snackbar.Add("API 名称不能为空", Severity.Warning);
|
||
return;
|
||
}
|
||
|
||
if (AvailableTypes.All(x => !string.Equals(x.Type, type, StringComparison.OrdinalIgnoreCase)))
|
||
{
|
||
Snackbar.Add("请选择有效的 API 类型", Severity.Warning);
|
||
return;
|
||
}
|
||
|
||
var apiKey = GenerateKey();
|
||
var def = new ExternalApiDefinition
|
||
{
|
||
Name = n,
|
||
Type = type,
|
||
Enabled = enabled,
|
||
ApiKey = apiKey,
|
||
Config = new System.Text.Json.Nodes.JsonObject()
|
||
};
|
||
|
||
if (string.Equals(type, ExternalApiTypes.Kick, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
def.Kick = new KickApiDefinition
|
||
{
|
||
BotId = 0,
|
||
UseAllChats = true,
|
||
ChatIds = new List<long>(),
|
||
PermanentBanDefault = false
|
||
};
|
||
}
|
||
|
||
MudDialog.Close(DialogResult.Ok(def));
|
||
}
|
||
|
||
private static string GenerateKey()
|
||
{
|
||
var bytes = RandomNumberGenerator.GetBytes(32);
|
||
var key = Convert.ToBase64String(bytes);
|
||
return key.Replace('+', '-').Replace('/', '_').TrimEnd('=');
|
||
}
|
||
}
|
||
|