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($"{HttpUtility.HtmlEncode("记录路径")} | {HttpUtility.HtmlEncode(recpath)} |
");
+ string url = $"{strOpacServerUrl}book.aspx?BiblioRecPath={HttpUtility.UrlEncode(biblio_recpath)}";
+ result.AppendLine($"{HttpUtility.HtmlEncode("记录路径")} | {HttpUtility.HtmlEncode(biblio_recpath)} |
");
}
else
- result.AppendLine($"{HttpUtility.HtmlEncode("记录路径")} | {HttpUtility.HtmlEncode(recpath)} |
");
+ result.AppendLine($"{HttpUtility.HtmlEncode("记录路径")} | {HttpUtility.HtmlEncode(biblio_recpath)} |
");
+
+ // items 占位
+ result.AppendLine($"{HttpUtility.HtmlEncode("册详情")} | {{items}} |
");
result.Append("
\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