Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

内务前端循环控制代码重构 #1165

Open
DigitalPlatform opened this issue Oct 31, 2022 · 8 comments
Open

内务前端循环控制代码重构 #1165

DigitalPlatform opened this issue Oct 31, 2022 · 8 comments

Comments

@DigitalPlatform
Copy link
Owner

DigitalPlatform commented Oct 31, 2022

内务前端的循环控制涉及到工具条上的 Stop 按钮显示,和状态行的进度条和处理进度文字显示,主要是围绕 Stop 类实现。长期以来代码书写比较繁冗;另外 MyForm 类中的 _stop 成员用法不恰当,造成循环之中再次重入循环发生问题。

为了解决这两个主要问题,最近新实现了 Looping 类内务前端的循环控制涉及到工具条上的 Stop 按钮显示,和状态行的进度条和处理进度文字显示,主要是围绕 Stop 类实现。长期以来代码书写比较繁冗;另外 MyForm 类中的 _stop 成员用法不恰当,造成循环之中再次重入循环发生问题。

为了解决这两个主要问题,最近新实现了 Looping 类。并设计了一套比较简单的编码范式,计划在内务前端代码中全部替换掉以前的相关代码。

重构前的代码:

    LibraryChannel channel = this.GetChannel();

    _stop.OnStop += new StopEventHandler(this.DoStop);
    _stop.Initial("正在装载读者记录 ...");
    _stop.BeginLoop();

    EnableControls(false);
    try
    {

    }
    finally
    {
        EnableControls(true);

        _stop.EndLoop();
        _stop.OnStop -= new StopEventHandler(this.DoStop);
        _stop.Initial("");

        this.ReturnChannel(channel);
    }

重构后的代码:

    LibraryChannel channel = this.GetChannel();

    var looping = BeginLoop(this.DoStop, "正在装载读者记录 ...");

    EnableControls(false);
    try
    {

    }
    finally
    {
        EnableControls(true);

        EndLoop(looping);

        this.ReturnChannel(channel);
    }

再次重构,还可以把 GetChannel() 和 EnableControls() 合并到一起,并把 try catch 省去了:

    using (var looping = Looping(
        out LibraryChannel channel,
        "正在装载读者记录 ...",
        "disableControl"))
    {


    }
@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Oct 31, 2022

已经重构的模块清单

读者查询窗 ReaderSearchForm
实体查询窗 ItemSearchForm
书目查询窗 BiblioSearchForm

读者窗 ReaderInfoForm

EntityForm
ActivateForm
BatchTaskForm
CalendarForm
CardPrintForm
ChangePasswordForm
EasForm
QuickChargingForm

ReservationListForm
SelectItemDialog
SelectLocationDialog
UrgentChargingForm
CheckBorrowInfoForm
ClockForm
DupForm
EntityRegisterWizard
ImportExportForm
PrintBindingForm
ItemInfoForm
ManagerForm

MessageForm
ChannelForm
OperLogForm

BatchOrderForm
PrintClaimForm
PassGateForm
BatchPrintFormBase
QuickChangeBiblioForm
QuickChangeEntityForm
AmerceForm
ImportPatronForm
ReaderManageForm
SelectPatronDialog
MyScriptForm
InvoiceSearchForm
Marc856SearchForm

ItemSearchFormBase
SettlementForm
InventoryForm

ItemSearchFormBase 中的 FillBiblioSummaryColumn 函数要规整一下,不要那么多重载版本

ReportForm
TestingForm
TestSearchForm
UserForm
CallNumberForm
RfidToolForm

ZhongcihaoForm
UtilityForm

Global.GetBatchNoTable

PrintOderForm
AccountBookForm

: MyScriptForm
: BatchPrintFormBase

XmlStatisForm
BiblioStatisForm
ImportMarcForm
Iso2709StatisForm
ItemStatisForm
OperLogStatisForm
ReaderStatisForm

AcceptForm
ItemHandoverForm
PrintAcceptForm
LabelPrintForm

: StatisHostBase

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 5, 2022

ISO2709统计窗的“导入书目”方案重构

main.cs

// 导入书目
// 创建日期: 2012/11/19
// 最后修改日期:2012/11/19

// 2018/8/23 可选择将重复数据输出到 MARC 文件
// 2022/11/6 dp2library API 使用 Looping 方式调用

using System;
using System.Collections.Generic;	// List<?>
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using System.Drawing;	// Size

using dp2Circulation;
using DigitalPlatform.Marc;
using DigitalPlatform.dp2.Statis;
using DigitalPlatform.LibraryClient;
using DigitalPlatform.LibraryClient.localhost;

public class InputISO2709 : Iso2709Statis
{
    string ErrorFilename = "";	// 错误信息文件名
    StreamWriter sw_error = null;

    public string strOutputFilename = "";
    public Stream output = null;

    long m_lErrorCount = 0;

    string m_strBiblioDbName = "";
    string m_strBiblioSyntax = "";

    string m_strBatchNo = "";
    bool m_bSearchDup = false;
    string m_strProjectName = "";

    DupForm DupForm = null;
    bool m_bImportDup = false;

    int m_nDupCount = 0;
    int m_nImportCount = 0;
    long m_lOutputCount = 0;

    string _creator = "";

    public override void FreeResources()
    {
        if (this.sw_error != null)
        {
            this.sw_error.Close();
            this.sw_error = null;
        }

        if (this.output != null)
        {
            this.output.Close();
            this.output = null;
        }
    }

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        this.ClearConsoleForPureTextOutputing();

        this.ErrorFilename = this.ProjectDir + "\\~error.txt";

        sw_error = new StreamWriter(this.ErrorFilename,
                    false,	// append
                    Encoding.UTF8);
        sw_error.Write("<pre>\r\n");


        // 选目标书目库


        // 替换文件中的宏
        StreamReader sr = new StreamReader(this.ProjectDir + "\\input.html", Encoding.GetEncoding(936));
        string strText = sr.ReadToEnd();
        strText = strText.Replace("%options%", BuildOptionsString());
        sr.Close();
        sr = null;

        StreamWriter temp = new StreamWriter(this.ProjectDir + "\\~input.html",
                    false,	// append
                    Encoding.GetEncoding(936));
        temp.Write(strText);
        temp.Close();
        temp = null;

        // 获得输入参数
        HtmlInputDialog window = new HtmlInputDialog();

        window.Text = "指定输入参数";
        window.Url = this.ProjectDir + "\\~input.html";
        window.Size = new Size(700, 500);
        window.ShowDialog();
        if (window.DialogResult != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        // MessageBox.Show(window.SubmitUrl);


        if (window.SubmitUrl == "action://ok/")
        {
            // MessageBox.Show("[" + window.SubmitResult["OutputAllInOneTable"] + "]");

            this.m_strBiblioDbName = window.SubmitResult["bibliodbname"];
            this.m_strBatchNo = window.SubmitResult["batchno"]; // 批次号
            this.m_bSearchDup = (window.SubmitResult["SearchDup"] == "true");   // 查重
        }
        else
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        this.m_strBiblioSyntax = this.Iso2709StatisForm.MainForm.GetBiblioSyntax(this.m_strBiblioDbName);

        // 列出可用的查重方案名
        string strError = "";

        if (this.m_bSearchDup == true)
        {
            List<string> projectnames = null;
            int nRet = ListProjectNames(this.m_strBiblioDbName,
                out projectnames,
                out strError);
            if (nRet == -1)
                goto ERROR1;

            if (projectnames.Count == 0)
            {
                strError = "书目库 " + this.m_strBiblioDbName + " 没有关联的查重方案";
                goto ERROR1;
            }


            // 替换文件中的宏
            sr = new StreamReader(this.ProjectDir + "\\select_dupproject.html", Encoding.GetEncoding(936));
            strText = sr.ReadToEnd();
            strText = strText.Replace("%options%", BuildProjectsString(projectnames));
            sr.Close();
            sr = null;

            temp = new StreamWriter(this.ProjectDir + "\\~select_dupproject.html",
                        false,	// append
                        Encoding.GetEncoding(936));
            temp.Write(strText);
            temp.Close();
            temp = null;

            // 获得输入参数
            window = new HtmlInputDialog();

            window.Text = "指定输入参数";
            window.Url = this.ProjectDir + "\\~select_dupproject.html";
            window.Size = new Size(700, 500);
            window.ShowDialog();
            if (window.DialogResult != DialogResult.OK)
            {
                e.Continue = ContinueType.SkipAll;
                return;
            }

            if (window.SubmitUrl == "action://ok/")
            {
                this.m_strProjectName = window.SubmitResult["projectname"];
                this.m_strProjectName = this.m_strProjectName.Replace("*", "");

                string strImport = window.SubmitResult["import"];
                if (strImport == "ImportDup")
                    this.m_bImportDup = true;   // 发生重复的记录也要导入
                else
                {
                    nRet = InitOutput(out strError);
                    if (nRet == -1)
                        goto ERROR1;
                }
            }
            else
            {
                e.Continue = ContinueType.SkipAll;
                return;
            }

            this.DupForm = this.Iso2709StatisForm.MainForm.EnsureDupForm();
        }

        // 迫使登录一次,以便 Channel.UserName 可用
        string strValue = "";
        /*
        this.Iso2709StatisForm.Channel.GetSystemParameter(this.Iso2709StatisForm.Stop,
            "library",
            "name",
            out strValue,
            out strError);
        */
        using (var looping = this.Iso2709StatisForm.Looping(out LibraryChannel channel))
        {
            channel.GetSystemParameter(looping.Progress,
    "library",
    "name",
    out strValue,
    out strError);
            _creator = channel.UserName;
        }
        return;
    ERROR1:
        MessageBox.Show(this.Iso2709StatisForm, strError);
        e.Continue = ContinueType.SkipAll;
    }


    int InitOutput(out string strError)
    {
        strError = "";

        SaveFileDialog dlg = new SaveFileDialog();
        dlg.Title = "请指定要输出的ISO2709文件名";
        dlg.FileName = "";
        dlg.RestoreDirectory = true;
        dlg.CreatePrompt = false;
        dlg.OverwritePrompt = false;
        dlg.InitialDirectory = Environment.CurrentDirectory;
        dlg.Filter = "iso2709 files (*.iso)|*.iso|All files (*.*)|*.*";

        if (dlg.ShowDialog() != DialogResult.OK)
        {
            strError = "放弃处理...";
            return -1;
        }

        this.strOutputFilename = dlg.FileName;

        // 看看同名文件是否已经存在
        bool bExist = File.Exists(this.strOutputFilename);
        bool bAppend = false;

        if (bExist == true)
        {
            DialogResult result = MessageBox.Show(this.Iso2709StatisForm,
              "文件 '" + this.strOutputFilename + "' 已存在,是否以追加方式写入记录?\r\n\r\n--------------------\r\n注:(是)追加  (否)覆盖  (取消)放弃",
              "输出dt1000读者MARC格式文件",
              MessageBoxButtons.YesNoCancel,
              MessageBoxIcon.Question,
              MessageBoxDefaultButton.Button1);
            if (result == DialogResult.Yes)
                bAppend = true;

            if (result == DialogResult.No)
                bAppend = false;

            if (result == DialogResult.Cancel)
            {
                strError = "放弃处理...";
                return -1;
            }
        }

        try
        {
            output = File.Open(this.strOutputFilename, FileMode.OpenOrCreate);
            if (bAppend == false)
                output.SetLength(0);
            else
                output.Seek(0, SeekOrigin.End);
        }
        catch (Exception ex)
        {
            strError = "打开或创建文件 " + this.strOutputFilename + " 失败,原因: " + ex.Message;
            return -1;
        }

        return 1;
    }


