diff --git a/DigitalPlatform.LibraryServer/AppBrowseColumn.cs b/DigitalPlatform.LibraryServer/AppBrowseColumn.cs index 0e1b87d0d..61aaafc42 100644 --- a/DigitalPlatform.LibraryServer/AppBrowseColumn.cs +++ b/DigitalPlatform.LibraryServer/AppBrowseColumn.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.XPath; + using DigitalPlatform.IO; using DigitalPlatform.rms; using DigitalPlatform.rms.Client; diff --git a/DigitalPlatform.LibraryServer/AppEntity.cs b/DigitalPlatform.LibraryServer/AppEntity.cs index cbee5970a..d426cb221 100644 --- a/DigitalPlatform.LibraryServer/AppEntity.cs +++ b/DigitalPlatform.LibraryServer/AppEntity.cs @@ -16,6 +16,8 @@ using DigitalPlatform.IO; using DigitalPlatform.Text; using DigitalPlatform.rms.Client.rmsws_localhost; +using DigitalPlatform.LibraryClient; +using Jint.Parser.Ast; // using System.Data.SqlClient; @@ -2262,6 +2264,190 @@ public static void SetError(EntityInfo entityinfo, entityinfo.Action = ""; } + // 2023/7/4 + // 兑现 .Cols 中的 {{}} 命令 + // return: + // -1 出错 + // 0 cols 没有发生改变 + // 1 cols 发生了改变 + public int FilterMacro( + SessionInfo sessioninfo, + string path, + string[] cols, + string style, + out string strError) + { + strError = ""; + + if (cols == null || cols.Length == 0) + return 0; + + int IndexOf(string prefix) + { + int i = 0; + foreach (string s in cols) + { + if (s != null && s.StartsWith(prefix)) + return i; + i++; + } + return -1; + } + + bool RemoveMacroName() + { + bool c = false; + int i = 0; + foreach (string s in cols) + { + if (s != null && s.StartsWith("{{")) + { + cols[i] = ""; + c = true; + } + i++; + } + + return c; + } + + bool changed = false; + + /* + // 找到 ~p: 前缀 + int index = IndexOf("~p:"); + if (index == -1) + goto REMOVE_RETURN; + string path = cols[index].Substring("~p:".Length); + cols[index] = path; + changed = true; + if (string.IsNullOrEmpty(path)) + goto REMOVE_RETURN; + */ + + // 找到 {{fan}} + int temp = IndexOf("{{fan}}"); + if (temp == -1) + goto REMOVE_RETURN; + + var error_in_field = StringUtil.IsInList("error_in_field", style); + int nRet = GetSubRecords(sessioninfo, +path, +"firstAccessNo", +out string strResult, +out strError); + string accessNo = strResult; + + if (nRet == -1) + { + if (error_in_field) + { + cols[temp] = $"error:{strError}"; + return 1; + } + } + + cols[temp] = accessNo; + changed = true; + + if (RemoveMacroName()) + changed = true; + + return (changed ? 1 : 0); + REMOVE_RETURN: + return RemoveMacroName() ? 1 : (changed ? 1 : 0); + } + + // 获得书目记录的下级记录 + // parameters: + // strDataName 数据名称。为 firstAccessNo subrecord 之一 + public int GetSubRecords(SessionInfo sessioninfo, + string strRecPath, + string strDataName, + out string strResult, + out string strError) + { + strError = ""; + strResult = ""; + + var ret = this.GetBiblioInfos( + sessioninfo, + strRecPath, + // "", + new string[] { "subrecords:item" }, // "subrecords:item|order" + out string[] results, + out byte[] baTimestamp); + if (ret.Value == -1 || ret.Value == 0) + return -1; + if (results == null || results.Length == 0) + return 0; + string strSubRecords = results[0]; + if (strDataName == "firstAccessNo") + strResult = GetFirstAccessNo(strSubRecords); + else if (strDataName == "subrecords" || string.IsNullOrEmpty(strDataName)) + strResult = strSubRecords; + return 1; + } + + static string GetFirstAccessNo(string strSubRecords) + { + if (string.IsNullOrEmpty(strSubRecords)) + return ""; + + if (strSubRecords.StartsWith("error:")) + return strSubRecords.Substring("error:".Length); + + XmlDocument collection_dom = new XmlDocument(); + try + { + collection_dom.LoadXml(strSubRecords); + + { + string errorInfo = ""; + string itemTotalCount = collection_dom.DocumentElement.GetAttribute("itemTotalCount"); + if (itemTotalCount == "-1") + { + string itemErrorCode = collection_dom.DocumentElement.GetAttribute("itemErrorCode"); + string itemErrorInfo = collection_dom.DocumentElement.GetAttribute("itemErrorInfo"); + errorInfo = $"{itemErrorCode}:{itemErrorInfo}"; + return errorInfo; + } + + XmlNodeList nodes = collection_dom.DocumentElement.SelectNodes("item"); + int i = 0; + foreach (XmlElement item in nodes) + { + string rec_path = item.GetAttribute("recPath"); + string location = DomUtil.GetElementText(item, "location"); + string price = DomUtil.GetElementText(item, "price"); + string seller = DomUtil.GetElementText(item, "seller"); + string source = DomUtil.GetElementText(item, "source"); + string accessNo = DomUtil.GetElementText(item, "accessNo"); + + if (string.IsNullOrEmpty(accessNo) == false) + return accessNo; + i++; + } + + /* + Int32.TryParse(itemTotalCount, out int value); + if (i < value) + { + text.AppendLine($"... 有 {value - i} 项被略去 ..."); + } + */ + return ""; // not found + } + } + catch (Exception ex) + { + return "strSubRecords 装入 XMLDOM 时出现异常: " + + ex.Message + + "。(strSubRecords='" + StringUtil.CutString(strSubRecords, 300) + "')"; + } + } + + // 根据当前账户的权限,过滤浏览列中的 borrower 元素内容 // 注: browse 配置文件的 location 和 borrower 列要增配 prefix 属性,才能实现过滤效果 // return: @@ -2365,7 +2551,7 @@ bool RemovePrefix() int nRet = IsPatronInControl(null, sessioninfo, strBorrower, out strError); if (nRet == -1 && error_in_field) { - cols[index] = "error:{strError}"; + cols[index] = $"error:{strError}"; return 1; } if (nRet != 1) diff --git a/DigitalPlatform.LibraryServer/MongoDb/BuildMongoOperDatabase.cs b/DigitalPlatform.LibraryServer/MongoDb/BuildMongoOperDatabase.cs index ef78e340d..51164520e 100644 --- a/DigitalPlatform.LibraryServer/MongoDb/BuildMongoOperDatabase.cs +++ b/DigitalPlatform.LibraryServer/MongoDb/BuildMongoOperDatabase.cs @@ -215,7 +215,7 @@ public override void Worker() // 列出所有日志文件 DirectoryInfo di = new DirectoryInfo(this.App.OperLog.Directory); - FileInfo[] fis = di.GetFiles("*.log"); + FileInfo[] fis = di.GetFiles("????????.log"); Array.Sort(fis, (x, y) => { diff --git a/DigitalPlatform.LibraryServer/Properties/AssemblyInfo.cs b/DigitalPlatform.LibraryServer/Properties/AssemblyInfo.cs index 06e6d8155..fe06c4772 100644 --- a/DigitalPlatform.LibraryServer/Properties/AssemblyInfo.cs +++ b/DigitalPlatform.LibraryServer/Properties/AssemblyInfo.cs @@ -31,8 +31,8 @@ // // You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: -[assembly: AssemblyVersion("3.146.*")] -[assembly: AssemblyFileVersion("3.146.0.0")] +[assembly: AssemblyVersion("3.147.*")] +[assembly: AssemblyFileVersion("3.147.0.0")] // 2.1 (2012/4/5) 第一个具有版本号的版本。特点是增加了改造了GetIssueInfo() GetOrderInfo() GetCoomentInfo() 修改了第一参数名,去掉了第二参数 // 2.11 (2012/5/5) 为ListBiblioDbFroms() API增加了 item order issue 几个类型 @@ -369,3 +369,7 @@ public bool ItemCanReturn(Account account, // 3.146 (2023/6/20) SearchCharging() API 所返回的 ChargingItemWarpper 内的 ChargingItem 结构增加了一个成员 BorrowDate(string),表示还书动作的借书时间。 // 需要用最新版 dp2library 重建 mongodb 借阅历史库,这个 BorrowDate 才会有值,否则为 null // 改进 DefaultThread 中连接 dp2mserver 的过程,增加了超时跳过能力,并对 AppDown 敏感(早先版本这里连接 dp2mserver 的过程如果时间较长会阻止 dp2library down)。 +// 3.147 (2023/7/4) 书目库 browse 配置文件中可以通过下列片段: +// +// +// 定义一个列,其内容 {{fan}} 会在 dp2library 执行 GetSearchResult() 和 GetBrowseRecords() API 时兑现为书目记录下属册记录的第一个非空的索取号 diff --git a/DigitalPlatform.LibraryService/LibraryService.cs b/DigitalPlatform.LibraryService/LibraryService.cs index 596c4d53f..39f927460 100644 --- a/DigitalPlatform.LibraryService/LibraryService.cs +++ b/DigitalPlatform.LibraryService/LibraryService.cs @@ -4190,6 +4190,7 @@ void FilterBiblioRecord(Record record, } + if (bXmlChanged) // XML 记录发生过改变,也要重新创建 Cols { if (bHasCols) @@ -4217,6 +4218,20 @@ void FilterBiblioRecord(Record record, else record.Cols = null; } + + // 兑现 .Cols 中的 {{fan}} 命令 + { + // return: + // -1 出错 + // 0 cols 没有发生改变 + // 1 cols 发生了改变 + int nRet = app.FilterMacro( + sessioninfo, + record.Path, + record.Cols, + "error_in_field", + out string _); + } } #if OLDVERSION diff --git a/DigitalPlatform.rms/BrowseCfg.cs b/DigitalPlatform.rms/BrowseCfg.cs index 43b641633..4dcce60c4 100644 --- a/DigitalPlatform.rms/BrowseCfg.cs +++ b/DigitalPlatform.rms/BrowseCfg.cs @@ -247,7 +247,7 @@ public int BuildCols(XmlDocument domData, string prefix = nodeCol.GetAttribute("prefix"); - string strText = ""; + string strText = nodeCol.GetAttribute("text"); XPathExpression expr = cache_item.expr; diff --git a/dp2Circulation/SearchForms/BiblioSearchForm.cs b/dp2Circulation/SearchForms/BiblioSearchForm.cs index b830d237e..986a301d0 100644 --- a/dp2Circulation/SearchForms/BiblioSearchForm.cs +++ b/dp2Circulation/SearchForms/BiblioSearchForm.cs @@ -10521,8 +10521,12 @@ void menu_saveToHtmlFile_Click(object sender, EventArgs e) } // 构造一个 HTML 新书通报局部。 - static string BuildHtml(XmlDocument table_dom, - string recpath, + // parameters: + // biblio_table_dom 书目记录的 table 格式内容 + // biblio_recpath 书目记录路径 + static string BuildHtml( + XmlDocument biblio_table_dom, + string biblio_recpath, string strOpacServerUrl) { if (string.IsNullOrEmpty(strOpacServerUrl) == false @@ -10531,7 +10535,7 @@ static string BuildHtml(XmlDocument table_dom, StringBuilder result = new StringBuilder(); result.Append("\r\n"); - XmlNodeList lines = table_dom.DocumentElement.SelectNodes("line"); + XmlNodeList lines = biblio_table_dom.DocumentElement.SelectNodes("line"); foreach (XmlElement line in lines) { string type = line.GetAttribute("type"); @@ -10551,7 +10555,7 @@ static string BuildHtml(XmlDocument table_dom, url = value; else if (string.IsNullOrEmpty(strOpacServerUrl) == false) { - url = $"{strOpacServerUrl}getobject.aspx?uri={HttpUtility.UrlEncode(ScriptUtil.MakeObjectUrl(recpath, value))}"; + url = $"{strOpacServerUrl}getobject.aspx?uri={HttpUtility.UrlEncode(ScriptUtil.MakeObjectUrl(biblio_recpath, value))}"; } else continue; @@ -10563,11 +10567,14 @@ static string BuildHtml(XmlDocument table_dom, if (string.IsNullOrEmpty(strOpacServerUrl) == false) { - string url = $"{strOpacServerUrl}book.aspx?BiblioRecPath={HttpUtility.UrlEncode(recpath)}"; - result.AppendLine($""); + string url = $"{strOpacServerUrl}book.aspx?BiblioRecPath={HttpUtility.UrlEncode(biblio_recpath)}"; + result.AppendLine($""); } else - result.AppendLine($""); + result.AppendLine($""); + + // items 占位 + result.AppendLine($""); result.Append("
{HttpUtility.HtmlEncode("记录路径")}{HttpUtility.HtmlEncode(recpath)}
{HttpUtility.HtmlEncode("记录路径")}{HttpUtility.HtmlEncode(biblio_recpath)}
{HttpUtility.HtmlEncode("记录路径")}{HttpUtility.HtmlEncode(recpath)}
{HttpUtility.HtmlEncode("记录路径")}{HttpUtility.HtmlEncode(biblio_recpath)}
{HttpUtility.HtmlEncode("册详情")}{{items}}
\r\n"); return result.ToString(); diff --git a/dp2Circulation/SearchForms/ItemSearchForm.cs b/dp2Circulation/SearchForms/ItemSearchForm.cs index 3add85dd0..eda086cac 100644 --- a/dp2Circulation/SearchForms/ItemSearchForm.cs +++ b/dp2Circulation/SearchForms/ItemSearchForm.cs @@ -10726,6 +10726,7 @@ void _exportSelectedToBiblioDumpFile() ShowMessageBox(strError); } + // 将从属的书目记录保存到MARC文件 async void menu_saveBiblioRecordToMarcFile_Click(object sender, EventArgs e) { diff --git a/dp2Installer/dp2Installer.csproj b/dp2Installer/dp2Installer.csproj index 6d6af8965..6f8b7b7ed 100644 --- a/dp2Installer/dp2Installer.csproj +++ b/dp2Installer/dp2Installer.csproj @@ -35,7 +35,7 @@ dp2 V3 true publish.htm - 405 + 406 3.135.0.%2a false true diff --git a/dp2LibraryXE/dp2LibraryXE.csproj b/dp2LibraryXE/dp2LibraryXE.csproj index 81a03ccca..02db33cc7 100644 --- a/dp2LibraryXE/dp2LibraryXE.csproj +++ b/dp2LibraryXE/dp2LibraryXE.csproj @@ -41,7 +41,7 @@ dp2 V3 true publish.htm - 376 + 378 3.135.0.%2a false true