@@ -1,42 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI应用输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiAppCreateInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 应用名称
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用名称不能为空")]
|
|
||||||
[StringLength(100, ErrorMessage = "应用名称不能超过100个字符")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用终结点
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用终结点不能为空")]
|
|
||||||
[StringLength(500, ErrorMessage = "应用终结点不能超过500个字符")]
|
|
||||||
public string Endpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外URL
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(500, ErrorMessage = "额外URL不能超过500个字符")]
|
|
||||||
public string? ExtraUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用Key
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用Key不能为空")]
|
|
||||||
[StringLength(500, ErrorMessage = "应用Key不能超过500个字符")]
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
[Range(0, int.MaxValue, ErrorMessage = "排序必须大于等于0")]
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI应用DTO
|
|
||||||
/// </summary>
|
|
||||||
public class AiAppDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 应用ID
|
|
||||||
/// </summary>
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用终结点
|
|
||||||
/// </summary>
|
|
||||||
public string Endpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外URL
|
|
||||||
/// </summary>
|
|
||||||
public string? ExtraUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用Key
|
|
||||||
/// </summary>
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建时间
|
|
||||||
/// </summary>
|
|
||||||
public DateTime CreationTime { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using Yi.Framework.Ddd.Application.Contracts;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI应用列表输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiAppGetListInput : PagedAllResultRequestDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 搜索关键词(搜索应用名称)
|
|
||||||
/// </summary>
|
|
||||||
public string? SearchKey { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI应用输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiAppUpdateInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 应用ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用ID不能为空")]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用名称
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用名称不能为空")]
|
|
||||||
[StringLength(100, ErrorMessage = "应用名称不能超过100个字符")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用终结点
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用终结点不能为空")]
|
|
||||||
[StringLength(500, ErrorMessage = "应用终结点不能超过500个字符")]
|
|
||||||
public string Endpoint { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外URL
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(500, ErrorMessage = "额外URL不能超过500个字符")]
|
|
||||||
public string? ExtraUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用Key
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "应用Key不能为空")]
|
|
||||||
[StringLength(500, ErrorMessage = "应用Key不能超过500个字符")]
|
|
||||||
public string ApiKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
[Range(0, int.MaxValue, ErrorMessage = "排序必须大于等于0")]
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI模型输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiModelCreateInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 处理名
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "处理名不能为空")]
|
|
||||||
[StringLength(100, ErrorMessage = "处理名不能超过100个字符")]
|
|
||||||
public string HandlerName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型ID不能为空")]
|
|
||||||
[StringLength(200, ErrorMessage = "模型ID不能超过200个字符")]
|
|
||||||
public string ModelId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型名称
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型名称不能为空")]
|
|
||||||
[StringLength(200, ErrorMessage = "模型名称不能超过200个字符")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型描述
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(1000, ErrorMessage = "模型描述不能超过1000个字符")]
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
[Range(0, int.MaxValue, ErrorMessage = "排序必须大于等于0")]
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI应用ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "AI应用ID不能为空")]
|
|
||||||
public Guid AiAppId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外信息
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(2000, ErrorMessage = "额外信息不能超过2000个字符")]
|
|
||||||
public string? ExtraInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型类型
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型类型不能为空")]
|
|
||||||
public ModelTypeEnum ModelType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型API类型
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型API类型不能为空")]
|
|
||||||
public ModelApiTypeEnum ModelApiType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型倍率
|
|
||||||
/// </summary>
|
|
||||||
[Range(0.01, double.MaxValue, ErrorMessage = "模型倍率必须大于0")]
|
|
||||||
public decimal Multiplier { get; set; } = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型显示倍率
|
|
||||||
/// </summary>
|
|
||||||
[Range(0.01, double.MaxValue, ErrorMessage = "模型显示倍率必须大于0")]
|
|
||||||
public decimal MultiplierShow { get; set; } = 1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 供应商分组名称
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(100, ErrorMessage = "供应商分组名称不能超过100个字符")]
|
|
||||||
public string? ProviderName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型图标URL
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(500, ErrorMessage = "模型图标URL不能超过500个字符")]
|
|
||||||
public string? IconUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为尊享模型
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPremium { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI模型DTO
|
|
||||||
/// </summary>
|
|
||||||
public class AiModelDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 处理名
|
|
||||||
/// </summary>
|
|
||||||
public string HandlerName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
public string ModelId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型描述
|
|
||||||
/// </summary>
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI应用ID
|
|
||||||
/// </summary>
|
|
||||||
public Guid AiAppId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外信息
|
|
||||||
/// </summary>
|
|
||||||
public string? ExtraInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型类型
|
|
||||||
/// </summary>
|
|
||||||
public ModelTypeEnum ModelType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型API类型
|
|
||||||
/// </summary>
|
|
||||||
public ModelApiTypeEnum ModelApiType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型倍率
|
|
||||||
/// </summary>
|
|
||||||
public decimal Multiplier { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型显示倍率
|
|
||||||
/// </summary>
|
|
||||||
public decimal MultiplierShow { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 供应商分组名称
|
|
||||||
/// </summary>
|
|
||||||
public string? ProviderName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型图标URL
|
|
||||||
/// </summary>
|
|
||||||
public string? IconUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为尊享模型
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPremium { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using Yi.Framework.Ddd.Application.Contracts;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI模型列表输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiModelGetListInput : PagedAllResultRequestDto
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 搜索关键词(搜索模型名称、模型ID)
|
|
||||||
/// </summary>
|
|
||||||
public string? SearchKey { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI应用ID筛选
|
|
||||||
/// </summary>
|
|
||||||
public Guid? AiAppId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否只显示尊享模型
|
|
||||||
/// </summary>
|
|
||||||
public bool? IsPremiumOnly { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Enums;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI模型输入
|
|
||||||
/// </summary>
|
|
||||||
public class AiModelUpdateInput
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型ID不能为空")]
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 处理名
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "处理名不能为空")]
|
|
||||||
[StringLength(100, ErrorMessage = "处理名不能超过100个字符")]
|
|
||||||
public string HandlerName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型ID不能为空")]
|
|
||||||
[StringLength(200, ErrorMessage = "模型ID不能超过200个字符")]
|
|
||||||
public string ModelId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型名称
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型名称不能为空")]
|
|
||||||
[StringLength(200, ErrorMessage = "模型名称不能超过200个字符")]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型描述
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(1000, ErrorMessage = "模型描述不能超过1000个字符")]
|
|
||||||
public string? Description { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 排序
|
|
||||||
/// </summary>
|
|
||||||
[Range(0, int.MaxValue, ErrorMessage = "排序必须大于等于0")]
|
|
||||||
public int OrderNum { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AI应用ID
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "AI应用ID不能为空")]
|
|
||||||
public Guid AiAppId { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 额外信息
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(2000, ErrorMessage = "额外信息不能超过2000个字符")]
|
|
||||||
public string? ExtraInfo { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型类型
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型类型不能为空")]
|
|
||||||
public ModelTypeEnum ModelType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型API类型
|
|
||||||
/// </summary>
|
|
||||||
[Required(ErrorMessage = "模型API类型不能为空")]
|
|
||||||
public ModelApiTypeEnum ModelApiType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型倍率
|
|
||||||
/// </summary>
|
|
||||||
[Range(0.01, double.MaxValue, ErrorMessage = "模型倍率必须大于0")]
|
|
||||||
public decimal Multiplier { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型显示倍率
|
|
||||||
/// </summary>
|
|
||||||
[Range(0.01, double.MaxValue, ErrorMessage = "模型显示倍率必须大于0")]
|
|
||||||
public decimal MultiplierShow { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 供应商分组名称
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(100, ErrorMessage = "供应商分组名称不能超过100个字符")]
|
|
||||||
public string? ProviderName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 模型图标URL
|
|
||||||
/// </summary>
|
|
||||||
[StringLength(500, ErrorMessage = "模型图标URL不能超过500个字符")]
|
|
||||||
public string? IconUrl { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为尊享模型
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPremium { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Contracts.IServices;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 渠道商管理服务接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IChannelService
|
|
||||||
{
|
|
||||||
#region AI应用管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI应用列表
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">查询参数</param>
|
|
||||||
/// <returns>分页应用列表</returns>
|
|
||||||
Task<PagedResultDto<AiAppDto>> GetAppListAsync(AiAppGetListInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据ID获取AI应用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">应用ID</param>
|
|
||||||
/// <returns>应用详情</returns>
|
|
||||||
Task<AiAppDto> GetAppByIdAsync(Guid id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI应用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">创建输入</param>
|
|
||||||
/// <returns>创建的应用</returns>
|
|
||||||
Task<AiAppDto> CreateAppAsync(AiAppCreateInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI应用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">更新输入</param>
|
|
||||||
/// <returns>更新后的应用</returns>
|
|
||||||
Task<AiAppDto> UpdateAppAsync(AiAppUpdateInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除AI应用
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">应用ID</param>
|
|
||||||
Task DeleteAppAsync(Guid id);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region AI模型管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI模型列表
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">查询参数</param>
|
|
||||||
/// <returns>分页模型列表</returns>
|
|
||||||
Task<PagedResultDto<AiModelDto>> GetModelListAsync(AiModelGetListInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据ID获取AI模型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">模型ID</param>
|
|
||||||
/// <returns>模型详情</returns>
|
|
||||||
Task<AiModelDto> GetModelByIdAsync(Guid id);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI模型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">创建输入</param>
|
|
||||||
/// <returns>创建的模型</returns>
|
|
||||||
Task<AiModelDto> CreateModelAsync(AiModelCreateInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI模型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">更新输入</param>
|
|
||||||
/// <returns>更新后的模型</returns>
|
|
||||||
Task<AiModelDto> UpdateModelAsync(AiModelUpdateInput input);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除AI模型(软删除)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">模型ID</param>
|
|
||||||
Task DeleteModelAsync(Guid id);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@@ -179,16 +179,10 @@ public class DailyTaskService : ApplicationService
|
|||||||
var tomorrow = today.AddDays(1);
|
var tomorrow = today.AddDays(1);
|
||||||
|
|
||||||
// 查询今日所有使用尊享包模型的消息(role=system 表示消耗)
|
// 查询今日所有使用尊享包模型的消息(role=system 表示消耗)
|
||||||
// 先获取所有尊享模型的ModelId列表
|
|
||||||
var premiumModelIds = await _aiModelRepository._DbQueryable
|
|
||||||
.Where(x => x.IsPremium)
|
|
||||||
.Select(x => x.ModelId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var totalTokens = await _messageRepository._DbQueryable
|
var totalTokens = await _messageRepository._DbQueryable
|
||||||
.Where(x => x.UserId == userId)
|
.Where(x => x.UserId == userId)
|
||||||
.Where(x => x.Role == "system") // system角色表示实际消耗
|
.Where(x => x.Role == "system") // system角色表示实际消耗
|
||||||
.Where(x => premiumModelIds.Contains(x.ModelId)) // 尊享包模型
|
.Where(x => PremiumPackageConst.ModeIds.Contains(x.ModelId)) // 尊享包模型
|
||||||
.Where(x => x.CreationTime >= today && x.CreationTime < tomorrow)
|
.Where(x => x.CreationTime >= today && x.CreationTime < tomorrow)
|
||||||
.SumAsync(x => x.TokenUsage.TotalTokenCount);
|
.SumAsync(x => x.TokenUsage.TotalTokenCount);
|
||||||
|
|
||||||
|
|||||||
@@ -1,233 +0,0 @@
|
|||||||
using Mapster;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using SqlSugar;
|
|
||||||
using Volo.Abp.Application.Dtos;
|
|
||||||
using Volo.Abp.Application.Services;
|
|
||||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.Channel;
|
|
||||||
using Yi.Framework.AiHub.Application.Contracts.IServices;
|
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
|
||||||
|
|
||||||
namespace Yi.Framework.AiHub.Application.Services;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 渠道商管理服务实现
|
|
||||||
/// </summary>
|
|
||||||
[Authorize]
|
|
||||||
public class ChannelService : ApplicationService, IChannelService
|
|
||||||
{
|
|
||||||
private readonly ISqlSugarRepository<AiAppAggregateRoot, Guid> _appRepository;
|
|
||||||
private readonly ISqlSugarRepository<AiModelEntity, Guid> _modelRepository;
|
|
||||||
|
|
||||||
public ChannelService(
|
|
||||||
ISqlSugarRepository<AiAppAggregateRoot, Guid> appRepository,
|
|
||||||
ISqlSugarRepository<AiModelEntity, Guid> modelRepository)
|
|
||||||
{
|
|
||||||
_appRepository = appRepository;
|
|
||||||
_modelRepository = modelRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region AI应用管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI应用列表
|
|
||||||
/// </summary>
|
|
||||||
public async Task<PagedResultDto<AiAppDto>> GetAppListAsync(AiAppGetListInput input)
|
|
||||||
{
|
|
||||||
RefAsync<int> total = 0;
|
|
||||||
|
|
||||||
var entities = await _appRepository._DbQueryable
|
|
||||||
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), x => x.Name.Contains(input.SearchKey))
|
|
||||||
.OrderBy(x => x.OrderNum)
|
|
||||||
.OrderByDescending(x => x.CreationTime)
|
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
|
||||||
|
|
||||||
var output = entities.Adapt<List<AiAppDto>>();
|
|
||||||
return new PagedResultDto<AiAppDto>(total, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据ID获取AI应用
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiAppDto> GetAppByIdAsync(Guid id)
|
|
||||||
{
|
|
||||||
var entity = await _appRepository.GetByIdAsync(id);
|
|
||||||
return entity.Adapt<AiAppDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI应用
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiAppDto> CreateAppAsync(AiAppCreateInput input)
|
|
||||||
{
|
|
||||||
var entity = new AiAppAggregateRoot
|
|
||||||
{
|
|
||||||
Name = input.Name,
|
|
||||||
Endpoint = input.Endpoint,
|
|
||||||
ExtraUrl = input.ExtraUrl,
|
|
||||||
ApiKey = input.ApiKey,
|
|
||||||
OrderNum = input.OrderNum
|
|
||||||
};
|
|
||||||
|
|
||||||
await _appRepository.InsertAsync(entity);
|
|
||||||
return entity.Adapt<AiAppDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI应用
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiAppDto> UpdateAppAsync(AiAppUpdateInput input)
|
|
||||||
{
|
|
||||||
var entity = await _appRepository.GetByIdAsync(input.Id);
|
|
||||||
|
|
||||||
entity.Name = input.Name;
|
|
||||||
entity.Endpoint = input.Endpoint;
|
|
||||||
entity.ExtraUrl = input.ExtraUrl;
|
|
||||||
entity.ApiKey = input.ApiKey;
|
|
||||||
entity.OrderNum = input.OrderNum;
|
|
||||||
|
|
||||||
await _appRepository.UpdateAsync(entity);
|
|
||||||
return entity.Adapt<AiAppDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除AI应用
|
|
||||||
/// </summary>
|
|
||||||
public async Task DeleteAppAsync(Guid id)
|
|
||||||
{
|
|
||||||
// 检查是否有关联的模型
|
|
||||||
var hasModels = await _modelRepository._DbQueryable
|
|
||||||
.Where(x => x.AiAppId == id && !x.IsDeleted)
|
|
||||||
.AnyAsync();
|
|
||||||
|
|
||||||
if (hasModels)
|
|
||||||
{
|
|
||||||
throw new Volo.Abp.UserFriendlyException("该应用下存在模型,无法删除");
|
|
||||||
}
|
|
||||||
|
|
||||||
await _appRepository.DeleteAsync(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region AI模型管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取AI模型列表
|
|
||||||
/// </summary>
|
|
||||||
public async Task<PagedResultDto<AiModelDto>> GetModelListAsync(AiModelGetListInput input)
|
|
||||||
{
|
|
||||||
RefAsync<int> total = 0;
|
|
||||||
|
|
||||||
var query = _modelRepository._DbQueryable
|
|
||||||
.Where(x => !x.IsDeleted)
|
|
||||||
.WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), x =>
|
|
||||||
x.Name.Contains(input.SearchKey) || x.ModelId.Contains(input.SearchKey))
|
|
||||||
.WhereIF(input.AiAppId.HasValue, x => x.AiAppId == input.AiAppId.Value)
|
|
||||||
.WhereIF(input.IsPremiumOnly == true, x => x.IsPremium);
|
|
||||||
|
|
||||||
var entities = await query
|
|
||||||
.OrderBy(x => x.OrderNum)
|
|
||||||
.OrderByDescending(x => x.Id)
|
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
|
|
||||||
|
|
||||||
var output = entities.Adapt<List<AiModelDto>>();
|
|
||||||
return new PagedResultDto<AiModelDto>(total, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据ID获取AI模型
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiModelDto> GetModelByIdAsync(Guid id)
|
|
||||||
{
|
|
||||||
var entity = await _modelRepository.GetByIdAsync(id);
|
|
||||||
return entity.Adapt<AiModelDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建AI模型
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiModelDto> CreateModelAsync(AiModelCreateInput input)
|
|
||||||
{
|
|
||||||
// 验证应用是否存在
|
|
||||||
var appExists = await _appRepository._DbQueryable
|
|
||||||
.Where(x => x.Id == input.AiAppId)
|
|
||||||
.AnyAsync();
|
|
||||||
|
|
||||||
if (!appExists)
|
|
||||||
{
|
|
||||||
throw new Volo.Abp.UserFriendlyException("指定的AI应用不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = new AiModelEntity
|
|
||||||
{
|
|
||||||
HandlerName = input.HandlerName,
|
|
||||||
ModelId = input.ModelId,
|
|
||||||
Name = input.Name,
|
|
||||||
Description = input.Description,
|
|
||||||
OrderNum = input.OrderNum,
|
|
||||||
AiAppId = input.AiAppId,
|
|
||||||
ExtraInfo = input.ExtraInfo,
|
|
||||||
ModelType = input.ModelType,
|
|
||||||
ModelApiType = input.ModelApiType,
|
|
||||||
Multiplier = input.Multiplier,
|
|
||||||
MultiplierShow = input.MultiplierShow,
|
|
||||||
ProviderName = input.ProviderName,
|
|
||||||
IconUrl = input.IconUrl,
|
|
||||||
IsPremium = input.IsPremium,
|
|
||||||
IsDeleted = false
|
|
||||||
};
|
|
||||||
|
|
||||||
await _modelRepository.InsertAsync(entity);
|
|
||||||
return entity.Adapt<AiModelDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新AI模型
|
|
||||||
/// </summary>
|
|
||||||
public async Task<AiModelDto> UpdateModelAsync(AiModelUpdateInput input)
|
|
||||||
{
|
|
||||||
var entity = await _modelRepository.GetByIdAsync(input.Id);
|
|
||||||
|
|
||||||
// 验证应用是否存在
|
|
||||||
if (entity.AiAppId != input.AiAppId)
|
|
||||||
{
|
|
||||||
var appExists = await _appRepository._DbQueryable
|
|
||||||
.Where(x => x.Id == input.AiAppId)
|
|
||||||
.AnyAsync();
|
|
||||||
|
|
||||||
if (!appExists)
|
|
||||||
{
|
|
||||||
throw new Volo.Abp.UserFriendlyException("指定的AI应用不存在");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.HandlerName = input.HandlerName;
|
|
||||||
entity.ModelId = input.ModelId;
|
|
||||||
entity.Name = input.Name;
|
|
||||||
entity.Description = input.Description;
|
|
||||||
entity.OrderNum = input.OrderNum;
|
|
||||||
entity.AiAppId = input.AiAppId;
|
|
||||||
entity.ExtraInfo = input.ExtraInfo;
|
|
||||||
entity.ModelType = input.ModelType;
|
|
||||||
entity.ModelApiType = input.ModelApiType;
|
|
||||||
entity.Multiplier = input.Multiplier;
|
|
||||||
entity.MultiplierShow = input.MultiplierShow;
|
|
||||||
entity.ProviderName = input.ProviderName;
|
|
||||||
entity.IconUrl = input.IconUrl;
|
|
||||||
entity.IsPremium = input.IsPremium;
|
|
||||||
|
|
||||||
await _modelRepository.UpdateAsync(entity);
|
|
||||||
return entity.Adapt<AiModelDto>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除AI模型(软删除)
|
|
||||||
/// </summary>
|
|
||||||
public async Task DeleteModelAsync(Guid id)
|
|
||||||
{
|
|
||||||
await _modelRepository.DeleteByIdAsync(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@@ -109,7 +109,7 @@ public class AiChatService : ApplicationService
|
|||||||
ApiHost = null,
|
ApiHost = null,
|
||||||
ApiKey = null,
|
ApiKey = null,
|
||||||
Remark = x.Description,
|
Remark = x.Description,
|
||||||
IsPremiumPackage = x.IsPremium
|
IsPremiumPackage = PremiumPackageConst.ModeIds.Contains(x.ModelId)
|
||||||
}).ToListAsync();
|
}).ToListAsync();
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -144,21 +144,13 @@ public class AiChatService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//如果是尊享包服务,需要校验是是否尊享包足够
|
//如果是尊享包服务,需要校验是是否尊享包足够
|
||||||
if (CurrentUser.IsAuthenticated)
|
if (CurrentUser.IsAuthenticated && PremiumPackageConst.ModeIds.Contains(input.Model))
|
||||||
{
|
{
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
// 检查尊享token包用量
|
||||||
.Where(x => x.ModelId == input.Model)
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(CurrentUser.GetId());
|
||||||
.Select(x => x.IsPremium)
|
if (availableTokens <= 0)
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
// 检查尊享token包用量
|
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
||||||
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(CurrentUser.GetId());
|
|
||||||
if (availableTokens <= 0)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException("尊享token包用量不足,请先购买尊享token包");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,12 +219,7 @@ public class AiChatService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
//如果是尊享包服务,需要校验是是否尊享包足够
|
//如果是尊享包服务,需要校验是是否尊享包足够
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
if (PremiumPackageConst.ModeIds.Contains(input.ModelId))
|
||||||
.Where(x => x.ModelId == input.ModelId)
|
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
// 检查尊享token包用量
|
// 检查尊享token包用量
|
||||||
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(tokenValidation.UserId);
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(tokenValidation.UserId);
|
||||||
|
|||||||
@@ -69,9 +69,6 @@ public class AiImageService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 尊享包校验
|
// 尊享包校验
|
||||||
// 注意: AiImageService目前没有注入AiModelEntity仓储
|
|
||||||
// 由于图片生成功能使用频率较低,且当前所有图片模型都不是尊享模型
|
|
||||||
// 暂时保留原逻辑,等待后续重构时再注入仓储
|
|
||||||
if (PremiumPackageConst.ModeIds.Contains(input.ModelId))
|
if (PremiumPackageConst.ModeIds.Contains(input.ModelId))
|
||||||
{
|
{
|
||||||
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ public class ModelService : ApplicationService, IModelService
|
|||||||
input.ModelTypes.Contains(x.ModelType))
|
input.ModelTypes.Contains(x.ModelType))
|
||||||
.WhereIF(input.ModelApiTypes is not null, x =>
|
.WhereIF(input.ModelApiTypes is not null, x =>
|
||||||
input.ModelApiTypes.Contains(x.ModelApiType))
|
input.ModelApiTypes.Contains(x.ModelApiType))
|
||||||
.WhereIF(input.IsPremiumOnly == true, x => x.IsPremium)
|
.WhereIF(input.IsPremiumOnly == true, x =>
|
||||||
|
PremiumPackageConst.ModeIds.Contains(x.ModelId))
|
||||||
.GroupBy(x => x.ModelId)
|
.GroupBy(x => x.ModelId)
|
||||||
.Select(x => x.ModelId)
|
.Select(x => x.ModelId)
|
||||||
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total));
|
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total));
|
||||||
@@ -60,7 +61,7 @@ public class ModelService : ApplicationService, IModelService
|
|||||||
MultiplierShow = x.First().MultiplierShow,
|
MultiplierShow = x.First().MultiplierShow,
|
||||||
ProviderName = x.First().ProviderName,
|
ProviderName = x.First().ProviderName,
|
||||||
IconUrl = x.First().IconUrl,
|
IconUrl = x.First().IconUrl,
|
||||||
IsPremium = x.First().IsPremium,
|
IsPremium = PremiumPackageConst.ModeIds.Contains(x.First().ModelId),
|
||||||
OrderNum = x.First().OrderNum
|
OrderNum = x.First().OrderNum
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,7 @@ public class TokenService : ApplicationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取尊享包模型ID列表
|
// 获取尊享包模型ID列表
|
||||||
var premiumModelIds = await _aiModelRepository._DbQueryable
|
var premiumModelIds = PremiumPackageConst.ModeIds;
|
||||||
.Where(x => x.IsPremium)
|
|
||||||
.Select(x => x.ModelId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// 批量查询所有Token的尊享包已使用额度
|
// 批量查询所有Token的尊享包已使用额度
|
||||||
var tokenIds = tokens.Select(t => t.Id).ToList();
|
var tokenIds = tokens.Select(t => t.Id).ToList();
|
||||||
|
|||||||
@@ -65,12 +65,7 @@ public class OpenApiService : ApplicationService
|
|||||||
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
await _aiBlacklistManager.VerifiyAiBlacklist(userId);
|
||||||
|
|
||||||
//如果是尊享包服务,需要校验是是否尊享包足够
|
//如果是尊享包服务,需要校验是是否尊享包足够
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
if (PremiumPackageConst.ModeIds.Contains(input.Model))
|
||||||
.Where(x => x.ModelId == input.Model)
|
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
// 检查尊享token包用量
|
// 检查尊享token包用量
|
||||||
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
var availableTokens = await _premiumPackageManager.GetAvailableTokensAsync(userId);
|
||||||
|
|||||||
@@ -181,12 +181,7 @@ public class UsageStatisticsService : ApplicationService, IUsageStatisticsServic
|
|||||||
public async Task<List<TokenPremiumUsageDto>> GetPremiumTokenUsageByTokenAsync()
|
public async Task<List<TokenPremiumUsageDto>> GetPremiumTokenUsageByTokenAsync()
|
||||||
{
|
{
|
||||||
var userId = CurrentUser.GetId();
|
var userId = CurrentUser.GetId();
|
||||||
|
var premiumModelIds = PremiumPackageConst.ModeIds;
|
||||||
// 先获取所有尊享模型的ModelId列表
|
|
||||||
var premiumModelIds = await _aiModelRepository._DbQueryable
|
|
||||||
.Where(x => x.IsPremium)
|
|
||||||
.Select(x => x.ModelId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
// 从UsageStatistics表获取尊享模型的token消耗统计(按TokenId聚合)
|
// 从UsageStatistics表获取尊享模型的token消耗统计(按TokenId聚合)
|
||||||
var tokenUsages = await _usageStatisticsRepository._DbQueryable
|
var tokenUsages = await _usageStatisticsRepository._DbQueryable
|
||||||
|
|||||||
@@ -80,9 +80,4 @@ public class AiModelEntity : Entity<Guid>, IOrderNum, ISoftDelete
|
|||||||
/// 模型图标URL
|
/// 模型图标URL
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? IconUrl { get; set; }
|
public string? IconUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为尊享模型
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPremium { get; set; }
|
|
||||||
}
|
}
|
||||||
@@ -150,12 +150,7 @@ public class AiGateWayManager : DomainService
|
|||||||
await _usageStatisticsManager.SetUsageAsync(userId.Value, request.Model, data.Usage, tokenId);
|
await _usageStatisticsManager.SetUsageAsync(userId.Value, request.Model, data.Usage, tokenId);
|
||||||
|
|
||||||
// 扣减尊享token包用量
|
// 扣减尊享token包用量
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
if (PremiumPackageConst.ModeIds.Contains(request.Model))
|
||||||
.Where(x => x.ModelId == request.Model)
|
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
var totalTokens = data.Usage?.TotalTokens ?? 0;
|
var totalTokens = data.Usage?.TotalTokens ?? 0;
|
||||||
if (totalTokens > 0)
|
if (totalTokens > 0)
|
||||||
@@ -305,20 +300,12 @@ public class AiGateWayManager : DomainService
|
|||||||
await _usageStatisticsManager.SetUsageAsync(userId, request.Model, tokenUsage, tokenId);
|
await _usageStatisticsManager.SetUsageAsync(userId, request.Model, tokenUsage, tokenId);
|
||||||
|
|
||||||
// 扣减尊享token包用量
|
// 扣减尊享token包用量
|
||||||
if (userId is not null)
|
if (userId is not null && PremiumPackageConst.ModeIds.Contains(request.Model))
|
||||||
{
|
{
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
var totalTokens = tokenUsage.TotalTokens ?? 0;
|
||||||
.Where(x => x.ModelId == request.Model)
|
if (totalTokens > 0)
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
var totalTokens = tokenUsage.TotalTokens ?? 0;
|
await PremiumPackageManager.TryConsumeTokensAsync(userId.Value, totalTokens);
|
||||||
if (totalTokens > 0)
|
|
||||||
{
|
|
||||||
await PremiumPackageManager.TryConsumeTokensAsync(userId.Value, totalTokens);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,20 +363,12 @@ public class AiGateWayManager : DomainService
|
|||||||
await _usageStatisticsManager.SetUsageAsync(userId, model, response.Usage, tokenId);
|
await _usageStatisticsManager.SetUsageAsync(userId, model, response.Usage, tokenId);
|
||||||
|
|
||||||
// 扣减尊享token包用量
|
// 扣减尊享token包用量
|
||||||
if (userId is not null)
|
if (userId is not null && PremiumPackageConst.ModeIds.Contains(request.Model))
|
||||||
{
|
{
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
var totalTokens = response.Usage.TotalTokens ?? 0;
|
||||||
.Where(x => x.ModelId == request.Model)
|
if (totalTokens > 0)
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
var totalTokens = response.Usage.TotalTokens ?? 0;
|
await PremiumPackageManager.TryConsumeTokensAsync(userId.Value, totalTokens);
|
||||||
if (totalTokens > 0)
|
|
||||||
{
|
|
||||||
await PremiumPackageManager.TryConsumeTokensAsync(userId.Value, totalTokens);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ using Volo.Abp.Domain.Services;
|
|||||||
using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
using Yi.Framework.AiHub.Application.Contracts.Dtos.Chat;
|
||||||
using Yi.Framework.AiHub.Domain.AiGateWay;
|
using Yi.Framework.AiHub.Domain.AiGateWay;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
using Yi.Framework.AiHub.Domain.Entities.Chat;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
|
||||||
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Attributes;
|
using Yi.Framework.AiHub.Domain.Shared.Attributes;
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
||||||
@@ -35,13 +34,12 @@ public class ChatManager : DomainService
|
|||||||
private readonly UsageStatisticsManager _usageStatisticsManager;
|
private readonly UsageStatisticsManager _usageStatisticsManager;
|
||||||
private readonly PremiumPackageManager _premiumPackageManager;
|
private readonly PremiumPackageManager _premiumPackageManager;
|
||||||
private readonly AiGateWayManager _aiGateWayManager;
|
private readonly AiGateWayManager _aiGateWayManager;
|
||||||
private readonly ISqlSugarRepository<AiModelEntity, Guid> _aiModelRepository;
|
|
||||||
|
|
||||||
public ChatManager(ILoggerFactory loggerFactory,
|
public ChatManager(ILoggerFactory loggerFactory,
|
||||||
ISqlSugarRepository<MessageAggregateRoot> messageRepository,
|
ISqlSugarRepository<MessageAggregateRoot> messageRepository,
|
||||||
ISqlSugarRepository<AgentStoreAggregateRoot> agentStoreRepository, AiMessageManager aiMessageManager,
|
ISqlSugarRepository<AgentStoreAggregateRoot> agentStoreRepository, AiMessageManager aiMessageManager,
|
||||||
UsageStatisticsManager usageStatisticsManager, PremiumPackageManager premiumPackageManager,
|
UsageStatisticsManager usageStatisticsManager, PremiumPackageManager premiumPackageManager,
|
||||||
AiGateWayManager aiGateWayManager, ISqlSugarRepository<AiModelEntity, Guid> aiModelRepository)
|
AiGateWayManager aiGateWayManager)
|
||||||
{
|
{
|
||||||
_loggerFactory = loggerFactory;
|
_loggerFactory = loggerFactory;
|
||||||
_messageRepository = messageRepository;
|
_messageRepository = messageRepository;
|
||||||
@@ -50,7 +48,6 @@ public class ChatManager : DomainService
|
|||||||
_usageStatisticsManager = usageStatisticsManager;
|
_usageStatisticsManager = usageStatisticsManager;
|
||||||
_premiumPackageManager = premiumPackageManager;
|
_premiumPackageManager = premiumPackageManager;
|
||||||
_aiGateWayManager = aiGateWayManager;
|
_aiGateWayManager = aiGateWayManager;
|
||||||
_aiModelRepository = aiModelRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -210,12 +207,7 @@ public class ChatManager : DomainService
|
|||||||
await _usageStatisticsManager.SetUsageAsync(userId, modelId, usage, tokenId);
|
await _usageStatisticsManager.SetUsageAsync(userId, modelId, usage, tokenId);
|
||||||
|
|
||||||
//扣减尊享token包用量
|
//扣减尊享token包用量
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
if (PremiumPackageConst.ModeIds.Contains(modelId))
|
||||||
.Where(x => x.ModelId == modelId)
|
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
var totalTokens = usage?.TotalTokens ?? 0;
|
var totalTokens = usage?.TotalTokens ?? 0;
|
||||||
if (totalTokens > 0)
|
if (totalTokens > 0)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Volo.Abp.Domain.Services;
|
using Volo.Abp.Domain.Services;
|
||||||
using Yi.Framework.AiHub.Domain.Entities;
|
using Yi.Framework.AiHub.Domain.Entities;
|
||||||
using Yi.Framework.AiHub.Domain.Entities.Model;
|
|
||||||
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
using Yi.Framework.AiHub.Domain.Entities.OpenApi;
|
||||||
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
using Yi.Framework.AiHub.Domain.Shared.Consts;
|
||||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||||
@@ -28,16 +27,13 @@ public class TokenManager : DomainService
|
|||||||
{
|
{
|
||||||
private readonly ISqlSugarRepository<TokenAggregateRoot> _tokenRepository;
|
private readonly ISqlSugarRepository<TokenAggregateRoot> _tokenRepository;
|
||||||
private readonly ISqlSugarRepository<UsageStatisticsAggregateRoot> _usageStatisticsRepository;
|
private readonly ISqlSugarRepository<UsageStatisticsAggregateRoot> _usageStatisticsRepository;
|
||||||
private readonly ISqlSugarRepository<AiModelEntity, Guid> _aiModelRepository;
|
|
||||||
|
|
||||||
public TokenManager(
|
public TokenManager(
|
||||||
ISqlSugarRepository<TokenAggregateRoot> tokenRepository,
|
ISqlSugarRepository<TokenAggregateRoot> tokenRepository,
|
||||||
ISqlSugarRepository<UsageStatisticsAggregateRoot> usageStatisticsRepository,
|
ISqlSugarRepository<UsageStatisticsAggregateRoot> usageStatisticsRepository)
|
||||||
ISqlSugarRepository<AiModelEntity, Guid> aiModelRepository)
|
|
||||||
{
|
{
|
||||||
_tokenRepository = tokenRepository;
|
_tokenRepository = tokenRepository;
|
||||||
_usageStatisticsRepository = usageStatisticsRepository;
|
_usageStatisticsRepository = usageStatisticsRepository;
|
||||||
_aiModelRepository = aiModelRepository;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -80,20 +76,14 @@ public class TokenManager : DomainService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果是尊享模型且Token设置了额度限制,检查是否超限
|
// 如果是尊享模型且Token设置了额度限制,检查是否超限
|
||||||
if (!string.IsNullOrEmpty(modelId) && entity.PremiumQuotaLimit.HasValue)
|
if (!string.IsNullOrEmpty(modelId) &&
|
||||||
|
PremiumPackageConst.ModeIds.Contains(modelId) &&
|
||||||
|
entity.PremiumQuotaLimit.HasValue)
|
||||||
{
|
{
|
||||||
var isPremium = await _aiModelRepository._DbQueryable
|
var usedQuota = await GetTokenPremiumUsedQuotaAsync(entity.UserId, entity.Id);
|
||||||
.Where(x => x.ModelId == modelId)
|
if (usedQuota >= entity.PremiumQuotaLimit.Value)
|
||||||
.Select(x => x.IsPremium)
|
|
||||||
.FirstAsync();
|
|
||||||
|
|
||||||
if (isPremium)
|
|
||||||
{
|
{
|
||||||
var usedQuota = await GetTokenPremiumUsedQuotaAsync(entity.UserId, entity.Id);
|
throw new UserFriendlyException($"当前Token的尊享包额度已用完(已使用:{usedQuota},限制:{entity.PremiumQuotaLimit.Value}),请调整额度限制或使用其他Token", "403");
|
||||||
if (usedQuota >= entity.PremiumQuotaLimit.Value)
|
|
||||||
{
|
|
||||||
throw new UserFriendlyException($"当前Token的尊享包额度已用完(已使用:{usedQuota},限制:{entity.PremiumQuotaLimit.Value}),请调整额度限制或使用其他Token", "403");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,11 +99,7 @@ public class TokenManager : DomainService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<long> GetTokenPremiumUsedQuotaAsync(Guid userId, Guid tokenId)
|
private async Task<long> GetTokenPremiumUsedQuotaAsync(Guid userId, Guid tokenId)
|
||||||
{
|
{
|
||||||
// 先获取所有尊享模型的ModelId列表
|
var premiumModelIds = PremiumPackageConst.ModeIds;
|
||||||
var premiumModelIds = await _aiModelRepository._DbQueryable
|
|
||||||
.Where(x => x.IsPremium)
|
|
||||||
.Select(x => x.ModelId)
|
|
||||||
.ToListAsync();
|
|
||||||
|
|
||||||
var usedQuota = await _usageStatisticsRepository._DbQueryable
|
var usedQuota = await _usageStatisticsRepository._DbQueryable
|
||||||
.Where(x => x.UserId == userId && x.TokenId == tokenId && premiumModelIds.Contains(x.ModelId))
|
.Where(x => x.UserId == userId && x.TokenId == tokenId && premiumModelIds.Contains(x.ModelId))
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
import { del, get, post, put } from '@/utils/request';
|
|
||||||
import type {
|
|
||||||
AiAppDto,
|
|
||||||
AiAppCreateInput,
|
|
||||||
AiAppUpdateInput,
|
|
||||||
AiAppGetListInput,
|
|
||||||
AiModelDto,
|
|
||||||
AiModelCreateInput,
|
|
||||||
AiModelUpdateInput,
|
|
||||||
AiModelGetListInput,
|
|
||||||
PagedResultDto,
|
|
||||||
} from './types';
|
|
||||||
|
|
||||||
// ==================== AI应用管理 ====================
|
|
||||||
|
|
||||||
// 获取AI应用列表
|
|
||||||
export function getAppList(params?: AiAppGetListInput) {
|
|
||||||
const queryParams = new URLSearchParams();
|
|
||||||
if (params?.searchKey) {
|
|
||||||
queryParams.append('SearchKey', params.searchKey);
|
|
||||||
}
|
|
||||||
if (params?.skipCount !== undefined) {
|
|
||||||
queryParams.append('SkipCount', params.skipCount.toString());
|
|
||||||
}
|
|
||||||
if (params?.maxResultCount !== undefined) {
|
|
||||||
queryParams.append('MaxResultCount', params.maxResultCount.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryString = queryParams.toString();
|
|
||||||
const url = queryString ? `/channel/app?${queryString}` : '/channel/app';
|
|
||||||
|
|
||||||
return get<PagedResultDto<AiAppDto>>(url).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据ID获取AI应用
|
|
||||||
export function getAppById(id: string) {
|
|
||||||
return get<AiAppDto>(`/channel/app/${id}`).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建AI应用
|
|
||||||
export function createApp(data: AiAppCreateInput) {
|
|
||||||
return post<AiAppDto>('/channel/app', data).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新AI应用
|
|
||||||
export function updateApp(data: AiAppUpdateInput) {
|
|
||||||
return put<AiAppDto>('/channel/app', data).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除AI应用
|
|
||||||
export function deleteApp(id: string) {
|
|
||||||
return del(`/channel/app/${id}`).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== AI模型管理 ====================
|
|
||||||
|
|
||||||
// 获取AI模型列表
|
|
||||||
export function getModelList(params?: AiModelGetListInput) {
|
|
||||||
const queryParams = new URLSearchParams();
|
|
||||||
if (params?.searchKey) {
|
|
||||||
queryParams.append('SearchKey', params.searchKey);
|
|
||||||
}
|
|
||||||
if (params?.aiAppId) {
|
|
||||||
queryParams.append('AiAppId', params.aiAppId);
|
|
||||||
}
|
|
||||||
if (params?.isPremiumOnly !== undefined) {
|
|
||||||
queryParams.append('IsPremiumOnly', params.isPremiumOnly.toString());
|
|
||||||
}
|
|
||||||
if (params?.skipCount !== undefined) {
|
|
||||||
queryParams.append('SkipCount', params.skipCount.toString());
|
|
||||||
}
|
|
||||||
if (params?.maxResultCount !== undefined) {
|
|
||||||
queryParams.append('MaxResultCount', params.maxResultCount.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryString = queryParams.toString();
|
|
||||||
const url = queryString ? `/channel/model?${queryString}` : '/channel/model';
|
|
||||||
|
|
||||||
return get<PagedResultDto<AiModelDto>>(url).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据ID获取AI模型
|
|
||||||
export function getModelById(id: string) {
|
|
||||||
return get<AiModelDto>(`/channel/model/${id}`).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建AI模型
|
|
||||||
export function createModel(data: AiModelCreateInput) {
|
|
||||||
return post<AiModelDto>('/channel/model', data).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新AI模型
|
|
||||||
export function updateModel(data: AiModelUpdateInput) {
|
|
||||||
return put<AiModelDto>('/channel/model', data).json();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除AI模型
|
|
||||||
export function deleteModel(id: string) {
|
|
||||||
return del(`/channel/model/${id}`).json();
|
|
||||||
}
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
// 模型类型枚举
|
|
||||||
export enum ModelTypeEnum {
|
|
||||||
Chat = 0,
|
|
||||||
Image = 1,
|
|
||||||
Embedding = 2,
|
|
||||||
PremiumChat = 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模型API类型枚举
|
|
||||||
export enum ModelApiTypeEnum {
|
|
||||||
OpenAi = 0,
|
|
||||||
Claude = 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI应用DTO
|
|
||||||
export interface AiAppDto {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
endpoint: string;
|
|
||||||
extraUrl?: string;
|
|
||||||
apiKey: string;
|
|
||||||
orderNum: number;
|
|
||||||
creationTime: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建AI应用输入
|
|
||||||
export interface AiAppCreateInput {
|
|
||||||
name: string;
|
|
||||||
endpoint: string;
|
|
||||||
extraUrl?: string;
|
|
||||||
apiKey: string;
|
|
||||||
orderNum: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新AI应用输入
|
|
||||||
export interface AiAppUpdateInput {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
endpoint: string;
|
|
||||||
extraUrl?: string;
|
|
||||||
apiKey: string;
|
|
||||||
orderNum: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取AI应用列表输入
|
|
||||||
export interface AiAppGetListInput {
|
|
||||||
searchKey?: string;
|
|
||||||
skipCount?: number;
|
|
||||||
maxResultCount?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI模型DTO
|
|
||||||
export interface AiModelDto {
|
|
||||||
id: string;
|
|
||||||
handlerName: string;
|
|
||||||
modelId: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
orderNum: number;
|
|
||||||
aiAppId: string;
|
|
||||||
extraInfo?: string;
|
|
||||||
modelType: ModelTypeEnum;
|
|
||||||
modelApiType: ModelApiTypeEnum;
|
|
||||||
multiplier: number;
|
|
||||||
multiplierShow: number;
|
|
||||||
providerName?: string;
|
|
||||||
iconUrl?: string;
|
|
||||||
isPremium: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建AI模型输入
|
|
||||||
export interface AiModelCreateInput {
|
|
||||||
handlerName: string;
|
|
||||||
modelId: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
orderNum: number;
|
|
||||||
aiAppId: string;
|
|
||||||
extraInfo?: string;
|
|
||||||
modelType: ModelTypeEnum;
|
|
||||||
modelApiType: ModelApiTypeEnum;
|
|
||||||
multiplier: number;
|
|
||||||
multiplierShow: number;
|
|
||||||
providerName?: string;
|
|
||||||
iconUrl?: string;
|
|
||||||
isPremium: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新AI模型输入
|
|
||||||
export interface AiModelUpdateInput {
|
|
||||||
id: string;
|
|
||||||
handlerName: string;
|
|
||||||
modelId: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
orderNum: number;
|
|
||||||
aiAppId: string;
|
|
||||||
extraInfo?: string;
|
|
||||||
modelType: ModelTypeEnum;
|
|
||||||
modelApiType: ModelApiTypeEnum;
|
|
||||||
multiplier: number;
|
|
||||||
multiplierShow: number;
|
|
||||||
providerName?: string;
|
|
||||||
iconUrl?: string;
|
|
||||||
isPremium: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取AI模型列表输入
|
|
||||||
export interface AiModelGetListInput {
|
|
||||||
searchKey?: string;
|
|
||||||
aiAppId?: string;
|
|
||||||
isPremiumOnly?: boolean;
|
|
||||||
skipCount?: number;
|
|
||||||
maxResultCount?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 分页结果
|
|
||||||
export interface PagedResultDto<T> {
|
|
||||||
items: T[];
|
|
||||||
totalCount: number;
|
|
||||||
}
|
|
||||||
@@ -1,548 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { onMounted, ref } from 'vue';
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
||||||
import { Delete, Edit, Plus, Refresh, View } from '@element-plus/icons-vue';
|
|
||||||
import type { AiAppDto, AiModelDto } from '@/api/channel/types';
|
|
||||||
import {
|
|
||||||
getAppList,
|
|
||||||
createApp,
|
|
||||||
updateApp,
|
|
||||||
deleteApp,
|
|
||||||
getModelList,
|
|
||||||
createModel,
|
|
||||||
updateModel,
|
|
||||||
deleteModel,
|
|
||||||
} from '@/api/channel';
|
|
||||||
|
|
||||||
// ==================== 应用管理 ====================
|
|
||||||
const appList = ref<AiAppDto[]>([]);
|
|
||||||
const appLoading = ref(false);
|
|
||||||
const selectedAppId = ref<string>('');
|
|
||||||
|
|
||||||
// 应用对话框
|
|
||||||
const appDialogVisible = ref(false);
|
|
||||||
const appDialogTitle = ref('');
|
|
||||||
const appForm = ref<Partial<AiAppDto>>({});
|
|
||||||
const appDetailDialogVisible = ref(false);
|
|
||||||
const appDetailData = ref<AiAppDto | null>(null);
|
|
||||||
|
|
||||||
// 获取应用列表
|
|
||||||
async function fetchAppList() {
|
|
||||||
appLoading.value = true;
|
|
||||||
try {
|
|
||||||
const res = await getAppList({
|
|
||||||
skipCount: 0,
|
|
||||||
maxResultCount: 100,
|
|
||||||
});
|
|
||||||
appList.value = res.data.items;
|
|
||||||
|
|
||||||
// 默认选中第一个应用
|
|
||||||
if (appList.value.length > 0 && !selectedAppId.value) {
|
|
||||||
selectedAppId.value = appList.value[0].id;
|
|
||||||
fetchModelList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
ElMessage.error(error.message || '获取应用列表失败');
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
appLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择应用
|
|
||||||
function handleSelectApp(appId: string) {
|
|
||||||
selectedAppId.value = appId;
|
|
||||||
fetchModelList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看应用详情
|
|
||||||
function handleViewAppDetail(app: AiAppDto) {
|
|
||||||
appDetailData.value = app;
|
|
||||||
appDetailDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开应用对话框
|
|
||||||
function openAppDialog(type: 'create' | 'edit', row?: AiAppDto) {
|
|
||||||
appDialogTitle.value = type === 'create' ? '创建应用' : '编辑应用';
|
|
||||||
if (type === 'create') {
|
|
||||||
appForm.value = {
|
|
||||||
name: '',
|
|
||||||
endpoint: '',
|
|
||||||
extraUrl: '',
|
|
||||||
apiKey: '',
|
|
||||||
orderNum: 0,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
appForm.value = { ...row };
|
|
||||||
}
|
|
||||||
appDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存应用
|
|
||||||
async function saveApp() {
|
|
||||||
try {
|
|
||||||
if (appForm.value.id) {
|
|
||||||
await updateApp(appForm.value as any);
|
|
||||||
ElMessage.success('更新成功');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await createApp(appForm.value as any);
|
|
||||||
ElMessage.success('创建成功');
|
|
||||||
}
|
|
||||||
appDialogVisible.value = false;
|
|
||||||
fetchAppList();
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
ElMessage.error(error.message || '保存失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除应用
|
|
||||||
async function handleDeleteApp(row: AiAppDto) {
|
|
||||||
try {
|
|
||||||
await ElMessageBox.confirm('确定要删除该应用吗?删除后该应用下的所有模型将无法使用。', '警告', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
});
|
|
||||||
await deleteApp(row.id);
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
|
|
||||||
// 如果删除的是当前选中的应用,清空选中状态
|
|
||||||
if (selectedAppId.value === row.id) {
|
|
||||||
selectedAppId.value = '';
|
|
||||||
modelList.value = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchAppList();
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
if (error !== 'cancel') {
|
|
||||||
ElMessage.error(error.message || '删除失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 模型管理 ====================
|
|
||||||
const modelList = ref<AiModelDto[]>([]);
|
|
||||||
const modelLoading = ref(false);
|
|
||||||
const modelSearchKey = ref('');
|
|
||||||
const modelDialogVisible = ref(false);
|
|
||||||
const modelDialogTitle = ref('');
|
|
||||||
const modelForm = ref<Partial<AiModelDto>>({});
|
|
||||||
|
|
||||||
// 获取模型列表
|
|
||||||
async function fetchModelList() {
|
|
||||||
if (!selectedAppId.value) {
|
|
||||||
modelList.value = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
modelLoading.value = true;
|
|
||||||
try {
|
|
||||||
const res = await getModelList({
|
|
||||||
aiAppId: selectedAppId.value,
|
|
||||||
searchKey: modelSearchKey.value,
|
|
||||||
skipCount: 0,
|
|
||||||
maxResultCount: 100,
|
|
||||||
});
|
|
||||||
modelList.value = res.data.items;
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
ElMessage.error(error.message || '获取模型列表失败');
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
modelLoading.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开模型对话框
|
|
||||||
function openModelDialog(type: 'create' | 'edit', row?: AiModelDto) {
|
|
||||||
if (!selectedAppId.value) {
|
|
||||||
ElMessage.warning('请先选择一个应用');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
modelDialogTitle.value = type === 'create' ? '创建模型' : '编辑模型';
|
|
||||||
if (type === 'create') {
|
|
||||||
modelForm.value = {
|
|
||||||
handlerName: '',
|
|
||||||
modelId: '',
|
|
||||||
name: '',
|
|
||||||
description: '',
|
|
||||||
orderNum: 0,
|
|
||||||
aiAppId: selectedAppId.value,
|
|
||||||
extraInfo: '',
|
|
||||||
modelType: 0,
|
|
||||||
modelApiType: 0,
|
|
||||||
multiplier: 1,
|
|
||||||
multiplierShow: 1,
|
|
||||||
providerName: '',
|
|
||||||
iconUrl: '',
|
|
||||||
isPremium: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
modelForm.value = { ...row };
|
|
||||||
}
|
|
||||||
modelDialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存模型
|
|
||||||
async function saveModel() {
|
|
||||||
try {
|
|
||||||
if (modelForm.value.id) {
|
|
||||||
await updateModel(modelForm.value as any);
|
|
||||||
ElMessage.success('更新成功');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await createModel(modelForm.value as any);
|
|
||||||
ElMessage.success('创建成功');
|
|
||||||
}
|
|
||||||
modelDialogVisible.value = false;
|
|
||||||
fetchModelList();
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
ElMessage.error(error.message || '保存失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 删除模型
|
|
||||||
async function handleDeleteModel(row: AiModelDto) {
|
|
||||||
try {
|
|
||||||
await ElMessageBox.confirm('确定要删除该模型吗?', '警告', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
});
|
|
||||||
await deleteModel(row.id);
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
fetchModelList();
|
|
||||||
}
|
|
||||||
catch (error: any) {
|
|
||||||
if (error !== 'cancel') {
|
|
||||||
ElMessage.error(error.message || '删除失败');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化
|
|
||||||
onMounted(() => {
|
|
||||||
fetchAppList();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="channel-management">
|
|
||||||
<div class="channel-container">
|
|
||||||
<!-- 左侧应用列表 -->
|
|
||||||
<div class="app-list-panel">
|
|
||||||
<div class="panel-header">
|
|
||||||
<h3>应用列表</h3>
|
|
||||||
<el-button type="primary" size="small" :icon="Plus" @click="openAppDialog('create')">
|
|
||||||
新建
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-scrollbar class="app-list-scrollbar">
|
|
||||||
<div v-loading="appLoading" class="app-list">
|
|
||||||
<div
|
|
||||||
v-for="app in appList"
|
|
||||||
:key="app.id"
|
|
||||||
class="app-item"
|
|
||||||
:class="{ active: selectedAppId === app.id }"
|
|
||||||
@click="handleSelectApp(app.id)"
|
|
||||||
>
|
|
||||||
<div class="app-item-content">
|
|
||||||
<div class="app-name">{{ app.name }}</div>
|
|
||||||
<div class="app-actions">
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
:icon="View"
|
|
||||||
@click.stop="handleViewAppDetail(app)"
|
|
||||||
>
|
|
||||||
详情
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
type="primary"
|
|
||||||
size="small"
|
|
||||||
:icon="Edit"
|
|
||||||
@click.stop="openAppDialog('edit', app)"
|
|
||||||
>
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
link
|
|
||||||
type="danger"
|
|
||||||
size="small"
|
|
||||||
:icon="Delete"
|
|
||||||
@click.stop="handleDeleteApp(app)"
|
|
||||||
>
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty v-if="!appLoading && appList.length === 0" description="暂无应用" />
|
|
||||||
</div>
|
|
||||||
</el-scrollbar>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧模型列表 -->
|
|
||||||
<div class="model-list-panel">
|
|
||||||
<div class="panel-header">
|
|
||||||
<h3>模型列表</h3>
|
|
||||||
<div class="header-actions">
|
|
||||||
<el-input
|
|
||||||
v-model="modelSearchKey"
|
|
||||||
placeholder="搜索模型"
|
|
||||||
style="width: 200px; margin-right: 10px"
|
|
||||||
clearable
|
|
||||||
@keyup.enter="fetchModelList"
|
|
||||||
/>
|
|
||||||
<el-button type="primary" size="small" :icon="Plus" @click="openModelDialog('create')">
|
|
||||||
新建
|
|
||||||
</el-button>
|
|
||||||
<el-button size="small" :icon="Refresh" @click="fetchModelList">
|
|
||||||
刷新
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!selectedAppId" class="empty-tip">
|
|
||||||
<el-empty description="请先选择左侧的应用" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-table
|
|
||||||
v-else
|
|
||||||
v-loading="modelLoading"
|
|
||||||
:data="modelList"
|
|
||||||
border
|
|
||||||
stripe
|
|
||||||
height="calc(100vh - 220px)"
|
|
||||||
>
|
|
||||||
<el-table-column prop="name" label="模型名称" min-width="150" />
|
|
||||||
<el-table-column prop="modelId" label="模型ID" min-width="200" show-overflow-tooltip />
|
|
||||||
<el-table-column prop="handlerName" label="处理名" min-width="120" />
|
|
||||||
<el-table-column prop="providerName" label="供应商" width="100" />
|
|
||||||
<el-table-column label="是否尊享" width="100">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-tag :type="row.isPremium ? 'warning' : 'info'">
|
|
||||||
{{ row.isPremium ? '尊享' : '普通' }}
|
|
||||||
</el-tag>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="multiplierShow" label="显示倍率" width="100" />
|
|
||||||
<el-table-column prop="orderNum" label="排序" width="80" />
|
|
||||||
<el-table-column label="操作" width="150" fixed="right">
|
|
||||||
<template #default="{ row }">
|
|
||||||
<el-button link type="primary" :icon="Edit" @click="openModelDialog('edit', row)">
|
|
||||||
编辑
|
|
||||||
</el-button>
|
|
||||||
<el-button link type="danger" :icon="Delete" @click="handleDeleteModel(row)">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 应用详情对话框 -->
|
|
||||||
<el-dialog v-model="appDetailDialogVisible" title="应用详情" width="600px">
|
|
||||||
<el-descriptions v-if="appDetailData" :column="1" border>
|
|
||||||
<el-descriptions-item label="应用名称">{{ appDetailData.name }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="终结点">{{ appDetailData.endpoint }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="额外URL">{{ appDetailData.extraUrl || '-' }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="API Key">
|
|
||||||
<el-input :model-value="appDetailData.apiKey" type="textarea" readonly />
|
|
||||||
</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="排序">{{ appDetailData.orderNum }}</el-descriptions-item>
|
|
||||||
<el-descriptions-item label="创建时间">{{ appDetailData.creationTime }}</el-descriptions-item>
|
|
||||||
</el-descriptions>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- 应用编辑对话框 -->
|
|
||||||
<el-dialog v-model="appDialogVisible" :title="appDialogTitle" width="600px">
|
|
||||||
<el-form :model="appForm" label-width="120px">
|
|
||||||
<el-form-item label="应用名称" required>
|
|
||||||
<el-input v-model="appForm.name" placeholder="请输入应用名称" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="终结点" required>
|
|
||||||
<el-input v-model="appForm.endpoint" placeholder="请输入应用终结点URL" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="额外URL">
|
|
||||||
<el-input v-model="appForm.extraUrl" placeholder="请输入额外URL(可选)" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="API Key" required>
|
|
||||||
<el-input v-model="appForm.apiKey" type="textarea" placeholder="请输入API Key" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="排序">
|
|
||||||
<el-input-number v-model="appForm.orderNum" :min="0" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="appDialogVisible = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="saveApp">保存</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
|
|
||||||
<!-- 模型编辑对话框 -->
|
|
||||||
<el-dialog v-model="modelDialogVisible" :title="modelDialogTitle" width="700px">
|
|
||||||
<el-form :model="modelForm" label-width="120px">
|
|
||||||
<el-form-item label="模型名称" required>
|
|
||||||
<el-input v-model="modelForm.name" placeholder="请输入模型名称" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="模型ID" required>
|
|
||||||
<el-input v-model="modelForm.modelId" placeholder="请输入模型ID" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="处理名" required>
|
|
||||||
<el-input v-model="modelForm.handlerName" placeholder="请输入处理名" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="供应商名称">
|
|
||||||
<el-input v-model="modelForm.providerName" placeholder="如:OpenAI、Anthropic等" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="模型描述">
|
|
||||||
<el-input v-model="modelForm.description" type="textarea" placeholder="请输入模型描述" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="是否尊享模型">
|
|
||||||
<el-switch v-model="modelForm.isPremium" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="模型倍率">
|
|
||||||
<el-input-number v-model="modelForm.multiplier" :min="0.01" :step="0.1" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="显示倍率">
|
|
||||||
<el-input-number v-model="modelForm.multiplierShow" :min="0.01" :step="0.1" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="模型类型" required>
|
|
||||||
<el-select v-model="modelForm.modelType" placeholder="请选择模型类型">
|
|
||||||
<el-option label="聊天" :value="0" />
|
|
||||||
<el-option label="图片" :value="1" />
|
|
||||||
<el-option label="嵌入" :value="2" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="API类型" required>
|
|
||||||
<el-select v-model="modelForm.modelApiType" placeholder="请选择API类型">
|
|
||||||
<el-option label="OpenAI" :value="0" />
|
|
||||||
<el-option label="Claude" :value="1" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="图标URL">
|
|
||||||
<el-input v-model="modelForm.iconUrl" placeholder="请输入模型图标URL" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="排序">
|
|
||||||
<el-input-number v-model="modelForm.orderNum" :min="0" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="modelDialogVisible = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="saveModel">保存</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.channel-management {
|
|
||||||
padding: 20px;
|
|
||||||
height: calc(100vh - 40px);
|
|
||||||
|
|
||||||
.channel-container {
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list-panel {
|
|
||||||
width: 350px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.model-list-panel {
|
|
||||||
flex: 1;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-header {
|
|
||||||
padding: 16px 20px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list-scrollbar {
|
|
||||||
flex: 1;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-list {
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-item {
|
|
||||||
padding: 12px 16px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
border: 1px solid #e4e7ed;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.3s;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
border-color: #409eff;
|
|
||||||
background: #f0f9ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
border-color: #409eff;
|
|
||||||
background: #ecf5ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-item-content {
|
|
||||||
.app-name {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: #303133;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty-tip {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -19,7 +19,6 @@ const navItems = [
|
|||||||
{ name: 'daily-task', label: '每日任务(限时)', icon: 'Trophy', path: '/console/daily-task' },
|
{ name: 'daily-task', label: '每日任务(限时)', icon: 'Trophy', path: '/console/daily-task' },
|
||||||
{ name: 'invite', label: '每周邀请(限时)', icon: 'Present', path: '/console/invite' },
|
{ name: 'invite', label: '每周邀请(限时)', icon: 'Present', path: '/console/invite' },
|
||||||
{ name: 'activation', label: '激活码兑换', icon: 'MagicStick', path: '/console/activation' },
|
{ name: 'activation', label: '激活码兑换', icon: 'MagicStick', path: '/console/activation' },
|
||||||
{ name: 'channel', label: '渠道商管理', icon: 'Setting', path: '/console/channel' },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// 当前激活的菜单
|
// 当前激活的菜单
|
||||||
|
|||||||
@@ -207,14 +207,6 @@ export const layoutRouter: RouteRecordRaw[] = [
|
|||||||
title: '激活码兑换',
|
title: '激活码兑换',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: 'channel',
|
|
||||||
name: 'consoleChannel',
|
|
||||||
component: () => import('@/pages/console/channel/index.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '渠道商管理',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
2
Yi.Ai.Vue3/types/components.d.ts
vendored
2
Yi.Ai.Vue3/types/components.d.ts
vendored
@@ -25,8 +25,6 @@ declare module 'vue' {
|
|||||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
||||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
|
||||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
ElDivider: typeof import('element-plus/es')['ElDivider']
|
||||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||||
|
|||||||
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
1
Yi.Ai.Vue3/types/import_meta.d.ts
vendored
@@ -7,6 +7,7 @@ interface ImportMetaEnv {
|
|||||||
readonly VITE_WEB_BASE_API: string;
|
readonly VITE_WEB_BASE_API: string;
|
||||||
readonly VITE_API_URL: string;
|
readonly VITE_API_URL: string;
|
||||||
readonly VITE_FILE_UPLOAD_API: string;
|
readonly VITE_FILE_UPLOAD_API: string;
|
||||||
|
readonly VITE_BUILD_COMPRESS: string;
|
||||||
readonly VITE_SSO_SEVER_URL: string;
|
readonly VITE_SSO_SEVER_URL: string;
|
||||||
readonly VITE_APP_VERSION: string;
|
readonly VITE_APP_VERSION: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user