    public override void OnRecord(object sender, StatisEventArgs e)
    {
        string strError = "";
        int nRet = 0;

        string strMARC = this.MARC;

        // 转换回XML,为了查重需要
        XmlDocument domMarc = null;
        nRet = MarcUtil.Marc2Xml(strMARC,
            this.m_strBiblioSyntax,
            out domMarc,
            out strError);
        if (nRet == -1)
            goto ERROR1;

        // 查重
        bool bDup = false;
        if (this.m_bSearchDup == true)
        {
            this.DupForm.ProjectName = this.m_strProjectName;    // "<默认>";
            this.DupForm.XmlRecord = domMarc.DocumentElement.OuterXml;
            this.DupForm.RecordPath = this.m_strBiblioDbName + "/?";

            // form.Activate();
            nRet = this.DupForm.DoSearch(out strError);
            if (nRet == -1)
                goto ERROR1;

            if (this.DupForm.GetDupCount() > 0)
            {
                this.m_nDupCount++;
                bDup = true;

                if (m_bImportDup == false)
                {
                    byte[] baResult = null;
                    nRet = MarcUtil.CvtJineiToISO2709(
                      strMARC,
                      "unimarc",
                      Encoding.GetEncoding(936),
                      out baResult,
                      out strError);
                    if (nRet == -1)
                    {
                        this.m_lErrorCount++;
                        sw_error.Write("MARC 记录 " + this.CurrentRecordIndex + " 处理过程中,CvtJineiToISO2709()出错: " + strError + "\r\n");
                        return;
                    }
                    this.output.Write(baResult, 0, baResult.Length);
                    m_lOutputCount++;
                    return;
                }
            }
        }

        // 998$a 批次号
        if (string.IsNullOrEmpty(this.m_strBatchNo) == false)
        {
            MarcUtil.SetFirstSubfield(ref strMARC,
                "998",
                "a",
                this.m_strBatchNo);
        }

        // 998$u 创建时间
        DateTime now = DateTime.Now;
        string strCreateTime = now.ToString("u");
        MarcUtil.SetFirstSubfield(ref strMARC,
            "998",
            "u",
            strCreateTime);

        // 998$z 操作者
        string strCreator = _creator;   // this.Iso2709StatisForm.Channel.UserName;
        MarcUtil.SetFirstSubfield(ref strMARC,
            "998",
            "z",
            strCreator);

        if (bDup == true)
        {
            MarcUtil.SetFirstSubfield(ref strMARC,
                "998",
                "s",
                "重");
        }

        // 转换回XML,为了写入
        domMarc = null;
        nRet = MarcUtil.Marc2Xml(strMARC,
            this.m_strBiblioSyntax,
            out domMarc,
            out strError);
        if (nRet == -1)
            goto ERROR1;


        string strBiblioRecPath = this.m_strBiblioDbName + "/?";
        string strOutputBiblioRecPath = "";
        byte[] baNewTimestamp = null;

        nRet = this.Iso2709StatisForm.SetBiblioInfo(
            "new",
            strBiblioRecPath,
            "xml",
            domMarc.DocumentElement.OuterXml,
            null,	// timestamp
            out strOutputBiblioRecPath,
            out baNewTimestamp,
            out strError);
        if (nRet == -1)
        {
            strError = "创建书目记录 '" + strBiblioRecPath + "' 时出错: " + strError + "\r\n";
            WriteTextToConsole(strError);

            this.m_lErrorCount++;
            sw_error.Write(strError);
            return;
        }

        this.m_nImportCount++;
        strBiblioRecPath = strOutputBiblioRecPath;
        return;
    ERROR1:
        WriteTextToConsole(strError + "\r\n");
        this.m_lErrorCount++;
        sw_error.Write(strError + "\r\n");
    }

    public override void OnEnd(object sender, StatisEventArgs e)
    {
        if (this.sw_error != null)
        {
            this.sw_error.Close();
            this.sw_error = null;
        }

        if (this.output != null)
        {
            this.output.Close();
            this.output = null;
        }

        if (this.DupForm != null)
        {
            this.DupForm.Close();
            this.DupForm = null;
        }

        if (this.m_lErrorCount > 0)
        {
            MessageBox.Show(this.Iso2709StatisForm, "处理结束。有 " + this.m_lErrorCount.ToString() + " 条错误信息,已经输出到文件 " + this.ErrorFilename + " 中。在“打印结果”中也可以看到。");

            // 写入打印输出文件
            string strPrintFile = this.NewOutputFileName();
            File.Copy(this.ErrorFilename, strPrintFile, true);
        }

        string strText = "共导入 " + this.m_nImportCount.ToString() + " 条书目记录。";
        if (this.m_nDupCount > 0)
        {
            if (m_bImportDup == false)
                strText += "\r\n\r\n有 " + this.m_nDupCount.ToString() + " 条记录因为发现重复而被放弃导入书目库,输出到文件有:" + this.m_lOutputCount + "条";
            else
                strText += "\r\n\r\n其中有 " + this.m_nDupCount.ToString() + " 条记录发现重复,但依然导入了书目库(998$s具有“重”标记)";
        }

        MessageBox.Show(this.Iso2709StatisForm, strText);
    }

    string BuildOptionsString()
    {
        string strResult = "";

        // 遍历书目库
        for (int i = 0; i < this.Iso2709StatisForm.MainForm.BiblioDbProperties.Count; i++)
        {
            BiblioDbProperty prop = this.Iso2709StatisForm.MainForm.BiblioDbProperties[i];

            strResult += "<option value='" + prop.DbName + "'>";
            strResult += prop.DbName;
            strResult += "</option>";
        }

        return strResult;
    }

    string BuildProjectsString(List<string> names)
    {
        string strResult = "";

        foreach (string s in names)
        {
            strResult += "<option value='" + s + "'>";
            strResult += s;
            strResult += "</option>";
        }

        return strResult;
    }

    // 列出可用的查重方案名
    // 带有 * 的方案名是关联了当前库名的
    public int ListProjectNames(string strBiblioDbName,
        out List<string> projectnames,
        out string strError)
    {
        strError = "";
        projectnames = new List<string>();

        DupProjectInfo[] dpis = null;


        long lRet;
        using (var looping = this.Iso2709StatisForm.Looping(out LibraryChannel channel))
        {
            /*
long lRet = this.Iso2709StatisForm.Channel.ListDupProjectInfos(
    this.Iso2709StatisForm.Stop,
    strBiblioDbName,
    out dpis,
    out strError);
if (lRet == -1)
    goto ERROR1;
*/
            lRet = channel.ListDupProjectInfos(
    looping.Progress,
    strBiblioDbName,
    out dpis,
    out strError);
            if (lRet == -1)
                goto ERROR1;


            for (int i = 0; i < dpis.Length; i++)
            {
                projectnames.Add(dpis[i].Name);
            }

            // 重新获得一次,全部的方案
            /*
            lRet = this.Iso2709StatisForm.Channel.ListDupProjectInfos(
        this.Iso2709StatisForm.Stop,
        "",
        out dpis,
        out strError);
            if (lRet == -1)
                goto ERROR1;
            */
            lRet = channel.ListDupProjectInfos(
looping.Progress,
"",
out dpis,
out strError);
            if (lRet == -1)
                goto ERROR1;
        }

        for (int i = 0; i < dpis.Length; i++)
        {
            int index = projectnames.IndexOf(dpis[i].Name);
            if (index == -1)
                projectnames.Add(dpis[i].Name);
            else
                projectnames[index] = "*" + projectnames[index];
        }

        return (int)lRet;
    ERROR1:
        return -1;
    }
}

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 5, 2022

日志统计窗的“借阅排行[分馆]”方案重构

main.cs

// *** 借阅排行[分馆] ***
// 修改历史:
//	2013/12/25 创建
//  2013/12/26 增加未借出图书的表格
//  2022/1/10 用 GetChannel() 获得 channel
//  2022/11/6 用 Looping 方式改写 OperLogStatisForm.Progress

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Drawing;	// Size

using dp2Circulation;

using DigitalPlatform;
using DigitalPlatform.Xml;
using DigitalPlatform.Text;
using DigitalPlatform.dp2.Statis;
using DigitalPlatform.LibraryClient;
using DigitalPlatform.CirculationClient;

public class MyStatis : OperLogStatis
{
    TableCollection tables = new TableCollection();

#if NO
    Table tableDepartment = new Table(1);	// 按单位

    Table tableReader = new Table(3);	// 按读者(人)
    // 列定义:条码 姓名 单位 册次

    Table tableBook = new Table(2);		// 按图书(种)
    // 列定义:种记录路径 摘要 册次

    Table tableClass = new Table(1);	// 按图书(分类)
    // 列定义:类目 册次
#endif

    List<string> ClassNames = null;	// 类名列表

    int m_nDepartmentTableMaxLine = -1;
    int m_nReaderTableMaxLine = 100;
    int m_nBookTableMaxLine = 100;
    int m_nNotBorrowBookTableMaxLine = -1;

    bool m_bFixClassColumn = true;	// 图书分类报表:恒定类目列
    bool m_bBiblioClass = false;	// 图书分类报表:是否从书目记录中获得分类号 (否则从册记录中的索取号中获得)

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        this.ClearConsoleForPureTextOutputing();

        // 获得输入参数
        HtmlInputDialog window = new HtmlInputDialog();

        window.Text = "借阅排行 -- 指定输出特性";
        window.Url = this.ProjectDir + "\\input.html";
        window.Size = new Size(700, 500);
        window.ShowDialog();
        if (window.DialogResult != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        // MessageBox.Show(window.SubmitUrl);

        string strError = "";

        if (window.SubmitUrl == "action://ok/")
        {
            string strValue = window.SubmitResult["DepartmentTableMaxLine"];
            try
            {
                this.m_nDepartmentTableMaxLine = Convert.ToInt32(strValue);
            }
            catch
            {
                strError = "参数DepartmentTableMaxLine '" + strValue + "' 格式错误";
                goto ERROR1;
            }


            strValue = window.SubmitResult["ReaderTableMaxLine"];
            try
            {
                this.m_nReaderTableMaxLine = Convert.ToInt32(strValue);
            }
            catch
            {
                strError = "参数ReaderTableMaxLine '" + strValue + "' 格式错误";
                goto ERROR1;
            }

            strValue = window.SubmitResult["BookTableMaxLine"];
            try
            {
                this.m_nBookTableMaxLine = Convert.ToInt32(strValue);
            }
            catch
            {
                strError = "参数BookTableMaxLine '" + strValue + "' 格式错误";
                goto ERROR1;
            }

            strValue = window.SubmitResult["NotBorrowBookTableMaxLine"];
            try
            {
                this.m_nNotBorrowBookTableMaxLine = Convert.ToInt32(strValue);
            }
            catch
            {
                strError = "参数 NotBorrowBookTableMaxLine '" + strValue + "' 格式错误";
                goto ERROR1;
            }



            this.m_bFixClassColumn = (window.SubmitResult["FixClassColumn"] == "true");
            this.m_bBiblioClass = (window.SubmitResult["BiblioClass"] == "true" || window.SubmitResult["BiblioClass"] == "on");
        }
        else
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        string strClassNameFilename = this.ProjectDir + "\\class.txt";
        LoadClassNames(strClassNameFilename);


        return;
    ERROR1:
        MessageBox.Show(this.OperLogStatisForm, strError);
    }


