😎1、统一系统logo文件上传模式 2、增加轮播图上传管理 3、ai组件改成按需加载 4、升级依赖
This commit is contained in:
parent
ad69c7e5b5
commit
17c3fb6a98
@ -4,7 +4,7 @@
|
|||||||
"Upload": {
|
"Upload": {
|
||||||
"Path": "upload/{yyyy}/{MM}/{dd}", // 文件上传目录
|
"Path": "upload/{yyyy}/{MM}/{dd}", // 文件上传目录
|
||||||
"MaxSize": 51200, // 文件最大限制KB:1024*50
|
"MaxSize": 51200, // 文件最大限制KB:1024*50
|
||||||
"ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "text/xml", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx", "application/wps-office.pptx", "application/vnd.android.package-archive", "application/octet-stream" ],
|
"ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "image/svg+xml", "text/plain", "text/xml", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx", "application/wps-office.pptx", "application/vnd.android.package-archive", "application/octet-stream" ],
|
||||||
"EnableMd5": false, // 启用文件MDF5验证-防止重复上传
|
"EnableMd5": false, // 启用文件MDF5验证-防止重复上传
|
||||||
"EnableSaveDb": false // 启用文件存储到数据库
|
"EnableSaveDb": false // 启用文件存储到数据库
|
||||||
},
|
},
|
||||||
|
|||||||
@ -28,9 +28,9 @@
|
|||||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.6.1" Aliases="BouncyCastleV2" />
|
||||||
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.7" />
|
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.0.7" />
|
||||||
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.105" />
|
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.106" />
|
||||||
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.105" />
|
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.106" />
|
||||||
<PackageReference Include="Furion.Pure" Version="4.9.7.105" />
|
<PackageReference Include="Furion.Pure" Version="4.9.7.106" />
|
||||||
<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
|
<PackageReference Include="Hardware.Info" Version="101.0.1.1" />
|
||||||
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
<PackageReference Include="Hashids.net" Version="1.7.0" />
|
||||||
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
<PackageReference Include="IPTools.China" Version="1.6.0" />
|
||||||
@ -74,7 +74,7 @@
|
|||||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
<ItemGroup Condition=" '$(TargetFramework)' == 'net8.0' ">
|
||||||
<PackageReference Include="AspNet.Security.OAuth.Gitee" Version="8.3.0" />
|
<PackageReference Include="AspNet.Security.OAuth.Gitee" Version="8.3.0" />
|
||||||
<PackageReference Include="AspNet.Security.OAuth.Weixin" Version="8.3.0" />
|
<PackageReference Include="AspNet.Security.OAuth.Weixin" Version="8.3.0" />
|
||||||
<PackageReference Include="Lazy.Captcha.Core" Version="2.2.0" />
|
<PackageReference Include="Lazy.Captcha.Core" Version="2.2.1" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="8.0.11" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.11" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="8.0.11" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="8.0.11" />
|
||||||
|
|||||||
@ -66,6 +66,11 @@ public class UploadFileInput
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <example></example>
|
/// <example></example>
|
||||||
public string AllowSuffix { get; set; }
|
public string AllowSuffix { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 业务数据Id
|
||||||
|
/// </summary>
|
||||||
|
public long DataId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -21,7 +21,7 @@ public class SysFileService : IDynamicApiController, ITransient
|
|||||||
private readonly UploadOptions _uploadOptions;
|
private readonly UploadOptions _uploadOptions;
|
||||||
private readonly INamedServiceProvider<ICustomFileProvider> _namedServiceProvider;
|
private readonly INamedServiceProvider<ICustomFileProvider> _namedServiceProvider;
|
||||||
private readonly ICustomFileProvider _customFileProvider;
|
private readonly ICustomFileProvider _customFileProvider;
|
||||||
private readonly string _imageType = ".jpeg.jpg.png.bmp.gif.tif";
|
private readonly string _imageType = ".jpeg.jpg.png.bmp.gif.tif.svg";
|
||||||
|
|
||||||
public SysFileService(UserManager userManager,
|
public SysFileService(UserManager userManager,
|
||||||
SqlSugarRepository<SysFile> sysFileRep,
|
SqlSugarRepository<SysFile> sysFileRep,
|
||||||
@ -373,6 +373,41 @@ public class SysFileService : IDynamicApiController, ITransient
|
|||||||
return sysFile;
|
return sysFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上传Logo 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="file"></param>
|
||||||
|
/// <param name="tenantId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("上传Logo")]
|
||||||
|
public async Task<SysFile> UploadLogo([Required] IFormFile file, [Required] long tenantId)
|
||||||
|
{
|
||||||
|
// 先清空
|
||||||
|
var sysFile = await _sysFileRep.GetFirstAsync(u => u.FileType == "Logo" && u.DataId == tenantId);
|
||||||
|
if (sysFile != null)
|
||||||
|
await DeleteFile(new BaseIdInput { Id = sysFile.Id });
|
||||||
|
|
||||||
|
return await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType, FileType = "Logo", DataId = tenantId }, $"upload/system/{tenantId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 上传轮播图 🔖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="files"></param>
|
||||||
|
/// <param name="tenantId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[DisplayName("上传轮播图")]
|
||||||
|
public async Task<List<SysFile>> UploadCarousel([Required] List<IFormFile> files, [Required] long tenantId)
|
||||||
|
{
|
||||||
|
var sysFileList = new List<SysFile>();
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
var tFile = await UploadFile(new UploadFileInput { File = file, AllowSuffix = _imageType, FileType = "Carousel", DataId = tenantId }, $"upload/system/{tenantId}");
|
||||||
|
sysFileList.Add(tFile);
|
||||||
|
}
|
||||||
|
return sysFileList;
|
||||||
|
}
|
||||||
|
|
||||||
#region 统一实体与文件关联时,业务应用实体只需要定义一个SysFile集合导航属性,业务增加和更新、删除分别调用即可
|
#region 统一实体与文件关联时,业务应用实体只需要定义一个SysFile集合导航属性,业务增加和更新、删除分别调用即可
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -17,14 +17,9 @@ public class SysInfoInput
|
|||||||
public long TenantId { get; set; }
|
public long TenantId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 图标(Data URI scheme base64 编码)
|
/// 系统图标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string LogoBase64 { get; set; }
|
public string Logo { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 图标文件名
|
|
||||||
/// </summary>
|
|
||||||
public string LogoFileName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 主标题
|
/// 主标题
|
||||||
@ -99,7 +94,7 @@ public class SysInfoInput
|
|||||||
public bool SecondVer { get; set; } = false;
|
public bool SecondVer { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 轮播图
|
/// 轮播图Id集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<IFormFile> CarouselFiles { get; set; }
|
public List<long> CarouselFileIds { get; set; }
|
||||||
}
|
}
|
||||||
@ -26,7 +26,6 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
private readonly SysRoleMenuService _sysRoleMenuService;
|
private readonly SysRoleMenuService _sysRoleMenuService;
|
||||||
private readonly SysConfigService _sysConfigService;
|
private readonly SysConfigService _sysConfigService;
|
||||||
private readonly SysCacheService _sysCacheService;
|
private readonly SysCacheService _sysCacheService;
|
||||||
private readonly SysFileService _sysFileService;
|
|
||||||
private readonly IEventPublisher _eventPublisher;
|
private readonly IEventPublisher _eventPublisher;
|
||||||
|
|
||||||
public SysTenantService(SqlSugarRepository<SysTenant> sysTenantRep,
|
public SysTenantService(SqlSugarRepository<SysTenant> sysTenantRep,
|
||||||
@ -43,7 +42,6 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
SysRoleMenuService sysRoleMenuService,
|
SysRoleMenuService sysRoleMenuService,
|
||||||
SysConfigService sysConfigService,
|
SysConfigService sysConfigService,
|
||||||
SysCacheService sysCacheService,
|
SysCacheService sysCacheService,
|
||||||
SysFileService sysFileService,
|
|
||||||
IEventPublisher eventPublisher)
|
IEventPublisher eventPublisher)
|
||||||
{
|
{
|
||||||
_sysTenantRep = sysTenantRep;
|
_sysTenantRep = sysTenantRep;
|
||||||
@ -60,7 +58,6 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
_sysRoleMenuService = sysRoleMenuService;
|
_sysRoleMenuService = sysRoleMenuService;
|
||||||
_sysConfigService = sysConfigService;
|
_sysConfigService = sysConfigService;
|
||||||
_sysCacheService = sysCacheService;
|
_sysCacheService = sysCacheService;
|
||||||
_sysFileService = sysFileService;
|
|
||||||
_eventPublisher = eventPublisher;
|
_eventPublisher = eventPublisher;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -571,8 +568,8 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
if (string.IsNullOrWhiteSpace(tenant.Title))
|
if (string.IsNullOrWhiteSpace(tenant.Title))
|
||||||
tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == SqlSugarConst.DefaultTenantId);
|
tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == SqlSugarConst.DefaultTenantId);
|
||||||
|
|
||||||
//// 获取首页轮播图列表
|
// 获取首页轮播图列表
|
||||||
//var carouselFiles = await _fileRep.GetListAsync(u => u.BelongId == tenant.Id && u.RelationId == tenant.Id && u.FileType == "Carousel");
|
var carouselFiles = await _sysTenantRep.ChangeRepository<SqlSugarRepository<SysFile>>().GetListAsync(u => u.DataId == tenant.Id && u.FileType == "Carousel");
|
||||||
|
|
||||||
var forceChangePassword = await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysForceChangePassword); // 强制修改密码
|
var forceChangePassword = await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysForceChangePassword); // 强制修改密码
|
||||||
var passwordExpirationTime = await _sysConfigService.GetConfigValueByCode<int>(ConfigConst.SysPasswordExpirationTime); // 密码有效期
|
var passwordExpirationTime = await _sysConfigService.GetConfigValueByCode<int>(ConfigConst.SysPasswordExpirationTime); // 密码有效期
|
||||||
@ -601,7 +598,7 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
ForceChangePassword = forceChangePassword,
|
ForceChangePassword = forceChangePassword,
|
||||||
PasswordExpirationTime = passwordExpirationTime,
|
PasswordExpirationTime = passwordExpirationTime,
|
||||||
PublicKey = publicKey,
|
PublicKey = publicKey,
|
||||||
//CarouselFiles = carouselFiles,
|
CarouselFiles = carouselFiles,
|
||||||
I18NSwitch = i18NSwitch,
|
I18NSwitch = i18NSwitch,
|
||||||
IdleTimeout = idleTimeout,
|
IdleTimeout = idleTimeout,
|
||||||
OnlineNotice = onlineNotice,
|
OnlineNotice = onlineNotice,
|
||||||
@ -616,52 +613,18 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
[DisplayName("保存系统信息")]
|
[DisplayName("保存系统信息")]
|
||||||
public async Task SaveSysInfo(SysInfoInput input)
|
public async Task SaveSysInfo(SysInfoInput input)
|
||||||
{
|
{
|
||||||
if (input.TenantId < 1)
|
input.TenantId = input.TenantId < 1 ? long.Parse(App.User?.FindFirst(ClaimConst.TenantId)?.Value ?? "0") : input.TenantId;
|
||||||
input.TenantId = long.Parse(App.User?.FindFirst(ClaimConst.TenantId)?.Value ?? "0");
|
var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == input.TenantId) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||||
var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == input.TenantId);
|
|
||||||
_ = tenant ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
|
||||||
|
|
||||||
var originLogo = tenant.Logo;
|
|
||||||
tenant = input.Adapt<SysTenant>();
|
tenant = input.Adapt<SysTenant>();
|
||||||
tenant.Id = input.TenantId;
|
tenant.Id = input.TenantId;
|
||||||
|
|
||||||
// logo 不为空才保存
|
// 先清空轮播图再更新
|
||||||
if (!string.IsNullOrEmpty(input.LogoBase64))
|
var carouselFileIds = await _sysTenantRep.ChangeRepository<SqlSugarRepository<SysFile>>().AsQueryable()
|
||||||
{
|
.WhereIF(input.CarouselFileIds != null && input.CarouselFileIds.Count != 0, u => !input.CarouselFileIds.Contains(u.Id))
|
||||||
// 旧图标文件相对路径
|
.Where(u => u.FileType == "Carousel" && u.DataId == input.TenantId)
|
||||||
var oldSysLogoRelativeFilePath = tenant.Logo ?? "";
|
.Select(u => u.Id).ToListAsync();
|
||||||
var oldSysLogoAbsoluteFilePath = Path.Combine(App.WebHostEnvironment.WebRootPath, oldSysLogoRelativeFilePath.TrimStart('/'));
|
foreach (var fileId in carouselFileIds)
|
||||||
|
await App.GetRequiredService<SysFileService>().DeleteFile(new BaseIdInput { Id = fileId });
|
||||||
var groups = Regex.Match(input.LogoBase64, @"data:image/(?<type>.+?);base64,(?<data>.+)").Groups;
|
|
||||||
//var type = groups["type"].Value;
|
|
||||||
var base64Data = groups["data"].Value;
|
|
||||||
var binData = Convert.FromBase64String(base64Data);
|
|
||||||
// 根据文件名取扩展名
|
|
||||||
var ext = string.IsNullOrWhiteSpace(input.LogoFileName) ? ".png" : Path.GetExtension(input.LogoFileName);
|
|
||||||
// 本地图标保存路径
|
|
||||||
var path = $"upload/{input.TenantId}/";
|
|
||||||
var fileName = $"logo{ext}".ToLower();
|
|
||||||
var absoluteFilePath = Path.Combine(App.WebHostEnvironment.WebRootPath, path, fileName);
|
|
||||||
|
|
||||||
// 删除已存在文件
|
|
||||||
if (File.Exists(oldSysLogoAbsoluteFilePath))
|
|
||||||
File.Delete(oldSysLogoAbsoluteFilePath);
|
|
||||||
|
|
||||||
// 创建文件夹
|
|
||||||
var absoluteFileDir = Path.GetDirectoryName(absoluteFilePath);
|
|
||||||
if (!Directory.Exists(absoluteFileDir))
|
|
||||||
Directory.CreateDirectory(absoluteFileDir);
|
|
||||||
|
|
||||||
// 保存图标文件
|
|
||||||
await File.WriteAllBytesAsync(absoluteFilePath, binData);
|
|
||||||
|
|
||||||
// 保存图标配置
|
|
||||||
tenant.Logo = $"/{path}/{fileName}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tenant.Logo = originLogo;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _sysTenantRep.AsUpdateable(tenant).UpdateColumns(u => new
|
await _sysTenantRep.AsUpdateable(tenant).UpdateColumns(u => new
|
||||||
{
|
{
|
||||||
@ -684,40 +647,4 @@ public class SysTenantService : IDynamicApiController, ITransient
|
|||||||
// 更新租户缓存
|
// 更新租户缓存
|
||||||
await CacheTenant();
|
await CacheTenant();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 上传轮播图单文件 🔖
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="file"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[DisplayName("上传轮播图单文件")]
|
|
||||||
public async Task<SysFile> UploadCarouselFile([Required] IFormFile file)
|
|
||||||
{
|
|
||||||
var tenantId = long.Parse(App.User?.FindFirst(ClaimConst.TenantId)?.Value ?? "0");
|
|
||||||
if (tenantId < 1) tenantId = SqlSugarConst.DefaultTenantId;
|
|
||||||
var tenant = await _sysTenantRep.GetFirstAsync(u => u.Id == tenantId);
|
|
||||||
if (tenant == null) return null;
|
|
||||||
|
|
||||||
if (file == null)
|
|
||||||
throw Oops.Oh(ErrorCodeEnum.D8000);
|
|
||||||
|
|
||||||
// 本地轮播图保存路径
|
|
||||||
var path = $"upload/{tenantId}/carousel";
|
|
||||||
var absoluteDirPath = Path.Combine(App.WebHostEnvironment.WebRootPath, path);
|
|
||||||
|
|
||||||
// 创建文件夹
|
|
||||||
if (!Directory.Exists(absoluteDirPath))
|
|
||||||
Directory.CreateDirectory(absoluteDirPath);
|
|
||||||
|
|
||||||
// 保存轮播图文件
|
|
||||||
var sysFile = await _sysFileService.UploadFile(new UploadFileInput { File = file, FileType = "Carousel" });
|
|
||||||
|
|
||||||
//// 保存轮播图配置
|
|
||||||
//sysFile.BelongId = tenant.Id;
|
|
||||||
//sysFile.RelationId = tenant.Id;
|
|
||||||
|
|
||||||
await _sysFileService.UpdateFile(sysFile);
|
|
||||||
|
|
||||||
return sysFile;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
"name": "admin.net.pro",
|
"name": "admin.net.pro",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.4.33",
|
"version": "2.4.33",
|
||||||
"lastBuildTime": "2025.07.27",
|
"lastBuildTime": "2025.07.28",
|
||||||
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
||||||
"author": "zuohuaijun",
|
"author": "zuohuaijun",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -74,7 +74,7 @@
|
|||||||
"vue-clipboard3": "^2.0.0",
|
"vue-clipboard3": "^2.0.0",
|
||||||
"vue-demi": "0.14.10",
|
"vue-demi": "0.14.10",
|
||||||
"vue-draggable-plus": "^0.6.0",
|
"vue-draggable-plus": "^0.6.0",
|
||||||
"vue-element-plus-x": "^1.3.0",
|
"vue-element-plus-x": "^1.3.1",
|
||||||
"vue-grid-layout": "3.0.0-beta1",
|
"vue-grid-layout": "3.0.0-beta1",
|
||||||
"vue-i18n": "^11.1.11",
|
"vue-i18n": "^11.1.11",
|
||||||
"vue-json-pretty": "^2.5.0",
|
"vue-json-pretty": "^2.5.0",
|
||||||
@ -82,8 +82,8 @@
|
|||||||
"vue-router": "^4.5.1",
|
"vue-router": "^4.5.1",
|
||||||
"vue-signature-pad": "^3.0.2",
|
"vue-signature-pad": "^3.0.2",
|
||||||
"vue3-tree-org": "^4.2.2",
|
"vue3-tree-org": "^4.2.2",
|
||||||
"vxe-pc-ui": "^4.7.28",
|
"vxe-pc-ui": "^4.7.30",
|
||||||
"vxe-table": "^4.14.7",
|
"vxe-table": "^4.14.8",
|
||||||
"xe-utils": "^3.7.8",
|
"xe-utils": "^3.7.8",
|
||||||
"xlsx-js-style": "^1.2.0"
|
"xlsx-js-style": "^1.2.0"
|
||||||
},
|
},
|
||||||
@ -96,10 +96,10 @@
|
|||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
"@typescript-eslint/eslint-plugin": "^8.38.0",
|
||||||
"@typescript-eslint/parser": "^8.38.0",
|
"@typescript-eslint/parser": "^8.38.0",
|
||||||
"@vitejs/plugin-vue": "^6.0.0",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
"@vitejs/plugin-vue-jsx": "^5.0.1",
|
||||||
"@vue/compiler-sfc": "^3.5.18",
|
"@vue/compiler-sfc": "^3.5.18",
|
||||||
"code-inspector-plugin": "^1.0.0",
|
"code-inspector-plugin": "^1.0.2",
|
||||||
"eslint": "^9.32.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-plugin-vue": "^10.3.0",
|
"eslint-plugin-vue": "^10.3.0",
|
||||||
"globals": "^16.3.0",
|
"globals": "^16.3.0",
|
||||||
|
|||||||
@ -518,6 +518,65 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传轮播图 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Array<Blob>} [files]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysFileUploadCarouselTenantIdPostForm: async (tenantId: number, files?: Array<Blob>, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'tenantId' is not null or undefined
|
||||||
|
if (tenantId === null || tenantId === undefined) {
|
||||||
|
throw new RequiredError('tenantId','Required parameter tenantId was null or undefined when calling apiSysFileUploadCarouselTenantIdPostForm.');
|
||||||
|
}
|
||||||
|
const localVarPath = `/api/sysFile/uploadCarousel/{tenantId}`
|
||||||
|
.replace(`{${"tenantId"}}`, encodeURIComponent(String(tenantId)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
const localVarFormParams = new FormData();
|
||||||
|
|
||||||
|
// authentication Bearer required
|
||||||
|
// http bearer authentication required
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const accessToken = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken()
|
||||||
|
: await configuration.accessToken;
|
||||||
|
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files) {
|
||||||
|
files.forEach((element) => {
|
||||||
|
localVarFormParams.append('files', element as any);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
|
||||||
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
|
for (const key in localVarQueryParameter) {
|
||||||
|
query.set(key, localVarQueryParameter[key]);
|
||||||
|
}
|
||||||
|
for (const key in options.params) {
|
||||||
|
query.set(key, options.params[key]);
|
||||||
|
}
|
||||||
|
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = localVarFormParams;
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传文件Base64 🔖
|
* @summary 上传文件Base64 🔖
|
||||||
@ -574,10 +633,11 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
* @param {string} [fileAlias]
|
* @param {string} [fileAlias]
|
||||||
* @param {boolean} [isPublic]
|
* @param {boolean} [isPublic]
|
||||||
* @param {string} [allowSuffix]
|
* @param {string} [allowSuffix]
|
||||||
|
* @param {number} [dataId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
apiSysFileUploadFilePostForm: async (file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
const localVarPath = `/api/sysFile/uploadFile`;
|
const localVarPath = `/api/sysFile/uploadFile`;
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
@ -620,6 +680,10 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
localVarFormParams.append('AllowSuffix', allowSuffix as any);
|
localVarFormParams.append('AllowSuffix', allowSuffix as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dataId !== undefined) {
|
||||||
|
localVarFormParams.append('DataId', dataId as any);
|
||||||
|
}
|
||||||
|
|
||||||
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
|
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
|
||||||
const query = new URLSearchParams(localVarUrlObj.search);
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
for (const key in localVarQueryParameter) {
|
for (const key in localVarQueryParameter) {
|
||||||
@ -691,6 +755,64 @@ export const SysFileApiAxiosParamCreator = function (configuration?: Configurati
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传Logo 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Blob} [file]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
apiSysFileUploadLogoTenantIdPostForm: async (tenantId: number, file?: Blob, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
|
// verify required parameter 'tenantId' is not null or undefined
|
||||||
|
if (tenantId === null || tenantId === undefined) {
|
||||||
|
throw new RequiredError('tenantId','Required parameter tenantId was null or undefined when calling apiSysFileUploadLogoTenantIdPostForm.');
|
||||||
|
}
|
||||||
|
const localVarPath = `/api/sysFile/uploadLogo/{tenantId}`
|
||||||
|
.replace(`{${"tenantId"}}`, encodeURIComponent(String(tenantId)));
|
||||||
|
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||||
|
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
||||||
|
let baseOptions;
|
||||||
|
if (configuration) {
|
||||||
|
baseOptions = configuration.baseOptions;
|
||||||
|
}
|
||||||
|
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
|
||||||
|
const localVarHeaderParameter = {} as any;
|
||||||
|
const localVarQueryParameter = {} as any;
|
||||||
|
const localVarFormParams = new FormData();
|
||||||
|
|
||||||
|
// authentication Bearer required
|
||||||
|
// http bearer authentication required
|
||||||
|
if (configuration && configuration.accessToken) {
|
||||||
|
const accessToken = typeof configuration.accessToken === 'function'
|
||||||
|
? await configuration.accessToken()
|
||||||
|
: await configuration.accessToken;
|
||||||
|
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (file !== undefined) {
|
||||||
|
localVarFormParams.append('file', file as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
|
||||||
|
const query = new URLSearchParams(localVarUrlObj.search);
|
||||||
|
for (const key in localVarQueryParameter) {
|
||||||
|
query.set(key, localVarQueryParameter[key]);
|
||||||
|
}
|
||||||
|
for (const key in options.params) {
|
||||||
|
query.set(key, options.params[key]);
|
||||||
|
}
|
||||||
|
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
||||||
|
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
||||||
|
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
||||||
|
localVarRequestOptions.data = localVarFormParams;
|
||||||
|
|
||||||
|
return {
|
||||||
|
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
||||||
|
options: localVarRequestOptions,
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传电子签名 🔖
|
* @summary 上传电子签名 🔖
|
||||||
@ -945,6 +1067,21 @@ export const SysFileApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传轮播图 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Array<Blob>} [files]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysFileUploadCarouselTenantIdPostForm(tenantId: number, files?: Array<Blob>, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultListSysFile>>> {
|
||||||
|
const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadCarouselTenantIdPostForm(tenantId, files, options);
|
||||||
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
|
return axios.request(axiosRequestArgs);
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传文件Base64 🔖
|
* @summary 上传文件Base64 🔖
|
||||||
@ -967,11 +1104,12 @@ export const SysFileApiFp = function(configuration?: Configuration) {
|
|||||||
* @param {string} [fileAlias]
|
* @param {string} [fileAlias]
|
||||||
* @param {boolean} [isPublic]
|
* @param {boolean} [isPublic]
|
||||||
* @param {string} [allowSuffix]
|
* @param {string} [allowSuffix]
|
||||||
|
* @param {number} [dataId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysFile>>> {
|
async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysFile>>> {
|
||||||
const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, options);
|
const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options);
|
||||||
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
@ -991,6 +1129,21 @@ export const SysFileApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传Logo 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Blob} [file]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysFileUploadLogoTenantIdPostForm(tenantId: number, file?: Blob, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysFile>>> {
|
||||||
|
const localVarAxiosArgs = await SysFileApiAxiosParamCreator(configuration).apiSysFileUploadLogoTenantIdPostForm(tenantId, file, options);
|
||||||
|
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
||||||
|
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
||||||
|
return axios.request(axiosRequestArgs);
|
||||||
|
};
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传电子签名 🔖
|
* @summary 上传电子签名 🔖
|
||||||
@ -1129,6 +1282,17 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
|
|||||||
async apiSysFileUploadAvatarPostForm(file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
async apiSysFileUploadAvatarPostForm(file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
return SysFileApiFp(configuration).apiSysFileUploadAvatarPostForm(file, options).then((request) => request(axios, basePath));
|
return SysFileApiFp(configuration).apiSysFileUploadAvatarPostForm(file, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传轮播图 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Array<Blob>} [files]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysFileUploadCarouselTenantIdPostForm(tenantId: number, files?: Array<Blob>, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
||||||
|
return SysFileApiFp(configuration).apiSysFileUploadCarouselTenantIdPostForm(tenantId, files, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传文件Base64 🔖
|
* @summary 上传文件Base64 🔖
|
||||||
@ -1147,11 +1311,12 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
|
|||||||
* @param {string} [fileAlias]
|
* @param {string} [fileAlias]
|
||||||
* @param {boolean} [isPublic]
|
* @param {boolean} [isPublic]
|
||||||
* @param {string} [allowSuffix]
|
* @param {string} [allowSuffix]
|
||||||
|
* @param {number} [dataId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, options).then((request) => request(axios, basePath));
|
return SysFileApiFp(configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -1163,6 +1328,17 @@ export const SysFileApiFactory = function (configuration?: Configuration, basePa
|
|||||||
async apiSysFileUploadFilesPostForm(files?: Array<Blob>, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
async apiSysFileUploadFilesPostForm(files?: Array<Blob>, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
||||||
return SysFileApiFp(configuration).apiSysFileUploadFilesPostForm(files, options).then((request) => request(axios, basePath));
|
return SysFileApiFp(configuration).apiSysFileUploadFilesPostForm(files, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传Logo 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Blob} [file]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
*/
|
||||||
|
async apiSysFileUploadLogoTenantIdPostForm(tenantId: number, file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
|
return SysFileApiFp(configuration).apiSysFileUploadLogoTenantIdPostForm(tenantId, file, options).then((request) => request(axios, basePath));
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传电子签名 🔖
|
* @summary 上传电子签名 🔖
|
||||||
@ -1304,6 +1480,18 @@ export class SysFileApi extends BaseAPI {
|
|||||||
public async apiSysFileUploadAvatarPostForm(file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
public async apiSysFileUploadAvatarPostForm(file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
return SysFileApiFp(this.configuration).apiSysFileUploadAvatarPostForm(file, options).then((request) => request(this.axios, this.basePath));
|
return SysFileApiFp(this.configuration).apiSysFileUploadAvatarPostForm(file, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传轮播图 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Array<Blob>} [files]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof SysFileApi
|
||||||
|
*/
|
||||||
|
public async apiSysFileUploadCarouselTenantIdPostForm(tenantId: number, files?: Array<Blob>, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
||||||
|
return SysFileApiFp(this.configuration).apiSysFileUploadCarouselTenantIdPostForm(tenantId, files, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传文件Base64 🔖
|
* @summary 上传文件Base64 🔖
|
||||||
@ -1323,12 +1511,13 @@ export class SysFileApi extends BaseAPI {
|
|||||||
* @param {string} [fileAlias]
|
* @param {string} [fileAlias]
|
||||||
* @param {boolean} [isPublic]
|
* @param {boolean} [isPublic]
|
||||||
* @param {string} [allowSuffix]
|
* @param {string} [allowSuffix]
|
||||||
|
* @param {number} [dataId]
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
* @memberof SysFileApi
|
* @memberof SysFileApi
|
||||||
*/
|
*/
|
||||||
public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
public async apiSysFileUploadFilePostForm(file?: Blob, fileType?: string, fileAlias?: string, isPublic?: boolean, allowSuffix?: string, dataId?: number, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, options).then((request) => request(this.axios, this.basePath));
|
return SysFileApiFp(this.configuration).apiSysFileUploadFilePostForm(file, fileType, fileAlias, isPublic, allowSuffix, dataId, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -1341,6 +1530,18 @@ export class SysFileApi extends BaseAPI {
|
|||||||
public async apiSysFileUploadFilesPostForm(files?: Array<Blob>, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
public async apiSysFileUploadFilesPostForm(files?: Array<Blob>, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultListSysFile>> {
|
||||||
return SysFileApiFp(this.configuration).apiSysFileUploadFilesPostForm(files, options).then((request) => request(this.axios, this.basePath));
|
return SysFileApiFp(this.configuration).apiSysFileUploadFilesPostForm(files, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @summary 上传Logo 🔖
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {Blob} [file]
|
||||||
|
* @param {*} [options] Override http request option.
|
||||||
|
* @throws {RequiredError}
|
||||||
|
* @memberof SysFileApi
|
||||||
|
*/
|
||||||
|
public async apiSysFileUploadLogoTenantIdPostForm(tenantId: number, file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
||||||
|
return SysFileApiFp(this.configuration).apiSysFileUploadLogoTenantIdPostForm(tenantId, file, options).then((request) => request(this.axios, this.basePath));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 上传电子签名 🔖
|
* @summary 上传电子签名 🔖
|
||||||
|
|||||||
@ -25,7 +25,6 @@ import { AdminNETResultListSysUser } from '../models';
|
|||||||
import { AdminNETResultObject } from '../models';
|
import { AdminNETResultObject } from '../models';
|
||||||
import { AdminNETResultSqlSugarPagedListTenantOutput } from '../models';
|
import { AdminNETResultSqlSugarPagedListTenantOutput } from '../models';
|
||||||
import { AdminNETResultString } from '../models';
|
import { AdminNETResultString } from '../models';
|
||||||
import { AdminNETResultSysFile } from '../models';
|
|
||||||
import { DeleteTenantInput } from '../models';
|
import { DeleteTenantInput } from '../models';
|
||||||
import { PageTenantInput } from '../models';
|
import { PageTenantInput } from '../models';
|
||||||
import { RoleMenuInput } from '../models';
|
import { RoleMenuInput } from '../models';
|
||||||
@ -703,58 +702,6 @@ export const SysTenantApiAxiosParamCreator = function (configuration?: Configura
|
|||||||
options: localVarRequestOptions,
|
options: localVarRequestOptions,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @summary 上传轮播图单文件 🔖
|
|
||||||
* @param {Blob} [file]
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
apiSysTenantUploadCarouselFilePostForm: async (file?: Blob, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
|
||||||
const localVarPath = `/api/sysTenant/uploadCarouselFile`;
|
|
||||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
|
||||||
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
|
|
||||||
let baseOptions;
|
|
||||||
if (configuration) {
|
|
||||||
baseOptions = configuration.baseOptions;
|
|
||||||
}
|
|
||||||
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
|
|
||||||
const localVarHeaderParameter = {} as any;
|
|
||||||
const localVarQueryParameter = {} as any;
|
|
||||||
const localVarFormParams = new FormData();
|
|
||||||
|
|
||||||
// authentication Bearer required
|
|
||||||
// http bearer authentication required
|
|
||||||
if (configuration && configuration.accessToken) {
|
|
||||||
const accessToken = typeof configuration.accessToken === 'function'
|
|
||||||
? await configuration.accessToken()
|
|
||||||
: await configuration.accessToken;
|
|
||||||
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (file !== undefined) {
|
|
||||||
localVarFormParams.append('file', file as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
localVarHeaderParameter['Content-Type'] = 'multipart/form-data';
|
|
||||||
const query = new URLSearchParams(localVarUrlObj.search);
|
|
||||||
for (const key in localVarQueryParameter) {
|
|
||||||
query.set(key, localVarQueryParameter[key]);
|
|
||||||
}
|
|
||||||
for (const key in options.params) {
|
|
||||||
query.set(key, options.params[key]);
|
|
||||||
}
|
|
||||||
localVarUrlObj.search = (new URLSearchParams(query)).toString();
|
|
||||||
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
|
|
||||||
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
|
|
||||||
localVarRequestOptions.data = localVarFormParams;
|
|
||||||
|
|
||||||
return {
|
|
||||||
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
|
|
||||||
options: localVarRequestOptions,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取租户下的用户列表 🔖
|
* @summary 获取租户下的用户列表 🔖
|
||||||
@ -1006,20 +953,6 @@ export const SysTenantApiFp = function(configuration?: Configuration) {
|
|||||||
return axios.request(axiosRequestArgs);
|
return axios.request(axiosRequestArgs);
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @summary 上传轮播图单文件 🔖
|
|
||||||
* @param {Blob} [file]
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
async apiSysTenantUploadCarouselFilePostForm(file?: Blob, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<AdminNETResultSysFile>>> {
|
|
||||||
const localVarAxiosArgs = await SysTenantApiAxiosParamCreator(configuration).apiSysTenantUploadCarouselFilePostForm(file, options);
|
|
||||||
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
|
|
||||||
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
|
|
||||||
return axios.request(axiosRequestArgs);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取租户下的用户列表 🔖
|
* @summary 获取租户下的用户列表 🔖
|
||||||
@ -1181,16 +1114,6 @@ export const SysTenantApiFactory = function (configuration?: Configuration, base
|
|||||||
async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
|
async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
|
||||||
return SysTenantApiFp(configuration).apiSysTenantUpdatePost(body, options).then((request) => request(axios, basePath));
|
return SysTenantApiFp(configuration).apiSysTenantUpdatePost(body, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @summary 上传轮播图单文件 🔖
|
|
||||||
* @param {Blob} [file]
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
*/
|
|
||||||
async apiSysTenantUploadCarouselFilePostForm(file?: Blob, options?: AxiosRequestConfig): Promise<AxiosResponse<AdminNETResultSysFile>> {
|
|
||||||
return SysTenantApiFp(configuration).apiSysTenantUploadCarouselFilePostForm(file, options).then((request) => request(axios, basePath));
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取租户下的用户列表 🔖
|
* @summary 获取租户下的用户列表 🔖
|
||||||
@ -1363,17 +1286,6 @@ export class SysTenantApi extends BaseAPI {
|
|||||||
public async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
|
public async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
|
||||||
return SysTenantApiFp(this.configuration).apiSysTenantUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
|
return SysTenantApiFp(this.configuration).apiSysTenantUpdatePost(body, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @summary 上传轮播图单文件 🔖
|
|
||||||
* @param {Blob} [file]
|
|
||||||
* @param {*} [options] Override http request option.
|
|
||||||
* @throws {RequiredError}
|
|
||||||
* @memberof SysTenantApi
|
|
||||||
*/
|
|
||||||
public async apiSysTenantUploadCarouselFilePostForm(file?: Blob, options?: AxiosRequestConfig) : Promise<AxiosResponse<AdminNETResultSysFile>> {
|
|
||||||
return SysTenantApiFp(this.configuration).apiSysTenantUploadCarouselFilePostForm(file, options).then((request) => request(this.axios, this.basePath));
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @summary 获取租户下的用户列表 🔖
|
* @summary 获取租户下的用户列表 🔖
|
||||||
|
|||||||
@ -503,7 +503,6 @@ export * from './sys-report-group';
|
|||||||
export * from './sys-report-layout-config';
|
export * from './sys-report-layout-config';
|
||||||
export * from './sys-report-param';
|
export * from './sys-report-param';
|
||||||
export * from './sys-schedule';
|
export * from './sys-schedule';
|
||||||
export * from './sys-tenant-upload-carousel-file-body';
|
|
||||||
export * from './sys-upgrade';
|
export * from './sys-upgrade';
|
||||||
export * from './sys-user';
|
export * from './sys-user';
|
||||||
export * from './sys-user-ext-org';
|
export * from './sys-user-ext-org';
|
||||||
@ -553,7 +552,9 @@ export * from './update-schedule-input';
|
|||||||
export * from './update-sys-ldap-input';
|
export * from './update-sys-ldap-input';
|
||||||
export * from './update-tenant-input';
|
export * from './update-tenant-input';
|
||||||
export * from './update-user-input';
|
export * from './update-user-input';
|
||||||
|
export * from './upload-carousel-tenant-id-body';
|
||||||
export * from './upload-file-from-base64-input';
|
export * from './upload-file-from-base64-input';
|
||||||
|
export * from './upload-logo-tenant-id-body';
|
||||||
export * from './user-menu-input';
|
export * from './user-menu-input';
|
||||||
export * from './user-output';
|
export * from './user-output';
|
||||||
export * from './user-role-input';
|
export * from './user-role-input';
|
||||||
|
|||||||
@ -59,4 +59,12 @@ export interface SysFileUploadFileBody {
|
|||||||
* @memberof SysFileUploadFileBody
|
* @memberof SysFileUploadFileBody
|
||||||
*/
|
*/
|
||||||
allowSuffix?: string;
|
allowSuffix?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 业务数据Id
|
||||||
|
*
|
||||||
|
* @type {number}
|
||||||
|
* @memberof SysFileUploadFileBody
|
||||||
|
*/
|
||||||
|
dataId?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,20 +29,12 @@ export interface SysInfoInput {
|
|||||||
tenantId?: number;
|
tenantId?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图标(Data URI scheme base64 编码)
|
* 系统图标
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SysInfoInput
|
* @memberof SysInfoInput
|
||||||
*/
|
*/
|
||||||
logoBase64?: string | null;
|
logo?: string | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 图标文件名
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof SysInfoInput
|
|
||||||
*/
|
|
||||||
logoFileName?: string | null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主标题
|
* 主标题
|
||||||
@ -149,10 +141,10 @@ export interface SysInfoInput {
|
|||||||
secondVer?: boolean;
|
secondVer?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 轮播图
|
* 轮播图Id集合
|
||||||
*
|
*
|
||||||
* @type {Array<Blob>}
|
* @type {Array<number>}
|
||||||
* @memberof SysInfoInput
|
* @memberof SysInfoInput
|
||||||
*/
|
*/
|
||||||
carouselFiles?: Array<Blob> | null;
|
carouselFileIds?: Array<number> | null;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,28 @@
|
|||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
/**
|
||||||
|
* Admin.NET 通用权限开发平台
|
||||||
|
* 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>
|
||||||
|
*
|
||||||
|
* OpenAPI spec version: 1.0.0
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* NOTE: This class is auto generated by the swagger code generator program.
|
||||||
|
* https://github.com/swagger-api/swagger-codegen.git
|
||||||
|
* Do not edit the class manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @export
|
||||||
|
* @interface UploadCarouselTenantIdBody
|
||||||
|
*/
|
||||||
|
export interface UploadCarouselTenantIdBody {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Array<Blob>}
|
||||||
|
* @memberof UploadCarouselTenantIdBody
|
||||||
|
*/
|
||||||
|
files: Array<Blob>;
|
||||||
|
}
|
||||||
@ -16,13 +16,13 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @interface SysTenantUploadCarouselFileBody
|
* @interface UploadLogoTenantIdBody
|
||||||
*/
|
*/
|
||||||
export interface SysTenantUploadCarouselFileBody {
|
export interface UploadLogoTenantIdBody {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Blob}
|
* @type {Blob}
|
||||||
* @memberof SysTenantUploadCarouselFileBody
|
* @memberof UploadLogoTenantIdBody
|
||||||
*/
|
*/
|
||||||
file: Blob;
|
file: Blob;
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ interface iVxeOption {
|
|||||||
sortConfig?: VxeTablePropTypes.SortConfig<any>;
|
sortConfig?: VxeTablePropTypes.SortConfig<any>;
|
||||||
showFooter?: boolean;
|
showFooter?: boolean;
|
||||||
footerData?: VxeTablePropTypes.FooterData;
|
footerData?: VxeTablePropTypes.FooterData;
|
||||||
footerMethod?: VxeTablePropTypes.FooterMethod<D>;
|
footerMethod?: VxeTablePropTypes.FooterMethod<any>;
|
||||||
remoteCustom?: boolean;
|
remoteCustom?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,8 +23,6 @@ import 'vform3-builds/dist/designer.style.css';
|
|||||||
import { setupVXETable } from '/@/hooks/setupVXETableHook';
|
import { setupVXETable } from '/@/hooks/setupVXETableHook';
|
||||||
// 自定义字典组件
|
// 自定义字典组件
|
||||||
import sysDict from '/@/components/sysDict/sysDict.vue';
|
import sysDict from '/@/components/sysDict/sysDict.vue';
|
||||||
// AI组件
|
|
||||||
import ElementPlusX from 'vue-element-plus-x';
|
|
||||||
// 关闭自动打印
|
// 关闭自动打印
|
||||||
import { disAutoConnect } from 'vue-plugin-hiprint';
|
import { disAutoConnect } from 'vue-plugin-hiprint';
|
||||||
disAutoConnect();
|
disAutoConnect();
|
||||||
@ -36,4 +34,4 @@ other.elSvg(app);
|
|||||||
// 注册全局字典组件
|
// 注册全局字典组件
|
||||||
app.component('GSysDict', sysDict);
|
app.component('GSysDict', sysDict);
|
||||||
|
|
||||||
app.use(pinia).use(i18n).use(router).use(ElementPlus).use(setupVXETable).use(VueGridLayout).use(VForm3).use(VueSignaturePad).use(vue3TreeOrg).use(ElementPlusX).mount('#app');
|
app.use(pinia).use(i18n).use(router).use(ElementPlus).use(setupVXETable).use(VueGridLayout).use(VForm3).use(VueSignaturePad).use(vue3TreeOrg).mount('#app');
|
||||||
|
|||||||
1
Web/src/types/pinia.d.ts
vendored
1
Web/src/types/pinia.d.ts
vendored
@ -100,6 +100,7 @@ declare interface ThemeConfigState {
|
|||||||
icp: string; // Icp备案号
|
icp: string; // Icp备案号
|
||||||
icpUrl: string; // Icp地址
|
icpUrl: string; // Icp地址
|
||||||
version?: string; // 版本号
|
version?: string; // 版本号
|
||||||
|
carouselFiles?: any[]; // 轮播图集合
|
||||||
secondVer?: boolean; // 是否开启二级验证
|
secondVer?: boolean; // 是否开启二级验证
|
||||||
captcha?: boolean; // 是否开启验证码
|
captcha?: boolean; // 是否开启验证码
|
||||||
forceChangePassword?: boolean; // 是否开启强制修改密码
|
forceChangePassword?: boolean; // 是否开启强制修改密码
|
||||||
|
|||||||
@ -42,6 +42,8 @@ export async function loadSysInfo(tenantid: number) {
|
|||||||
themeConfig.value.copyright = data.copyright;
|
themeConfig.value.copyright = data.copyright;
|
||||||
// 版本号
|
// 版本号
|
||||||
themeConfig.value.version = data.version;
|
themeConfig.value.version = data.version;
|
||||||
|
// 轮播图
|
||||||
|
themeConfig.value.carouselFiles = data.carouselFiles;
|
||||||
// 全局主题
|
// 全局主题
|
||||||
themeConfig.value.primary = data.themeColor;
|
themeConfig.value.primary = data.themeColor;
|
||||||
// 布局切换
|
// 布局切换
|
||||||
|
|||||||
@ -2,8 +2,7 @@
|
|||||||
<div style="flex: 1; background: #f3f4f6; overflow: auto">
|
<div style="flex: 1; background: #f3f4f6; overflow: auto">
|
||||||
<el-container>
|
<el-container>
|
||||||
<!-- 侧边栏 -->
|
<!-- 侧边栏 -->
|
||||||
<el-aside v-show="!isFold" :class="isFold ? 'sidebar-fold' : 'expand-sidebar'"
|
<el-aside v-show="!isFold" :class="isFold ? 'sidebar-fold' : 'expand-sidebar'" style="background: #f3f4f6; border-right: 1px solid #f0f0f0; display: flex; flex-direction: column">
|
||||||
style="background: #f3f4f6; border-right: 1px solid #f0f0f0; display: flex; flex-direction: column">
|
|
||||||
<div class="chat-action">
|
<div class="chat-action">
|
||||||
<el-tooltip :content="$t('message.chat.newChat')" placement="top">
|
<el-tooltip :content="$t('message.chat.newChat')" placement="top">
|
||||||
<div class="chat-action-item" @click.stop="handleNewChat">
|
<div class="chat-action-item" @click.stop="handleNewChat">
|
||||||
@ -16,23 +15,28 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div style="display: flex; flex-direction: column; align-items: center; padding-bottom: 8px; padding-top: 0px; margin-top: 0px">
|
||||||
style="display: flex; flex-direction: column; align-items: center; padding-bottom: 8px; padding-top: 0px; margin-top: 0px">
|
<el-avatar :size="60" style="background-color: #f3f4f6" src="/chat.png" fit="fill" class="avatar-with-shadow" />
|
||||||
<el-avatar :size="60" style="background-color: #f3f4f6" src="/chat.png" fit="fill"
|
<div style="margin-top: 10px; font-weight: bold; font-size: 18px; color: #333">{{ $t('message.chat.title') }}</div>
|
||||||
class="avatar-with-shadow" />
|
|
||||||
<div style="margin-top: 10px; font-weight: bold; font-size: 18px; color: #333">{{
|
|
||||||
$t('message.chat.title') }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="flex: 1; overflow-y: auto; width: 100%">
|
<div style="flex: 1; overflow-y: auto; width: 100%">
|
||||||
<div style="display: flex; flex-direction: column; gap: 12px; height: 100%">
|
<div style="display: flex; flex-direction: column; gap: 12px; height: 100%">
|
||||||
<Conversations style="border-radius: 0%; width: 255px" v-model:active="activeHistoryKey"
|
<Conversations
|
||||||
:items="sideBarHistoryList" row-key="key" :show-tooltip="true" showToTopBtn
|
style="border-radius: 0%; width: 255px"
|
||||||
:label-max-width="210" :load-more="loadMoreHistoryItems"
|
v-model:active="activeHistoryKey"
|
||||||
:load-more-loading="isHistoryListLoading" showBuiltInMenu @change="handleChange">
|
:items="sideBarHistoryList"
|
||||||
|
row-key="key"
|
||||||
|
:show-tooltip="true"
|
||||||
|
showToTopBtn
|
||||||
|
:label-max-width="210"
|
||||||
|
:load-more="loadMoreHistoryItems"
|
||||||
|
:load-more-loading="isHistoryListLoading"
|
||||||
|
showBuiltInMenu
|
||||||
|
@change="handleChange"
|
||||||
|
>
|
||||||
<template #menu="{ item }">
|
<template #menu="{ item }">
|
||||||
<div class="menu-buttons">
|
<div class="menu-buttons">
|
||||||
<el-button v-for="menuItem in actionMenuItems" :key="menuItem.key" link
|
<el-button v-for="menuItem in actionMenuItems" :key="menuItem.key" link size="default" @click="handleMenuClick(menuItem.key, item)">
|
||||||
size="default" @click="handleMenuClick(menuItem.key, item)">
|
|
||||||
<el-icon v-if="menuItem.icon">
|
<el-icon v-if="menuItem.icon">
|
||||||
<component :is="menuItem.icon" />
|
<component :is="menuItem.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -47,7 +51,8 @@
|
|||||||
|
|
||||||
<!-- 主体内容 -->
|
<!-- 主体内容 -->
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-main style="
|
<el-main
|
||||||
|
style="
|
||||||
flex: 1;
|
flex: 1;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -60,12 +65,12 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
">
|
"
|
||||||
|
>
|
||||||
<div class="main_action_toolbar" style="position: absolute; top: 0px; width: 500px; left: 20px">
|
<div class="main_action_toolbar" style="position: absolute; top: 0px; width: 500px; left: 20px">
|
||||||
<div v-if="isFold" class="chat-action-item main_action_item">
|
<div v-if="isFold" class="chat-action-item main_action_item">
|
||||||
<el-tooltip :content="$t('message.chat.expandChat')" placement="top">
|
<el-tooltip :content="$t('message.chat.expandChat')" placement="top">
|
||||||
<Expand style="width: 1.5em; height: 1.5em; color: #333"
|
<Expand style="width: 1.5em; height: 1.5em; color: #333" @click.stop="handleExpandChat" />
|
||||||
@click.stop="handleExpandChat" />
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isFold" class="chat-action-item main_action_item" @click="handleNewChat">
|
<div v-if="isFold" class="chat-action-item main_action_item" @click="handleNewChat">
|
||||||
@ -83,12 +88,10 @@
|
|||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item v-for="item in modellList.models" :key="item.modelName"
|
<el-dropdown-item v-for="item in modellList.models" :key="item.modelName" @click="handleChangeModel(item)">
|
||||||
@click="handleChangeModel(item)">
|
|
||||||
<div class="model-item">
|
<div class="model-item">
|
||||||
<span>{{ item.providerName }}/{{ item.modelName }}</span>
|
<span>{{ item.providerName }}/{{ item.modelName }}</span>
|
||||||
<el-icon v-if="item.modelName == modellList.currentModel"
|
<el-icon v-if="item.modelName == modellList.currentModel" style="color: #409eff">
|
||||||
style="color: #409eff">
|
|
||||||
<Select />
|
<Select />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
@ -99,42 +102,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isNew" class="new_chat_title">
|
<div v-if="isNew" class="new_chat_title">
|
||||||
<div style="margin-top: 60px; font-size: 36px; font-weight: bold; letter-spacing: 2px">Hello, {{
|
<div style="margin-top: 60px; font-size: 36px; font-weight: bold; letter-spacing: 2px">Hello, {{ userName }}</div>
|
||||||
userName }}
|
<div style="margin-top: 20px; width: 100%; text-align: center; color: #999; font-size: 16px; font-weight: bold; letter-spacing: 2px">
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style="margin-top: 20px; width: 100%; text-align: center; color: #999; font-size: 16px; font-weight: bold; letter-spacing: 2px">
|
|
||||||
{{ $t('message.chat.subTitle') }}
|
{{ $t('message.chat.subTitle') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="chat_content">
|
<div v-else class="chat_content">
|
||||||
<BubbleList class="chat_content_list" ref="chatRef" :list="chatList" maxHeight="100%"
|
<BubbleList class="chat_content_list" ref="chatRef" :list="chatList" maxHeight="100%" style="padding: 0 60px 100px 60px" @complete="handleBubbleComplete" :triggerIndices="triggerIndices">
|
||||||
style="padding: 0 60px 100px 60px" @complete="handleBubbleComplete"
|
|
||||||
:triggerIndices="triggerIndices">
|
|
||||||
<template #content="{ item }">
|
<template #content="{ item }">
|
||||||
<Typewriter v-if="chatList.length > 0 && chatList[chatList.length - 1].key === item.key && isSenderLoading" :content="item.content" :is-markdown="true" :typing="true" @finish="handleTypeingComplete"/>
|
<Typewriter
|
||||||
<XMarkdown
|
v-if="chatList.length > 0 && chatList[chatList.length - 1].key === item.key && isSenderLoading"
|
||||||
v-else
|
:content="item.content"
|
||||||
:markdown="item.content"
|
:is-markdown="true"
|
||||||
default-theme-mode="light"
|
:typing="true"
|
||||||
class="markdown-body"
|
@finish="handleTypeingComplete"
|
||||||
/>
|
/>
|
||||||
|
<XMarkdown v-else :markdown="item.content" default-theme-mode="light" class="markdown-body" />
|
||||||
</template>
|
</template>
|
||||||
<template #header="{ item }">
|
<template #header="{ item }">
|
||||||
<div v-if="item.role == 'assistant' && deepThinkingVisible && item.key == chatList[chatList.length - 1].key"
|
<div v-if="item.role == 'assistant' && deepThinkingVisible && item.key == chatList[chatList.length - 1].key" class="header-wrapper">
|
||||||
class="header-wrapper">
|
<Thinking max-width="100%" buttonWidth="250px" autoCollapse :content="deepThinkingMessage" :status="deepThinkingStatus" backgroundColor="#fff9e6" color="#000">
|
||||||
<Thinking max-width="100%" buttonWidth="250px" autoCollapse
|
|
||||||
:content="deepThinkingMessage" :status="deepThinkingStatus"
|
|
||||||
backgroundColor="#fff9e6" color="#000">
|
|
||||||
<template #label="{ status }">
|
<template #label="{ status }">
|
||||||
<span v-if="status === 'start'">{{ $t('message.chat.startThinking')
|
<span v-if="status === 'start'">{{ $t('message.chat.startThinking') }}</span>
|
||||||
}}</span>
|
<span v-else-if="status === 'thinking'">{{ $t('message.chat.thinking') }}</span>
|
||||||
<span v-else-if="status === 'thinking'">{{ $t('message.chat.thinking')
|
<span v-else-if="status === 'end'">{{ $t('message.chat.thinkingDone') }}</span>
|
||||||
}}</span>
|
<span v-else-if="status === 'error'">{{ $t('message.chat.thinkingFailed') }}</span>
|
||||||
<span v-else-if="status === 'end'">{{ $t('message.chat.thinkingDone')
|
|
||||||
}}</span>
|
|
||||||
<span v-else-if="status === 'error'">{{ $t('message.chat.thinkingFailed')
|
|
||||||
}}</span>
|
|
||||||
</template>
|
</template>
|
||||||
<template #content="{ content }">
|
<template #content="{ content }">
|
||||||
<span>
|
<span>
|
||||||
@ -146,15 +138,12 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #footer="{ item }">
|
<template #footer="{ item }">
|
||||||
<div v-if="item.role == 'assistant'" class="footer-container">
|
<div v-if="item.role == 'assistant'" class="footer-container">
|
||||||
<el-button type="info" text :icon="CopyDocument" size="small"
|
<el-button type="info" text :icon="CopyDocument" size="small" @click="handleCopy(item)" />
|
||||||
@click="handleCopy(item)" />
|
|
||||||
<el-button type="info" text size="small">
|
<el-button type="info" text size="small">
|
||||||
<el-icon v-if="!isPlaying || playAudioKey != item.key"
|
<el-icon v-if="!isPlaying || playAudioKey != item.key" @click="handlePlay(item)">
|
||||||
@click="handlePlay(item)">
|
|
||||||
<VideoPlay />
|
<VideoPlay />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<el-icon v-if="isPlaying && playAudioKey == item.key"
|
<el-icon v-if="isPlaying && playAudioKey == item.key" @click="handlePause(item)">
|
||||||
@click="handlePause(item)">
|
|
||||||
<VideoPause />
|
<VideoPause />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -163,9 +152,18 @@
|
|||||||
</BubbleList>
|
</BubbleList>
|
||||||
</div>
|
</div>
|
||||||
<div :class="isNew ? 'chat_new_input_style' : 'chat_edit_input_style'">
|
<div :class="isNew ? 'chat_new_input_style' : 'chat_edit_input_style'">
|
||||||
<sender ref="senderRef" variant="updown" clearable allow-speech :loading="isSenderLoading"
|
<sender
|
||||||
:read-only="isSenderLoading" :auto-size="{ minRows: 1, maxRows: 5 }" v-model="senderInput"
|
ref="senderRef"
|
||||||
@submit="handleSend" :placeholder="$t('message.chat.inputPlaceholder')">
|
variant="updown"
|
||||||
|
clearable
|
||||||
|
allow-speech
|
||||||
|
:loading="isSenderLoading"
|
||||||
|
:read-only="isSenderLoading"
|
||||||
|
:auto-size="{ minRows: 1, maxRows: 5 }"
|
||||||
|
v-model="senderInput"
|
||||||
|
@submit="handleSend"
|
||||||
|
:placeholder="$t('message.chat.inputPlaceholder')"
|
||||||
|
>
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
|
<div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap">
|
||||||
<el-button round plain>
|
<el-button round plain>
|
||||||
@ -174,9 +172,11 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
<div :class="{ isDeepThinking }"
|
<div
|
||||||
|
:class="{ isDeepThinking }"
|
||||||
style="display: flex; align-items: center; gap: 4px; padding: 4px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px"
|
style="display: flex; align-items: center; gap: 4px; padding: 4px 12px; border: 1px solid silver; border-radius: 15px; cursor: pointer; font-size: 12px"
|
||||||
@click="handleDeepThinking">
|
@click="handleDeepThinking"
|
||||||
|
>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ElementPlus />
|
<ElementPlus />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -197,12 +197,10 @@
|
|||||||
<div class="ai-rename-icon ai-rename-drag" @mousedown="startDrag">
|
<div class="ai-rename-icon ai-rename-drag" @mousedown="startDrag">
|
||||||
<el-avatar :size="48" src="/chat.png" />
|
<el-avatar :size="48" src="/chat.png" />
|
||||||
</div>
|
</div>
|
||||||
<el-input v-model="renameInput" @keyup.enter="confirmRename" ref="renameInputRef"
|
<el-input v-model="renameInput" @keyup.enter="confirmRename" ref="renameInputRef" class="ai-rename-input" />
|
||||||
class="ai-rename-input" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="ai-dialog-footer">
|
<div class="ai-dialog-footer">
|
||||||
<el-button @click="cancelRename" class="ai-btn-cancel">{{ $t('message.chat.cancel')
|
<el-button @click="cancelRename" class="ai-btn-cancel">{{ $t('message.chat.cancel') }}</el-button>
|
||||||
}}</el-button>
|
|
||||||
<el-button type="primary" @click="confirmRename" class="ai-btn-confirm">
|
<el-button type="primary" @click="confirmRename" class="ai-btn-confirm">
|
||||||
{{ $t('message.chat.confirm') }}
|
{{ $t('message.chat.confirm') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -222,12 +220,10 @@ import { useI18n } from 'vue-i18n';
|
|||||||
|
|
||||||
import { franc } from 'franc';
|
import { franc } from 'franc';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
import { BubbleList, Conversations, Sender, Thinking, Typewriter, XMarkdown } from 'vue-element-plus-x';
|
||||||
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/components/BubbleList/types';
|
import type { BubbleListItemProps, BubbleListProps } from 'vue-element-plus-x/types/components/BubbleList/types';
|
||||||
import type { ConversationItem } from 'vue-element-plus-x/types/components/Conversations/types';
|
import type { ConversationItem } from 'vue-element-plus-x/types/components/Conversations/types';
|
||||||
import type { TypewriterInstance } from 'vue-element-plus-x/types/components/Typewriter/types';
|
import type { TypewriterInstance } from 'vue-element-plus-x/types/components/Typewriter/types';
|
||||||
// import 'vue-element-plus-x/styles/prism-coy.min.css'
|
|
||||||
// import 'vue-element-plus-x/styles/prism.min.css'
|
|
||||||
|
|
||||||
|
|
||||||
import { getAPI } from '/@/utils/axios-utils';
|
import { getAPI } from '/@/utils/axios-utils';
|
||||||
import { LLMChatApi } from '/@/api-services/api';
|
import { LLMChatApi } from '/@/api-services/api';
|
||||||
@ -311,11 +307,11 @@ const initSSEConnection = () => {
|
|||||||
monitorSSEConnectionHandler = setInterval(() => {
|
monitorSSEConnectionHandler = setInterval(() => {
|
||||||
isSSEConnectionClosed = Date.now() - lastSseConnectionTime > SSE_CONNECTION_TIMEOUT;
|
isSSEConnectionClosed = Date.now() - lastSseConnectionTime > SSE_CONNECTION_TIMEOUT;
|
||||||
if (isSSEConnectionClosed) {
|
if (isSSEConnectionClosed) {
|
||||||
console.log("SSE connection timed out, reconnecting");
|
console.log('SSE connection timed out, reconnecting');
|
||||||
try {
|
try {
|
||||||
initSSEConnectionCore();
|
initSSEConnectionCore();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("SSE connection timed out, reconnecting failed", err);
|
console.log('SSE connection timed out, reconnecting failed', err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, SSE_CONNECTION_TIMEOUT);
|
}, SSE_CONNECTION_TIMEOUT);
|
||||||
@ -327,7 +323,7 @@ const checkSSEConnectionStatus = () => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
};
|
||||||
// 初始化sse连接核心代码
|
// 初始化sse连接核心代码
|
||||||
const initSSEConnectionCore = () => {
|
const initSSEConnectionCore = () => {
|
||||||
closeSSEConnection();
|
closeSSEConnection();
|
||||||
@ -378,12 +374,10 @@ const initSSEConnectionCore = () => {
|
|||||||
lastSseConnectionTime = Date.now();
|
lastSseConnectionTime = Date.now();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
eventSource.onerror = () => {
|
eventSource.onerror = () => {
|
||||||
console.log('SSE connection error');
|
console.log('SSE connection error');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
eventSource.onopen = (event) => {
|
eventSource.onopen = (event) => {
|
||||||
console.log('SSE connection opened:', event);
|
console.log('SSE connection opened:', event);
|
||||||
};
|
};
|
||||||
@ -401,10 +395,10 @@ const handleBubbleComplete = (instance: TypewriterInstance, index: number) => {
|
|||||||
chatRef?.value?.scrollToBottom();
|
chatRef?.value?.scrollToBottom();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTypeingComplete = ()=>{
|
const handleTypeingComplete = () => {
|
||||||
isSenderLoading.value = false;
|
isSenderLoading.value = false;
|
||||||
chatRef?.value?.scrollToBottom();
|
chatRef?.value?.scrollToBottom();
|
||||||
}
|
};
|
||||||
|
|
||||||
//#endregion sse客户端
|
//#endregion sse客户端
|
||||||
const handleSend = async () => {
|
const handleSend = async () => {
|
||||||
@ -688,8 +682,6 @@ const loadMoreHistoryItems = async () => {
|
|||||||
isHistoryListLoading.value = false;
|
isHistoryListLoading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleMenuClick = (menuKey: string, item: any) => {
|
const handleMenuClick = (menuKey: string, item: any) => {
|
||||||
switch (menuKey) {
|
switch (menuKey) {
|
||||||
case 'rename':
|
case 'rename':
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-carousel height="500px" class="login-carousel">
|
<el-carousel height="500px" class="login-carousel">
|
||||||
|
<template v-if="themeConfig.carouselFiles == undefined || themeConfig.carouselFiles.length < 1">
|
||||||
<el-carousel-item>
|
<el-carousel-item>
|
||||||
<img :src="loginIconTwo" class="login-icon-group-icon" />
|
<img :src="loginIconTwo" class="login-icon-group-icon" />
|
||||||
</el-carousel-item>
|
</el-carousel-item>
|
||||||
@ -19,6 +20,12 @@
|
|||||||
<el-carousel-item>
|
<el-carousel-item>
|
||||||
<img :src="loginIconTwo2" class="login-icon-group-icon" />
|
<img :src="loginIconTwo2" class="login-icon-group-icon" />
|
||||||
</el-carousel-item>
|
</el-carousel-item>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<el-carousel-item v-for="(item, key) in themeConfig.carouselFiles" :key="key">
|
||||||
|
<img :src="item.url" class="login-icon-group-icon" />
|
||||||
|
</el-carousel-item>
|
||||||
|
</template>
|
||||||
</el-carousel>
|
</el-carousel>
|
||||||
</div>
|
</div>
|
||||||
<div class="login-right flex">
|
<div class="login-right flex">
|
||||||
@ -95,6 +102,7 @@ import { Local } from '/@/utils/storage';
|
|||||||
// 引入多语言
|
// 引入多语言
|
||||||
import { languageList, getCountryCode } from '/@/i18n';
|
import { languageList, getCountryCode } from '/@/i18n';
|
||||||
import '/node_modules/flag-icons/css/flag-icons.min.css';
|
import '/node_modules/flag-icons/css/flag-icons.min.css';
|
||||||
|
import { template } from 'xe-utils';
|
||||||
|
|
||||||
// 引入组件
|
// 引入组件
|
||||||
const Account = defineAsyncComponent(() => import('/@/views/login/component/account.vue'));
|
const Account = defineAsyncComponent(() => import('/@/views/login/component/account.vue'));
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<el-icon><ele-School /></el-icon> 系统图标
|
<el-icon><ele-School /></el-icon> 系统图标
|
||||||
</template>
|
</template>
|
||||||
<el-upload ref="uploadRef" class="avatar-uploader" :showFileList="false" :autoUpload="false" accept=".jpg,.png,.svg" action :limit="1" :onChange="handleUploadChange">
|
<el-upload ref="uploadRef" class="avatar-uploader" :showFileList="false" :autoUpload="false" accept=".jpg,.png,.svg" action :limit="1" :onChange="handleUploadLogoChange">
|
||||||
<img v-if="state.sysInfo.logo" :src="state.sysInfo.logo" class="avatar" />
|
<img v-if="state.sysInfo.logo" :src="state.sysInfo.logo" class="avatar" />
|
||||||
<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" :size="28" />
|
<SvgIcon v-else class="avatar-uploader-icon" name="ele-Plus" :size="28" />
|
||||||
</el-upload>
|
</el-upload>
|
||||||
@ -152,13 +152,21 @@
|
|||||||
<template #label>
|
<template #label>
|
||||||
<el-icon><ele-Picture /></el-icon> 首页轮播图
|
<el-icon><ele-Picture /></el-icon> 首页轮播图
|
||||||
</template>
|
</template>
|
||||||
<el-upload :file-list="state.carouselFileList" list-type="picture-card" :http-request="uploadCarouselFile" :on-preview="previewCarouselFile" :before-remove="beforeRemoveCarouselFile">
|
<el-upload
|
||||||
|
:file-list="state.carouselFileList"
|
||||||
|
list-type="picture-card"
|
||||||
|
:autoUpload="false"
|
||||||
|
accept=".jpg,.png,.svg"
|
||||||
|
:onChange="handleCarouselChange"
|
||||||
|
:on-preview="handleCarouselPreview"
|
||||||
|
:before-remove="handleCarouselRemove"
|
||||||
|
>
|
||||||
<el-icon><ele-Plus /></el-icon>
|
<el-icon><ele-Plus /></el-icon>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
|
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<el-button type="primary" icon="ele-SuccessFilled" @click="saveSysInfo">保存</el-button>
|
<el-button type="primary" icon="ele-SuccessFilled" @click="saveSysInfo">保存配置</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
</el-card>
|
</el-card>
|
||||||
@ -182,63 +190,67 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog v-model="state.dialogImagePreviewVisible">
|
|
||||||
<img w-full :src="state.dialogImagePreviewUrl" alt="" />
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="sysInfoSetting">
|
<script setup lang="ts" name="sysInfoSetting">
|
||||||
import { nextTick, onMounted, reactive, ref } from 'vue';
|
import { nextTick, onMounted, reactive, ref } from 'vue';
|
||||||
import { ElMessage, ElMessageBox, UploadInstance } from 'element-plus';
|
import { ElMessage, UploadFile, UploadFiles, UploadInstance } from 'element-plus';
|
||||||
import { fileToBase64 } from '/@/utils/base64Conver';
|
|
||||||
import { loadSysInfo } from '/@/utils/sysInfo';
|
import { loadSysInfo } from '/@/utils/sysInfo';
|
||||||
import chineseColors from '/@/layout/navBars/topBar/colors.json';
|
import chineseColors from '/@/layout/navBars/topBar/colors.json';
|
||||||
|
|
||||||
import { getAPI } from '/@/utils/axios-utils';
|
import { getAPI } from '/@/utils/axios-utils';
|
||||||
import { SysFileApi, SysInfoInput, SysTenantApi } from '/@/api-services';
|
import { SysFileApi, SysTenantApi } from '/@/api-services';
|
||||||
|
|
||||||
const host = window.location.host;
|
const host = window.location.host;
|
||||||
const uploadRef = ref<UploadInstance>();
|
const uploadRef = ref<UploadInstance>();
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
sysInfo: {} as SysInfoInput | any, // 系统信息数据
|
sysInfo: {} as any, // 系统信息数据
|
||||||
logoFile: undefined as any, // logo上传文件
|
logoFile: undefined as any, // logo上传文件
|
||||||
dialogChineseColorVisible: false, // 中国传统颜色弹窗
|
dialogChineseColorVisible: false, // 中国传统颜色弹窗
|
||||||
colorName: '飞燕草蓝', // 主题颜色名称
|
colorName: '飞燕草蓝', // 主题颜色名称
|
||||||
dialogImagePreviewVisible: false, // 预览图片弹窗
|
carouselFileList: [] as any, // 轮播图文件列表
|
||||||
dialogImagePreviewUrl: '', // 预览图片地址
|
|
||||||
isDelete: false, // 是否已删除图片
|
|
||||||
carouselFileList: [] as any, // 轮播图片文件列表
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 页面初始化
|
// 页面初始化
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await loadSysInfoData();
|
state.isLoading = true;
|
||||||
|
state.sysInfo = await getAPI(SysTenantApi)
|
||||||
|
.apiSysTenantSysInfoTenantIdGet(0)
|
||||||
|
.then((res) => res.data.result ?? []);
|
||||||
|
if (state.sysInfo.carouselFiles) state.carouselFileList = state.sysInfo.carouselFiles;
|
||||||
|
state.isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 通过onChange方法获得文件列表
|
|
||||||
const handleUploadChange = (file: any) => {
|
|
||||||
uploadRef.value!.clearFiles();
|
|
||||||
state.logoFile = file;
|
|
||||||
state.sysInfo.logo = URL.createObjectURL(state.logoFile.raw); // 显示预览logo
|
|
||||||
};
|
|
||||||
|
|
||||||
// 保存
|
// 保存
|
||||||
const saveSysInfo = async () => {
|
const saveSysInfo = async () => {
|
||||||
// 如果有选择图标,则转换为 base64
|
|
||||||
if (state.logoFile) {
|
|
||||||
state.sysInfo.logoBase64 = (await fileToBase64(state.logoFile.raw)) as string;
|
|
||||||
state.sysInfo.logoFileName = state.logoFile.raw.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
state.isLoading = true;
|
state.isLoading = true;
|
||||||
|
if (state.logoFile != undefined && state.logoFile.raw != undefined) {
|
||||||
|
var res = await getAPI(SysFileApi).apiSysFileUploadLogoTenantIdPostForm(state.sysInfo.tenantId, state.logoFile.raw);
|
||||||
|
state.sysInfo.logo = res.data.result?.url;
|
||||||
|
}
|
||||||
|
if (state.carouselFileList != undefined && state.carouselFileList.length > 0) {
|
||||||
|
// 已有的轮播图
|
||||||
|
state.sysInfo.carouselFileIds = state.carouselFileList.filter((file: any) => file.raw == undefined && file.id != undefined).map((file: any) => file.id);
|
||||||
|
|
||||||
|
// 新增的轮播图
|
||||||
|
var carouselFiles = state.carouselFileList.filter((file: any) => file.raw != undefined).map((file: any) => file.raw);
|
||||||
|
if (carouselFiles.length > 0) {
|
||||||
|
var sysFileIds = await getAPI(SysFileApi)
|
||||||
|
.apiSysFileUploadCarouselTenantIdPostForm(state.sysInfo.tenantId, carouselFiles)
|
||||||
|
.then((res) => res.data.result?.map((file: any) => file.id) ?? []);
|
||||||
|
state.sysInfo.carouselFileIds.push(...sysFileIds);
|
||||||
|
}
|
||||||
|
console.log(state.sysInfo.carouselFileIds);
|
||||||
|
}
|
||||||
await getAPI(SysTenantApi).apiSysTenantSaveSysInfoPost(state.sysInfo);
|
await getAPI(SysTenantApi).apiSysTenantSaveSysInfoPost(state.sysInfo);
|
||||||
state.logoFile = undefined;
|
|
||||||
ElMessage.success('保存成功');
|
ElMessage.success('保存成功');
|
||||||
|
|
||||||
|
// 置空上传文件
|
||||||
|
state.logoFile = undefined;
|
||||||
|
|
||||||
// 更新系统信息
|
// 更新系统信息
|
||||||
await loadSysInfo(state.sysInfo.tenantId);
|
await loadSysInfo(state.sysInfo.tenantId);
|
||||||
} finally {
|
} finally {
|
||||||
@ -248,65 +260,27 @@ const saveSysInfo = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载系统信息数据
|
// 上传系统logo
|
||||||
const loadSysInfoData = async () => {
|
const handleUploadLogoChange = (file: any) => {
|
||||||
try {
|
uploadRef.value!.clearFiles();
|
||||||
state.isLoading = true;
|
state.logoFile = file;
|
||||||
const res = await getAPI(SysTenantApi).apiSysTenantSysInfoTenantIdGet(0);
|
state.sysInfo.logo = URL.createObjectURL(state.logoFile.raw); // 显示预览logo
|
||||||
if (res.data!.type !== 'success') return;
|
|
||||||
|
|
||||||
state.sysInfo = res.data.result;
|
|
||||||
if (state.sysInfo.carouselFiles) state.carouselFileList = state.sysInfo.carouselFiles;
|
|
||||||
} finally {
|
|
||||||
nextTick(() => {
|
|
||||||
state.isLoading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 图片转file
|
|
||||||
// const onlineImageToFile = async (imageUrl: string | URL | Request, fileName: string) => {
|
|
||||||
// try {
|
|
||||||
// const response = await fetch(imageUrl);
|
|
||||||
// const blob = await response.blob();
|
|
||||||
// const file = new File([blob], fileName, { type: blob.type });
|
|
||||||
// return file;
|
|
||||||
// } catch (error) {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// 上传轮播图文件
|
// 上传轮播图文件
|
||||||
const uploadCarouselFile = async (e: any) => {
|
const handleCarouselChange = async (file: UploadFile, files: UploadFiles) => {
|
||||||
await getAPI(SysTenantApi).apiSysTenantUploadCarouselFilePostForm(e.file);
|
state.carouselFileList = files;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除轮播图文件
|
// 删除轮播图文件
|
||||||
const beforeRemoveCarouselFile = (file: any, fileList: any) => {
|
const handleCarouselRemove = (file: UploadFile) => {
|
||||||
const result = new Promise((resolve, reject) => {
|
let index = state.carouselFileList.indexOf(file);
|
||||||
ElMessageBox.confirm(`确定删除此轮播图?`, '提示', {
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
})
|
|
||||||
.then(async () => {
|
|
||||||
state.isDelete = true;
|
|
||||||
let index = fileList.indexOf(file);
|
|
||||||
await getAPI(SysFileApi).apiSysFileDeletePost(fileList[index]);
|
|
||||||
fileList.splice(index, 1);
|
|
||||||
state.carouselFileList.splice(index, 1);
|
state.carouselFileList.splice(index, 1);
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
reject(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 预览轮播图
|
// 预览轮播图
|
||||||
const previewCarouselFile = (file: any) => {
|
const handleCarouselPreview = (file: UploadFile) => {
|
||||||
state.dialogImagePreviewUrl = file.url!;
|
window.open(file.url);
|
||||||
state.dialogImagePreviewVisible = true;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 选择主题色
|
// 选择主题色
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user