diff --git a/Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs b/Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs index 41792e4c..c8b510e3 100644 --- a/Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs +++ b/Admin.NET/Admin.NET.Core/Service/Tenant/SysTenantService.cs @@ -20,10 +20,12 @@ public class SysTenantService : IDynamicApiController, ITransient private readonly SqlSugarRepository _sysUserExtOrgRep; private readonly SqlSugarRepository _sysRoleMenuRep; private readonly SqlSugarRepository _userRoleRep; + private readonly SqlSugarRepository _fileRep; private readonly SysUserRoleService _sysUserRoleService; private readonly SysRoleMenuService _sysRoleMenuService; private readonly SysConfigService _sysConfigService; private readonly SysCacheService _sysCacheService; + private readonly SysFileService _sysFileService; private readonly IEventPublisher _eventPublisher; public SysTenantService(SqlSugarRepository sysTenantRep, @@ -34,10 +36,12 @@ public class SysTenantService : IDynamicApiController, ITransient SqlSugarRepository sysUserExtOrgRep, SqlSugarRepository sysRoleMenuRep, SqlSugarRepository userRoleRep, + SqlSugarRepository fileRep, SysUserRoleService sysUserRoleService, SysRoleMenuService sysRoleMenuService, SysConfigService sysConfigService, SysCacheService sysCacheService, + SysFileService sysFileService, IEventPublisher eventPublisher) { _sysTenantRep = sysTenantRep; @@ -48,10 +52,12 @@ public class SysTenantService : IDynamicApiController, ITransient _sysUserExtOrgRep = sysUserExtOrgRep; _sysRoleMenuRep = sysRoleMenuRep; _userRoleRep = userRoleRep; + _fileRep = fileRep; _sysUserRoleService = sysUserRoleService; _sysRoleMenuService = sysRoleMenuService; _sysConfigService = sysConfigService; _sysCacheService = sysCacheService; + _sysFileService = sysFileService; _eventPublisher = eventPublisher; } @@ -572,6 +578,7 @@ public class SysTenantService : IDynamicApiController, ITransient 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 forceChangePassword = await _sysConfigService.GetConfigValueByCode(ConfigConst.SysForceChangePassword); // 强制修改密码 var passwordExpirationTime = await _sysConfigService.GetConfigValueByCode(ConfigConst.SysPasswordExpirationTime); // 密码有效期 @@ -596,7 +603,8 @@ public class SysTenantService : IDynamicApiController, ITransient tenant.SecondVer, ForceChangePassword = forceChangePassword, PasswordExpirationTime = passwordExpirationTime, - PublicKey = publicKey + PublicKey = publicKey, + CarouselFiles = carouselFiles }; } @@ -616,8 +624,6 @@ public class SysTenantService : IDynamicApiController, ITransient tenant = input.Adapt(); tenant.Id = input.TenantId; - // 保存轮播图 - // logo 不为空才保存 if (!string.IsNullOrEmpty(input.LogoBase64)) { @@ -672,4 +678,40 @@ public class SysTenantService : IDynamicApiController, ITransient }) .ExecuteCommandAsync(); } + + /// + /// 上传轮播图单文件 🔖 + /// + /// + /// + [DisplayName("上传轮播图单文件")] + public async Task 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", SavePath = path }); + + // 保存轮播图配置 + sysFile.BelongId = tenant.Id; + sysFile.RelationId = tenant.Id; + + await _sysFileService.UpdateFile(sysFile); + + return sysFile; + } } \ No newline at end of file diff --git a/Web/src/api-services/apis/sys-tenant-api.ts b/Web/src/api-services/apis/sys-tenant-api.ts index 6fa1c32c..5555581a 100644 --- a/Web/src/api-services/apis/sys-tenant-api.ts +++ b/Web/src/api-services/apis/sys-tenant-api.ts @@ -24,6 +24,7 @@ import { AdminNETResultListSysUser } from '../models'; import { AdminNETResultObject } from '../models'; import { AdminNETResultSqlSugarPagedListTenantOutput } from '../models'; import { AdminNETResultString } from '../models'; +import { AdminNETResultSysFile } from '../models'; import { DeleteTenantInput } from '../models'; import { PageTenantInput } from '../models'; import { RoleMenuInput } from '../models'; @@ -658,6 +659,58 @@ export const SysTenantApiAxiosParamCreator = function (configuration?: Configura options: localVarRequestOptions, }; }, + /** + * + * @summary 上传轮播图单文件 🔖 + * @param {Blob} [file] + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + apiSysTenantUploadCarouselFilePostForm: async (file?: Blob, options: AxiosRequestConfig = {}): Promise => { + 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 获取租户下的用户列表 🔖 @@ -896,6 +949,20 @@ export const SysTenantApiFp = function(configuration?: Configuration) { 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>> { + 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 获取租户下的用户列表 🔖 @@ -1048,6 +1115,16 @@ export const SysTenantApiFactory = function (configuration?: Configuration, base async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig): Promise> { 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> { + return SysTenantApiFp(configuration).apiSysTenantUploadCarouselFilePostForm(file, options).then((request) => request(axios, basePath)); + }, /** * * @summary 获取租户下的用户列表 🔖 @@ -1210,6 +1287,17 @@ export class SysTenantApi extends BaseAPI { public async apiSysTenantUpdatePost(body?: UpdateTenantInput, options?: AxiosRequestConfig) : Promise> { 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> { + return SysTenantApiFp(this.configuration).apiSysTenantUploadCarouselFilePostForm(file, options).then((request) => request(this.axios, this.basePath)); + } /** * * @summary 获取租户下的用户列表 🔖 diff --git a/Web/src/api-services/models/index.ts b/Web/src/api-services/models/index.ts index 41b68c1f..e3c806d4 100644 --- a/Web/src/api-services/models/index.ts +++ b/Web/src/api-services/models/index.ts @@ -409,6 +409,7 @@ export * from './sys-plugin'; export * from './sys-print'; export * from './sys-region'; export * from './sys-schedule'; +export * from './sys-tenant-upload-carousel-file-body'; export * from './sys-upgrade'; export * from './sys-user'; export * from './sys-user-ext-org'; diff --git a/Web/src/api-services/models/sys-tenant-upload-carousel-file-body.ts b/Web/src/api-services/models/sys-tenant-upload-carousel-file-body.ts new file mode 100644 index 00000000..402b1822 --- /dev/null +++ b/Web/src/api-services/models/sys-tenant-upload-carousel-file-body.ts @@ -0,0 +1,28 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Admin.NET 通用权限开发平台 + * 让 .NET 开发更简单、更通用、更流行。整合最新技术,模块插件式开发,前后端分离,开箱即用。
👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! + * + * 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 SysTenantUploadCarouselFileBody + */ +export interface SysTenantUploadCarouselFileBody { + + /** + * @type {Blob} + * @memberof SysTenantUploadCarouselFileBody + */ + file: Blob; +} diff --git a/Web/src/router/index.ts b/Web/src/router/index.ts index 63edae5b..21a176bf 100644 --- a/Web/src/router/index.ts +++ b/Web/src/router/index.ts @@ -105,9 +105,7 @@ router.beforeEach(async (to, from, next) => { var routeLocation = `/login?redirect=${to.path}¶ms=${JSON.stringify(to.query ? to.query : to.params)}`; // 附加租户Id标识 var tenantid = Number(Local.get('tid')); - if (!isNaN(tenantid) && tenantid > 99999) { - routeLocation += `&tid=${tenantid}`; - } + if (!isNaN(tenantid) && tenantid > 99999) routeLocation += `&tid=${tenantid}`; next(routeLocation); Session.clear(); NProgress.done(); diff --git a/Web/src/views/system/infoSetting/index.vue b/Web/src/views/system/infoSetting/index.vue index 58c9c64f..6d1ea6ea 100644 --- a/Web/src/views/system/infoSetting/index.vue +++ b/Web/src/views/system/infoSetting/index.vue @@ -20,7 +20,7 @@ {{ state.sysInfo.tenantId }}

- 访问地址:{{ host }}/#/login?tid={{ state.sysInfo.tenantId }} + 访问地址:{{ host }}/#/login?tenantid={{ state.sysInfo.tenantId }}

@@ -152,7 +152,7 @@ - + @@ -208,9 +208,7 @@ const state = reactive({ colorName: '飞燕草蓝', // 主题颜色名称 dialogImagePreviewVisible: false, // 预览图片弹窗 dialogImagePreviewUrl: '', // 预览图片地址 - isDelete: false, // 是否删除图片 - fileList: [] as any, // 轮播图片文件列表 - fileDeleteList: [] as any, // 删除文件列表 + isDelete: false, // 是否已删除图片 carouselFileList: [] as any, // 轮播图片文件列表 }); @@ -234,11 +232,6 @@ const saveSysInfo = async () => { state.sysInfo.logoFileName = state.logoFile.raw.name; } - // 轮播图文件列表处理 - // state.sysInfo.carouselFiles = []; - // state.carouselFileList.forEach((e: any) => { - // state.sysInfo.carouselFiles.push(e.raw); - // }); try { state.isLoading = true; await getAPI(SysTenantApi).apiSysTenantSaveSysInfoPost(state.sysInfo); @@ -257,7 +250,9 @@ const loadSysInfoData = async () => { state.isLoading = true; const res = await getAPI(SysTenantApi).apiSysTenantSysInfoTenantIdGet(0); 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; @@ -265,9 +260,21 @@ const loadSysInfoData = async () => { } }; +// 图片转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) => { - await getAPI(SysFileApi).apiSysFileUploadFilePostForm(e.file); + await getAPI(SysTenantApi).apiSysTenantUploadCarouselFilePostForm(e.file); }; // 删除轮播图文件 @@ -279,9 +286,11 @@ const beforeRemoveCarouselFile = (file: any, fileList: any) => { type: 'warning', }) .then(async () => { - await getAPI(SysFileApi).apiSysFileDeletePost({ id: 0 }); + state.isDelete = true; let index = fileList.indexOf(file); + await getAPI(SysFileApi).apiSysFileDeletePost(fileList[index]); fileList.splice(index, 1); + state.carouselFileList.splice(index, 1); }) .catch(() => { reject(false);