    public override void OnRecord(object sender, StatisEventArgs e)
    {
        string strError = "";
        int nRet = 0;

        XmlDocument dom = new XmlDocument();

        try
        {
            dom.LoadXml(this.Xml);
        }
        catch (Exception ex)
        {
            strError = "Load Xml to DOM error: " + ex.Message;
            goto ERROR1;
        }

        this.WriteTextToConsole(this.CurrentLogFileName + ":" + this.CurrentRecordIndex.ToString() + "\r\n");

        string strOperation = DomUtil.GetElementText(dom.DocumentElement, "operation");
        string strAction = DomUtil.GetElementText(dom.DocumentElement, "action");

        if (strOperation != "borrow" && strOperation != "return")
            return;

        string strOperator = DomUtil.GetElementText(dom.DocumentElement, "operator");

        string strAccessClass = "";	// 索书号中的分类号
        string strBiblioRecPath = "";	// 书目记录路径

        string strLocation = "";    // 册馆藏地点

        XmlNode nodeItem = null;
        string strItemXml = DomUtil.GetElementText(dom.DocumentElement,
                "itemRecord", out nodeItem);
        string strItemRecPath = "";
        if (nodeItem != null)
            strItemRecPath = DomUtil.GetAttr(nodeItem, "recPath");

        if (String.IsNullOrEmpty(strItemXml) == false
            && nodeItem != null)
        {

            // this.WriteTextToConsole( strItemRecPath + "\r\n");

            // 从册记录中提取<parent>
            XmlDocument itemdom = new XmlDocument();
            itemdom.LoadXml(strItemXml);
            string strParentID = DomUtil.GetElementText(itemdom.DocumentElement,
                "parent");

            strBiblioRecPath = BuildBiblioRecPath(strItemRecPath, strParentID);

            strLocation = DomUtil.GetElementText(itemdom.DocumentElement,
                "location");
            strLocation = StringUtil.GetPureLocation(strLocation);

            if (this.m_bBiblioClass == true)
            {
                if (strBiblioRecPath != null)
                {
                    string strResultValue = "";
                    nRet = this.OperLogStatisForm.GetBiblioPart(strBiblioRecPath,
                        null,	// strInputXml
                        "@class",
                        out strResultValue,
                        out strError);
                    if (nRet == -1)
                    {
                        // strResultValue = "?";
                        if (string.IsNullOrEmpty(strError) == true)
                            strError = strResultValue;
                        goto ERROR1;
                    }

                    // this.WriteTextToConsole("class:" + strResultValue + "\r\n");

                    if (String.IsNullOrEmpty(strResultValue) == true)
                        strResultValue = "?";

                    strAccessClass = GetClassName(strResultValue);
                }
            }
            else
            {
                // 从册记录的索取号中获得分类号部分
                string strAccessNo = DomUtil.GetElementText(itemdom.DocumentElement,
    "accessNo");
                strAccessNo = StringUtil.BuildLocationClassEntry(strAccessNo);
                // 丢掉'/'后面的部分
                nRet = strAccessNo.IndexOf("/");
                if (nRet != -1)
                    strAccessNo = strAccessNo.Substring(0, nRet);

                strAccessClass = GetClassName(strAccessNo);
            }
        }


        if (strBiblioRecPath == null)
        {
            this.WriteTextToConsole(this.CurrentLogFileName + ":" + this.CurrentRecordIndex.ToString() + "没有书目记录路径\r\n");
            strBiblioRecPath = "?";
        }

        XmlNode nodeReader = null;
        string strReaderXml = DomUtil.GetElementText(dom.DocumentElement,
                "readerRecord", out nodeReader);
        string strReaderRecPath = DomUtil.GetAttr(nodeReader, "recPath");
        string strReaderDbName = Global.GetDbName(strReaderRecPath);

        string strReaderBarcode = "?";
        string strReaderName = "?";
        string strDepartment = "?";
        if (String.IsNullOrEmpty(strReaderXml) == false
            && nodeReader != null)
        {
            // string strReaderRecPath = DomUtil.GetAttr(nodeReader, "recPath");

            // 从读者记录中提取各种信息
            XmlDocument readerdom = new XmlDocument();
            readerdom.LoadXml(strReaderXml);
            strReaderBarcode = DomUtil.GetElementText(readerdom.DocumentElement,
                "barcode");
            strReaderName = DomUtil.GetElementText(readerdom.DocumentElement,
                "name");
            strDepartment = DomUtil.GetElementText(readerdom.DocumentElement,
                "department");
        }

        if (strOperation == "borrow" && strAction != "renew")
        {
            // 借阅量

            // 按部门
            this.tables.IncValue("department_" + strReaderDbName, strDepartment, 0, 1, 1);
            // 按读者
            this.tables.IncValue("reader_" + strReaderDbName, strReaderBarcode, 2, 1, 1);
            // 按图书种
            this.tables.IncValue("book_" + strLocation, strBiblioRecPath, 1, 1, 1);

            // 按图书分类
            this.tables.IncValue("class_" + strLocation, strAccessClass, 0, 1, 1);

            // 因为类目可能互相重叠,所以Report那里计算的合计是不准确的,必须在统计过程中累加
            this.tables.IncValue("class_" + strLocation, "合计", 0, 1, 1);

            // 按照馆藏地点、每种,累计被借阅次数
            this.tables.IncValue("item_" + strLocation, strItemRecPath, 0, 1, 1);


            /*
            // 需要将类号变换为列号
            // 借阅册 列号0
            table.IncValue(strAccessClass, 0, 1, 1);
            */

        }


        if (strOperation == "borrow" && strAction == "renew")
        {
            // 续借册 列号2

        }


        if (strOperation == "return" && strAction == "return")
        {
            // 还书册 列号4
        }


        return;
    ERROR1:
        DialogResult result = MessageBox.Show(this.OperLogStatisForm,
strError + "\r\n\r\n是否继续处理?",
"统计",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
        if (result == DialogResult.No)
            e.Continue = ContinueType.SkipAll;
    }

    public override void OnEnd(object sender, StatisEventArgs e)
    {
        int nRet = 0;
        string strError = "";

        using (var looping = this.OperLogStatisForm.Looping(out LibraryChannel channel))
        {
            string strDeleteComment = "";

            // *** 按部门

            List<string> names = this.tables.GetNames("department_");
            names.Sort();
            foreach (string strName in names)
            {
                looping.Progress.SetMessage("正在处理表格 " + strName + " ...");

                string strReaderDbName = strName.Substring("department_".Length);

                Table tableDepartment = this.tables.GetTable(strName);

                tableDepartment.Sort("0:d");

                // 删除多余的行
                strDeleteComment = "内容共 " + tableDepartment.Count.ToString() + " 行";
                if (this.m_nDepartmentTableMaxLine != -1
                    && tableDepartment.Count > this.m_nDepartmentTableMaxLine)
                {
                    tableDepartment.RemoveLines(this.m_nDepartmentTableMaxLine);
                    strDeleteComment += "; 只保留了前 " + this.m_nDepartmentTableMaxLine.ToString() + "行";
                }

                Report report = Report.BuildReport(tableDepartment,
                    "部门||department,借书(册)||borrowitem",
                    "&nbsp;",
                    true);

                if (report != null)
                {

                    string strHead = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
                        + "<meta http-equiv='Content-Type' content=\"text/html; charset=utf-8\">"
                        + "<title></title>"
                        + "<link rel='stylesheet' href='" + this.ProjectDir + "/style_department.css' type='text/css'>"
                        + "</head><body>"
                        + "<div class='tabletitle'>借阅排行 按部门 <br/>" + strReaderDbName + "<br/>[" + this.GetTimeRangeString() + "]</div>"
                        + "<div class='titlecomment'>" + strDeleteComment + "</div>";
                    string strTail = "</body></html>";

                    string strHtml = strHead + report.HtmlTable(tableDepartment) + strTail;

                    // this.WriteTextToConsole("</pre>" + strHtml);

                    // 写入输出文件
                    string strOutputFileName = this.NewOutputFileName();
                    this.WriteToOutputFile(strOutputFileName,
                        strHtml,
                        Encoding.UTF8);
                }
            }

            // *** 按读者

            names = this.tables.GetNames("reader_");
            names.Sort();
            foreach (string strName in names)
            {
                looping.Progress.SetMessage("正在处理表格 " + strName + " ...");

                string strReaderDbName = strName.Substring("reader_".Length);

                Table tableReader = this.tables.GetTable(strName);


                tableReader.Sort("2:d");

                // 删除多余的行
                strDeleteComment = "内容共 " + tableReader.Count.ToString() + " 行";
                if (this.m_nReaderTableMaxLine != -1
                    && tableReader.Count > this.m_nReaderTableMaxLine)
                {
                    tableReader.RemoveLines(this.m_nReaderTableMaxLine);
                    strDeleteComment += "; 只保留了前 " + this.m_nReaderTableMaxLine.ToString() + "行";
                }

                // 加入姓名和单位列
                this.WriteTextToConsole("正在加入读者姓名和单位列\r\n");
                for (int i = 0; i < tableReader.Count; i++)
                {
                    looping.Progress.SetMessage("正在加入 " + (i + 1).ToString() + "/" + tableReader.Count.ToString() + " 个读者姓名和单位,可能需要较长时间 ...");

                    Line line = tableReader[i];
                    string strReaderBarcode = line.Entry;

                    if (String.IsNullOrEmpty(strReaderBarcode) == true
                        || strReaderBarcode == "?")
                        continue;

                    string strReaderName = "";
                    string strDepartment = "";

                    string[] results = null;
                    string strRecPath = "";
                    byte[] baTimestamp = null;
                    nRet = this.OperLogStatisForm.GetReaderInfo(strReaderBarcode,
                        "xml:noborrowhistory",
                        out results,
                        out strRecPath,
                        out baTimestamp,
                        out strError);
                    if (nRet == -1)
                    {
                        strReaderName = "***error: " + strError;
                        goto DOADD;
                    }
                    else
                    {
                        if (results == null || results.Length == 0)
                        {
                            strReaderName = "not found";
                            goto DOADD;
                        }

                    }

                    // 从读者记录中提取各种信息
                    XmlDocument readerdom = new XmlDocument();
                    try
                    {
                        readerdom.LoadXml(results[0]);
                    }
                    catch (Exception ex)
                    {
                        strReaderName = "LOADDOM error: " + ex.Message;
                        goto DOADD;
                    }

                    strReaderName = DomUtil.GetElementText(readerdom.DocumentElement,
                        "name");
                    strDepartment = DomUtil.GetElementText(readerdom.DocumentElement,
                        "department");

                /*
                this.WriteTextToConsole("---strReaderName=["+strReaderName+"]\r\n");
                this.WriteTextToConsole("---strDepartment=["+strDepartment+"]\r\n");
                */

                DOADD:
                    line.SetValue(0, strReaderName);
                    line.SetValue(1, strDepartment);

                }


                Report report = Report.BuildReport(tableReader,
                    "读者证条码||readerbarcode,姓名||readername,单位||department,借书(册)||borrowitem",
                    "&nbsp;",
                    true);

                if (report != null)
                {
                    report[1].Sum = false;
                    report[2].Sum = false;

                    string strHead = "<html><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
                        + "<meta http-equiv='Content-Type' content=\"text/html; charset=utf-8\">"
                        + "<title></title>"
                        + "<link rel='stylesheet' href='" + this.ProjectDir + "/style_reader.css' type='text/css'>"
                        + "</head><body>"
                        + "<div class='tabletitle'>借阅排行 按读者 <br/>" + strReaderDbName + "<br/>[" + this.GetTimeRangeString() + "]</div>"
                        + "<div class='titlecomment'>" + strDeleteComment + "</div>";
                    string strTail = "</body></html>";

                    string strHtml = strHead + report.HtmlTable(tableReader) + strTail;

                    // this.WriteTextToConsole("</pre>" + strHtml);

                    // 写入输出文件
                    string strOutputFileName = this.NewOutputFileName();
                    this.WriteToOutputFile(strOutputFileName,
                        strHtml,
                        Encoding.UTF8);
                }

            }


            // *** 按图书(种)
            names = this.tables.GetNames("book_");
            names.Sort();
            foreach (string strName in names)
            {
                looping.Progress.SetMessage("正在处理表格 " + strName + " ...");

                string strLocation = strName.Substring("book_".Length);

                Table tableBook = this.tables.GetTable(strName);


                tableBook.Sort("1:d");

                // 删除多余的行
                strDeleteComment = "内容共 " + tableBook.Count.ToString() + " 行";
                if (this.m_nBookTableMaxLine != -1
                    && tableBook.Count > this.m_nBookTableMaxLine)
                {
                    // tableBook.RemoveLines(this.m_nBookTableMaxLine);
                    strDeleteComment += "; 只保留了前 " + this.m_nBookTableMaxLine.ToString() + "行";
                }

                if (this.m_nBookTableMaxLine == -1)
                    this.m_nBookTableMaxLine = tableBook.Count;

                // 加入摘要列
                this.WriteTextToConsole("正在加入书目摘要列\r\n");
                List<string> biblio_recpaths = new List<string>();
                for (int i = 0; i < Math.Min(this.m_nBookTableMaxLine, tableBook.Count); i++)
                {
                    Line line = tableBook[i];
                    biblio_recpaths.Add(line.Entry);
                }

                BiblioLoader loader = new BiblioLoader();
                loader.Channel = channel;   // this.OperLogStatisForm.Channel;
                loader.Stop = looping.Progress;
                loader.Format = "summary";
                loader.GetBiblioInfoStyle = GetBiblioInfoStyle.None;
                loader.RecPaths = biblio_recpaths;

                {
                    int i = 0;
                    foreach (BiblioItem item in loader)
                    {
                        looping.Progress.SetMessage("正在加入 " + (i + 1).ToString() + "/" + biblio_recpaths.Count.ToString() + " 个书目摘要,可能需要较长时间 ...");

                        tableBook.SetValue(item.RecPath, 0, item.Content);
                        i++;
                    }
                }

                Report report = Report.BuildReport(tableBook,
                    "图书种路径||bibliorecpath,书目摘要||summary,借书(册)||borrowitem",
                    "&nbsp;",
                    true);

                if (report != null)
                {
                    report[1].Sum = false;

                    string strHead = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
                        + "<meta http-equiv='Content-Type' content=\"text/html; charset=utf-8\">"
                        + "<title></title>"
                        + "<link rel='stylesheet' href='" + this.ProjectDir + "/style_book.css' type='text/css'>"
                        + "</head><body>"
                        + "<div class='tabletitle'>借阅排行 按图书(种) <br/>" + strLocation + "<br/>[" + this.GetTimeRangeString() + "]</div>"
                        + "<div class='titlecomment'>" + strDeleteComment + "</div>";
                    string strTail = "</body></html>";

                    string strHtml = strHead + report.HtmlTable(tableBook, this.m_nBookTableMaxLine) + strTail;

                    // this.WriteTextToConsole("</pre>" + strHtml);

                    // 写入输出文件
                    string strOutputFileName = this.NewOutputFileName();
                    this.WriteToOutputFile(strOutputFileName,
                        strHtml,
                        Encoding.UTF8);
                }

            }

            // *** 按图书(分类)
            names = this.tables.GetNames("class_");
            names.Sort();
            foreach (string strName in names)
            {
                looping.Progress.SetMessage("正在处理表格 " + strName + " ...");

                string strLocation = strName.Substring("class_".Length);

                Table tableClass = this.tables.GetTable(strName);

                tableClass.Sort("-1:a");

                // 在table中确保加入预定义的class行
                if (this.m_bFixClassColumn == true
                    && this.ClassNames != null)
                {
                    for (int j = 0; j < this.ClassNames.Count; j++)
                    {
                        string strClassName = this.ClassNames[j];
                        tableClass.EnsureLine(strClassName, 1);
                    }
                    tableClass.Sort("-1:a");
                }

                strDeleteComment = "";

                Report report = Report.BuildReport(tableClass,
                    "类目||class,借书(册)||borrowitem",
                    "&nbsp;",
                    false);

                if (report != null)
                {

                    string strHead = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
                        + "<meta http-equiv='Content-Type' content=\"text/html; charset=utf-8\">"
                        + "<title></title>"
                        + "<link rel='stylesheet' href='" + this.ProjectDir + "/style_bookclass.css' type='text/css'>"
                        + "</head><body>"
                        + "<div class='tabletitle'>借阅排行 按图书(分类) <br/>" + strLocation + "<br/>[" + this.GetTimeRangeString() + "]</div>"
                        + "<div class='titlecomment'>" + strDeleteComment + "</div>";
                    string strTail = "</body></html>";

                    string strHtml = strHead + report.HtmlTable(tableClass) + strTail;

                    // this.WriteTextToConsole("</pre>" + strHtml);

                    // 写入输出文件
                    string strOutputFileName = this.NewOutputFileName();
                    this.WriteToOutputFile(strOutputFileName,
                        strHtml,
                        Encoding.UTF8);
                }
            }

            // *** 没有被借阅过的种
            if (m_nNotBorrowBookTableMaxLine != 0)
            {
                names = this.tables.GetNames("book_");
                names.Sort();
                foreach (string strName in names)
                {
                    looping.Progress.SetMessage("正在处理表格 " + strName + " ...");

                    string strLocation = strName.Substring("book_".Length);

                    Table tableBook = this.tables.GetTable(strName);

                    List<string> biblio_recpaths = new List<string>();
                    foreach (string key in tableBook.Keys)
                    {
                        biblio_recpaths.Add(key);
                    }
                    List<string> all_bibliorecpaths = null;
                    nRet = ItemSearchForm.SearchOneLocationItems(
                        this.OperLogStatisForm.MainForm,
                        channel,    // this.OperLogStatisForm.Channel,
                        looping.Progress,
                        strLocation,
                        "bibliorecpath",
                        out all_bibliorecpaths,
                        out strError);
                    if (nRet == -1)
                        goto ERROR1;

                    all_bibliorecpaths.Sort();
                    // StringUtil.RemoveDup(ref all_bibliorecpaths);
                    biblio_recpaths.Sort();
                    // StringUtil.RemoveDup(ref biblio_recpaths);

                    string strDebugInfo = "";

                    List<string> targetLeft = new List<string>();
                    List<string> targetMiddle = null;
                    List<string> targetRight = null;

                    nRet = StringUtil.LogicOper("SUB",
            all_bibliorecpaths,
            biblio_recpaths,
            ref targetLeft,
            ref targetMiddle,
            ref targetRight,
            false,
            out strDebugInfo,
            out strError);
                    if (nRet == -1)
                        goto ERROR1;

                    // 删除多余的行
                    strDeleteComment = "内容共 " + targetLeft.Count.ToString() + " 行 (被借阅过的共有 " + tableBook.Count.ToString() + " 种,此馆藏点全部图书 " + all_bibliorecpaths.Count.ToString() + " 种)";
                    if (this.m_nNotBorrowBookTableMaxLine != -1
                        && targetLeft.Count > this.m_nNotBorrowBookTableMaxLine)
                    {
                        targetLeft.RemoveRange(this.m_nNotBorrowBookTableMaxLine,
                            targetLeft.Count - this.m_nNotBorrowBookTableMaxLine);
                        strDeleteComment += "; 只保留了前 " + this.m_nNotBorrowBookTableMaxLine.ToString() + "行";
                    }

                    Table temp = new Table(1);

                    BiblioLoader loader = new BiblioLoader();
                    loader.Channel = channel;   // this.OperLogStatisForm.Channel;
                    loader.Stop = looping.Progress;
                    loader.Format = "summary";
                    loader.GetBiblioInfoStyle = GetBiblioInfoStyle.None;
                    loader.RecPaths = targetLeft;

                    int i = 0;
                    foreach (BiblioItem item in loader)
                    {
                        looping.Progress.SetMessage("正在加入 " + (i + 1).ToString() + "/" + targetLeft.Count.ToString() + " 个书目摘要,可能需要较长时间 ...");

                        temp.SetValue(item.RecPath, 0, item.Content);
                        i++;
                    }

                    temp.Sort("-1:aP");

                    Report report = Report.BuildReport(temp,
                        "图书种路径||bibliorecpath,书目摘要||summary",
                        "&nbsp;",
                        true);

                    if (report != null)
                    {
                        report[1].Sum = false;

                        string strHead = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"><html xmlns=\"http://www.w3.org/1999/xhtml\"><head>"
                            + "<meta http-equiv='Content-Type' content=\"text/html; charset=utf-8\">"
                            + "<title></title>"
                            + "<link rel='stylesheet' href='" + this.ProjectDir + "/style_book.css' type='text/css'>"
                            + "</head><body>"
                            + "<div class='tabletitle'>从没有被借阅过的图书 按图书(种) <br/>" + strLocation + "<br/>[" + this.GetTimeRangeString() + "]</div>"
                            + "<div class='titlecomment'>" + strDeleteComment + "</div>";
                        string strTail = "</body></html>";

                        string strHtml = strHead + report.HtmlTable(temp) + strTail;

                        // this.WriteTextToConsole("</pre>" + strHtml);

                        // 写入输出文件
                        string strOutputFileName = this.NewOutputFileName();
                        this.WriteToOutputFile(strOutputFileName,
                            strHtml,
                            Encoding.UTF8);
                    }
                }
            }

            looping.Progress.SetMessage("");
        }

        this.WriteTextToConsole("输出报表完成。\r\n");
        return;
    ERROR1:
        MessageBox.Show(this.OperLogStatisForm, strError);
    }

    // 将分类号名称定义从文件读入内存
    void LoadClassNames(string strClassNameFile)
    {
        if (File.Exists(strClassNameFile) == false)
            return;

        StreamReader sr = null;

        try
        {
            sr = new StreamReader(strClassNameFile, Encoding.ASCII);
        }
        catch (Exception ex)
        {
            throw new Exception("打开文件 " + strClassNameFile + " 失败: " + ex.Message);
        }

        try
        {
            this.ClassNames = new List<string>();
            for (; ; )
            {
                string strLine = sr.ReadLine();
                if (strLine == null)
                    break;
                if (String.IsNullOrEmpty(strLine) == true)
                    continue;
                this.ClassNames.Add(strLine);
            }
        }
        finally
        {
            sr.Close();
        }

    }


    // 将分类号字符串对预定义的分类号表进行匹配
    string GetClassName(string strClassString)
    {
        if (String.IsNullOrEmpty(strClassString) == true)
            return "?";

        // 如果没有分类号定义,直接返回分类号头部的1字符
        if (this.ClassNames == null
            || this.ClassNames.Count == 0)
            return strClassString.Substring(0, 1);

        string strHead = "";
        string strResult = "";
        for (int i = 0; i < this.ClassNames.Count; i++)
        {
            string strClassName = this.ClassNames[i];
            if (strClassString.Length < strClassName.Length)
                continue;
            if (strHead.Length != strClassName.Length)
                strHead = strClassString.Substring(0, strClassName.Length);

            if (strHead == strClassName)
            {
                // 命中了的,长度更长的才进入strResult
                if (strResult.Length < strClassName.Length)
                    strResult = strClassName;
            }

        }

        if (strResult == "")
            return "?";	// 没有找到
        return strResult;
    }

    // 根据册记录路径和父(种)记录ID构造出种记录路径
    string BuildBiblioRecPath(string strItemRecPath, string strParentID)
    {
        string strItemDbName = Global.GetDbName(strItemRecPath);
        // 根据实体库名获得对应的书目库名
        string strBiblioDbName = this.OperLogStatisForm.MainForm.GetBiblioDbNameFromItemDbName(strItemDbName);

        if (strBiblioDbName == null)
            return null;

        return strBiblioDbName + "/" + strParentID;
    }
}

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 5, 2022

读者统计窗的“注销或删除读者记录”方案重构

main.cs

// 注销或删除读者记录
// 修改历史:
//	2009/8/10 创建
//	2009/9/26
//	2011/4/20 将input.html中的name=action修改为name=operation
// TODO: 要在读者记录<comment>元素中增补内容,记录注销时间,注销前的<state>原有状态值。
//	2011/11/26 增加metadata.xml
//  2022/11/6 用 Looping 重构 this.ReaderStatisForm.Channel 用法

using System;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using System.Drawing;	// Size

using DigitalPlatform;
using DigitalPlatform.Xml;
using DigitalPlatform.Text;
using DigitalPlatform.dp2.Statis;
using DigitalPlatform.LibraryClient;

// for SaveReaderRecord()
using DigitalPlatform.CirculationClient;
using DigitalPlatform.CirculationClient.localhost;

using dp2Circulation;

public class MyStatis : ReaderStatis
{
    Table table = new Table(4);

