diff --git a/ZR.Admin.WebApi/Controllers/Business/OdfAppUpdatesController.cs b/ZR.Admin.WebApi/Controllers/Business/OdfAppUpdatesController.cs
new file mode 100644
index 0000000..c5c4c8a
--- /dev/null
+++ b/ZR.Admin.WebApi/Controllers/Business/OdfAppUpdatesController.cs
@@ -0,0 +1,130 @@
+using Microsoft.AspNetCore.Mvc;
+
+using System.Linq.Expressions;
+using System.Threading.Tasks;
+
+using ZR.Model.Business;
+using ZR.Model.Business.Dto;
+using ZR.Service.Business;
+using ZR.Service.Business.IBusinessService;
+
+//创建时间:2025-09-23
+namespace ZR.Admin.WebApi.Controllers.Business
+{
+ ///
+ /// App 更新表
+ ///
+ [Route("business/OdfAppUpdates")]
+ public class OdfAppUpdatesController : BaseController
+ {
+ ///
+ /// App 更新表接口
+ ///
+ private readonly IOdfAppUpdatesService _OdfAppUpdatesService;
+
+ public OdfAppUpdatesController(IOdfAppUpdatesService OdfAppUpdatesService)
+ {
+ _OdfAppUpdatesService = OdfAppUpdatesService;
+ }
+
+ ///
+ /// 查询App 更新表列表
+ ///
+ ///
+ ///
+ [HttpGet("list")]
+ [ActionPermissionFilter(Permission = "odfappupdates:list")]
+ public IActionResult QueryOdfAppUpdates([FromQuery] OdfAppUpdatesQueryDto parm)
+ {
+ var response = _OdfAppUpdatesService.GetList(parm);
+ return SUCCESS(response);
+ }
+
+
+ ///
+ /// 查询App 更新表详情
+ ///
+ ///
+ ///
+ [HttpGet("{Id}")]
+ [ActionPermissionFilter(Permission = "odfappupdates:query")]
+ public IActionResult GetOdfAppUpdates(int Id)
+ {
+ var response = _OdfAppUpdatesService.GetInfo(Id);
+
+ var info = response.Adapt();
+ return SUCCESS(info);
+ }
+
+ ///
+ /// 修改状态
+ ///
+ ///
+ [HttpPost("status")]
+ [ActionPermissionFilter(Permission = "odfappupdates:add")]
+ [Log(Title = "App 更新表", BusinessType = BusinessType.INSERT)]
+ public IActionResult OdfAppStatus([FromBody] OdfAppUpdatesStatusDto parm)
+ {
+ var modal = _OdfAppUpdatesService.GetById(parm.Id);
+ if (modal != null)
+ {
+ if (parm.IsActive)
+ {
+ // 先将所有激活状态设置为未激活
+ _OdfAppUpdatesService.UpdateAllActiveToInactive();
+ }
+ modal.IsActive = parm.IsActive;
+ var response = _OdfAppUpdatesService.UpdateOdfAppUpdates(modal);
+
+ return SUCCESS(response);
+ }
+ return SUCCESS(null);
+ }
+
+ ///
+ /// 添加App 更新表
+ ///
+ ///
+ [HttpPost("add")]
+ [ActionPermissionFilter(Permission = "odfappupdates:add")]
+ [Log(Title = "App 更新表", BusinessType = BusinessType.INSERT)]
+ public IActionResult AddOdfAppUpdates([FromBody] OdfAppUpdatesDto parm)
+ {
+ var modal = parm.Adapt().ToCreate(HttpContext);
+ parm.CreateTime = DateTime.Now;
+ var response = _OdfAppUpdatesService.AddOdfAppUpdates(modal);
+
+ return SUCCESS(response);
+ }
+
+ ///
+ /// 更新App 更新表
+ ///
+ ///
+ [HttpPut]
+ [ActionPermissionFilter(Permission = "odfappupdates:edit")]
+ [Log(Title = "App 更新表", BusinessType = BusinessType.UPDATE)]
+ public IActionResult UpdateOdfAppUpdates([FromBody] OdfAppUpdatesDto parm)
+ {
+ var modal = parm.Adapt().ToUpdate(HttpContext);
+ var response = _OdfAppUpdatesService.UpdateOdfAppUpdates(modal);
+
+ return ToResponse(response);
+ }
+
+ ///
+ /// 删除App 更新表
+ ///
+ ///
+ [HttpPost("delete/{ids}")]
+ [ActionPermissionFilter(Permission = "odfappupdates:delete")]
+ [Log(Title = "App 更新表", BusinessType = BusinessType.DELETE)]
+ public IActionResult DeleteOdfAppUpdates([FromRoute] string ids)
+ {
+ var idArr = Tools.SplitAndConvert(ids);
+
+ return ToResponse(_OdfAppUpdatesService.Delete(idArr));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ZR.Admin.WebApi/Controllers/CommonController.cs b/ZR.Admin.WebApi/Controllers/CommonController.cs
index ede239c..8b693d2 100644
--- a/ZR.Admin.WebApi/Controllers/CommonController.cs
+++ b/ZR.Admin.WebApi/Controllers/CommonController.cs
@@ -103,7 +103,7 @@ namespace ZR.Admin.WebApi.Controllers
///
[HttpPost]
[ActionPermissionFilter(Permission = "common")]
- public async Task UploadFile([FromForm] UploadDto uploadDto, IFormFile file, StoreType storeType = StoreType.ALIYUN)
+ public async Task UploadFile([FromForm] UploadDto uploadDto, IFormFile file, StoreType storeType = StoreType.LOCAL)
{
if (file == null) throw new CustomException(ResultCode.PARAM_ERROR, "上传文件不能为空");
SysFile sysfile = new();
diff --git a/ZR.Admin.WebApi/Controllers/WebApiController.cs b/ZR.Admin.WebApi/Controllers/WebApiController.cs
index e30af06..0e2d1ec 100644
--- a/ZR.Admin.WebApi/Controllers/WebApiController.cs
+++ b/ZR.Admin.WebApi/Controllers/WebApiController.cs
@@ -21,5 +21,44 @@ namespace ZR.Admin.WebApi.Controllers
public class WebApiController : BaseController
{
private readonly WechatApiClient _client;
+ private readonly IOdfAppUpdatesService _odfAppUpdatesService;
+
+ public WebApiController(WechatApiClient client, IOdfAppUpdatesService odfAppUpdatesService)
+ {
+ _client = client;
+ _odfAppUpdatesService = odfAppUpdatesService;
+ }
+
+ ///
+ /// 检查App版本更新
+ ///
+ /// 版本
+ ///
+ [HttpGet]
+ public IActionResult CheckAppVersion([FromQuery] string version)
+ {
+ if (version == null || string.IsNullOrEmpty(version))
+ {
+ return ToResponse(ResultCode.CUSTOM_ERROR, "版本号不能为空");
+ }
+
+ try
+ {
+ var response = _odfAppUpdatesService.CheckAppVersion(version);
+
+ if (response.NeedUpdate)
+ {
+ return SUCCESS(response, "发现新版本");
+ }
+ else
+ {
+ return SUCCESS(new { }, "当前已是最新版本");
+ }
+ }
+ catch (Exception ex)
+ {
+ return ToResponse(ResultCode.CUSTOM_ERROR, $"版本检查失败: {ex.Message}");
+ }
+ }
}
}
diff --git a/ZR.Admin.WebApi/appsettings.json b/ZR.Admin.WebApi/appsettings.json
index 5b9fbf0..4d25b1d 100644
--- a/ZR.Admin.WebApi/appsettings.json
+++ b/ZR.Admin.WebApi/appsettings.json
@@ -49,7 +49,7 @@
"sqlExecutionTime": 5, //Sql执行时间超过多少秒记录日志并警报
"Upload": {
"uploadUrl": "http://localhost:8888", //本地存储资源访问路径
- "localSavePath": "", //本地上传默认文件存储目录 wwwroot
+ "localSavePath": "/file/", //本地上传默认文件存储目录 wwwroot
"maxSize": 15, //上传文件大小限制 15M
"notAllowedExt": [ ".bat", ".exe", ".jar", ".js" ],
"requestLimitSize": 50 //请求body大小限制
diff --git a/ZR.Admin.WebApi/wwwroot/2025/0923/341f5ae608caea22.xlsx b/ZR.Admin.WebApi/wwwroot/2025/0923/341f5ae608caea22.xlsx
new file mode 100644
index 0000000..02aad15
Binary files /dev/null and b/ZR.Admin.WebApi/wwwroot/2025/0923/341f5ae608caea22.xlsx differ
diff --git a/ZR.Admin.WebApi/wwwroot/2025/0923/603d60c6c874695e.xlsx b/ZR.Admin.WebApi/wwwroot/2025/0923/603d60c6c874695e.xlsx
new file mode 100644
index 0000000..02aad15
Binary files /dev/null and b/ZR.Admin.WebApi/wwwroot/2025/0923/603d60c6c874695e.xlsx differ
diff --git a/ZR.Admin.WebApi/wwwroot/2025/0923/efd4757512a8be29.xlsx b/ZR.Admin.WebApi/wwwroot/2025/0923/efd4757512a8be29.xlsx
new file mode 100644
index 0000000..02aad15
Binary files /dev/null and b/ZR.Admin.WebApi/wwwroot/2025/0923/efd4757512a8be29.xlsx differ
diff --git a/ZR.Model/Business/Dto/OdfAppUpdatesDto.cs b/ZR.Model/Business/Dto/OdfAppUpdatesDto.cs
new file mode 100644
index 0000000..575b1ea
--- /dev/null
+++ b/ZR.Model/Business/Dto/OdfAppUpdatesDto.cs
@@ -0,0 +1,93 @@
+
+namespace ZR.Model.Business.Dto
+{
+ ///
+ /// App 更新表查询对象
+ ///
+ public class OdfAppUpdatesQueryDto : PagerInfo
+ {
+ public int? VersionCode { get; set; }
+ }
+
+ ///
+ /// App 更新表输入输出对象
+ ///
+ public class OdfAppUpdatesDto
+ {
+ public int? Id { get; set; }
+
+ [Required(ErrorMessage = "版本号不能为空")]
+ public int VersionCode { get; set; }
+
+ [Required(ErrorMessage = "更新类型不能为空")]
+ public string UpdateType { get; set; }
+
+ [Required(ErrorMessage = "下载地址不能为空")]
+ public string DownloadUrl { get; set; }
+
+ [Required(ErrorMessage = "是否启用不能为空")]
+ public bool IsActive { get; set; }
+
+ public DateTime? CreateTime { get; set; }
+
+
+
+ [ExcelColumn(Name = "更新类型")]
+ public string UpdateTypeLabel { get; set; }
+ }
+
+ ///
+ /// App 更新表输入输出对象
+ ///
+ public class OdfAppUpdatesStatusDto
+ {
+ public int? Id { get; set; }
+
+ [Required(ErrorMessage = "是否启用不能为空")]
+ public bool IsActive { get; set; }
+
+ }
+
+ ///
+ /// App版本检查请求对象
+ ///
+ public class AppVersionCheckRequestDto
+ {
+ ///
+ /// 当前App版本号 (如: 1.0.1)
+ ///
+ [Required(ErrorMessage = "版本号不能为空")]
+ public string Version { get; set; }
+ }
+
+ ///
+ /// App版本检查响应对象
+ ///
+ public class AppVersionCheckResponseDto
+ {
+ ///
+ /// 是否需要更新
+ ///
+ public bool NeedUpdate { get; set; }
+
+ ///
+ /// 是否强制更新
+ ///
+ public bool ForceUpdate { get; set; }
+
+ ///
+ /// 最新版本号
+ ///
+ public string LatestVersion { get; set; }
+
+ ///
+ /// 下载地址
+ ///
+ public string DownloadUrl { get; set; }
+
+ ///
+ /// 更新说明
+ ///
+ public string UpdateDescription { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ZR.Model/Business/OdfAppUpdates.cs b/ZR.Model/Business/OdfAppUpdates.cs
new file mode 100644
index 0000000..1e4d47d
--- /dev/null
+++ b/ZR.Model/Business/OdfAppUpdates.cs
@@ -0,0 +1,42 @@
+
+namespace ZR.Model.Business
+{
+ ///
+ /// App 更新表
+ ///
+ [SugarTable("odf_app_updates")]
+ public class OdfAppUpdates
+ {
+ ///
+ /// Id
+ ///
+ [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
+ public int? Id { get; set; }
+
+ ///
+ /// 版本号
+ ///
+ public int VersionCode { get; set; }
+
+ ///
+ /// 更新类型
+ ///
+ public string UpdateType { get; set; }
+
+ ///
+ /// 下载地址
+ ///
+ public string DownloadUrl { get; set; }
+
+ ///
+ /// 是否启用
+ ///
+ public bool IsActive { get; set; }
+
+ ///
+ /// 发布时间
+ ///
+ public DateTime? CreateTime { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/ZR.Service/Business/IBusinessService/IOdfAppUpdatesService.cs b/ZR.Service/Business/IBusinessService/IOdfAppUpdatesService.cs
new file mode 100644
index 0000000..c07021a
--- /dev/null
+++ b/ZR.Service/Business/IBusinessService/IOdfAppUpdatesService.cs
@@ -0,0 +1,33 @@
+using ZR.Model.Business.Dto;
+using ZR.Model.Business;
+
+namespace ZR.Service.Business.IBusinessService
+{
+ ///
+ /// App 更新表service接口
+ ///
+ public interface IOdfAppUpdatesService : IBaseService
+ {
+ PagedInfo GetList(OdfAppUpdatesQueryDto parm);
+
+ OdfAppUpdates GetInfo(int Id);
+
+
+ OdfAppUpdates AddOdfAppUpdates(OdfAppUpdates parm);
+ int UpdateOdfAppUpdates(OdfAppUpdates parm);
+
+ ///
+ /// 批量更新所有激活状态为未激活
+ ///
+ ///
+ int UpdateAllActiveToInactive();
+
+ ///
+ /// 检查App版本是否需要更新
+ ///
+ /// 当前App版本号
+ ///
+ AppVersionCheckResponseDto CheckAppVersion(string currentVersion);
+
+ }
+}
diff --git a/ZR.Service/Business/OdfAppUpdatesService.cs b/ZR.Service/Business/OdfAppUpdatesService.cs
new file mode 100644
index 0000000..bea0e5c
--- /dev/null
+++ b/ZR.Service/Business/OdfAppUpdatesService.cs
@@ -0,0 +1,176 @@
+using Infrastructure.Attribute;
+using Infrastructure.Extensions;
+using ZR.Model.Business.Dto;
+using ZR.Model.Business;
+using ZR.Repository;
+using ZR.Service.Business.IBusinessService;
+
+namespace ZR.Service.Business
+{
+ ///
+ /// App 更新表Service业务层处理
+ ///
+ [AppService(ServiceType = typeof(IOdfAppUpdatesService), ServiceLifetime = LifeTime.Transient)]
+ public class OdfAppUpdatesService : BaseService, IOdfAppUpdatesService
+ {
+ ///
+ /// 查询App 更新表列表
+ ///
+ ///
+ ///
+ public PagedInfo GetList(OdfAppUpdatesQueryDto parm)
+ {
+ var predicate = QueryExp(parm);
+
+ var response = Queryable()
+ //.OrderBy("IsActive desc")
+ .Where(predicate.ToExpression())
+ .ToPage(parm);
+
+ return response;
+ }
+
+
+ ///
+ /// 获取详情
+ ///
+ ///
+ ///
+ public OdfAppUpdates GetInfo(int Id)
+ {
+ var response = Queryable()
+ .Where(x => x.Id == Id)
+ .First();
+
+ return response;
+ }
+
+ ///
+ /// 添加App 更新表
+ ///
+ ///
+ ///
+ public OdfAppUpdates AddOdfAppUpdates(OdfAppUpdates model)
+ {
+ return Insertable(model).ExecuteReturnEntity();
+ }
+
+ ///
+ /// 修改App 更新表
+ ///
+ ///
+ ///
+ public int UpdateOdfAppUpdates(OdfAppUpdates model)
+ {
+ return Update(model, true);
+ }
+
+ ///
+ /// 批量更新所有激活状态为未激活
+ ///
+ ///
+ public int UpdateAllActiveToInactive()
+ {
+ return Update(x => x.IsActive == true, x => new OdfAppUpdates { IsActive = false });
+ }
+
+ ///
+ /// 检查App版本是否需要更新
+ ///
+ /// 当前App版本号
+ ///
+ public AppVersionCheckResponseDto CheckAppVersion(string currentVersion)
+ {
+ var response = new AppVersionCheckResponseDto
+ {
+ NeedUpdate = false,
+ ForceUpdate = false
+ };
+
+ // 获取当前启用的最新版本
+ var latestUpdate = Queryable()
+ .Where(x => x.IsActive == true)
+ .OrderByDescending(x => x.VersionCode)
+ .First();
+
+ if (latestUpdate == null)
+ {
+ return response; // 没有启用的版本,不需要更新
+ }
+
+ // 将版本号转换为可比较的格式 (如: 1.0.1 -> 1001)
+ var currentVersionCode = ConvertVersionToCode(currentVersion);
+ var latestVersionCode = latestUpdate.VersionCode;
+
+ // 如果数据库中的版本号大于当前版本号,则需要更新
+ if (latestVersionCode > currentVersionCode)
+ {
+ response.NeedUpdate = true;
+ response.LatestVersion = latestVersionCode.ToString();
+ response.DownloadUrl = latestUpdate.DownloadUrl;
+ response.ForceUpdate = latestUpdate.UpdateType == "1"; // 假设UpdateType为"force"表示强制更新
+ response.UpdateDescription = $"发现新版本 {response.LatestVersion},请及时更新";
+ }
+
+ return response;
+ }
+
+ ///
+ /// 将版本号字符串转换为数字代码 (如: 1.0.1 -> 1001)
+ ///
+ /// 版本号字符串
+ ///
+ private int ConvertVersionToCode(string version)
+ {
+ if (string.IsNullOrEmpty(version))
+ return 0;
+ var newCode = version.Replace(".", "");
+ if (int.TryParse(newCode, out int result))
+ {
+ return result;
+ }
+ return 100;
+ //var parts = version.Split('.');
+ //var code = 0;
+ //var multiplier = 100; // 支持到百位
+
+ //foreach (var part in parts)
+ //{
+ // if (int.TryParse(part, out int num))
+ // {
+ // code += num * multiplier;
+ // multiplier /= 100; // 每段占2位
+ // }
+ //}
+
+ //return code;
+ }
+
+ ///
+ /// 将数字代码转换为版本号字符串 (如: 1001 -> 1.0.1)
+ ///
+ /// 数字代码
+ ///
+ private string ConvertCodeToVersion(int code)
+ {
+ var major = code / 10000;
+ var minor = (code % 10000) / 100;
+ var patch = code % 100;
+
+ return $"{major}.{minor}.{patch}";
+ }
+
+ ///
+ /// 查询导出表达式
+ ///
+ ///
+ ///
+ private static Expressionable QueryExp(OdfAppUpdatesQueryDto parm)
+ {
+ var predicate = Expressionable.Create();
+
+ predicate = predicate.AndIF(parm.VersionCode != null, it => it.VersionCode == parm.VersionCode);
+ return predicate;
+ }
+ }
+}
\ No newline at end of file