diff --git a/YLErpWeb/Common/HtmlUtil.cs b/YLErpWeb/Common/HtmlUtil.cs
index 1292f24e..12b6ed9c 100644
--- a/YLErpWeb/Common/HtmlUtil.cs
+++ b/YLErpWeb/Common/HtmlUtil.cs
@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Html;
+using System.IO;
using System.Reflection;
using YLErp.Events;
@@ -27,18 +28,44 @@ namespace YLErp
static HtmlUtil()
{
- //获取bin目录中YLErp开头的文件最后修改日期作为JS和CSS文件版本
+ //获取bin目录中YLErp开头的文件最后修改日期作为后端构建版本
var binDir = new DirectoryInfo(AppContext.BaseDirectory);
var files = binDir.GetFiles("YLErp*");
BinFileVersion = files.Any() ? files.Max(n => n.LastWriteTime) : DateTime.MinValue;
- JsVersion = BinFileVersion.ToString("yyMMddHHmmss");
+
+ //JsVersion(浏览器 ?v= 缓存戳)必须同时反映【后端 DLL】和【前端脚本】的变更:
+ //历史上只取 DLL mtime,导致纯前端改动(改 wwwroot/Scripts 而不重编 DLL)时
+ //缓存戳不变、浏览器仍加载旧版——即"发布了但不更新"(见 ?otcdebug=1 排查时的症状)。
+ //现纳入 wwwroot/Scripts(业务脚本)+ wwwroot/Statics/bundles(打包产物)的 mtime 取 max。
+ //wwwroot 定位用 Directory.GetCurrentDirectory()(与 StaticUrlMiddleware 一致,
+ //开发时=项目根、部署时=publish 目录),目录不存在则回退到仅 DLL mtime。
+ var versionClock = BinFileVersion;
+ var webRoot = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot");
+ foreach (var sub in new[] { "Scripts", Path.Combine("Statics", "bundles") })
+ {
+ var dir = Path.Combine(webRoot, sub);
+ if (Directory.Exists(dir))
+ {
+ foreach (var f in new DirectoryInfo(dir).GetFiles("*", SearchOption.AllDirectories))
+ {
+ if (f.LastWriteTime > versionClock) versionClock = f.LastWriteTime;
+ }
+ }
+ }
+ JsVersion = versionClock.ToString("yyMMddHHmmss");
//从 AssemblyInformationalVersion 读取 git sha(SDK 编译时已嵌入,零额外依赖)
var infoVer = typeof(HtmlUtil).Assembly
.GetCustomAttribute()?.InformationalVersion;
- //格式 "1.0.0+",取 + 之后部分;无则回退到完整字符串
- GitCommit = string.IsNullOrEmpty(infoVer) ? "unknown"
- : (infoVer.Contains('+') ? infoVer.Substring(infoVer.LastIndexOf('+') + 1) : infoVer);
+ //格式 "1.0.0+",取 + 之后部分;无 +(如固定版本号 1.0.0)则回退读 .git/HEAD
+ if (!string.IsNullOrEmpty(infoVer) && infoVer.Contains('+'))
+ {
+ GitCommit = infoVer.Substring(infoVer.LastIndexOf('+') + 1);
+ }
+ else
+ {
+ GitCommit = ReadGitCommitFromRepo() ?? (infoVer ?? "unknown");
+ }
EventBus.Subscribe(t =>
{
@@ -46,6 +73,51 @@ namespace YLErp
});
}
+ ///
+ /// 从 .git/HEAD 读取当前 commit 短 sha,作为 AssemblyInformationalVersion 无 sha 时的回退。
+ /// 找不到 .git 或读取失败返回 null(不影响启动)。
+ ///
+ static string ReadGitCommitFromRepo()
+ {
+ try
+ {
+ //从 ContentRoot 向上找 .git 目录(开发时在项目根/仓库根)
+ var dir = new DirectoryInfo(Directory.GetCurrentDirectory());
+ while (dir != null)
+ {
+ var gitDir = Path.Combine(dir.FullName, ".git");
+ if (Directory.Exists(gitDir))
+ {
+ return ParseGitHead(gitDir);
+ }
+ dir = dir.Parent;
+ }
+ }
+ catch { /* 读取失败不影响启动,返回 null */ }
+ return null;
+ }
+
+ static string ParseGitHead(string gitDir)
+ {
+ var headFile = Path.Combine(gitDir, "HEAD");
+ if (!File.Exists(headFile)) return null;
+ var head = File.ReadAllText(headFile).Trim();
+ //HEAD 格式:"ref: refs/heads/xxx" 或 detached 时的直接 sha
+ if (head.StartsWith("ref: "))
+ {
+ var refPath = Path.Combine(gitDir, head.Substring(5).Replace('/', Path.DirectorySeparatorChar));
+ if (File.Exists(refPath))
+ {
+ return File.ReadAllText(refPath).Trim().Substring(0, 12);
+ }
+ }
+ else if (head.Length >= 12)
+ {
+ return head.Substring(0, 12);
+ }
+ return null;
+ }
+
///
/// 获取基础数据JS连接
///