    string strOutputErrorFilename = ""; // 输出的错误信息文件名
    StreamWriter sw_error = null;

    int nErrorCount = 0;    // 删除时发生错误的读者记录数

    int nSkipCount = 0; // 跳过的册记录数。因操作前状态已经为“注销”

    int nDeleteCount = 0;   // 成功删除的读者记录个数

    string strAction = "";  // 动作

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        this.ClearConsoleForPureTextOutputing();

        // 获得输入参数
        HtmlInputDialog window = new HtmlInputDialog();

        window.Text = "注销或删除读者记录 -- 指定参数";
        window.Url = this.ProjectDir + "\\input.html";
        window.Size = new Size(700, 500);
        window.ShowDialog();
        if (window.DialogResult != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        string strError = "";

        if (window.SubmitUrl == "action://ok/")
        {
            strAction = window.SubmitResult["operation"];
        }
        else
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        if (strAction == "delete")
        {
            // 警告
            DialogResult result = MessageBox.Show(this.ReaderStatisForm,
                "警告:读者库记录一旦删除就无法恢复。确实要删除读者库中指定范围的记录?\r\n\r\n(OK 删除;Cancel 放弃)",
                "删除读者记录",
                MessageBoxButtons.OKCancel,
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2);
            if (result == DialogResult.Cancel)
            {
                e.Continue = ContinueType.SkipAll;
                return;
            }
        }


        strOutputErrorFilename = this.ProjectDir + "\\error.txt";

        sw_error = new StreamWriter(strOutputErrorFilename,
                    false,  // append
                    Encoding.GetEncoding(936)); // gb2312
        sw_error.Write("<pre>\r\n");
    }

    public override void OnRecord(object sender, StatisEventArgs e)
    {
        string strError = "";
        int nRet = 0;

        // 读者条码
        string strReaderBarcode = DomUtil.GetElementText(this.ReaderDom.DocumentElement, "barcode");

        this.WriteTextToConsole(this.CurrentRecordIndex.ToString() + " : " + strReaderBarcode + "\r\n");

        // 读者姓名
        string strReaderName = DomUtil.GetElementText(this.ReaderDom.DocumentElement, "name");

        // 单位名称
        string strDepartment = DomUtil.GetElementText(this.ReaderDom.DocumentElement, "department");

        string strSummary = strReaderName + " " + strReaderBarcode + " " + strDepartment;

        byte[] baNewTimestamp = null;
        string strSavedPath = "";
        string strSavedXml = "";

        if (strAction == "delete")
        {
            // 删除读者记录
            nRet = this.SaveReaderRecord(
                this.CurrentRecPath,
                        "delete",
                this.Xml,
                        this.Timestamp,
                        "", // strNewXml,
                        out baNewTimestamp,
                        out strSavedPath,
                        out strSavedXml,
                        out strError);
            if (nRet == -1)
            {
                nErrorCount++;
                sw_error.Write("读者记录 [" + strSummary + "] " + this.CurrentRecPath + " 删除时发生错误: " + strError + "\r\n");
            }
            else
            {
                nDeleteCount++;
            }
        }
        else
        {
            string strState = DomUtil.GetElementText(this.ReaderDom.DocumentElement, "state");
            if (strAction == "nullify" && strState == "注销")
            {
                nSkipCount++;
                return; // 已经在注销状态了
            }


            DomUtil.SetElementText(this.ReaderDom.DocumentElement, "state", "注销");

            // 注销读者记录
            nRet = this.SaveReaderRecord(
                this.CurrentRecPath,
                        "change",
                this.Xml,
                        this.Timestamp,
                        this.ReaderDom.DocumentElement.OuterXml,    // strNewXml,
                        out baNewTimestamp,
                        out strSavedPath,
                        out strSavedXml,
                        out strError);
            if (nRet == -1)
            {
                nErrorCount++;
                sw_error.Write("读者记录 [" + strSummary + "] " + this.CurrentRecPath + " 注销时发生错误: " + strError + "\r\n");
            }
            else
            {
                nDeleteCount++;
            }

        }

        return;
    ERROR1:
        MessageBox.Show(this.ReaderStatisForm, strError);
        e.Continue = ContinueType.SkipAll;
    }

    public override void FreeResources()
    {
        if (sw_error != null)
        {
            sw_error.Close();
            sw_error = null;
        }
    }

    public override void OnEnd(object sender, StatisEventArgs e)
    {
        if (sw_error != null)
        {
            sw_error.Close();
            sw_error = null;
        }

        string strText = "";

        strText = "共"
            + (strAction == "delete" ? "删除" : "注销")
            + "读者记录 " + nDeleteCount.ToString() + " 个。";

        if (strAction == "nullify")
        {
            if (nSkipCount != 0)
                strText += "有 "
                    + nSkipCount.ToString()
                    + " 条册记录被跳过(因在操作前其状态已经为“注销”)。";
        }

        if (nErrorCount > 0)
        {
            strText += "\r\n\r\n错误信息 " + nErrorCount.ToString() + " 条,请看文件 " + strOutputErrorFilename + " (在读者统计窗的打印结果里面可以看到)";

            // 写入打印输出文件
            string strPrintFile = this.NewOutputFileName();
            File.Copy(this.strOutputErrorFilename, strPrintFile, true);
        }

        MessageBox.Show(this.ReaderStatisForm, strText);

        /*
                // 写入输出文件
                string strOutputFileName = this.NewOutputFileName();
                this.WriteToOutputFile(strOutputFileName,
                    strHtml,
                    Encoding.UTF8);
        */

    }

    // 保存读者记录
    public int SaveReaderRecord(
        string strRecPath,
        string strAction,
        string strOldXml,
        byte[] baOldTimestamp,
        string strNewXml,
        out byte[] baNewTimestamp,
        out string strSavedPath,
        out string strSavedXml,
        out string strError)
    {
        strError = "";
        baNewTimestamp = null;
        strSavedXml = "";
        strSavedPath = "";

        using (var looping = this.ReaderStatisForm.Looping(out LibraryChannel channel))
        {
            long lRet = channel.SetReaderInfo(
                looping.Progress,
                strAction,
                strRecPath,
                strNewXml,
                strOldXml, // this.readerEditControl1.OldRecord,
                baOldTimestamp,
                out string strExistingXml,
                out strSavedXml,
                out strSavedPath,
                out baNewTimestamp,
                out ErrorCodeValue kernel_errorcode,
                out strError);
            if (lRet == -1)
                return -1;

            if (lRet == 1)
            {
                // 部分字段被拒绝
            }

            return (int)lRet;
        }
    }

}


@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 5, 2022

册统计窗“注销或删除册记录”方案重构

main.cs

// 注销或删除册记录
// 修改历史:
// 2009/9/25 创建
// 2009/10/21 修改出错提示
// 2011/4/20 input.html中name=action修改为name=operation
// 2011/11/26 增加metadata.xml
// 2012/4/18 修改SaveEntityRecord()函数,避免错误地返回-1
// 2022/11/6 用 Looping 重构 this.ItemStatisForm.Channel 用法

using System;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;
using System.Drawing;	// Size

using dp2Circulation;

using DigitalPlatform;
using DigitalPlatform.Xml;
using DigitalPlatform.dp2.Statis;
using DigitalPlatform.LibraryClient;

// for SaveEntityRecord()
using DigitalPlatform.CirculationClient;
using DigitalPlatform.CirculationClient.localhost;


public class MyStatis : ItemStatis
{
    string strOutputErrorFilename = ""; // 输出的错误信息文件名
    StreamWriter sw_error = null;

    int nErrorCount = 0;    // 发生错误的册记录数

    int nSkipCount = 0; // 跳过的册记录数。因操作前状态已经为“注销”

    int nDeleteCount = 0;   // 成功删除的册记录个数

    string strAction = "";  // 动作

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        this.ClearConsoleForPureTextOutputing();

        // 获得输入参数
        HtmlInputDialog window = new HtmlInputDialog();

        window.Text = "注销或删除册记录 -- 指定参数";
        window.Url = this.ProjectDir + "\\input.html";
        window.Size = new Size(700, 500);
        window.ShowDialog();
        if (window.DialogResult != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        string strError = "";

        if (window.SubmitUrl == "action://ok/")
        {
            strAction = window.SubmitResult["operation"];
        }
        else
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        if (strAction == "delete")
        {
            // 警告
            DialogResult result = MessageBox.Show(this.ItemStatisForm,
                "警告:册记录一旦删除就无法恢复。确实要删除实体库中指定范围的册记录?\r\n\r\n(OK 删除;Cancel 放弃)",
                "删除册记录",
                MessageBoxButtons.OKCancel,
                MessageBoxIcon.Question,
                MessageBoxDefaultButton.Button2);
            if (result == DialogResult.Cancel)
            {
                e.Continue = ContinueType.SkipAll;
                return;
            }
        }


        strOutputErrorFilename = this.ProjectDir + "\\~error.txt";  // 带有~才会被Project管理模块自动删除或者忽略

        sw_error = new StreamWriter(strOutputErrorFilename,
                    false,  // append
                    Encoding.GetEncoding(936)); // gb2312
        sw_error.Write("<pre>\r\n");

    }


    // 保存实体记录
    // 不负责刷新界面和报错
    int SaveEntityRecord(
    string strBiblioRecPath,
    string strItemRecPath,
    string strAction,
    string strOldXml,
            byte[] baOldTimestamp,
    string strNewXml,
    out string strError)
    {
        strError = "";


        EntityInfo[] entities = new EntityInfo[1];
        EntityInfo info = new EntityInfo();

        info.Action = strAction;
        info.OldRecPath = strItemRecPath;
        info.NewRecPath = strItemRecPath;

        info.NewRecord = strNewXml;
        info.NewTimestamp = null;

        info.OldRecord = strOldXml;
        info.OldTimestamp = baOldTimestamp;

        info.RefID = "refid";

        entities[0] = info;

        using (var looping = this.ItemStatisForm.Looping(out LibraryChannel channel))
        {
            long lRet = channel.SetEntities(
                looping.Progress,
                strBiblioRecPath,
                entities,
                out EntityInfo[] errorinfos,
                out strError);
            if (lRet == -1)
                return -1;

            // 获取数组中的错误信息
            for (int i = 0; i < errorinfos.Length; i++)
            {
                if (errorinfos[i].ErrorCode != ErrorCodeValue.NoError)
                {
                    if (i > 0)
                        strError += "; ";
                    strError += errorinfos[i].ErrorInfo;
                    return -1;  // 2012/4/18 移动到这里
                }
            }

            return (int)lRet;
        }
    }

    public override void OnRecord(object sender, StatisEventArgs e)
    {
        string strError = "";
        int nRet = 0;

        // 册条码
        string strItemBarcode = DomUtil.GetElementText(this.ItemDom.DocumentElement, "barcode");

        this.WriteTextToConsole(this.CurrentRecordIndex.ToString() + " : " + strItemBarcode + "\r\n");

        byte[] baNewTimestamp = null;
        string strSavedPath = "";
        string strSavedXml = "";

        if (strAction == "delete")
        {
            // 删除册记录
            nRet = SaveEntityRecord(
                this.CurrentBiblioRecPath,
                this.CurrentRecPath,
                "delete",
                this.Xml,
                this.Timestamp,
                "", // strNewXml,
                out strError);
            if (nRet == -1)
            {
                nErrorCount++;
                sw_error.Write("册记录 [册条码:" + strItemBarcode + "] " + this.CurrentRecPath + " 删除时发生错误: " + strError + "\r\n");
            }
            else
            {
                nDeleteCount++;
            }
        }
        else
        {
            string strState = DomUtil.GetElementText(this.ItemDom.DocumentElement, "state");
            if (strAction == "nullify" && strState == "注销")
            {
                nSkipCount++;
                return; // 已经在注销状态了
            }


            DomUtil.SetElementText(this.ItemDom.DocumentElement, "state", "注销");

            // 注销册记录
            nRet = SaveEntityRecord(
                this.CurrentBiblioRecPath,
                this.CurrentRecPath,
                "change",
                this.Xml,
                this.Timestamp,
                this.ItemDom.DocumentElement.OuterXml,  // strNewXml,
                out strError);
            if (nRet == -1)
            {
                nErrorCount++;
                sw_error.Write("册记录 [册条码:" + strItemBarcode + "] " + this.CurrentRecPath + " 注销时发生错误: " + strError + "\r\n");
            }
            else
            {
                nDeleteCount++;
            }
        }

        return;
    ERROR1:
        MessageBox.Show(this.ItemStatisForm, strError);
        e.Continue = ContinueType.SkipAll;
    }

    public override void FreeResources()
    {
        if (sw_error != null)
        {
            sw_error.Close();
            sw_error = null;
        }
    }

    public override void OnEnd(object sender, StatisEventArgs e)
    {
        if (sw_error != null)
        {
            sw_error.Close();
            sw_error = null;
        }

        string strText = "";

        strText = "共"
            + (strAction == "delete" ? "删除" : "注销")
            + "册记录 " + nDeleteCount.ToString() + " 个。";

        if (strAction == "nullify")
        {
            if (nSkipCount != 0)
                strText += "有 "
                    + nSkipCount.ToString()
                    + " 条册记录被跳过(因在操作前其状态已经为“注销”)。";
        }

        if (nErrorCount > 0)
        {
            strText += "\r\n\r\n错误信息 " + nErrorCount.ToString() + " 条,请看文件 " + strOutputErrorFilename + " (在册统计窗的打印结果里面可以看到)";

            // 写入打印输出文件
            string strPrintFile = this.NewOutputFileName();
            File.Copy(this.strOutputErrorFilename, strPrintFile, true);
        }

        MessageBox.Show(this.ItemStatisForm, strText);
    }
}

@DigitalPlatform
Copy link
Owner Author

书目统计窗“添加封面图像”方案重构

main.cs

/**
 * 添加封面图像
 * 创建时间:2015/1/29
 * 如果已经有了 856 $3Cover image 则不再重复加入
 * 2015/1/30 增加对多个 ISBN 的顺序处理机制;能分别对不同国家的 ISBN 针对不同国家的亚马逊服务器发出请求
 * 2022/11/5 用 HasLooping() 重构 this.BiblioStatisForm.Progress 用法
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using System.IO;
using System.Text;
using System.Xml;

using dp2Circulation;

using DigitalPlatform;
using DigitalPlatform.GUI;
using DigitalPlatform.Xml;
using DigitalPlatform.Text;
using DigitalPlatform.IO;
using DigitalPlatform.Marc;
using DigitalPlatform.Script;
using DigitalPlatform.AmazonInterface;

public class AndCover : BiblioStatis
{
    public string ResultString = "";	// MARC过滤器输出结果


    AmazonSearchForm _dlg = null;
    BiblioSearchForm _searchForm = null;

    StreamWriter sw = null;
    StreamWriter success_sw = null;
    StreamWriter dup_sw = null;

    CommentViewerForm m_commentViewer = null;

    bool bSkipDup = false;
    bool bSelectFirstItem = false;
    int _count = 0;
    int _addCoverCount = 0;
    int _noAddCoverCount = 0;
    int _dupCount = 0;

    public override void FreeResources()
    {
        if (this.sw != null)
        {
            this.sw.Close();
            this.sw = null;
        }
        if (this.success_sw != null)
        {
            this.success_sw.Close();
            this.success_sw = null;
        }

        if (this.dup_sw != null)
        {
            this.dup_sw.Close();
            this.dup_sw = null;
        }
    }

    public override void OnBegin(object sender, StatisEventArgs e)
    {
        this.ClearConsoleForPureTextOutputing();

        FolderBrowserDialog dlg = new FolderBrowserDialog()
        {
            Description = "指定文件输出目录:",
            RootFolder = Environment.SpecialFolder.MyComputer,
            ShowNewFolderButton = true,
        };
        if (dlg.ShowDialog() != DialogResult.OK)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        string strSourceDir = dlg.SelectedPath;

        DialogResult result = MessageBox.Show(this.BiblioStatisForm,
            "如果命中多条是否处理?\r\n\r\n【是】处理,需要人工值守。\r\n【否】跳过或默认选择第一项。\r\n【取消】退出。",
            "命中多条处理方式",
            MessageBoxButtons.YesNoCancel,
            MessageBoxIcon.Asterisk,
            MessageBoxDefaultButton.Button2);
        if (result == DialogResult.No)
        {
            DialogResult dialogResult = MessageBox.Show(this.BiblioStatisForm,
                "命中多条是否跳过?\r\n\r\n【是】跳过\r\n【否】默认选择第一项",
                "是否跳过",
                MessageBoxButtons.YesNo,
                MessageBoxIcon.Asterisk,
                MessageBoxDefaultButton.Button1);
            if (dialogResult == DialogResult.Yes)
            {
                bSkipDup = true;

                dup_sw = new StreamWriter(strSourceDir + "\\~跳过的记录.txt",
                    false,// append
                    Encoding.UTF8);
            }
            else
            {
                bSelectFirstItem = true;
                dup_sw = new StreamWriter(strSourceDir + "\\~默认选择第一个封面的记录.txt",
                    false,// append
                    Encoding.UTF8);
            }
        }
        else if (result == DialogResult.Cancel)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        this.BiblioStatisForm.MainForm.PanelFixedVisible = true;
        this.BiblioStatisForm.MainForm.ActivatePropertyPage();

        sw = new StreamWriter(strSourceDir + "\\~没加入封面的记录.txt",
                false,// append
                Encoding.UTF8);

        success_sw = new StreamWriter(strSourceDir + "\\~加入封面的记录.txt",
                false,// append
                Encoding.UTF8);

        _dlg = new AmazonSearchForm()
        {
            Size = new System.Drawing.Size(550, 300),
            TempFileDir = this.BiblioStatisForm.MainForm.DataDir,
            UiState = this.BiblioStatisForm.MainForm.AppInfo.GetString("TestForm", "AmazonSearchForm_uiState", ""),
            From = "ISBN",
            FloatingMode = true,
        };
        MainForm.SetControlFont(_dlg, this.BiblioStatisForm.MainForm.Font, false);
        _dlg.FormClosing += new FormClosingEventHandler(this._dlg_FormClosing);
        _dlg.FormClosed += new FormClosedEventHandler(this._dlg_FormClosed);
        _dlg.Show(this.BiblioStatisForm);
    }

    void _dlg_FormClosing(object sender, FormClosingEventArgs e)
    {
        if (this.BiblioStatisForm.HasLooping())
        {
            MessageBox.Show(this.BiblioStatisForm, "请在关闭窗口前停止正在进行的长时操作。");
            e.Cancel = true;
            return;
        }
        /*
        if (this.BiblioStatisForm != null)
        {
            if (this.BiblioStatisForm.Progress != null)
            {
                if (this.BiblioStatisForm.Progress.State == 0)    // 0 表示正在处理
                {
                    MessageBox.Show(this.BiblioStatisForm, "请在关闭窗口前停止正在进行的长时操作。");
                    e.Cancel = true;
                    return;
                }
            }
        }
        */
    }

    void _dlg_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (_dlg != null && this.BiblioStatisForm != null)
        {
            if (this.BiblioStatisForm.MainForm == null)
                return;

            this.BiblioStatisForm.MainForm.AppInfo.UnlinkFormState(_dlg);
            this.BiblioStatisForm.MainForm.AppInfo.SetString(
              "TestForm",
              "AmazonSearchForm_uiState",
              _dlg.UiState);
            _dlg = null;
        }
    }

    public override void OnRecord(object sender, StatisEventArgs e)
    {
        bool bChanged = false;

        if (_dlg == null)
        {
            e.Continue = ContinueType.SkipAll;
            return;
        }

        string strError = "";
        int nRet = 0;
        this._count++; // 计总数

        MarcRecord record = new MarcRecord(this.MarcRecord);
        // 如果数据中已经存在
        MarcNodeList subfields = record.select("field[@name='856']/subfield[@name='3']");
        if (subfields.count > 0)
        {
            foreach (MarcSubfield subfield in subfields)
            {
                // if (subfield.Content == "Cover image")
                if (subfield.Content.Replace(" ", "").ToLower() == "coverimage")
                    return;
            }
        }

        string strBiblioDbName = Global.GetDbName(CurrentRecPath);
        string strSyntax = this.BiblioStatisForm.MainForm.GetBiblioSyntax(strBiblioDbName);
        string strISBnFieldName = "";
        if (strSyntax == "unimarc")
            strISBnFieldName = "010";
        else
            strISBnFieldName = "020";

        MarcNodeList nodes = record.select("field[@name='" + strISBnFieldName + "']/subfield[@name='a']");
        foreach (MarcNode node in nodes)
        {
            string strISBN = node.Content.Replace("-", "");
            if (String.IsNullOrEmpty(strISBN))
                continue;
            nRet = IsbnSplitter.VerifyISBN(strISBN, out strError);
            if (nRet != 0)
                continue;

            string strServerUrl = GetServerUrl(strISBN);
            if (String.IsNullOrEmpty(strServerUrl))
                continue;

            REDO_SEARCH:
            _dlg.QueryWord = strISBN;
            nRet = _dlg.DoSearch(out strError);
            if (nRet == -1)
            {
                DialogResult result = AutoCloseMessageBox.Show(_dlg,
                    strError + "\r\n\r\n点右上角关闭按钮停止自动重试并继续处理下一条",
                            10 * 1000,
                            "检索出错");
                if (result != DialogResult.Cancel)
                    goto REDO_SEARCH;
            }

            if (_dlg.SelectedItem == null)
                break;

            if (nRet == 0)
                continue;

            if (nRet > 1)
            {
                if (bSkipDup)
                {
                    dup_sw.WriteLine(this.CurrentRecPath);
                    this._dupCount++; // 跳过的记录数
                    return;
                }
                else if (bSelectFirstItem == true)
                {
                    dup_sw.WriteLine(this.CurrentRecPath);
                    this._dupCount++; // 默认选择第一项的记录数
                }
                else
                {

                    DoViewComment(this.CurrentRecPath, record, strSyntax);

                    // 出现透明提示
                    _dlg.SetFloatMessage("", "命中 " + nRet.ToString() + " 条,请选择(可与【属性】页内容比对) ...");
                    _dlg.Activate();
                    bool bRet = _dlg.WaitSelect();
                    // 清除透明显示
                    _dlg.SetFloatMessage("", "");
                    if (bRet == false)
                        break;
                }
            }

            Hashtable table = _dlg.GetImageUrls(_dlg.SelectedItem.Xml);
            foreach (string name in table.Keys)
            {
                AmazonSearch.ImageInfo info = table[name] as AmazonSearch.ImageInfo;

                MarcField field = new MarcField("856", "42");
                record.ChildNodes.insertSequence(field);

                field.ChildNodes.add(new MarcSubfield("3", "Cover image"));
                field.ChildNodes.add(new MarcSubfield("u", info.Url));
                field.ChildNodes.add(new MarcSubfield("q", AmazonSearch.GetMime(info.Url)));

                field.ChildNodes.add(new MarcSubfield("x", "type:FrontCover." + name + ";size:" + info.Size
                    + ";source:Amazon:" + _dlg.SelectedItem.ASIN));

                bChanged = true;
            }
        }

        if (bChanged == true)
        {
            nRet = this.SaveMarcRecord(record.Text, out strError);
            if (nRet == -1)
            {
                this.WriteToConsole("书目记录 " + this.CurrentRecPath + " 处理中出错: " + strError + "<br />");
            }
            else
            {
                success_sw.WriteLine(this.CurrentRecPath);
                this._addCoverCount++; // 加入封面的记录数
            }
        }
        else
        {
            sw.WriteLine(this.CurrentRecPath);
            this._noAddCoverCount++; // 没有加入封面的记录数
        }
    }


    string GetServerUrl(string strISBN)
    {
        string strError = "";
        string strServerUrl = "";

        if (string.IsNullOrEmpty(strISBN) == false)
        {
            strISBN = strISBN.Trim();
            int index = strISBN.IndexOf(" ");
            if (index != -1)
            {
                strISBN = strISBN.Substring(0, index).Trim();
            }
        }

        if (string.IsNullOrEmpty(strISBN) == true)
            return null;

        Debug.Assert(this.BiblioStatisForm != null, "this.BiblioStatisForm == null");
        Debug.Assert(this.BiblioStatisForm.MainForm != null, "this.BiblioStatisForm.MainForm == null");

        int nRet = this.BiblioStatisForm.MainForm.LoadIsbnSplitter(true, out strError);
        if (nRet == -1)
        {
            strError = "在取出版社号前,发现ISBN号中没有横杠,在加入横杠的过程中,出现错误: " + strError;
            return null;
        }

        Debug.Assert(this.BiblioStatisForm.MainForm.IsbnSplitter != null,
            "this.BiblioStatisForm.MainForm.IsbnSplitter == null");
        string strOutputISBN = "";
        nRet = this.BiblioStatisForm.MainForm.IsbnSplitter.IsbnInsertHyphen(strISBN,
            "force10",
            out strOutputISBN,
            out strError);
        if (nRet != -1)
        {
            string strHead = "";
            string strOther = "";

            StringUtil.ParseTwoPart(strOutputISBN, "-", out strHead, out strOther);

            if (strHead == "7")
                strServerUrl = "webservices.amazon.cn";  // 中国
            else
                strServerUrl = "webservices.amazon.com";  // 美国

        }
        else
            strServerUrl = "webservices.amazon.cn";  // 中国

        return strServerUrl;
    }


    void DoViewComment(string strRecPath, MarcRecord record, string strSyntax)
    {
        string strHtml = GetBiblioHtml(record, strSyntax);

        if (this.m_commentViewer == null)
        {
            this.m_commentViewer = new CommentViewerForm();
            MainForm.SetControlFont(m_commentViewer, this.BiblioStatisForm.MainForm.Font, false);
            this.m_commentViewer.MainForm = this.BiblioStatisForm.MainForm;  // 必须是第一句
            this.m_commentViewer.InitialWebBrowser();
        }

        m_commentViewer.Text = strRecPath;
        m_commentViewer.HtmlString = strHtml;

        if (this.BiblioStatisForm.MainForm.CurrentPropertyControl != m_commentViewer.MainControl)
            m_commentViewer.DoDock(false);
    }

    static string GetBiblioHtml(MarcRecord record, string strSyntax)
    {
        string strTitle = "";
        string strSubtitle = "";
        string strSeries = "";
        string strAuthor = "";
        string strPublisher = "";
        string strPubDate = "";
        if (strSyntax == "unimarc")
        {
            strTitle = record.select("field[@name='200']/subfield[@name='a']").FirstContent;
            strSubtitle = record.select("field[@name='200']/subfield[@name='e']").FirstContent;
            strSeries = record.select("field[@name='225']/subfield[@name='a']").FirstContent;
            strAuthor = record.select("field[@name='200']/subfield[@name='f' or @name='g']").FirstContent;
            strPublisher = record.select("field[@name='210']/subfield[@name='c']").FirstContent;
            strPubDate = record.select("field[@name='210']/subfield[@name='d']").FirstContent;
        }
        else
        {
            strTitle = record.select("field[@name='245']/subfield[@name='a']").FirstContent;
            strSubtitle = record.select("field[@name='245']/subfield[@name='b']").FirstContent;
            strSeries = record.select("field[@name='440']/subfield[@name='a']").FirstContent;
            strAuthor = record.select("field[@name='245']/subfield[@name='c']").FirstContent;
            strPublisher = record.select("field[@name='260']/subfield[@name='b']").FirstContent;
            strPubDate = record.select("field[@name='260']/subfield[@name='c']").FirstContent;
        }
        StringBuilder sb = new StringBuilder(512);
        sb.Append("<html><head>");
        sb.Append("<link href='%mappeddir%\\styles\\biblio.css' type='text/css' rel='stylesheet' />");
        sb.Append("<link href=\"%mappeddir%/jquery-ui-1.8.7/css/jquery-ui-1.8.7.css\" rel=\"stylesheet\" type=\"text/css\" />");
        sb.Append("<script type=\"text/javascript\" src=\"%mappeddir%/jquery-ui-1.8.7/js/jquery-1.4.4.min.js\"></script>");
        sb.Append("<script type=\"text/javascript\" src=\"%mappeddir%/jquery-ui-1.8.7/js/jquery-ui-1.8.7.min.js\"></script>");
        sb.Append("<script type='text/javascript' charset='UTF-8' src='%datadir%\\getsummary.js'></script>");
        sb.Append("</head><body>");
        sb.Append("<table class='biblio'>");

        // 题名
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>题名</td>");
        sb.Append("<td class='value' width='90%'>").Append(strTitle).Append("</td>");
        sb.Append("</tr>");

        // 副题名
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>副题名</td>");
        sb.Append("<td class='value' width='90%'>").Append(strSubtitle).Append("</td>");
        sb.Append("</tr>");

        // 丛编
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>丛编</td>");
        sb.Append("<td class='value' width='90%'>(").Append(strSeries).Append(")</td>");
        sb.Append("</tr>");

        // 作者
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>责任者</td>");
        sb.Append("<td class='value' width='90%'>").Append(strAuthor).Append("</td>");
        sb.Append("</tr>");

        // 出版者
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>出版者</td>");
        sb.Append("<td class='value' width='90%'>").Append(strPublisher).Append("</td>");
        sb.Append("</tr>");

        // 出版时间
        sb.Append("<tr class='content title'>");
        sb.Append("<td class='name' width='10%' nowrap>出版时间</td>");
        sb.Append("<td class='value' width='90%'>").Append(strPubDate).Append("</td>");
        sb.Append("</tr>");

        sb.Append("</table>");
        sb.Append("</body></html>");

        return sb.ToString();
    }


    public override void OnEnd(object sender, StatisEventArgs e)
    {
        if (this.sw != null)
        {
            this.sw.Close();
            this.sw = null;
        }

        if (this.success_sw != null)
        {
            this.success_sw.Close();
            this.success_sw = null;
        }

        if (this.dup_sw != null)
        {
            this.dup_sw.Close();
            this.dup_sw = null;
        }

        StringBuilder sb = new StringBuilder(256);
        sb.Append(String.Format("共处理【{0}】条记录,其中【{1}】条加入封面图像",
            this._count.ToString(),
            this._addCoverCount.ToString()));
        if (bSkipDup)
        {
            sb.Append(String.Format("(【{0}】条命中多项,跳过未处理)", this._dupCount.ToString()));
        }
        else if (bSelectFirstItem)
        {
            sb.Append(String.Format("(【{0}】条命中多项,默认选择第一项)", this._dupCount.ToString()));
        }

        sb.Append(String.Format(",【{0}】条未查到封面。", this._noAddCoverCount.ToString()));

        this.WriteToConsole(sb.ToString());
    }
}

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 5, 2022

框架窗口“打印书本型格式”方案重构

main.cs

// 打印书本型格式
// 修改历史:
// 2022/11/6 用 Looping 重构 BiblioSearchForm.Progress 用法

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;
using System.Xml;

using DigitalPlatform.IO;
using DigitalPlatform.LibraryClient;
using DigitalPlatform.Marc;
using DigitalPlatform.Xml;

using dp2Circulation;

public class PrintBiblioStyle : MainFormHost
{
    public override void Main(object sender, EventArgs e)
    {
        string strError = "";

        BiblioSearchForm search_form = this.MainForm.EnsureChildForm<BiblioSearchForm>();
        // search_form.BeginLoop("halfstop", "正在处理记录");
        using (var looping = search_form.Looping(out LibraryChannel channel, 
            null,
            "halfstop"))
        {
            int iRecord = 0;
            int nRet = 0;

            StringBuilder sb = new StringBuilder(256);
            // search_form.Progress.SetProgressRange(0, search_form.ListViewRecords.Items.Count);
            looping.Progress.SetProgressRange(0, search_form.ListViewRecords.Items.Count);
            foreach (ListViewItem item in search_form.ListViewRecords.Items)
            {
                // if (search_form.IsStopped() == true)
                if (looping.Stopped)
                {
                    strError = "用户中断";
                    goto ERROR1;
                }

                string strRecPath = item.Text;
                // LibraryChannel channel = this.MainForm.GetChannel();
                try
                {
                    string strTableFormats = "table:title_area|publication_area|material_description_area|resource_identifier_area|summary|series_area|notes_area|clc_class";
                    string strResultXml = "xml";
                    List<string> formats = new List<string> { strTableFormats, strResultXml };
                    string[] results = null;
                    byte[] timestamp = null;
                    long lRet = channel.GetBiblioInfos(
                        looping.Progress,   // this.MainForm.Stop,
                        strRecPath,
                        "",
                        formats.ToArray(),
                        out results,
                        out timestamp,
                        out strError);
                    if (lRet == -1 || lRet == 0)
                    {
                        if (lRet == 0 && String.IsNullOrEmpty(strError) == true)
                            strError = "书目记录 '" + strRecPath + "' 不存在";

                        goto ERROR1;
                    }
                    else
                    {
                        Debug.Assert(results != null && results.Length == formats.Count, "results必须包含 " + formats.Count + " 个元素");

                        string strRecordID = "";
                        MarcRecord record = null;
                        nRet = ConverterMarcRecord(results[1], out record, out strError);
                        if (nRet != -1)
                            strRecordID = record.select("field[@name='001']").FirstContent;
                        else
                            MessageBox.Show(strError);

                        // MessageBox.Show(this.MainForm, strRecordID + "\r" + record.Text);

                        string strResult = results[0];// DomUtil.GetIndentXml(results[0]); // DomUtil.GetIndentXml(results[0]).Replace("\"", "\'");

                        XmlDocument dom = new XmlDocument();
                        dom.LoadXml(strResult);

                        string clc_class = record.select("field[@name='690']/subfield[@name='a']").FirstContent; // DomUtil.GetAttr(dom.DocumentElement, "line[@type='clc_class']", "value");


                        string resource_identifier_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='resource_identifier_area']", "value");
                        resource_identifier_area = resource_identifier_area.Replace("ISBN ", "").Replace("ISSN", "").Replace("统一书刊号", "");
                        // string isbn = DomUtil.GetElementText(dom.DocumentElement, "isbn");
                        string title_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='title_area']", "value");
                        string publication_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='publication_area']", "value");
                        string material_description_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='material_description_area']", "value");
                        // string price = DomUtil.GetElementText(dom.DocumentElement, "price");
                        string summary = DomUtil.GetAttr(dom.DocumentElement, "line[@type='summary']", "value");

                        string series_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='series_area']", "value");

                        string notes_area = DomUtil.GetAttr(dom.DocumentElement, "line[@type='notes_area,notes']", "value");

                        if (!string.IsNullOrEmpty(strRecordID))
                        {
                            sb.Append("<p>").Append(strRecordID);
                            if (!string.IsNullOrEmpty(clc_class))
                                sb.Append(clc_class.PadLeft(22, ' '));
                            sb.Append("</p>");
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(clc_class))
                                sb.Append("<p>").Append(clc_class.PadLeft(22, ' ')).Append("</p>");
                        }

                        if (!string.IsNullOrEmpty(title_area))
                            sb.Append("<p><font size='10' style='bold'>").Append(title_area).Append("</font></p>");

                        if (!string.IsNullOrEmpty(publication_area))
                        {
                            sb.Append("<p>").Append(publication_area);
                            if (!string.IsNullOrEmpty(material_description_area))
                                sb.Append(". -- ").Append(material_description_area);
                            if (!string.IsNullOrEmpty(notes_area))
                                sb.Append(". -- ").Append(notes_area.Replace("一般性附注: ", ""));
                            sb.Append("</p>");
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(material_description_area))
                            {
                                sb.Append("<p>").Append(material_description_area);
                                if (!string.IsNullOrEmpty(notes_area))
                                    sb.Append(". -- ").Append(notes_area.Replace("一般性附注: ", ""));
                                sb.Append("</p>");
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(notes_area))
                                    sb.Append("<p>").Append(notes_area.Replace("一般性附注: ", "")).Append("</p>");
                            }
                        }

                        if (!string.IsNullOrEmpty(series_area))
                            sb.Append("<p>").Append(series_area).Append("</p>");

                        if (!string.IsNullOrEmpty(summary))
                            sb.Append("<p>  ").Append(summary.Replace("提要文摘: ", "")).Append("</p>");
                        // sb.Append("<p>").Append(summary).Append("</p>");

                        if (!string.IsNullOrEmpty(resource_identifier_area))
                            sb.Append("<p>").Append(resource_identifier_area.Replace("ISBN ", "")).Append("</p>");
                        // sb.Append("<p>").Append(resource_identifier_area).Append("</p>");

                        sb.Append("<p></p>");
                        // MessageBox.Show(this.MainForm, sb.ToString());
                    }
                }
                finally
                {
                    // this.MainForm.ReturnChannel(channel);
                }

                // search_form.Progress.SetProgressValue(++iRecord);
                looping.Progress.SetProgressValue(++iRecord);
            }

            string strOutputFilename = PathUtil.MergePath(this.MainForm.DataDir, "~printbibliostyle.xml");
            using (StreamWriter sw = new StreamWriter(strOutputFilename,
                false,  // append
                Encoding.UTF8))
            {
                string dataxml = DomUtil.GetIndentXml(WrapString(sb.ToString()));
                sw.Write(dataxml);
            }

            CardPrintForm form = new CardPrintForm();   // 总是新打开一个CardPrintForm
                                                        // 故意不设置MdiParent,可以避免出纳窗在最大化的时候调用打印出现问题
            form.MainForm = this.MainForm;
            form.PrinterInfo = this.MainForm.PreparePrinterInfo("书本型");
            form.CardFilename = strOutputFilename;  // 卡片文件名
            form.TestingGrid = false;   // 不打印调试线
            form.WindowState = FormWindowState.Minimized;
            form.Show();

            nRet = form.PrintFromCardFile(true);
            if (nRet == -1)
            {
                form.MdiParent = this.MainForm;
                form.WindowState = FormWindowState.Normal;
                strError = strError + "\r\n\r\n以下内容未能成功打印:\r\n" + sb.ToString();
                goto ERROR1;
            }

            form.Close();
        }

        return;
    ERROR1:
        MessageBox.Show(this.MainForm, strError);
    }

    static int ConverterMarcRecord(string xml,
        out MarcRecord record,
        out string strError)
    {
        record = null;
        strError = "";

        string strOutMarcSyntax = "";
        string strMarc = "";
        int nRet = MarcUtil.Xml2Marc(xml,
            false,
            "unimarc",
            out strOutMarcSyntax,
            out strMarc,
            out strError);
        if (nRet == -1)
            return -1;

        record = new MarcRecord(strMarc);
        return 1;
    }


    static string WrapString(string strText)
    {
        string strPrefix = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
            + "<root>\r\n"
            + "<pageSetting width='410'>\r\n"
            + "  <font name=\"新宋体\" size=\"10\" />\r\n"
            + "  <p align=\"left\" indent='0' lineBreak=\"word\" />\r\n"
            + "</pageSetting>\r\n"
            + "<document padding=\"30,60,30,60\">\r\n"
            + "  <column width=\"auto\" padding='10,0,5,0'>\r\n";

        string strPostfix = "</column></document></root>";

        return strPrefix + strText + strPostfix;
    }
}

@DigitalPlatform
Copy link
Owner Author

DigitalPlatform commented Nov 30, 2022

一些重构的功能和测试要点

内务书目查询窗,导出 .bdf 功能:
进行了独立线程改造,需要验证测试。
增加了覆盖 .bdf 文件的警告对话框。
建议修改一个册记录的 XML,让 XML 结构出错。可以用修改对象文件的方式实现。这样导出的时候会报错,并询问是否继续。是和否都要验证,原来版本这里不正确。

内务激活窗:
转移并激活按钮会发生左右两边装入相同读者记录 HTML XML 的故障,原因是前后紧挨着使用了同样的临时文件名。已经修正

实体查询窗:
导出到 ISO2709 文件功能。
分类统计功能。
导出到 .bdf 功能。
根据册条码号或者记录路径装载册记录。
前后翻页。

种册窗:
检索面板的检索。注意打开共享检索或者 Z39.50 检索,各种组合都检索一下。
从书目查询窗拖放记录路径到种册窗的(记录路径 textbox)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant