退役独立扒图程序与试验工具,消除重复源码:删 pdfbt 项目/cadbt C#部分(保留 node+CAD-Viewer 网页引擎,主程序扒图依赖)/ghj/yjktool;打包链同步(make_package 去独立exe/setup.iss 删pdfbt/更新包不再带pdfbt.exe);护栏扩到全部4对双胞胎文件;README 结构更新;编译+组装验证通过

This commit is contained in:
dqb-dev
2026-10-02 02:10:32 +08:00
parent e7f25a8ceb
commit 193035acfb
74 changed files with 34 additions and 26829 deletions
+4 -4
View File
@@ -30,16 +30,16 @@
```
成套报价软件\ 主程序源码(MainForm 拆 14 个 partial;xiangmu/shezhi/ku 子模块窗体)
└ 扒图\ CAD/PDF 扒图窗口 + OCR/PDF 基础设施(唯一权威源,pdfbt 链接共享)
cadbt\ CAD 扒图独立程序(含 CAD-Viewer 网页引擎)
pdfbt\ PDF 扒图独立程序(OCR 等基础设施链接主项目扒图\ 源码)
└ 扒图\ CAD/PDF 扒图窗口 + OCR/PDF 基础设施(唯一权威源)
cadbt\ CAD 网页引擎运行时(node.exe + CAD-Viewer;2026-10-01 独立 cadbt.exe 退役)
ai助手\ ZCode 引擎发行包 + 启停脚本(发行包不进 git)
会员服务器\ 肥牛 fnnas 会员服务端 v1.5.1(fpk 工程)
tools\ 构建/打包/维护脚本(见下表)
release\ 组装产物(仅 setup.iss 进 git)
ghj\ yjktool\ 历史试验小工具
```
(已退役:独立 cadbt.exe/pdfbt.exe 扒图程序、ghj/yjktool 试验小工具、cadcj 旧 AutoCAD 插件——扒图功能全部由主程序内嵌窗口承载。)
**数据目录**(运行时,均不进 git):`sjk\bjb\项目<编号>.db` 每项目一库;`sjk\fak.db` 公式库;`sjk\方案库\*.db` 一方案一库;`shezhi\` 用户配置;`xiangmu\` 报表模板。
## 构建与验证
-20
View File
@@ -1,20 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# SharpDevelop 5.2
VisualStudioVersion = 12.0.20827.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cadbt", "cadbt\cadbt.csproj", "{0A91D57B-B279-4672-9440-78088D022EB1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0A91D57B-B279-4672-9440-78088D022EB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A91D57B-B279-4672-9440-78088D022EB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A91D57B-B279-4672-9440-78088D022EB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A91D57B-B279-4672-9440-78088D022EB1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
-213
View File
@@ -1,213 +0,0 @@
// ============================================================
// CadBridge:WinForms 宿主与网页 CAD(CAD-Viewer)之间的互操作桥
// · 下行(C#→网页):PostMessage 发 startPick/zoomToHandle/deleteHandles/clearHighlight
// · 上行(网页→C#):WebMessageReceived 收 paPicked/entityErased/paExited
// · 扒图结果与实体删除事件以 C# 事件形式提供给 Form3(替代 AutoCAD 版
// 的 PaTextSelector.BatchTextsPicked 与 Database.ObjectErased)
// ============================================================
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.WinForms;
namespace cadbt
{
public static class CadBridge
{
private static WebView2 _wv;
private static readonly JavaScriptSerializer _json = new JavaScriptSerializer();
/// <summary>网页 CAD 是否已挂载(WebView2 已附加)。</summary>
public static bool IsViewerReady
{
get { return _wv != null && _wv.CoreWebView2 != null; }
}
/// <summary>网页 CAD 中实体被删除(句柄十六进制字符串)。</summary>
public static event Action<string> EntityErased;
/// <summary>网页 CAD 扒图完成一批(图号/箱号/元件)。</summary>
public static event Action<MyApp.PaMode, List<MyApp.PaTextResult>> PaPicked;
/// <summary>用户按 ESC 退出网页扒图连续模式。</summary>
public static event Action PaExited;
/// <summary>用户按 F1(焦点在网页或宿主时都触发)——元件两两合并。</summary>
public static event Action F1Requested;
/// <summary>用户按 F2——元件三个一组合并。</summary>
public static event Action F2Requested;
/// <summary>用户按 F3——元件四个一组合并。</summary>
public static event Action F3Requested;
/// <summary>触发 F1 请求(消息过滤器等宿主侧来源调用)。</summary>
public static void RaiseF1()
{
if (F1Requested != null) F1Requested();
}
/// <summary>触发 F2 请求(消息过滤器等宿主侧来源调用)。</summary>
public static void RaiseF2()
{
if (F2Requested != null) F2Requested();
}
/// <summary>触发 F3 请求(消息过滤器等宿主侧来源调用)。</summary>
public static void RaiseF3()
{
if (F3Requested != null) F3Requested();
}
/// <summary>把 WebView2 挂到桥上(在控件初始化完成后调用一次)。</summary>
public static void Attach(WebView2 wv)
{
if (_wv == wv) return;
if (_wv != null) _wv.WebMessageReceived -= OnMessage;
_wv = wv;
if (_wv != null) _wv.WebMessageReceived += OnMessage;
}
private static void OnMessage(object sender, CoreWebView2WebMessageReceivedEventArgs e)
{
try
{
if (e.TryGetWebMessageAsString() != null) return; // 只处理 JSON 消息
}
catch { }
try
{
var msg = _json.Deserialize<Dictionary<string, object>>(e.WebMessageAsJson);
if (msg == null || !msg.ContainsKey("type")) return;
string type = msg["type"] as string;
if (type == "paPicked")
{
int mode = Convert.ToInt32(msg["mode"]);
var results = new List<MyApp.PaTextResult>();
var arr = msg["results"] as System.Collections.ArrayList;
if (arr != null)
{
foreach (Dictionary<string, object> item in arr)
{
results.Add(new MyApp.PaTextResult
{
Text = Convert.ToString(item["text"]) ?? "",
FrameHandle = Convert.ToString(item["frameHandle"]) ?? "",
TextHandle = Convert.ToString(item["textHandle"]) ?? ""
});
}
}
// WebMessageReceived 在 UI 线程触发,可直接调用 Form3
if (PaPicked != null)
PaPicked((MyApp.PaMode)mode, results);
}
else if (type == "entityErased")
{
string handle = Convert.ToString(msg["handle"]);
if (!string.IsNullOrWhiteSpace(handle) && EntityErased != null)
EntityErased(handle);
}
else if (type == "paError")
{
string errMsg = Convert.ToString(msg["message"]);
System.Windows.Forms.MessageBox.Show(
"网页 CAD 返回错误:\n" + errMsg,
"扒数据", System.Windows.Forms.MessageBoxButtons.OK,
System.Windows.Forms.MessageBoxIcon.Warning);
}
else if (type == "f1")
{
if (F1Requested != null) F1Requested();
}
else if (type == "f2")
{
if (F2Requested != null) F2Requested();
}
else if (type == "f3")
{
if (F3Requested != null) F3Requested();
}
else if (type == "paExited")
{
if (PaExited != null) PaExited();
}
}
catch (Exception)
{
// 消息格式异常直接忽略,不影响宿主
}
}
private static void Post(object msg)
{
if (!IsViewerReady) return;
try
{
_wv.CoreWebView2.PostWebMessageAsJson(_json.Serialize(msg));
}
catch { }
}
/// <summary>
/// 发送扒图命令。接受原 CAD 命令名(CADPATU/CADPAXH/CADPAYJ/CADPACL)
/// 或网页命令名(patu/paxh/payj)。
/// </summary>
public static void SendPaCommand(string cmd)
{
if (string.IsNullOrWhiteSpace(cmd)) return;
string c = cmd.Trim().ToUpperInvariant();
int mode = 0;
if (c == "CADPATU" || c == "PATU") mode = 0;
else if (c == "CADPAXH" || c == "PAXH") mode = 1;
else if (c == "CADPAYJ" || c == "PAYJ") mode = 2;
else if (c == "CADPACL" || c == "PACL")
{
ClearHighlight();
return;
}
else return;
Post(new { type = "startPick", mode = mode });
}
/// <summary>缩放居中到指定 Handle 的实体并高亮(点击表格行定位框)。</summary>
public static void ZoomToFrameHandle(string handle)
{
if (string.IsNullOrWhiteSpace(handle)) return;
Post(new { type = "zoomToHandle", handle = handle });
}
/// <summary>批量删除指定 Handle 的实体(删表格行联动删框)。</summary>
public static void DeleteFramesByHandles(IEnumerable<string> handles)
{
if (handles == null) return;
var list = new List<string>();
foreach (string h in handles)
if (!string.IsNullOrWhiteSpace(h)) list.Add(h);
if (list.Count == 0) return;
Post(new { type = "deleteHandles", handles = list });
}
/// <summary>
/// 合并蒙版:保留 keep 句柄的蒙版并扩大到所有 removes 蒙版的并集,
/// 被合并行的蒙版从网页 CAD 移除(元件合并时蒙版同步合并)。
/// </summary>
public static void MergeMasks(string keep, System.Collections.Generic.IEnumerable<string> removes)
{
if (string.IsNullOrWhiteSpace(keep)) return;
var list = new List<string>();
if (removes != null)
foreach (string h in removes)
if (!string.IsNullOrWhiteSpace(h) && h != keep) list.Add(h);
if (list.Count == 0) return;
Post(new { type = "mergeMasks", keep = keep, removes = list });
}
/// <summary>清除网页 CAD 中的所有高亮。</summary>
public static void ClearHighlight()
{
Post(new { type = "clearHighlight" });
}
}
}
-27
View File
@@ -1,27 +0,0 @@
namespace cadbt.DockWindows
{
partial class CadViewerWindow
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
#region Designer generated code
private void InitializeComponent()
{
this.SuspendLayout();
//
// CadViewerWindow
//
this.Name = "CadViewerWindow";
this.ResumeLayout(false);
}
#endregion
}
}
-187
View File
@@ -1,187 +0,0 @@
// ============================================================
// 停靠窗口:CAD 查看器(中央文档区)
// WebView2 承载网页版 CAD-Viewer(localhost:5173),并挂到 CadBridge。
// ★ 网页服务自启动:exe 旁 node\node.exe + CAD-Viewer\dist\server.cjs
// (静态产物零依赖,客户机无需 Node 环境/pnpm dev;主程序同款端口探测模式)
// ============================================================
using System;
using System.Diagnostics;
using System.IO;
using System.Net.Sockets;
using System.Windows.Forms;
using Microsoft.Web.WebView2.WinForms;
namespace cadbt.DockWindows
{
/// <summary>停靠窗口:网页 CAD 查看器(DockState.Document)。</summary>
public partial class CadViewerWindow : WeifenLuo.WinFormsUI.Docking.DockContent
{
private WebView2 _webView;
private Label _hint;
/// <summary>静态服务进程句柄(退出时杀进程树)。</summary>
private static Process _serverProcess;
public CadViewerWindow()
{
InitializeComponent();
Text = "CAD 查看器";
TabText = "CAD 查看器";
FormClosed += (s, e) => 停止网页服务();
LoadViewer();
}
/// <summary>CAD 网页服务端口(与 server.cjs 一致)。</summary>
private const int 服务端口 = 5173;
private async void LoadViewer()
{
try
{
_webView = new WebView2();
_webView.Dock = DockStyle.Fill;
Controls.Add(_webView);
await _webView.EnsureCoreWebView2Async(null);
CadBridge.Attach(_webView);
// ★ 禁用浏览器快捷键(F5/Ctrl+R/Ctrl+F 等):刷新会丢掉所有扒图蒙版
_webView.CoreWebView2.Settings.AreBrowserAcceleratorKeysEnabled = false;
// ★ 先确保静态服务在线(复刻主程序 StartPriceWebView 的探测+拉起模式)
启动网页服务();
// 服务不可达时给用户明确提示
_webView.CoreWebView2.NavigationCompleted += (s, e) =>
{
if (!e.IsSuccess && _hint == null)
ShowLoadHint("无法连接网页 CAD 服务(端口 " + 服务端口 + ")。\r\n请确认 cadbt\\node\\node.exe 与 cadbt\\CAD-Viewer\\dist 目录完整,然后点击\"重新加载\"。");
};
_webView.CoreWebView2.Navigate("http://localhost:" + 服务端口 + "/");
}
catch (Exception ex)
{
ShowLoadHint("WebView2 初始化失败: " + ex.Message + "\r\n请确认系统已安装 Microsoft Edge WebView2 运行时。");
}
}
/// <summary>启动 CAD 网页静态服务(端口已通=复用;不通=node server.cjs 后台拉起)。</summary>
private void 启动网页服务()
{
try
{
if (端口已通()) return; // 上次实例或手动 dev server 已在服务
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string nodeExe = Path.Combine(baseDir, "node", "node.exe");
// dist 与 server.cjs 同目录;找不到时尝试上一级 CAD-Viewer 结构(开发机)
// 安装布局: {app}\cadbt\CAD-Viewer\dist\ (make_package 已展平 packages 层)
string serverScript = Path.Combine(baseDir, "CAD-Viewer", "dist", "server.cjs");
if (!File.Exists(serverScript))
{
// 开发机回退: bin\Debug 上两级 = cadbt\cadbt\,保留 monorepo 原始层级
serverScript = Path.GetFullPath(Path.Combine(baseDir, @"..\..\CAD-Viewer\packages\cad-viewer-example\dist\server.cjs"));
}
if (!File.Exists(nodeExe) || !File.Exists(serverScript))
{
WriteDiag("[CAD服务] 缺少 node.exe 或 server.cjs: node=" + nodeExe + " script=" + serverScript);
return;
}
var psi = new ProcessStartInfo
{
FileName = nodeExe,
Arguments = "\"" + Path.GetFullPath(serverScript) + "\"",
WorkingDirectory = Path.GetDirectoryName(Path.GetFullPath(serverScript)),
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
};
_serverProcess = Process.Start(psi);
WriteDiag("[CAD服务] 已启动 node PID=" + (_serverProcess == null ? "?" : _serverProcess.Id.ToString()));
// 等端口就绪(最多 8 秒)
for (int i = 0; i < 40; i++)
{
System.Threading.Thread.Sleep(200);
if (端口已通()) { WriteDiag("[CAD服务] 端口就绪, 耗时 " + (i + 1) * 200 + "ms"); return; }
}
WriteDiag("[CAD服务] 端口 8 秒未就绪(继续导航,由 NavigationCompleted 提示)");
}
catch (Exception ex) { WriteDiag("[CAD服务] 启动异常: " + ex.Message); }
}
/// <summary>快速探测本机端口。</summary>
private static bool 端口已通()
{
try
{
using (var client = new TcpClient())
{
var ar = client.BeginConnect("127.0.0.1", 服务端口, null, null);
bool ok = ar.AsyncWaitHandle.WaitOne(400);
if (ok && client.Connected) { client.EndConnect(ar); return true; }
}
}
catch { }
return false;
}
/// <summary>退出清理:杀 node 静态服务进程树(taskkill /T 覆盖可能的子进程)。</summary>
private void 停止网页服务()
{
try
{
if (_serverProcess != null && !_serverProcess.HasExited)
{
int pid = _serverProcess.Id;
Process.Start(new ProcessStartInfo("taskkill", "/PID " + pid + " /T /F")
{
CreateNoWindow = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden
});
WriteDiag("[CAD服务] 已停止 PID=" + pid);
}
_serverProcess = null;
}
catch (Exception ex) { WriteDiag("[CAD服务] 停止异常: " + ex.Message); }
}
/// <summary>简单诊断日志(logs\cad服务.log)。</summary>
private static void WriteDiag(string msg)
{
try
{
string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
Directory.CreateDirectory(dir);
File.AppendAllText(Path.Combine(dir, "cad服务.log"),
DateTime.Now.ToString("HH:mm:ss.fff") + " " + msg + Environment.NewLine);
}
catch { }
}
private void ShowLoadHint(string text)
{
if (_hint != null) return;
_hint = new Label();
_hint.Dock = DockStyle.Fill;
_hint.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
_hint.Text = text;
var reload = new Button();
reload.Text = "重新加载";
reload.Dock = DockStyle.Bottom;
reload.Click += (s, e) =>
{
Controls.Remove(_hint);
_hint.Dispose();
_hint = null;
启动网页服务();
if (_webView != null && _webView.CoreWebView2 != null)
_webView.CoreWebView2.Navigate("http://localhost:" + 服务端口 + "/");
};
Controls.Add(reload);
Controls.Add(_hint);
_hint.BringToFront();
}
}
}
-27
View File
@@ -1,27 +0,0 @@
namespace cadbt.DockWindows
{
partial class QuoteWindow
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
#region Designer generated code
private void InitializeComponent()
{
this.SuspendLayout();
//
// QuoteWindow
//
this.Name = "QuoteWindow";
this.ResumeLayout(false);
}
#endregion
}
}
-26
View File
@@ -1,26 +0,0 @@
// ============================================================
// 停靠窗口:报价插件工具栏(左侧)
// 把 cadcj 的 Form3 报价界面作为子控件嵌入(TopLevel=false)。
// ============================================================
using System.Windows.Forms;
namespace cadbt.DockWindows
{
/// <summary>停靠窗口:报价插件工具栏(DockState.DockLeft)。</summary>
public partial class QuoteWindow : WeifenLuo.WinFormsUI.Docking.DockContent
{
public QuoteWindow()
{
InitializeComponent();
Text = "报价工具";
TabText = "报价工具";
var form = new MyApp.Form3();
form.TopLevel = false;
form.FormBorderStyle = FormBorderStyle.None;
form.Dock = DockStyle.Fill;
Controls.Add(form);
form.Show();
}
}
}
-69
View File
@@ -1,69 +0,0 @@
namespace cadbt
{
partial class MainForm
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Disposes resources used by the form.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
this.dockSurface1 = new Smart.CustomComponents.DockSurface();
Smart.CustomComponents.DockWindows.DockWindowItem dockWindowItem1 = new Smart.CustomComponents.DockWindows.DockWindowItem();
Smart.CustomComponents.DockWindows.DockWindowItem dockWindowItem2 = new Smart.CustomComponents.DockWindows.DockWindowItem();
this.SuspendLayout();
//
// dockSurface1
//
dockWindowItem1.ClassName = "QuoteWindow";
dockWindowItem1.Title = "报价工具";
dockWindowItem1.DockState = WeifenLuo.WinFormsUI.Docking.DockState.DockLeft;
dockWindowItem1.DefaultWidth = 440;
dockWindowItem1.ShowCloseButton = false;
this.dockSurface1.DockWindows.Add(dockWindowItem1);
dockWindowItem2.ClassName = "CadViewerWindow";
dockWindowItem2.Title = "CAD 查看器";
dockWindowItem2.DockState = WeifenLuo.WinFormsUI.Docking.DockState.Document;
dockWindowItem2.ShowCloseButton = false;
this.dockSurface1.DockWindows.Add(dockWindowItem2);
this.dockSurface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dockSurface1.Location = new System.Drawing.Point(0, 0);
this.dockSurface1.Name = "dockSurface1";
this.dockSurface1.Size = new System.Drawing.Size(1184, 661);
this.dockSurface1.TabIndex = 0;
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1184, 661);
this.Controls.Add(this.dockSurface1);
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "cadbt - 报价工具 + 网页 CAD";
this.ResumeLayout(false);
this.PerformLayout();
}
private Smart.CustomComponents.DockSurface dockSurface1;
}
}
-28
View File
@@ -1,28 +0,0 @@
// 本文件由『生成停靠窗口代码』自动生成格式参考手写,集合变更后请同步刷新。
using System;
using WeifenLuo.WinFormsUI.Docking;
namespace cadbt
{
public partial class MainForm
{
void CreateDockWindows_dockSurface1()
{
var dockSurface1 = this.dockSurface1 as Smart.CustomComponents.DockSurface;
if (dockSurface1 == null) return;
dockSurface1.EnsureDefaultTheme(); // 必须:Show 前保证有效主题
var quote = new cadbt.DockWindows.QuoteWindow();
quote.CloseButtonVisible = false;
quote.TabText = "报价工具";
quote.Text = "报价工具";
quote.Show(dockSurface1, DockState.DockLeft);
var viewer = new cadbt.DockWindows.CadViewerWindow();
viewer.CloseButtonVisible = false;
viewer.TabText = "CAD 查看器";
viewer.Text = "CAD 查看器";
viewer.Show(dockSurface1, DockState.Document);
}
}
}
-59
View File
@@ -1,59 +0,0 @@
/*
* 由SharpDevelop创建。
* 用户: 099978
* 日期: 2026-09-04
* 时间: 12:24
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace cadbt
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
CreateDockWindows_dockSurface1();
// ★ 全局 F1 过滤器:焦点在任何 WinForms 控件上都触发元件合并
// (焦点在网页时由网页端转发,两路都汇聚到 CadBridge.F1Requested)
Application.AddMessageFilter(new F1MessageFilter());
FormClosed += (s, e) => Application.RemoveMessageFilter(f1Filter);
}
private readonly F1MessageFilter f1Filter = new F1MessageFilter();
/// <summary>把 F1 按键(0x70)转成 CadBridge.F1Requested,不拦截按键本身。</summary>
private class F1MessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
const int WM_KEYDOWN = 0x0100;
if (m.Msg == WM_KEYDOWN && (int)m.WParam == 0x70)
{
try { CadBridge.RaiseF1(); } catch { }
}
else if (m.Msg == WM_KEYDOWN && (int)m.WParam == 0x71)
{
try { CadBridge.RaiseF2(); } catch { }
}
else if (m.Msg == WM_KEYDOWN && (int)m.WParam == 0x72)
{
try { CadBridge.RaiseF3(); } catch { }
}
return false;
}
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-29
View File
@@ -1,29 +0,0 @@
// ============================================================
// 扒图数据类型(与原 cadcj 插件 / 网页端 cadbridge.ts 保持一致)
// ============================================================
using System.Collections.Generic;
namespace MyApp
{
/// <summary>
/// 扒数据模式:图号/箱号/元件
/// </summary>
public enum PaMode
{
Tuhao, // 扒图号
Xianghao, // 扒箱号
Yuanjian // 扒元件
}
/// <summary>
/// 扒图结果:一条文本 + 它对应的彩色框的 Handle(句柄字符串)
/// 用于关联表格数据行与网页 CAD 框实体,实现点击行定位、删除行删框。
/// ★ TextHandle:源文本实体自身的 Handle,用于判断"是否同一个文本"。
/// </summary>
public class PaTextResult
{
public string Text;
public string FrameHandle;
public string TextHandle = "";
}
}
-132
View File
@@ -1,132 +0,0 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace MyApp
{
/// <summary>
/// 新建项目 窗口(简化版,不依赖企业信息)。
/// UI 布局见 新建项目.ui.cs,本文件只含交互逻辑。
/// </summary>
public partial class 新建项目 : Form
{
// 价格格式化选项(与主项目 价格格式化.cs 保持一致)
private static readonly string[] 小数位选项 =
{
"保留整数", "保留1位小数", "保留2位小数", "保留3位小数",
"保留4位小数", "保留5位小数", "保留6位小数"
};
private static readonly string[] 取整方式选项 =
{
"不取整", "四舍五入", "四舍五入到角", "四舍五入到元",
"四舍五入到十元", "向上取整到元", "最近5元", "最近10元"
};
private readonly string _dbPath;
private readonly string _tableName;
public 新建项目() : this(null, null) { }
/// <summary>带数据库路径的构造函数(用于自动生成项目编号)。</summary>
public 新建项目(string dbPath, string tableName)
{
InitializeComponent();
_dbPath = dbPath;
_tableName = tableName;
InitPriceFormatCombos();
this.Load += 新建项目_Load;
}
private void InitPriceFormatCombos()
{
cmb单台价格.Items.Clear();
cmb单台价格.Items.AddRange(小数位选项);
cmb项目总价.Items.Clear();
cmb项目总价.Items.AddRange(小数位选项);
comboBox1.Items.Clear();
comboBox1.Items.AddRange(取整方式选项);
comboBox2.Items.Clear();
comboBox2.Items.AddRange(取整方式选项);
}
private void 新建项目_Load(object sender, EventArgs e)
{
FillAutoFields();
}
/// <summary>自动填充项目日期(当天)和项目编号(yyyyMMdd+3位序号)。</summary>
private void FillAutoFields()
{
DateTime today = DateTime.Today;
txt项目日期.Text = today.ToString("yyyy-MM-dd");
string datePart = today.ToString("yyyyMMdd");
int seq = GetNextSeqForDate(datePart);
txt项目编号.Text = datePart + seq.ToString("000");
txt项目编号.ReadOnly = true;
txt项目编号.TabStop = false;
txt项目编号.BackColor = System.Drawing.SystemColors.Control;
}
/// <summary>查数据库当天最大序号+1,失败返回1。</summary>
private int GetNextSeqForDate(string datePart)
{
if (string.IsNullOrEmpty(datePart) ||
string.IsNullOrEmpty(_dbPath) ||
string.IsNullOrEmpty(_tableName) ||
!System.IO.File.Exists(_dbPath))
{
return 1;
}
try
{
string connStr = "Data Source=" + _dbPath + ";Version=3;";
using (var conn = new System.Data.SQLite.SQLiteConnection(connStr))
{
conn.Open();
string sql =
"SELECT MAX(CAST(SUBSTR(项目编号, 9) AS INTEGER)) " +
"FROM " + _tableName + " " +
"WHERE SUBSTR(项目编号, 1, 8) = '" + datePart + "';";
using (var cmd = new System.Data.SQLite.SQLiteCommand(sql, conn))
{
object result = cmd.ExecuteScalar();
if (result == null || result == DBNull.Value) return 1;
int maxSeq;
if (int.TryParse(result.ToString(), out maxSeq)) return maxSeq + 1;
return 1;
}
}
}
catch { return 1; }
}
/// <summary>收集对话框字段,以列名为键返回(供 Form3 写入数据库)。</summary>
public Dictionary<string, string> GetInputValues()
{
var values = new Dictionary<string, string>();
AddIfNotEmpty(values, "项目编号", txt项目编号.Text);
AddIfNotEmpty(values, "项目日期", txt项目日期.Text);
AddIfNotEmpty(values, "项目名称", txt项目名称.Text);
AddIfNotEmpty(values, "客户名称", txt客户名称.Text);
AddIfNotEmpty(values, "客户地址", txt客户地址.Text);
AddIfNotEmpty(values, "联系人", txt联系人.Text);
AddIfNotEmpty(values, "联系电话", txt联系电话.Text);
AddIfNotEmpty(values, "备注", txt备注.Text);
AddIfNotEmpty(values, "成套厂名称", txt成套厂名称.Text);
AddIfNotEmpty(values, "成套厂地址", txt成套厂地址.Text);
AddIfNotEmpty(values, "成套厂联系人", txt成套厂联系人.Text);
AddIfNotEmpty(values, "成套厂联系电话", txt成套厂联系电话.Text);
values["单台小数位"] = (cmb单台价格.SelectedItem ?? cmb单台价格.Text ?? "").ToString();
values["项目小数位"] = (cmb项目总价.SelectedItem ?? cmb项目总价.Text ?? "").ToString();
values["单台取整方式"] = (comboBox1.SelectedItem ?? comboBox1.Text ?? "").ToString();
values["项目取整方式"] = (comboBox2.SelectedItem ?? comboBox2.Text ?? "").ToString();
return values;
}
private static void AddIfNotEmpty(Dictionary<string, string> dict, string key, string value)
{
if (!string.IsNullOrWhiteSpace(value)) dict[key] = value.Trim();
}
}
}
File diff suppressed because it is too large Load Diff
-43
View File
@@ -1,43 +0,0 @@
/*
* 由SharpDevelop创建。
* 用户: 099978
* 日期: 2026-09-04
* 时间: 12:24
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Windows.Forms;
namespace cadbt
{
/// <summary>
/// Class with program entry point.
/// </summary>
internal sealed class Program
{
/// <summary>
/// Program entry point.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
// 单实例保护:重复启动时激活已有实例并退出,避免残留多个进程
bool createdNew;
using (var mutex = new System.Threading.Mutex(true, "cadbt_SingleInstance", out createdNew))
{
if (!createdNew)
{
MessageBox.Show("cadbt 已在运行中。", "cadbt",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
GC.KeepAlive(mutex);
}
}
}
}
-31
View File
@@ -1,31 +0,0 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("cadbt")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("cadbt")]
[assembly: AssemblyCopyright("Copyright 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
-147
View File
@@ -1,147 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{0A91D57B-B279-4672-9440-78088D022EB1}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<RootNamespace>cadbt</RootNamespace>
<AssemblyName>cadbt</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<PlatformTarget>x86</PlatformTarget>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<Prefer32Bit>True</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Extensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="Smart.CustomComponents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ba044a4aa43e0dc4">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\Smart.CustomComponents.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="WeifenLuo.WinFormsUI.Docking">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\WeifenLuo.WinFormsUI.Docking.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="WeifenLuo.WinFormsUI.Docking.ThemeVS2015">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SQLite">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Data.SQLite.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\log4net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Resources.Extensions">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Resources.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Memory">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Memory.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics.Vectors">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AdvancedDataGridView">
<HintPath>libs\AdvancedDataGridView.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Web.WebView2.Core">
<HintPath>libs\webview2\Microsoft.Web.WebView2.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Web.WebView2.WinForms">
<HintPath>libs\webview2\Microsoft.Web.WebView2.WinForms.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="MainForm.DockWindows.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="CadBridge.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Plugin\Form3.cs" />
<Compile Include="Plugin\Form3.ui.cs">
<DependentUpon>Form3.cs</DependentUpon>
</Compile>
<Compile Include="Plugin\PaTypes.cs" />
<Compile Include="Plugin\新建项目.cs" />
<Compile Include="Plugin\新建项目.ui.cs">
<DependentUpon>新建项目.cs</DependentUpon>
</Compile>
<Compile Include="DockWindows\CadViewerWindow.cs" />
<Compile Include="DockWindows\CadViewerWindow.Designer.cs">
<DependentUpon>CadViewerWindow.cs</DependentUpon>
</Compile>
<Compile Include="DockWindows\QuoteWindow.cs" />
<Compile Include="DockWindows\QuoteWindow.Designer.cs">
<DependentUpon>QuoteWindow.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
<Content Include="libs\webview2\WebView2Loader.dll">
<Link>WebView2Loader.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Binary file not shown.
Binary file not shown.
Binary file not shown.
-47
View File
@@ -1,47 +0,0 @@
/*
* 由SharpDevelop创建。
* 用户: 099978
* 日期: 2026-09-28
* 时间: 13:00
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
namespace ghj
{
partial class MainForm
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Disposes resources used by the form.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor. The Forms designer might
/// not be able to load this method if it was changed manually.
/// </summary>
private void InitializeComponent()
{
//
// MainForm
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Text = "ghj";
this.Name = "MainForm";
}
}
}
-33
View File
@@ -1,33 +0,0 @@
/*
* 由SharpDevelop创建。
* 用户: 099978
* 日期: 2026-09-28
* 时间: 13:00
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace ghj
{
/// <summary>
/// Description of MainForm.
/// </summary>
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//
// TODO: Add constructor code after the InitializeComponent() call.
//
}
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
* 由SharpDevelop创建。
* 用户: 099978
* 日期: 2026-09-28
* 时间: 13:00
*
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
*/
using System;
using System.Windows.Forms;
namespace ghj
{
/// <summary>
/// Class with program entry point.
/// </summary>
internal sealed class Program
{
/// <summary>
/// Program entry point.
/// </summary>
[STAThread]
private static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
}
-31
View File
@@ -1,31 +0,0 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("ghj")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ghj")]
[assembly: AssemblyCopyright("Copyright 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
</configuration>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
-67
View File
@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{C9E28D5E-B911-4F7C-9C9D-75EBD3250694}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<RootNamespace>ghj</RootNamespace>
<AssemblyName>ghj</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<PlatformTarget>x86</PlatformTarget>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<Prefer32Bit>True</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="app.manifest" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -1,29 +0,0 @@
# 新增 UApiPro(uapis.cn) 通用文字识别引擎(第五个 OCR 引擎)
## 已确认的接口细节(官方文档 + 官网已核实)
- 端点:`POST https://uapis.cn/api/v1/image/ocr`,multipart/form-data
- 鉴权:`X-API-Key: <key>`(uapis.cn/console 邮箱注册即生成,免费积分 4积分/次,限速 4QPS)
- 请求字段:`image_base64`(纯 base64 或 DataURI)+ `need_location="true"`(返回坐标)+ `enable_cls="true"`(方向校正)
- 响应:`words_result[]{words, location{left,top,width,height}, score}` ——**每行带位置和置信度**,结构与百度OCR几乎一致
- 布尔参数是字符串形式;图片 ≤10MB
## 修改文件
### 1. 新增 UapisOcrClient.cs
- multipart/form-data 手工拼装(net48 无 MultipartFormDataContent)
- words_result 解析 → OcrItem(location 像素坐标直接用,score 保留供图形符号过滤用)
- 错误处理:HTTP 错误体 {code,message} 与业务 code 非 200 双查
- Key 存 baidu_ocr.json 的 uapis_api_key
### 2. OcrClient.cs 路由加 "uapis"
- 新增 _uapis 成员 + StatusChanged 转发 + LoadConfig 注入 Key + RecognizeAsync 路由
### 3. OcrSettingsForm 第四个引擎选项
- 下拉加"UApiPro 通用OCR(免费积分/带位置)";选中显示 UApiPro Key 输入行;保存 uapis_api_key
### 4. csproj 注册 → 编译 → 关闭重启 → 交付说明
## 说明
- 该引擎带 score 置信度,图形符号过滤(<0.8 短串拦截、<0.55 长文本兜底)对它自动生效
- 4QPS 限速对人工框选节奏完全够用;免费积分计费
- 五引擎格局:百度(内置Key即用)/ 智谱GLM / 千帆PaddleOCR-VL / UApiPro,外加本地GPU rapidocr 已退役
-27
View File
@@ -1,27 +0,0 @@
namespace pdfbt.DockWindows
{
partial class QuoteWindow
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
#region Designer generated code
private void InitializeComponent()
{
this.SuspendLayout();
//
// QuoteWindow
//
this.Name = "QuoteWindow";
this.ResumeLayout(false);
}
#endregion
}
}
-26
View File
@@ -1,26 +0,0 @@
// ============================================================
// 停靠窗口:报价插件工具栏(左侧)
// 把 cadcj 的 Form3 报价界面作为子控件嵌入(TopLevel=false)。
// ============================================================
using System.Windows.Forms;
namespace pdfbt.DockWindows
{
/// <summary>停靠窗口:报价插件工具栏(DockState.DockLeft)。</summary>
public partial class QuoteWindow : WeifenLuo.WinFormsUI.Docking.DockContent
{
public QuoteWindow()
{
InitializeComponent();
Text = "报价工具";
TabText = "报价工具";
var form = new MyApp.Form3();
form.TopLevel = false;
form.FormBorderStyle = FormBorderStyle.None;
form.Dock = DockStyle.Fill;
Controls.Add(form);
form.Show();
}
}
}
-71
View File
@@ -1,71 +0,0 @@
namespace pdfbt
{
partial class MainForm
{
/// <summary>
/// Designer variable used to keep track of non-visual components.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Disposes resources used by the form.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
if (components != null) {
components.Dispose();
}
}
base.Dispose(disposing);
}
/// <summary>
/// This method is required for Windows Forms designer support.
/// Do not change the method contents inside the source code editor.
/// </summary>
private void InitializeComponent()
{
Smart.CustomComponents.DockWindows.DockWindowItem dockWindowItem1 = new Smart.CustomComponents.DockWindows.DockWindowItem();
Smart.CustomComponents.DockWindows.DockWindowItem dockWindowItem2 = new Smart.CustomComponents.DockWindows.DockWindowItem();
this.dockSurface1 = new Smart.CustomComponents.DockSurface();
this.SuspendLayout();
//
// dockSurface1
//
this.dockSurface1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dockSurface1.DockBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(238)))), ((int)(((byte)(238)))), ((int)(((byte)(242)))));
dockWindowItem1.ClassName = "QuoteWindow";
dockWindowItem1.DefaultWidth = 440;
dockWindowItem1.ShowCloseButton = false;
dockWindowItem1.Title = "报价工具";
dockWindowItem2.ClassName = "PdfViewerWindow";
dockWindowItem2.DockState = WeifenLuo.WinFormsUI.Docking.DockState.Document;
dockWindowItem2.ShowCloseButton = false;
dockWindowItem2.Title = "PDF 查看器";
this.dockSurface1.DockWindows.Add(dockWindowItem1);
this.dockSurface1.DockWindows.Add(dockWindowItem2);
this.dockSurface1.Location = new System.Drawing.Point(0, 0);
this.dockSurface1.Name = "dockSurface1";
this.dockSurface1.Padding = new System.Windows.Forms.Padding(6);
this.dockSurface1.ShowAutoHideContentOnHover = false;
this.dockSurface1.Size = new System.Drawing.Size(1184, 661);
this.dockSurface1.TabIndex = 0;
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 18F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(1184, 661);
this.Controls.Add(this.dockSurface1);
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "PDF 扒图";
this.ResumeLayout(false);
}
private Smart.CustomComponents.DockSurface dockSurface1;
}
}
-28
View File
@@ -1,28 +0,0 @@
// 本文件由『生成停靠窗口代码』自动生成格式参考手写,集合变更后请同步刷新。
using System;
using WeifenLuo.WinFormsUI.Docking;
namespace pdfbt
{
public partial class MainForm
{
void CreateDockWindows_dockSurface1()
{
var dockSurface1 = this.dockSurface1 as Smart.CustomComponents.DockSurface;
if (dockSurface1 == null) return;
dockSurface1.EnsureDefaultTheme(); // 必须:Show 前保证有效主题
var quote = new pdfbt.DockWindows.QuoteWindow();
quote.CloseButtonVisible = false;
quote.TabText = "报价工具";
quote.Text = "报价工具";
quote.Show(dockSurface1, DockState.DockLeft);
var viewer = new pdfbt.PdfViewerWindow();
viewer.CloseButtonVisible = false;
viewer.TabText = "PDF 查看器";
viewer.Text = "PDF 查看器";
viewer.Show(dockSurface1, DockState.Document);
}
}
}
-82
View File
@@ -1,82 +0,0 @@
/*
* MainForm:主窗体(报价工具 + PDF 查看器)
* 由 cadbt 改造:WebView2 网页 CAD → pdfium 原生 PDF 查看 + 框选 OCR
*/
using System;
using System.IO;
using System.Windows.Forms;
using 成套报价软件; // ★ A1:OCR/PDF 基础设施已链接共享主项目源码(类型在 成套报价软件 命名空间)
namespace pdfbt
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
CreateDockWindows_dockSurface1();
// ★ 全局 F1/F2/F3 过滤器:焦点在任何 WinForms 控件上都触发元件合并
// (与 cadbt 一致,两路都汇聚到 PdfBridge.F*Requested)
Application.AddMessageFilter(new F1MessageFilter());
FormClosed += (s, e) => Application.RemoveMessageFilter(f1Filter);
// ★ Umi-OCR 预热:已装本体且当前引擎为 umi 时,主程序一启动就静默拉起
// (--hide 托盘),不等首次框选;后台线程跑,不拖慢窗口出现
System.Threading.ThreadPool.QueueUserWorkItem(_ =>
{
try
{
if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "baidu_ocr.json")))
{
var jsv = new System.Web.Script.Serialization.JavaScriptSerializer()
.Deserialize<System.Collections.Generic.Dictionary<string, string>>(
File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "baidu_ocr.json")));
string eng = jsv != null && jsv.ContainsKey("engine") ? jsv["engine"] : "baidu";
if (eng == "umi" && UmiOcrHost.IsInstalled) UmiOcrLauncher.EnsureRunning(); // ★ A1:启停已拆到 UmiOcrLauncher(主项目共享版)
}
}
catch { }
});
}
private readonly F1MessageFilter f1Filter = new F1MessageFilter();
/// <summary>
/// 把 F1/F2/F3 按键(0x70/0x71/0x72)转成 PdfBridge 事件。
/// ★ 焦点在报价插件(Form3)树内时不触发——那条路径由 Form3.ProcessCmdKey
/// 处理,此处再触发会双跑一次(F1 合并两遍:第一遍成功、第二遍弹
/// "请先选中至少2行"的误提示)。
/// </summary>
private class F1MessageFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
const int WM_KEYDOWN = 0x0100;
bool isFKey = m.Msg == WM_KEYDOWN &&
((int)m.WParam == 0x70 || (int)m.WParam == 0x71 || (int)m.WParam == 0x72);
if (!isFKey) return false;
// 焦点控件在 Form3 树内 → 交给 Form3.ProcessCmdKey,跳过
try
{
var focused = Control.FromHandle(m.HWnd);
for (var c = focused; c != null; c = c.Parent)
{
if (c is MyApp.Form3) return false;
}
}
catch { }
int key = (int)m.WParam;
try
{
if (key == 0x70) PdfBridge.RaiseF1();
else if (key == 0x71) PdfBridge.RaiseF2();
else if (key == 0x72) PdfBridge.RaiseF3();
}
catch { }
return false;
}
}
}
}
-120
View File
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-148
View File
@@ -1,148 +0,0 @@
// ============================================================
// PdfBridge:报价插件(Form3)与 PDF 查看器之间的桥
// 与 cadbt 的 CadBridge 保持相同的 API 形状:
// · 下行(Form3→查看器):SendPaCommand / ZoomToFrameHandle /
// DeleteFramesByHandles / MergeMasks / ClearHighlight
// · 上行(查看器→Form3):PaPicked / EntityErased / PaExited /
// F1/F2/F3Requested
// 扒图逻辑:用户在 PDF 上框选 → 裁剪 → OCR 工作进程识别 →
// 按 CAD 版语义组装 results(正向逐条/反向合并) → PaPicked
// → Form3 入表格;查看器在框选位置画彩色蒙版框。
// ============================================================
using System;
using System.Collections.Generic;
namespace pdfbt
{
public static class PdfBridge
{
private static PdfViewerWindow _viewer;
/// <summary>PDF 查看器是否已挂载且打开了文档。</summary>
public static bool IsViewerReady
{
get { return _viewer != null && _viewer.IsDocumentOpen; }
}
/// <summary>扒图连续模式当前是否激活(供 ESC 全局过滤判断)。</summary>
public static bool PickModeActive
{
get { return _viewer != null && _viewer.PickModeActive; }
}
/// <summary>兼容 CadBridge:查看器中蒙版被外部删除(当前无触发源,保留事件形状)。</summary>
public static event Action<string> EntityErased;
/// <summary>框选识别完成一批(图号/箱号/元件)。</summary>
public static event Action<MyApp.PaMode, List<MyApp.PaTextResult>> PaPicked;
/// <summary>用户按 ESC 退出连续扒图模式。</summary>
public static event Action PaExited;
/// <summary>用户按 F1 —— 元件两两合并。</summary>
public static event Action F1Requested;
/// <summary>用户按 F2 —— 元件三个一组合并。</summary>
public static event Action F2Requested;
/// <summary>用户按 F3 —— 元件四个一组合并。</summary>
public static event Action F3Requested;
/// <summary>把 PDF 查看器挂到桥上(查看器构造时调用一次)。</summary>
public static void Attach(PdfViewerWindow viewer)
{
_viewer = viewer;
}
// ------------------------------------------------------------
// 查看器 → Form3 的上行事件触发(仅查看器调用)
// ------------------------------------------------------------
public static void RaisePaPicked(MyApp.PaMode mode, List<MyApp.PaTextResult> results)
{
if (PaPicked != null) PaPicked(mode, results);
}
public static void RaisePaExited()
{
if (PaExited != null) PaExited();
}
public static void RaiseEntityErased(string handle)
{
if (!string.IsNullOrWhiteSpace(handle) && EntityErased != null)
EntityErased(handle);
}
public static void RaiseF1() { if (F1Requested != null) F1Requested(); }
public static void RaiseF2() { if (F2Requested != null) F2Requested(); }
public static void RaiseF3() { if (F3Requested != null) F3Requested(); }
// ------------------------------------------------------------
// Form3 → 查看器的下行命令
// ------------------------------------------------------------
/// <summary>
/// 发送扒图命令。接受原 CAD 命令名(CADPATU/CADPAXH/CADPAYJ/CADPACL)
/// 或网页命令名(patu/paxh/payj/pacl)。
/// </summary>
public static void SendPaCommand(string cmd)
{
if (string.IsNullOrWhiteSpace(cmd)) return;
string c = cmd.Trim().ToUpperInvariant();
int mode = 0;
if (c == "CADPATU" || c == "PATU") mode = 0;
else if (c == "CADPAXH" || c == "PAXH") mode = 1;
else if (c == "CADPAYJ" || c == "PAYJ") mode = 2;
else if (c == "CADPACL" || c == "PACL")
{
ClearHighlight();
return;
}
else return;
if (_viewer == null) return;
_viewer.StartPick(mode);
}
/// <summary>定位到指定 Handle 的蒙版框(点击表格行定位)。</summary>
public static void ZoomToFrameHandle(string handle)
{
if (string.IsNullOrWhiteSpace(handle) || _viewer == null) return;
_viewer.ZoomToFrame(handle);
}
/// <summary>批量删除指定 Handle 的蒙版(删表格行联动删框)。</summary>
public static void DeleteFramesByHandles(IEnumerable<string> handles)
{
if (handles == null || _viewer == null) return;
var list = new List<string>();
foreach (string h in handles)
if (!string.IsNullOrWhiteSpace(h)) list.Add(h);
if (list.Count == 0) return;
_viewer.DeleteFrames(list);
}
/// <summary>
/// 合并蒙版:保留 keep 的蒙版并扩大到所有 removes 蒙版的并集,
/// 被合并行的蒙版移除(元件合并时蒙版同步合并)。
/// </summary>
public static void MergeMasks(string keep, IEnumerable<string> removes)
{
if (string.IsNullOrWhiteSpace(keep) || _viewer == null) return;
var list = new List<string>();
if (removes != null)
foreach (string h in removes)
if (!string.IsNullOrWhiteSpace(h) && h != keep) list.Add(h);
if (list.Count == 0) return;
_viewer.MergeMasks(keep, list);
}
/// <summary>清除所有高亮。</summary>
public static void ClearHighlight()
{
if (_viewer == null) return;
_viewer.ClearHighlight();
}
}
}
File diff suppressed because it is too large Load Diff
-1321
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-120
View File
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-29
View File
@@ -1,29 +0,0 @@
// ============================================================
// 扒图数据类型(与原 cadcj 插件 / 网页端 cadbridge.ts 保持一致)
// ============================================================
using System.Collections.Generic;
namespace MyApp
{
/// <summary>
/// 扒数据模式:图号/箱号/元件
/// </summary>
public enum PaMode
{
Tuhao, // 扒图号
Xianghao, // 扒箱号
Yuanjian // 扒元件
}
/// <summary>
/// 扒图结果:一条文本 + 它对应的彩色框的 Handle(句柄字符串)
/// 用于关联表格数据行与网页 CAD 框实体,实现点击行定位、删除行删框。
/// ★ TextHandle:源文本实体自身的 Handle,用于判断"是否同一个文本"。
/// </summary>
public class PaTextResult
{
public string Text;
public string FrameHandle;
public string TextHandle = "";
}
}
-609
View File
@@ -1,609 +0,0 @@
namespace MyApp
{
public partial class 新建项目 : System.Windows.Forms.Form
{
/// <summary>必需的设计器变量。</summary>
private System.ComponentModel.IContainer components = null;
/// <summary>清理正在使用的资源。</summary>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
private void InitializeComponent()
{
this.lbl项目编号 = new System.Windows.Forms.Label();
this.txt项目编号 = new System.Windows.Forms.TextBox();
this.lbl项目日期 = new System.Windows.Forms.Label();
this.txt项目日期 = new System.Windows.Forms.TextBox();
this.lbl项目名称 = new System.Windows.Forms.Label();
this.txt项目名称 = new System.Windows.Forms.TextBox();
this.lbl客户名称 = new System.Windows.Forms.Label();
this.txt客户名称 = new System.Windows.Forms.TextBox();
this.btn选择客户 = new System.Windows.Forms.Button();
this.lbl客户地址 = new System.Windows.Forms.Label();
this.txt客户地址 = new System.Windows.Forms.TextBox();
this.lbl联系人 = new System.Windows.Forms.Label();
this.txt联系人 = new System.Windows.Forms.TextBox();
this.lbl联系电话 = new System.Windows.Forms.Label();
this.txt联系电话 = new System.Windows.Forms.TextBox();
this.lbl成套厂名称 = new System.Windows.Forms.Label();
this.txt成套厂名称 = new System.Windows.Forms.TextBox();
this.lbl成套厂地址 = new System.Windows.Forms.Label();
this.txt成套厂地址 = new System.Windows.Forms.TextBox();
this.lbl成套厂联系人 = new System.Windows.Forms.Label();
this.txt成套厂联系人 = new System.Windows.Forms.TextBox();
this.lbl成套厂联系电话 = new System.Windows.Forms.Label();
this.txt成套厂联系电话 = new System.Windows.Forms.TextBox();
this.lbl报出方式 = new System.Windows.Forms.Label();
this.cmb报出方式 = new System.Windows.Forms.ComboBox();
this.lbl箱柜模板 = new System.Windows.Forms.Label();
this.cmb箱柜模板 = new System.Windows.Forms.ComboBox();
this.lbl单台价格 = new System.Windows.Forms.Label();
this.cmb单台价格 = new System.Windows.Forms.ComboBox();
this.lbl项目总价 = new System.Windows.Forms.Label();
this.lbl备注 = new System.Windows.Forms.Label();
this.txt备注 = new System.Windows.Forms.TextBox();
this.btn确定 = new System.Windows.Forms.Button();
this.btn取消 = new System.Windows.Forms.Button();
this.comboBox1 = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.comboBox2 = new System.Windows.Forms.ComboBox();
this.cmb项目总价 = new System.Windows.Forms.ComboBox();
this.SuspendLayout();
//
// lbl项目编号
//
this.lbl项目编号.BackColor = System.Drawing.SystemColors.Control;
this.lbl项目编号.Font = new System.Drawing.Font("宋体", 9F);
this.lbl项目编号.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl项目编号.Location = new System.Drawing.Point(20, 25);
this.lbl项目编号.Name = "lbl项目编号";
this.lbl项目编号.Size = new System.Drawing.Size(70, 23);
this.lbl项目编号.TabIndex = 0;
this.lbl项目编号.Text = "项目编号:";
this.lbl项目编号.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt项目编号
//
this.txt项目编号.BackColor = System.Drawing.SystemColors.Window;
this.txt项目编号.Font = new System.Drawing.Font("宋体", 9F);
this.txt项目编号.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt项目编号.Location = new System.Drawing.Point(95, 25);
this.txt项目编号.Name = "txt项目编号";
this.txt项目编号.Size = new System.Drawing.Size(220, 28);
this.txt项目编号.TabIndex = 0;
//
// lbl项目日期
//
this.lbl项目日期.BackColor = System.Drawing.SystemColors.Control;
this.lbl项目日期.Font = new System.Drawing.Font("宋体", 9F);
this.lbl项目日期.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl项目日期.Location = new System.Drawing.Point(380, 28);
this.lbl项目日期.Name = "lbl项目日期";
this.lbl项目日期.Size = new System.Drawing.Size(70, 18);
this.lbl项目日期.TabIndex = 1;
this.lbl项目日期.Text = "项目日期:";
//
// txt项目日期
//
this.txt项目日期.BackColor = System.Drawing.SystemColors.Window;
this.txt项目日期.Font = new System.Drawing.Font("宋体", 9F);
this.txt项目日期.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt项目日期.Location = new System.Drawing.Point(455, 25);
this.txt项目日期.Name = "txt项目日期";
this.txt项目日期.Size = new System.Drawing.Size(210, 28);
this.txt项目日期.TabIndex = 1;
//
// lbl项目名称
//
this.lbl项目名称.BackColor = System.Drawing.SystemColors.Control;
this.lbl项目名称.Font = new System.Drawing.Font("宋体", 9F);
this.lbl项目名称.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl项目名称.Location = new System.Drawing.Point(20, 55);
this.lbl项目名称.Name = "lbl项目名称";
this.lbl项目名称.Size = new System.Drawing.Size(70, 23);
this.lbl项目名称.TabIndex = 2;
this.lbl项目名称.Text = "项目名称:";
this.lbl项目名称.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt项目名称
//
this.txt项目名称.BackColor = System.Drawing.SystemColors.Window;
this.txt项目名称.Font = new System.Drawing.Font("宋体", 9F);
this.txt项目名称.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt项目名称.Location = new System.Drawing.Point(95, 55);
this.txt项目名称.Name = "txt项目名称";
this.txt项目名称.Size = new System.Drawing.Size(570, 28);
this.txt项目名称.TabIndex = 2;
//
// lbl客户名称
//
this.lbl客户名称.BackColor = System.Drawing.SystemColors.Control;
this.lbl客户名称.Font = new System.Drawing.Font("宋体", 9F);
this.lbl客户名称.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl客户名称.Location = new System.Drawing.Point(20, 85);
this.lbl客户名称.Name = "lbl客户名称";
this.lbl客户名称.Size = new System.Drawing.Size(70, 23);
this.lbl客户名称.TabIndex = 3;
this.lbl客户名称.Text = "客户名称:";
this.lbl客户名称.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt客户名称
//
this.txt客户名称.BackColor = System.Drawing.SystemColors.Window;
this.txt客户名称.Font = new System.Drawing.Font("宋体", 9F);
this.txt客户名称.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt客户名称.Location = new System.Drawing.Point(95, 85);
this.txt客户名称.Name = "txt客户名称";
this.txt客户名称.Size = new System.Drawing.Size(479, 28);
this.txt客户名称.TabIndex = 3;
//
// btn选择客户
//
this.btn选择客户.BackColor = System.Drawing.SystemColors.Control;
this.btn选择客户.Font = new System.Drawing.Font("宋体", 9F);
this.btn选择客户.ForeColor = System.Drawing.SystemColors.ControlText;
this.btn选择客户.Location = new System.Drawing.Point(580, 85);
this.btn选择客户.Name = "btn选择客户";
this.btn选择客户.Size = new System.Drawing.Size(85, 28);
this.btn选择客户.TabIndex = 4;
this.btn选择客户.Text = "选择客户";
this.btn选择客户.UseVisualStyleBackColor = true;
//
// lbl客户地址
//
this.lbl客户地址.BackColor = System.Drawing.SystemColors.Control;
this.lbl客户地址.Font = new System.Drawing.Font("宋体", 9F);
this.lbl客户地址.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl客户地址.Location = new System.Drawing.Point(20, 115);
this.lbl客户地址.Name = "lbl客户地址";
this.lbl客户地址.Size = new System.Drawing.Size(70, 23);
this.lbl客户地址.TabIndex = 5;
this.lbl客户地址.Text = "客户地址:";
this.lbl客户地址.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt客户地址
//
this.txt客户地址.BackColor = System.Drawing.SystemColors.Window;
this.txt客户地址.Font = new System.Drawing.Font("宋体", 9F);
this.txt客户地址.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt客户地址.Location = new System.Drawing.Point(95, 115);
this.txt客户地址.Name = "txt客户地址";
this.txt客户地址.Size = new System.Drawing.Size(570, 28);
this.txt客户地址.TabIndex = 5;
//
// lbl联系人
//
this.lbl联系人.BackColor = System.Drawing.SystemColors.Control;
this.lbl联系人.Font = new System.Drawing.Font("宋体", 9F);
this.lbl联系人.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl联系人.Location = new System.Drawing.Point(30, 145);
this.lbl联系人.Name = "lbl联系人";
this.lbl联系人.Size = new System.Drawing.Size(60, 23);
this.lbl联系人.TabIndex = 6;
this.lbl联系人.Text = "联系人:";
this.lbl联系人.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt联系人
//
this.txt联系人.BackColor = System.Drawing.SystemColors.Window;
this.txt联系人.Font = new System.Drawing.Font("宋体", 9F);
this.txt联系人.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt联系人.Location = new System.Drawing.Point(95, 145);
this.txt联系人.Name = "txt联系人";
this.txt联系人.Size = new System.Drawing.Size(220, 28);
this.txt联系人.TabIndex = 6;
//
// lbl联系电话
//
this.lbl联系电话.BackColor = System.Drawing.SystemColors.Control;
this.lbl联系电话.Font = new System.Drawing.Font("宋体", 9F);
this.lbl联系电话.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl联系电话.Location = new System.Drawing.Point(380, 145);
this.lbl联系电话.Name = "lbl联系电话";
this.lbl联系电话.Size = new System.Drawing.Size(70, 21);
this.lbl联系电话.TabIndex = 7;
this.lbl联系电话.Text = "联系电话:";
//
// txt联系电话
//
this.txt联系电话.BackColor = System.Drawing.SystemColors.Window;
this.txt联系电话.Font = new System.Drawing.Font("宋体", 9F);
this.txt联系电话.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt联系电话.Location = new System.Drawing.Point(455, 145);
this.txt联系电话.Name = "txt联系电话";
this.txt联系电话.Size = new System.Drawing.Size(210, 28);
this.txt联系电话.TabIndex = 7;
//
// lbl成套厂名称
//
this.lbl成套厂名称.BackColor = System.Drawing.SystemColors.Control;
this.lbl成套厂名称.Font = new System.Drawing.Font("宋体", 9F);
this.lbl成套厂名称.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl成套厂名称.Location = new System.Drawing.Point(10, 175);
this.lbl成套厂名称.Name = "lbl成套厂名称";
this.lbl成套厂名称.Size = new System.Drawing.Size(80, 23);
this.lbl成套厂名称.TabIndex = 8;
this.lbl成套厂名称.Text = "成套厂名称:";
this.lbl成套厂名称.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt成套厂名称
//
this.txt成套厂名称.BackColor = System.Drawing.SystemColors.Window;
this.txt成套厂名称.Font = new System.Drawing.Font("宋体", 9F);
this.txt成套厂名称.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt成套厂名称.Location = new System.Drawing.Point(95, 175);
this.txt成套厂名称.Name = "txt成套厂名称";
this.txt成套厂名称.Size = new System.Drawing.Size(570, 28);
this.txt成套厂名称.TabIndex = 8;
//
// lbl成套厂地址
//
this.lbl成套厂地址.BackColor = System.Drawing.SystemColors.Control;
this.lbl成套厂地址.Font = new System.Drawing.Font("宋体", 9F);
this.lbl成套厂地址.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl成套厂地址.Location = new System.Drawing.Point(10, 205);
this.lbl成套厂地址.Name = "lbl成套厂地址";
this.lbl成套厂地址.Size = new System.Drawing.Size(80, 23);
this.lbl成套厂地址.TabIndex = 9;
this.lbl成套厂地址.Text = "成套厂地址:";
this.lbl成套厂地址.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt成套厂地址
//
this.txt成套厂地址.BackColor = System.Drawing.SystemColors.Window;
this.txt成套厂地址.Font = new System.Drawing.Font("宋体", 9F);
this.txt成套厂地址.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt成套厂地址.Location = new System.Drawing.Point(95, 205);
this.txt成套厂地址.Name = "txt成套厂地址";
this.txt成套厂地址.Size = new System.Drawing.Size(570, 28);
this.txt成套厂地址.TabIndex = 9;
//
// lbl成套厂联系人
//
this.lbl成套厂联系人.BackColor = System.Drawing.SystemColors.Control;
this.lbl成套厂联系人.Font = new System.Drawing.Font("宋体", 9F);
this.lbl成套厂联系人.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl成套厂联系人.Location = new System.Drawing.Point(30, 235);
this.lbl成套厂联系人.Name = "lbl成套厂联系人";
this.lbl成套厂联系人.Size = new System.Drawing.Size(60, 23);
this.lbl成套厂联系人.TabIndex = 10;
this.lbl成套厂联系人.Text = "联系人:";
this.lbl成套厂联系人.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt成套厂联系人
//
this.txt成套厂联系人.BackColor = System.Drawing.SystemColors.Window;
this.txt成套厂联系人.Font = new System.Drawing.Font("宋体", 9F);
this.txt成套厂联系人.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt成套厂联系人.Location = new System.Drawing.Point(95, 235);
this.txt成套厂联系人.Name = "txt成套厂联系人";
this.txt成套厂联系人.Size = new System.Drawing.Size(220, 28);
this.txt成套厂联系人.TabIndex = 10;
//
// lbl成套厂联系电话
//
this.lbl成套厂联系电话.BackColor = System.Drawing.SystemColors.Control;
this.lbl成套厂联系电话.Font = new System.Drawing.Font("宋体", 9F);
this.lbl成套厂联系电话.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl成套厂联系电话.Location = new System.Drawing.Point(380, 235);
this.lbl成套厂联系电话.Name = "lbl成套厂联系电话";
this.lbl成套厂联系电话.Size = new System.Drawing.Size(70, 21);
this.lbl成套厂联系电话.TabIndex = 11;
this.lbl成套厂联系电话.Text = "联系电话:";
//
// txt成套厂联系电话
//
this.txt成套厂联系电话.BackColor = System.Drawing.SystemColors.Window;
this.txt成套厂联系电话.Font = new System.Drawing.Font("宋体", 9F);
this.txt成套厂联系电话.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt成套厂联系电话.Location = new System.Drawing.Point(455, 232);
this.txt成套厂联系电话.Name = "txt成套厂联系电话";
this.txt成套厂联系电话.Size = new System.Drawing.Size(210, 28);
this.txt成套厂联系电话.TabIndex = 11;
//
// lbl报出方式
//
this.lbl报出方式.BackColor = System.Drawing.SystemColors.Control;
this.lbl报出方式.Font = new System.Drawing.Font("宋体", 9F);
this.lbl报出方式.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl报出方式.Location = new System.Drawing.Point(20, 265);
this.lbl报出方式.Name = "lbl报出方式";
this.lbl报出方式.Size = new System.Drawing.Size(70, 23);
this.lbl报出方式.TabIndex = 12;
this.lbl报出方式.Text = "报出方式:";
this.lbl报出方式.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// cmb报出方式
//
this.cmb报出方式.BackColor = System.Drawing.SystemColors.Window;
this.cmb报出方式.DropDownWidth = 200;
this.cmb报出方式.Font = new System.Drawing.Font("宋体", 9F);
this.cmb报出方式.ForeColor = System.Drawing.SystemColors.WindowText;
this.cmb报出方式.ItemHeight = 18;
this.cmb报出方式.Location = new System.Drawing.Point(95, 265);
this.cmb报出方式.Name = "cmb报出方式";
this.cmb报出方式.Size = new System.Drawing.Size(220, 26);
this.cmb报出方式.TabIndex = 12;
this.cmb报出方式.Text = "报出价=表价*采购系数*报出系数";
//
// lbl箱柜模板
//
this.lbl箱柜模板.BackColor = System.Drawing.SystemColors.Control;
this.lbl箱柜模板.Font = new System.Drawing.Font("宋体", 9F);
this.lbl箱柜模板.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl箱柜模板.Location = new System.Drawing.Point(380, 265);
this.lbl箱柜模板.Name = "lbl箱柜模板";
this.lbl箱柜模板.Size = new System.Drawing.Size(70, 20);
this.lbl箱柜模板.TabIndex = 13;
this.lbl箱柜模板.Text = "箱柜模板:";
//
// cmb箱柜模板
//
this.cmb箱柜模板.BackColor = System.Drawing.SystemColors.Window;
this.cmb箱柜模板.DropDownWidth = 200;
this.cmb箱柜模板.Font = new System.Drawing.Font("宋体", 9F);
this.cmb箱柜模板.ForeColor = System.Drawing.SystemColors.WindowText;
this.cmb箱柜模板.ItemHeight = 18;
this.cmb箱柜模板.Location = new System.Drawing.Point(455, 262);
this.cmb箱柜模板.Name = "cmb箱柜模板";
this.cmb箱柜模板.Size = new System.Drawing.Size(210, 26);
this.cmb箱柜模板.TabIndex = 13;
//
// lbl单台价格
//
this.lbl单台价格.BackColor = System.Drawing.SystemColors.Control;
this.lbl单台价格.Font = new System.Drawing.Font("宋体", 9F);
this.lbl单台价格.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl单台价格.Location = new System.Drawing.Point(20, 293);
this.lbl单台价格.Name = "lbl单台价格";
this.lbl单台价格.Size = new System.Drawing.Size(70, 23);
this.lbl单台价格.TabIndex = 14;
this.lbl单台价格.Text = "单台价格:";
this.lbl单台价格.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// cmb单台价格
//
this.cmb单台价格.BackColor = System.Drawing.SystemColors.Window;
this.cmb单台价格.DropDownWidth = 200;
this.cmb单台价格.Font = new System.Drawing.Font("宋体", 9F);
this.cmb单台价格.ForeColor = System.Drawing.SystemColors.WindowText;
this.cmb单台价格.ItemHeight = 18;
this.cmb单台价格.Location = new System.Drawing.Point(95, 293);
this.cmb单台价格.Name = "cmb单台价格";
this.cmb单台价格.Size = new System.Drawing.Size(220, 26);
this.cmb单台价格.TabIndex = 14;
this.cmb单台价格.Text = "保留整数";
//
// lbl项目总价
//
this.lbl项目总价.BackColor = System.Drawing.SystemColors.Control;
this.lbl项目总价.Font = new System.Drawing.Font("宋体", 9F);
this.lbl项目总价.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl项目总价.Location = new System.Drawing.Point(379, 293);
this.lbl项目总价.Name = "lbl项目总价";
this.lbl项目总价.Size = new System.Drawing.Size(70, 20);
this.lbl项目总价.TabIndex = 15;
this.lbl项目总价.Text = "项目总价:";
//
// lbl备注
//
this.lbl备注.BackColor = System.Drawing.SystemColors.Control;
this.lbl备注.Font = new System.Drawing.Font("宋体", 9F);
this.lbl备注.ForeColor = System.Drawing.SystemColors.ControlText;
this.lbl备注.Location = new System.Drawing.Point(44, 352);
this.lbl备注.Name = "lbl备注";
this.lbl备注.Size = new System.Drawing.Size(46, 23);
this.lbl备注.TabIndex = 16;
this.lbl备注.Text = "备注:";
this.lbl备注.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// txt备注
//
this.txt备注.BackColor = System.Drawing.SystemColors.Window;
this.txt备注.Font = new System.Drawing.Font("宋体", 9F);
this.txt备注.ForeColor = System.Drawing.SystemColors.WindowText;
this.txt备注.Location = new System.Drawing.Point(95, 352);
this.txt备注.Multiline = true;
this.txt备注.Name = "txt备注";
this.txt备注.Size = new System.Drawing.Size(570, 80);
this.txt备注.TabIndex = 16;
//
// btn确定
//
this.btn确定.BackColor = System.Drawing.SystemColors.Control;
this.btn确定.DialogResult = System.Windows.Forms.DialogResult.OK;
this.btn确定.Font = new System.Drawing.Font("宋体", 9F);
this.btn确定.ForeColor = System.Drawing.SystemColors.ControlText;
this.btn确定.Location = new System.Drawing.Point(455, 449);
this.btn确定.Name = "btn确定";
this.btn确定.Size = new System.Drawing.Size(100, 28);
this.btn确定.TabIndex = 17;
this.btn确定.Text = "确定";
this.btn确定.UseVisualStyleBackColor = true;
//
// btn取消
//
this.btn取消.BackColor = System.Drawing.SystemColors.Control;
this.btn取消.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btn取消.Font = new System.Drawing.Font("宋体", 9F);
this.btn取消.ForeColor = System.Drawing.SystemColors.ControlText;
this.btn取消.Location = new System.Drawing.Point(565, 449);
this.btn取消.Name = "btn取消";
this.btn取消.Size = new System.Drawing.Size(100, 28);
this.btn取消.TabIndex = 18;
this.btn取消.Text = "取消";
this.btn取消.UseVisualStyleBackColor = true;
//
// comboBox1
//
this.comboBox1.BackColor = System.Drawing.SystemColors.Window;
this.comboBox1.DropDownWidth = 210;
this.comboBox1.Font = new System.Drawing.Font("宋体", 9F);
this.comboBox1.ForeColor = System.Drawing.SystemColors.WindowText;
this.comboBox1.ItemHeight = 18;
this.comboBox1.Location = new System.Drawing.Point(455, 322);
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size(210, 26);
this.comboBox1.TabIndex = 14;
this.comboBox1.Text = "四舍五入";
//
// label1
//
this.label1.BackColor = System.Drawing.SystemColors.Control;
this.label1.Font = new System.Drawing.Font("宋体", 9F);
this.label1.ForeColor = System.Drawing.SystemColors.ControlText;
this.label1.Location = new System.Drawing.Point(19, 320);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(70, 23);
this.label1.TabIndex = 14;
this.label1.Text = "单台取整:";
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// label2
//
this.label2.BackColor = System.Drawing.SystemColors.Control;
this.label2.Font = new System.Drawing.Font("宋体", 9F);
this.label2.ForeColor = System.Drawing.SystemColors.ControlText;
this.label2.Location = new System.Drawing.Point(379, 324);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(70, 20);
this.label2.TabIndex = 15;
this.label2.Text = "项目取整:";
//
// comboBox2
//
this.comboBox2.BackColor = System.Drawing.SystemColors.Window;
this.comboBox2.DropDownWidth = 220;
this.comboBox2.Font = new System.Drawing.Font("宋体", 9F);
this.comboBox2.ForeColor = System.Drawing.SystemColors.WindowText;
this.comboBox2.ItemHeight = 18;
this.comboBox2.Location = new System.Drawing.Point(95, 324);
this.comboBox2.Name = "comboBox2";
this.comboBox2.Size = new System.Drawing.Size(220, 26);
this.comboBox2.TabIndex = 14;
this.comboBox2.Text = "四舍五入";
//
// cmb项目总价
//
this.cmb项目总价.BackColor = System.Drawing.SystemColors.Window;
this.cmb项目总价.DropDownWidth = 200;
this.cmb项目总价.Font = new System.Drawing.Font("宋体", 9F);
this.cmb项目总价.ForeColor = System.Drawing.SystemColors.WindowText;
this.cmb项目总价.ItemHeight = 18;
this.cmb项目总价.Location = new System.Drawing.Point(455, 290);
this.cmb项目总价.Name = "cmb项目总价";
this.cmb项目总价.Size = new System.Drawing.Size(210, 26);
this.cmb项目总价.TabIndex = 14;
this.cmb项目总价.Text = "保留整数";
//
// 新建项目
//
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
this.AutoValidate = System.Windows.Forms.AutoValidate.EnablePreventFocusChange;
this.BackColor = System.Drawing.SystemColors.Control;
this.ClientSize = new System.Drawing.Size(678, 482);
this.Controls.Add(this.lbl项目编号);
this.Controls.Add(this.txt项目编号);
this.Controls.Add(this.lbl项目日期);
this.Controls.Add(this.txt项目日期);
this.Controls.Add(this.lbl项目名称);
this.Controls.Add(this.txt项目名称);
this.Controls.Add(this.lbl客户名称);
this.Controls.Add(this.txt客户名称);
this.Controls.Add(this.btn选择客户);
this.Controls.Add(this.lbl客户地址);
this.Controls.Add(this.txt客户地址);
this.Controls.Add(this.lbl联系人);
this.Controls.Add(this.txt联系人);
this.Controls.Add(this.lbl联系电话);
this.Controls.Add(this.txt联系电话);
this.Controls.Add(this.lbl成套厂名称);
this.Controls.Add(this.txt成套厂名称);
this.Controls.Add(this.lbl成套厂地址);
this.Controls.Add(this.txt成套厂地址);
this.Controls.Add(this.lbl成套厂联系人);
this.Controls.Add(this.txt成套厂联系人);
this.Controls.Add(this.lbl成套厂联系电话);
this.Controls.Add(this.txt成套厂联系电话);
this.Controls.Add(this.lbl报出方式);
this.Controls.Add(this.cmb报出方式);
this.Controls.Add(this.lbl箱柜模板);
this.Controls.Add(this.cmb箱柜模板);
this.Controls.Add(this.lbl单台价格);
this.Controls.Add(this.cmb单台价格);
this.Controls.Add(this.lbl项目总价);
this.Controls.Add(this.lbl备注);
this.Controls.Add(this.txt备注);
this.Controls.Add(this.btn确定);
this.Controls.Add(this.btn取消);
this.Controls.Add(this.comboBox1);
this.Controls.Add(this.label1);
this.Controls.Add(this.label2);
this.Controls.Add(this.comboBox2);
this.Controls.Add(this.cmb项目总价);
this.Font = new System.Drawing.Font("宋体", 9F);
this.ForeColor = System.Drawing.SystemColors.ControlText;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "新建项目";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "新建项目";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lbl项目编号;
private System.Windows.Forms.TextBox txt项目编号;
private System.Windows.Forms.Label lbl项目日期;
private System.Windows.Forms.TextBox txt项目日期;
private System.Windows.Forms.Label lbl项目名称;
private System.Windows.Forms.TextBox txt项目名称;
private System.Windows.Forms.Label lbl客户名称;
private System.Windows.Forms.TextBox txt客户名称;
private System.Windows.Forms.Button btn选择客户;
private System.Windows.Forms.Label lbl客户地址;
private System.Windows.Forms.TextBox txt客户地址;
private System.Windows.Forms.Label lbl联系人;
private System.Windows.Forms.TextBox txt联系人;
private System.Windows.Forms.Label lbl联系电话;
private System.Windows.Forms.TextBox txt联系电话;
private System.Windows.Forms.Label lbl成套厂名称;
private System.Windows.Forms.TextBox txt成套厂名称;
private System.Windows.Forms.Label lbl成套厂地址;
private System.Windows.Forms.TextBox txt成套厂地址;
private System.Windows.Forms.Label lbl成套厂联系人;
private System.Windows.Forms.TextBox txt成套厂联系人;
private System.Windows.Forms.Label lbl成套厂联系电话;
private System.Windows.Forms.TextBox txt成套厂联系电话;
private System.Windows.Forms.Label lbl报出方式;
private System.Windows.Forms.ComboBox cmb报出方式;
private System.Windows.Forms.Label lbl箱柜模板;
private System.Windows.Forms.ComboBox cmb箱柜模板;
private System.Windows.Forms.Label lbl单台价格;
private System.Windows.Forms.ComboBox cmb单台价格;
private System.Windows.Forms.Label lbl项目总价;
private System.Windows.Forms.Label lbl备注;
private System.Windows.Forms.TextBox txt备注;
private System.Windows.Forms.Button btn确定;
private System.Windows.Forms.Button btn取消;
private System.Windows.Forms.ComboBox comboBox1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.ComboBox comboBox2;
private System.Windows.Forms.ComboBox cmb项目总价;
}
}
-132
View File
@@ -1,132 +0,0 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace MyApp
{
/// <summary>
/// 新建项目 窗口(简化版,不依赖企业信息)。
/// UI 布局见 新建项目.ui.cs,本文件只含交互逻辑。
/// </summary>
public partial class 新建项目 : Form
{
// 价格格式化选项(与主项目 价格格式化.cs 保持一致)
private static readonly string[] 小数位选项 =
{
"保留整数", "保留1位小数", "保留2位小数", "保留3位小数",
"保留4位小数", "保留5位小数", "保留6位小数"
};
private static readonly string[] 取整方式选项 =
{
"不取整", "四舍五入", "四舍五入到角", "四舍五入到元",
"四舍五入到十元", "向上取整到元", "最近5元", "最近10元"
};
private readonly string _dbPath;
private readonly string _tableName;
public 新建项目() : this(null, null) { }
/// <summary>带数据库路径的构造函数(用于自动生成项目编号)。</summary>
public 新建项目(string dbPath, string tableName)
{
InitializeComponent();
_dbPath = dbPath;
_tableName = tableName;
InitPriceFormatCombos();
this.Load += 新建项目_Load;
}
private void InitPriceFormatCombos()
{
cmb单台价格.Items.Clear();
cmb单台价格.Items.AddRange(小数位选项);
cmb项目总价.Items.Clear();
cmb项目总价.Items.AddRange(小数位选项);
comboBox1.Items.Clear();
comboBox1.Items.AddRange(取整方式选项);
comboBox2.Items.Clear();
comboBox2.Items.AddRange(取整方式选项);
}
private void 新建项目_Load(object sender, EventArgs e)
{
FillAutoFields();
}
/// <summary>自动填充项目日期(当天)和项目编号(yyyyMMdd+3位序号)。</summary>
private void FillAutoFields()
{
DateTime today = DateTime.Today;
txt项目日期.Text = today.ToString("yyyy-MM-dd");
string datePart = today.ToString("yyyyMMdd");
int seq = GetNextSeqForDate(datePart);
txt项目编号.Text = datePart + seq.ToString("000");
txt项目编号.ReadOnly = true;
txt项目编号.TabStop = false;
txt项目编号.BackColor = System.Drawing.SystemColors.Control;
}
/// <summary>查数据库当天最大序号+1,失败返回1。</summary>
private int GetNextSeqForDate(string datePart)
{
if (string.IsNullOrEmpty(datePart) ||
string.IsNullOrEmpty(_dbPath) ||
string.IsNullOrEmpty(_tableName) ||
!System.IO.File.Exists(_dbPath))
{
return 1;
}
try
{
string connStr = "Data Source=" + _dbPath + ";Version=3;";
using (var conn = new System.Data.SQLite.SQLiteConnection(connStr))
{
conn.Open();
string sql =
"SELECT MAX(CAST(SUBSTR(项目编号, 9) AS INTEGER)) " +
"FROM " + _tableName + " " +
"WHERE SUBSTR(项目编号, 1, 8) = '" + datePart + "';";
using (var cmd = new System.Data.SQLite.SQLiteCommand(sql, conn))
{
object result = cmd.ExecuteScalar();
if (result == null || result == DBNull.Value) return 1;
int maxSeq;
if (int.TryParse(result.ToString(), out maxSeq)) return maxSeq + 1;
return 1;
}
}
}
catch { return 1; }
}
/// <summary>收集对话框字段,以列名为键返回(供 Form3 写入数据库)。</summary>
public Dictionary<string, string> GetInputValues()
{
var values = new Dictionary<string, string>();
AddIfNotEmpty(values, "项目编号", txt项目编号.Text);
AddIfNotEmpty(values, "项目日期", txt项目日期.Text);
AddIfNotEmpty(values, "项目名称", txt项目名称.Text);
AddIfNotEmpty(values, "客户名称", txt客户名称.Text);
AddIfNotEmpty(values, "客户地址", txt客户地址.Text);
AddIfNotEmpty(values, "联系人", txt联系人.Text);
AddIfNotEmpty(values, "联系电话", txt联系电话.Text);
AddIfNotEmpty(values, "备注", txt备注.Text);
AddIfNotEmpty(values, "成套厂名称", txt成套厂名称.Text);
AddIfNotEmpty(values, "成套厂地址", txt成套厂地址.Text);
AddIfNotEmpty(values, "成套厂联系人", txt成套厂联系人.Text);
AddIfNotEmpty(values, "成套厂联系电话", txt成套厂联系电话.Text);
values["单台小数位"] = (cmb单台价格.SelectedItem ?? cmb单台价格.Text ?? "").ToString();
values["项目小数位"] = (cmb项目总价.SelectedItem ?? cmb项目总价.Text ?? "").ToString();
values["单台取整方式"] = (comboBox1.SelectedItem ?? comboBox1.Text ?? "").ToString();
values["项目取整方式"] = (comboBox2.SelectedItem ?? comboBox2.Text ?? "").ToString();
return values;
}
private static void AddIfNotEmpty(Dictionary<string, string> dict, string key, string value)
{
if (!string.IsNullOrWhiteSpace(value)) dict[key] = value.Trim();
}
}
}
-120
View File
@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
-38
View File
@@ -1,38 +0,0 @@
/*
* pdfbt:PDF 扒图报价工具(由 cadbt 改造,CAD 查看器 → PDF 查看 + 框选 OCR)
*/
using System;
using System.Windows.Forms;
namespace pdfbt
{
internal sealed class Program
{
[STAThread]
private static int Main(string[] args)
{
// 自检模式:pdfbt.exe --selftest <pdf路径> [输出目录]
if (args != null && args.Length >= 2 && args[0] == "--selftest")
{
return SelfTest.Run(args);
}
// 单实例保护:重复启动时激活已有实例并退出
bool createdNew;
using (var mutex = new System.Threading.Mutex(true, "pdfbt_SingleInstance", out createdNew))
{
if (!createdNew)
{
MessageBox.Show("pdfbt 已在运行中。", "pdfbt",
MessageBoxButtons.OK, MessageBoxIcon.Information);
return 0;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
GC.KeepAlive(mutex);
}
return 0;
}
}
}
-31
View File
@@ -1,31 +0,0 @@
#region Using directives
using System;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("pdfbt")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("pdfbt")]
[assembly: AssemblyCopyright("Copyright 2026")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// This sets the default COM visibility of types in the assembly to invisible.
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
// The assembly version has following format :
//
// Major.Minor.Build.Revision
//
// You can specify all the values or you can use the default the Revision and
// Build Numbers by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
-99
View File
@@ -1,99 +0,0 @@
// ============================================================
// SelfTest:命令行自检(--selftest <pdf> [outdir])
// 无 UI 验证:pdfium 渲染 → PNG 落盘;OCR 工作进程识别 → JSON 落盘
// 用法:pdfbt.exe --selftest test.pdf .
// 返回码:0 成功;1 失败
// ============================================================
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using 成套报价软件; // ★ A1:OCR/PDF 基础设施已链接共享主项目源码(类型在 成套报价软件 命名空间)
namespace pdfbt
{
internal static class SelfTest
{
public static int Run(string[] args)
{
string pdf = args[1];
string outDir = args.Length >= 3 ? args[2] : ".";
var log = new StringBuilder();
int exit = 0;
try
{
// 1) pdfium 渲染
string renderPath = Path.Combine(outDir, "selftest_render.png");
Bitmap page;
using (var doc = new PdfDocument())
{
doc.Open(pdf, null);
log.AppendLine("[render] 打开成功: " + pdf + " 页数=" + doc.PageCount);
page = doc.RenderPage(0, 1.5f);
if (page == null) throw new Exception("渲染返回 null");
}
using (page)
{
page.Save(renderPath, ImageFormat.Png);
log.AppendLine("[render] 已保存: " + renderPath +
" (" + page.Width + "x" + page.Height + ")");
// 2) OCR(渲染图上半区)
var crop = new Bitmap(page.Width, page.Height / 2,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
using (var g = Graphics.FromImage(crop))
{
g.DrawImage(page, new Rectangle(0, 0, crop.Width, crop.Height),
new Rectangle(0, 0, page.Width, page.Height / 2), GraphicsUnit.Pixel);
}
using (var ocr = new OcrClient())
{
var items = ocr.RecognizeAsync(crop, 180000).Result;
var json = new StringBuilder();
json.AppendLine("{");
json.AppendLine(" \"count\": " + (items == null ? 0 : items.Count) + ",");
json.AppendLine(" \"items\": [");
if (items != null)
{
for (int i = 0; i < items.Count; i++)
{
var it = items[i];
var b = it.Bounds;
json.AppendLine(" {\"text\": \"" +
(it.Text ?? "").Replace("\\", "\\\\").Replace("\"", "\\\"") +
"\", \"score\": " + it.Score.ToString("0.000") +
", \"bounds\": [" + b.X.ToString("0") + "," + b.Y.ToString("0") +
"," + b.Width.ToString("0") + "," + b.Height.ToString("0") + "]}" +
(i < items.Count - 1 ? "," : ""));
}
}
json.AppendLine(" ]");
json.AppendLine("}");
string ocrPath = Path.Combine(outDir, "selftest_ocr.json");
File.WriteAllText(ocrPath, json.ToString(), new UTF8Encoding(false));
log.AppendLine("[ocr] 识别 " + (items == null ? 0 : items.Count) +
" 条,已保存: " + ocrPath);
if (items != null)
{
foreach (var it in items)
log.AppendLine(" - " + it.Text);
}
}
}
}
catch (Exception ex)
{
log.AppendLine("[FAIL] " + ex);
exit = 1;
}
string resultPath = Path.Combine(outDir, "selftest_result.txt");
File.WriteAllText(resultPath, log.ToString(), new UTF8Encoding(false));
Console.Out.WriteLine(log.ToString());
return exit;
}
}
}
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
</startup>
<appSettings>
<!-- Python 解释器(已装 rapidocr + onnxruntime-directml) -->
<add key="PythonExe" value="F:\PythonDev\python\python\python.exe" />
<!-- OCR 工作进程脚本(相对 exe 目录) -->
<add key="OcrWorkerScript" value="ocr_worker.py" />
</appSettings>
</configuration>
-8
View File
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</windowsSettings>
</application>
</assembly>
-60
View File
@@ -1,60 +0,0 @@
-nologo
-target:winexe
-platform:x86
-utf8output
-optimize+
-out:bin\Debug\pdfbt_new.exe
-win32manifest:app.manifest
-resource:MainForm.resx,pdfbt.MainForm.resources
-resource:OcrSettingsForm.resx,pdfbt.OcrSettingsForm.resources
-resource:Plugin\Form3.resx,pdfbt.Plugin.Form3.resources
-resource:Plugin\新建项目.resx,pdfbt.Plugin.新建项目.resources
-r:bin\Debug\Smart.CustomComponents.dll
-r:bin\Debug\AdvancedDataGridView.dll
-r:bin\Debug\WeifenLuo.WinFormsUI.Docking.dll
-r:bin\Debug\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll
-r:bin\Debug\System.Data.SQLite.dll
-r:bin\Debug\System.Memory.dll
-r:bin\Debug\System.Numerics.Vectors.dll
-r:bin\Debug\System.Resources.Extensions.dll
-r:bin\Debug\System.Runtime.CompilerServices.Unsafe.dll
-r:System.dll
-r:System.Configuration.dll
-r:System.Data.dll
-r:System.Data.DataSetExtensions.dll
-r:System.Xml.Linq.dll
-r:System.IO.Compression.dll
-r:System.IO.Compression.FileSystem.dll
-r:bin\Debug\log4net.dll
-r:netstandard.dll
-r:System.Core.dll
-r:System.Drawing.dll
-r:System.Windows.Forms.dll
-r:System.Xml.dll
-r:System.Web.Extensions.dll
-r:Microsoft.CSharp.dll
MainForm.cs
MainForm.Designer.cs
MainForm.DockWindows.cs
Program.cs
SelfTest.cs
PdfBridge.cs
PdfiumNative.cs
PdfDocument.cs
OcrClient.cs
GlmOcrClient.cs
QianfanOcrClient.cs
UapisOcrClient.cs
UmiOcrClient.cs
UmiOcrHost.cs
OcrSettingsForm.cs
OcrSettingsForm.Designer.cs
PdfViewerWindow.cs
Properties\AssemblyInfo.cs
Plugin\Form3.cs
Plugin\Form3.Designer.cs
Plugin\PaTypes.cs
Plugin\新建项目.cs
Plugin\新建项目.Designer.cs
DockWindows\QuoteWindow.cs
DockWindows\QuoteWindow.Designer.cs
Binary file not shown.
Binary file not shown.
Binary file not shown.
-194
View File
@@ -1,194 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<RootNamespace>pdfbt</RootNamespace>
<AssemblyName>pdfbt</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<AppDesignerFolder>Properties</AppDesignerFolder>
<PlatformTarget>x86</PlatformTarget>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<Prefer32Bit>True</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.DataSetExtensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Extensions">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="Smart.CustomComponents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ba044a4aa43e0dc4">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\Smart.CustomComponents.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="WeifenLuo.WinFormsUI.Docking">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\WeifenLuo.WinFormsUI.Docking.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="WeifenLuo.WinFormsUI.Docking.ThemeVS2015">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SQLite">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Data.SQLite.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="log4net">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\log4net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Resources.Extensions">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Resources.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Memory">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Memory.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics.Vectors">
<HintPath>C:\Program Files (x86)\SharpDevelop\5.2\bin\System.Numerics.Vectors.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AdvancedDataGridView">
<HintPath>libs\AdvancedDataGridView.dll</HintPath>
<Private>True</Private>
</Reference>
<!-- System.Memory 等 facade 库触发 CS0012,需 netstandard 契约 -->
<Reference Include="netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.8\Facades\netstandard.dll</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="MainForm.DockWindows.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="SelfTest.cs" />
<Compile Include="PdfBridge.cs" />
<!-- ★ A1(2026-10-01):OCR/PDF 基础设施与主项目共享同一份源码(链接编译,不再各留副本)——
权威源 成套报价软件\扒图\(主项目版为演进版,含 OcrPaths 旧布局回退/ocr.cls 方向纠正/
UmiOcr 启停拆分等修复);此前 pdfbt 侧 10 个本地副本是旧快照,已删除(git 基线可找回) -->
<Compile Include="..\成套报价软件\扒图\PdfiumNative.cs">
<Link>共享扒图\PdfiumNative.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\PdfDocument.cs">
<Link>共享扒图\PdfDocument.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\OcrClient.cs">
<Link>共享扒图\OcrClient.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\GlmOcrClient.cs">
<Link>共享扒图\GlmOcrClient.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\QianfanOcrClient.cs">
<Link>共享扒图\QianfanOcrClient.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\UapisOcrClient.cs">
<Link>共享扒图\UapisOcrClient.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\UmiOcrClient.cs">
<Link>共享扒图\UmiOcrClient.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\UmiOcrHost.cs">
<Link>共享扒图\UmiOcrHost.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\UmiOcrLauncher.cs">
<Link>共享扒图\UmiOcrLauncher.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\OcrSettingsForm.cs">
<Link>共享扒图\OcrSettingsForm.cs</Link>
</Compile>
<Compile Include="..\成套报价软件\扒图\OcrSettingsForm.Designer.cs">
<Link>共享扒图\OcrSettingsForm.Designer.cs</Link>
<DependentUpon>OcrSettingsForm.cs</DependentUpon>
</Compile>
<Compile Include="PdfViewerWindow.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Plugin\Form3.cs" />
<Compile Include="Plugin\Form3.Designer.cs">
<DependentUpon>Form3.cs</DependentUpon>
</Compile>
<Compile Include="Plugin\PaTypes.cs" />
<Compile Include="Plugin\新建项目.cs" />
<Compile Include="Plugin\新建项目.Designer.cs">
<DependentUpon>新建项目.cs</DependentUpon>
</Compile>
<Compile Include="DockWindows\QuoteWindow.cs" />
<Compile Include="DockWindows\QuoteWindow.Designer.cs">
<DependentUpon>QuoteWindow.cs</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="app.manifest" />
</ItemGroup>
<ItemGroup>
<!-- x86 pdfium(pypdfium2 win32 wheel 提取,与 SQLite x86 一致) -->
<Content Include="libs\pdfium\pdfium.dll">
<Link>pdfium.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<!-- Python OCR 工作进程脚本(rapidocr + DirectML GPU 加速) -->
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<!-- OcrSettingsForm.resx 删除:表单已链接共享主项目源码(A1),本地空壳 resx 与链接 Designer 不再匹配 -->
<EmbeddedResource Include="Plugin\Form3.resx">
<DependentUpon>Form3.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Plugin\新建项目.resx">
<DependentUpon>新建项目.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
-20
View File
@@ -1,20 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
# SharpDevelop 5.2
VisualStudioVersion = 12.0.20827.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pdfbt", "pdfbt.csproj", "{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C2A9D4E-1F58-4B6A-9E77-3A5B10D9C8F1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
View File
-31
View File
@@ -1,31 +0,0 @@
// 复现 OCR 设置窗报错,把完整异常写到文件
using System;
using System.Windows.Forms;
namespace pdfbt
{
static class ShowErr
{
[STAThread]
static void Main()
{
try
{
var f = new OcrSettingsForm(null);
f.Show();
Application.DoEvents();
FileLog("窗口创建成功,无异常");
}
catch (Exception ex)
{
FileLog("EX: " + ex);
var inner = ex.InnerException;
while (inner != null) { FileLog("INNER: " + inner); inner = inner.InnerException; }
}
}
static void FileLog(string s)
{
System.IO.File.AppendAllText(@"C:\Users\099978\Documents\SharpDevelop Projects\pdfbt\showerr.log", s + "\r\n");
}
}
}
+1 -3
View File
@@ -118,10 +118,8 @@ Source: "sjk\*"; DestDir: "{app}\sjk"; Flags: ignoreversion recursesubdirs creat
Source: "shezhi\*"; DestDir: "{app}\shezhi"; Flags: ignoreversion recursesubdirs createallsubdirs
; 甲方报表 Excel 模板(按图号/按箱号/按箱号+箱体面积/按箱类型)
Source: "xiangmu\*"; DestDir: "{app}\xiangmu"; Flags: ignoreversion recursesubdirs createallsubdirs
; CAD 扒图(独立程序,默认安装)
; CAD 网页引擎运行时(node+CAD-Viewer;2026-10-01 独立 cadbt.exe 退役,主程序内嵌扒图窗口用)
Source: "cadbt\*"; DestDir: "{app}\cadbt"; Flags: ignoreversion recursesubdirs createallsubdirs
; PDF 扒图(独立程序+OCR 环境,默认安装)
Source: "pdfbt\*"; DestDir: "{app}\pdfbt"; Flags: ignoreversion recursesubdirs createallsubdirs
; AI 助手引擎(ZCode 开源版 zai-org/ZCode,Apache-2.0:zcode 发行包+捆绑 node+预置+启停 cmd;zcode数据 运行时自建不进包)
Source: "ai助手\*"; DestDir: "{app}\ai助手"; Flags: ignoreversion recursesubdirs createallsubdirs
; 会员服务器不进包(2026-09-22 用户长期规则:客户端默认连云端 https://ss61.odn.cc,部署套件单独交付)
+2 -17
View File
@@ -119,13 +119,9 @@ def main():
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
print("复制目录", d)
# ===== cadbt(CAD扒图独立程序,默认安装) =====
# ===== cadbt(CAD 网页引擎运行时;2026-10-01 独立 cadbt.exe 退役,只装 node+CAD-Viewer) =====
cadbt_src = os.path.join(ROOT, "cadbt", "cadbt", "bin", "Debug")
cadbt_dst = os.path.join(REL, "cadbt")
os.makedirs(cadbt_dst, exist_ok=True)
for f in os.listdir(cadbt_src):
if f.endswith((".exe", ".dll", ".config")):
shutil.copy2(os.path.join(cadbt_src, f), os.path.join(cadbt_dst, f))
os.makedirs(os.path.join(cadbt_dst, "node"), exist_ok=True)
shutil.copy2(os.path.join(cadbt_src, "node", "node.exe"), os.path.join(cadbt_dst, "node", "node.exe"))
dist_src = os.path.join(ROOT, "cadbt", "cadbt", "CAD-Viewer", "packages", "cad-viewer-example", "dist")
@@ -148,18 +144,7 @@ def main():
print("补齐 dist/server.cjs")
else:
print("!! 运行目录缺少 server.cjs(CAD 网页服务起不来!)")
os.makedirs(os.path.join(cadbt_dst, "sjk", "bjb"), exist_ok=True)
print("复制目录 cadbt(exe+DLL+node+dist 网页+fonts/templates/server.cjs)")
# ===== pdfbt(PDF扒图独立程序+OCR Python 环境,默认安装) =====
pdfbt_src = os.path.join(ROOT, "pdfbt", "bin", "Debug")
pdfbt_dst = os.path.join(REL, "pdfbt")
os.makedirs(pdfbt_dst, exist_ok=True)
for f in os.listdir(pdfbt_src):
if f.endswith((".exe", ".dll", ".config")):
shutil.copy2(os.path.join(pdfbt_src, f), os.path.join(pdfbt_dst, f))
os.makedirs(os.path.join(pdfbt_dst, "sjk", "bjb"), exist_ok=True)
print("复制目录 pdfbt(exe+pdfium,OCR=百度API无需本地环境)")
print("复制目录 cadbt(node+CAD-Viewer 网页引擎+fonts/templates/server.cjs;独立 exe 已退役)")
# ===== AI 助手引擎目录(2026-09-26 OpenClaw→ZCode 开源版 zai-org/ZCode) =====
# ai助手\ = zcode\(官方 build:zcode 发行包:bin/web/server/agent/node_modules + 捆绑 node)
+1 -3
View File
@@ -48,9 +48,7 @@ def main():
# 主程序
shutil.copy2(os.path.join(REL, "成套报价软件.exe"), PKG)
# PDF 扒图独立程序(2026-10-01 第2期:缩放卡顿同步修复)
shutil.copy2(os.path.join(REL, "pdfbt", "pdfbt.exe"), PKG)
# (2026-10-01 独立 pdfbt.exe 退役后不再随更新包分发)
# 使用说明(GBK,记事本直接打开不乱码)
with open(os.path.join(PKG, "使用说明.txt"), "w", encoding="gbk", newline="\r\n") as f:
+24 -10
View File
@@ -1,4 +1,4 @@
# ============================================================
# ============================================================
# 扒图同步检查.ps1 —— Cad/Pdf 扒图窗口 Form3.cs 漂移护栏
# ============================================================
# 背景: 扒图\Cad\Form3.cs 与 扒图\Pdf\Form3.cs 是约 98% 重复的双胞胎文件
@@ -18,8 +18,19 @@ $cadPath = Join-Path $root '成套报价软件\扒图\Cad\Form3.cs'
$pdfPath = Join-Path $root '成套报价软件\扒图\Pdf\Form3.cs'
$baseline = Join-Path $PSScriptRoot '扒图同步基线.txt'
foreach ($f in @($cadPath, $pdfPath)) {
# ★ 2026-10-01 扩充:从只查 Form3.cs 扩展到全部 Cad/Pdf 双胞胎文件对
# (新建项目.cs 与两对 Designer/ui.cs 此前是漂移盲区)
$pairs = @(
@('成套报价软件\扒图\Cad\Form3.cs', '成套报价软件\扒图\Pdf\Form3.cs'),
@('成套报价软件\扒图\Cad\新建项目.cs', '成套报价软件\扒图\Pdf\新建项目.cs'),
@('成套报价软件\扒图\Cad\Form3.ui.cs', '成套报价软件\扒图\Pdf\Form3.Designer.cs'),
@('成套报价软件\扒图\Cad\新建项目.ui.cs', '成套报价软件\扒图\Pdf\新建项目.Designer.cs')
)
foreach ($p in $pairs) {
foreach ($f in @((Join-Path $root $p[0]), (Join-Path $root $p[1]))) {
if (-not (Test-Path $f)) { Write-Host "[FAIL] 缺少文件: $f" -ForegroundColor Red; exit 2 }
}
}
function Normalize([string]$path) {
@@ -34,17 +45,20 @@ function Normalize([string]$path) {
$tmpCad = Join-Path $env:TEMP 'baotu_cad_norm.cs'
$tmpPdf = Join-Path $env:TEMP 'baotu_pdf_norm.cs'
Normalize $cadPath | Set-Content $tmpCad -Encoding UTF8
Normalize $pdfPath | Set-Content $tmpPdf -Encoding UTF8
$diffFile = Join-Path $env:TEMP 'baotu_drift.diff'
$null = git diff --no-index --unified=1 $tmpCad $tmpPdf 2>$null | Out-File $diffFile -Encoding UTF8
$numstat = git diff --no-index --numstat $tmpCad $tmpPdf 2>$null
$added = 0; $deleted = 0
if ($numstat) {
"" | Out-File $diffFile -Encoding UTF8
foreach ($p in $pairs) {
$cadF = Join-Path $root $p[0]; $pdfF = Join-Path $root $p[1]
Normalize $cadF | Set-Content $tmpCad -Encoding UTF8
Normalize $pdfF | Set-Content $tmpPdf -Encoding UTF8
$null = git diff --no-index --unified=1 $tmpCad $tmpPdf 2>$null | Out-File $diffFile -Append -Encoding UTF8
$numstat = git diff --no-index --numstat $tmpCad $tmpPdf 2>$null
if ($numstat) {
$parts = (@($numstat)[0]) -split "`t"
if ($parts.Count -ge 2) { $added = [int]$parts[0]; $deleted = [int]$parts[1] }
if ($parts.Count -ge 2) { $added += [int]$parts[0]; $deleted += [int]$parts[1] }
}
}
$drift = $added + $deleted
-269
View File
@@ -1,269 +0,0 @@
namespace yjktool
{
partial class MainForm
{
private System.ComponentModel.IContainer components = null;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null)) components.Dispose();
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
private void InitializeComponent()
{
this.lbl搜索 = new System.Windows.Forms.Label();
this.txt搜索 = new System.Windows.Forms.TextBox();
this.lst厂家 = new System.Windows.Forms.ListView();
this.btn全选 = new System.Windows.Forms.Button();
this.btn反选 = new System.Windows.Forms.Button();
this.lbl线程 = new System.Windows.Forms.Label();
this.num线程 = new System.Windows.Forms.NumericUpDown();
this.lbl输出 = new System.Windows.Forms.Label();
this.txt输出 = new System.Windows.Forms.TextBox();
this.btn开始 = new System.Windows.Forms.Button();
this.btn打包 = new System.Windows.Forms.Button();
this.chk代理 = new System.Windows.Forms.CheckBox();
this.lbl代理 = new System.Windows.Forms.Label();
this.chk清理 = new System.Windows.Forms.CheckBox();
this.progress = new System.Windows.Forms.ProgressBar();
this.lbl进度 = new System.Windows.Forms.Label();
this.rtb日志 = new System.Windows.Forms.RichTextBox();
this.lbl统计 = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.num线程)).BeginInit();
this.SuspendLayout();
//
// lbl搜索
//
this.lbl搜索.AutoSize = true;
this.lbl搜索.Location = new System.Drawing.Point(12, 15);
this.lbl搜索.Name = "lbl搜索";
this.lbl搜索.Size = new System.Drawing.Size(37, 17);
this.lbl搜索.TabIndex = 0;
this.lbl搜索.Text = "搜索:";
//
// txt搜索
//
this.txt搜索.Location = new System.Drawing.Point(55, 12);
this.txt搜索.Name = "txt搜索";
this.txt搜索.Size = new System.Drawing.Size(200, 25);
this.txt搜索.TabIndex = 1;
this.txt搜索.TextChanged += new System.EventHandler(this.txt搜索_TextChanged);
//
// lst厂家
//
this.lst厂家.CheckBoxes = true;
this.lst厂家.Columns.Add("厂家");
this.lst厂家.Columns[0].Width = 240;
this.lst厂家.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
this.lst厂家.HideSelection = true;
this.lst厂家.Location = new System.Drawing.Point(12, 44);
this.lst厂家.MultiSelect = false;
this.lst厂家.Name = "lst厂家";
this.lst厂家.ShowGroups = false;
this.lst厂家.Size = new System.Drawing.Size(262, 470);
this.lst厂家.TabIndex = 2;
this.lst厂家.View = System.Windows.Forms.View.Details;
//
// btn全选
//
this.btn全选.Location = new System.Drawing.Point(12, 520);
this.btn全选.Name = "btn全选";
this.btn全选.Size = new System.Drawing.Size(75, 28);
this.btn全选.TabIndex = 3;
this.btn全选.Text = "全选";
this.btn全选.UseVisualStyleBackColor = true;
this.btn全选.Click += new System.EventHandler(this.btn全选_Click);
//
// btn反选
//
this.btn反选.Location = new System.Drawing.Point(96, 520);
this.btn反选.Name = "btn反选";
this.btn反选.Size = new System.Drawing.Size(75, 28);
this.btn反选.TabIndex = 4;
this.btn反选.Text = "反选";
this.btn反选.UseVisualStyleBackColor = true;
this.btn反选.Click += new System.EventHandler(this.btn反选_Click);
//
// lbl统计
//
this.lbl统计.AutoSize = true;
this.lbl统计.ForeColor = System.Drawing.Color.DimGray;
this.lbl统计.Location = new System.Drawing.Point(180, 525);
this.lbl统计.Name = "lbl统计";
this.lbl统计.Size = new System.Drawing.Size(0, 17);
this.lbl统计.TabIndex = 5;
//
// lbl线程
//
this.lbl线程.AutoSize = true;
this.lbl线程.Location = new System.Drawing.Point(290, 15);
this.lbl线程.Name = "lbl线程";
this.lbl线程.Size = new System.Drawing.Size(52, 17);
this.lbl线程.TabIndex = 6;
this.lbl线程.Text = "线程数:";
//
// num线程
//
this.num线程.Location = new System.Drawing.Point(348, 12);
this.num线程.Maximum = new decimal(new int[] { 16, 0, 0, 0 });
this.num线程.Minimum = new decimal(new int[] { 1, 0, 0, 0 });
this.num线程.Name = "num线程";
this.num线程.Size = new System.Drawing.Size(52, 25);
this.num线程.TabIndex = 7;
this.num线程.Value = new decimal(new int[] { 4, 0, 0, 0 });
//
// lbl输出
//
this.lbl输出.AutoSize = true;
this.lbl输出.Location = new System.Drawing.Point(418, 15);
this.lbl输出.Name = "lbl输出";
this.lbl输出.Size = new System.Drawing.Size(67, 17);
this.lbl输出.TabIndex = 8;
this.lbl输出.Text = "输出目录:";
//
// txt输出
//
this.txt输出.Location = new System.Drawing.Point(487, 12);
this.txt输出.Name = "txt输出";
this.txt输出.Size = new System.Drawing.Size(340, 25);
this.txt输出.TabIndex = 9;
//
// btn开始
//
this.btn开始.Location = new System.Drawing.Point(290, 44);
this.btn开始.Name = "btn开始";
this.btn开始.Size = new System.Drawing.Size(120, 32);
this.btn开始.TabIndex = 10;
this.btn开始.Text = "开始抓取";
this.btn开始.UseVisualStyleBackColor = true;
this.btn开始.Click += new System.EventHandler(this.btn开始_Click);
//
// btn打包
//
this.btn打包.Location = new System.Drawing.Point(420, 44);
this.btn打包.Name = "btn打包";
this.btn打包.Size = new System.Drawing.Size(120, 32);
this.btn打包.TabIndex = 11;
this.btn打包.Text = "打包数据包";
this.btn打包.UseVisualStyleBackColor = true;
this.btn打包.Click += new System.EventHandler(this.btn打包_Click);
//
// progress
//
this.progress.Location = new System.Drawing.Point(560, 50);
this.progress.Name = "progress";
this.progress.Size = new System.Drawing.Size(180, 20);
this.progress.TabIndex = 12;
//
// lbl进度
//
this.lbl进度.AutoSize = true;
this.lbl进度.Location = new System.Drawing.Point(750, 54);
this.lbl进度.Name = "lbl进度";
this.lbl进度.Size = new System.Drawing.Size(0, 17);
this.lbl进度.TabIndex = 13;
//
// chk代理
//
this.chk代理.AutoSize = true;
this.chk代理.Location = new System.Drawing.Point(290, 82);
this.chk代理.Name = "chk代理";
this.chk代理.Size = new System.Drawing.Size(204, 21);
this.chk代理.TabIndex = 15;
this.chk代理.Text = "价格走旧代理(8081,自动启动)";
this.chk代理.UseVisualStyleBackColor = true;
this.chk代理.CheckedChanged += new System.EventHandler(this.chk代理_CheckedChanged);
//
// lbl代理
//
this.lbl代理.AutoSize = true;
this.lbl代理.ForeColor = System.Drawing.Color.Firebrick;
this.lbl代理.Location = new System.Drawing.Point(500, 85);
this.lbl代理.Name = "lbl代理";
this.lbl代理.Size = new System.Drawing.Size(103, 17);
this.lbl代理.TabIndex = 16;
this.lbl代理.Text = "旧代理:未检测";
//
// chk清理
//
this.chk清理.AutoSize = true;
this.chk清理.Checked = true;
this.chk清理.CheckState = System.Windows.Forms.CheckState.Checked;
this.chk清理.Location = new System.Drawing.Point(620, 82);
this.chk清理.Name = "chk清理";
this.chk清理.Size = new System.Drawing.Size(163, 21);
this.chk清理.TabIndex = 17;
this.chk清理.Text = "抓取前清空旧数据(缓存+输出)";
this.chk清理.UseVisualStyleBackColor = true;
//
// rtb日志
//
this.rtb日志.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(30)))), ((int)(((byte)(30)))), ((int)(((byte)(30)))));
this.rtb日志.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.rtb日志.ForeColor = System.Drawing.Color.Gainsboro;
this.rtb日志.Font = new System.Drawing.Font("Consolas", 9F);
this.rtb日志.Location = new System.Drawing.Point(290, 110);
this.rtb日志.Name = "rtb日志";
this.rtb日志.ReadOnly = true;
this.rtb日志.Size = new System.Drawing.Size(537, 404);
this.rtb日志.TabIndex = 14;
this.rtb日志.Text = "";
//
// MainForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(842, 561);
this.Controls.Add(this.lbl代理);
this.Controls.Add(this.chk代理);
this.Controls.Add(this.chk清理);
this.Controls.Add(this.rtb日志);
this.Controls.Add(this.lbl进度);
this.Controls.Add(this.progress);
this.Controls.Add(this.btn打包);
this.Controls.Add(this.btn开始);
this.Controls.Add(this.txt输出);
this.Controls.Add(this.lbl输出);
this.Controls.Add(this.num线程);
this.Controls.Add(this.lbl线程);
this.Controls.Add(this.lbl统计);
this.Controls.Add(this.btn反选);
this.Controls.Add(this.btn全选);
this.Controls.Add(this.lst厂家);
this.Controls.Add(this.txt搜索);
this.Controls.Add(this.lbl搜索);
this.MaximizeBox = false;
this.Name = "MainForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "元件库厂家数据工具";
((System.ComponentModel.ISupportInitialize)(this.num线程)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lbl搜索;
private System.Windows.Forms.TextBox txt搜索;
private System.Windows.Forms.ListView lst厂家;
private System.Windows.Forms.Button btn全选;
private System.Windows.Forms.Button btn反选;
private System.Windows.Forms.Label lbl统计;
private System.Windows.Forms.Label lbl线程;
private System.Windows.Forms.NumericUpDown num线程;
private System.Windows.Forms.Label lbl输出;
private System.Windows.Forms.TextBox txt输出;
private System.Windows.Forms.Button btn开始;
private System.Windows.Forms.Button btn打包;
private System.Windows.Forms.ProgressBar progress;
private System.Windows.Forms.Label lbl进度;
private System.Windows.Forms.RichTextBox rtb日志;
private System.Windows.Forms.CheckBox chk代理;
private System.Windows.Forms.Label lbl代理;
private System.Windows.Forms.CheckBox chk清理;
}
}
-352
View File
@@ -1,352 +0,0 @@
// 元件库数据工具:按厂家勾选抓取数据(树/系列/价格),打包成数据包 zip 供新服务读取
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace yjktool
{
public partial class MainForm : Form
{
private List<厂家项> 全部厂家 = new List<厂家项>();
private string 工作根; // 抓取落盘根(data 布局)
private 抓取器 抓;
private volatile bool 运行中;
private class 厂家项
{
public string 树id;
public string 名称;
public override string ToString() { return 名称; }
}
public MainForm()
{
InitializeComponent();
工作根 = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "抓取输出");
txt输出.Text = 工作根;
加载厂家清单();
chk代理.Checked = true; // 默认走旧代理(抓取时会自动启动工具内置的旧代理)
检测旧代理(); // 启动时显示旧代理在线状态
FormClosing += (s, e) => 关闭内置旧代理();
}
// ---------- 旧代理(工具内置副本,8081;node 新服务占 8080 不能同端口) ----------
private const int 代理端口 = 8081;
private System.Diagnostics.Process _代理进程; // 本工具拉起的内置旧代理(退出时收尾)
private static bool 端口通(int 端口)
{
try
{
using (var c = new System.Net.Sockets.TcpClient())
{
var ar = c.BeginConnect("127.0.0.1", 端口, null, null);
return ar.AsyncWaitHandle.WaitOne(600) && c.Connected;
}
}
catch { return false; }
}
/// <summary>8081 不通时自动启动工具旁的内置旧代理(旧代理\python\python.exe -u proxy_server.py --port 8081)。
/// 阻塞最多约 15 秒等端口就绪,应在后台线程调用。</summary>
private bool 确保旧代理运行()
{
if (端口通(代理端口)) return true;
string dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "旧代理");
string py = Path.Combine(dir, "python", "python.exe");
if (!File.Exists(py) || !File.Exists(Path.Combine(dir, "proxy_server.py")))
{
UI日志("! 工具旁没有内置旧代理目录(旧代理\\python\\python.exe),价格将全部落空");
return false;
}
UI日志("正在启动内置旧代理(端口 " + 代理端口 + ")…");
try
{
_代理进程 = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
{
FileName = py,
Arguments = "-u proxy_server.py --port " + 代理端口,
WorkingDirectory = dir,
UseShellExecute = false,
CreateNoWindow = true,
});
}
catch (Exception ex) { UI日志("! 启动旧代理失败: " + ex.Message); return false; }
for (int i = 0; i < 30 && !端口通(代理端口); i++) Thread.Sleep(500);
bool ok = 端口通(代理端口);
UI日志(ok ? "✅ 内置旧代理已启动(端口 " + 代理端口 + ")" : "! 内置旧代理 15 秒内未就绪(可能启动报错)");
检测旧代理();
return ok;
}
/// <summary>工具退出时结束自己拉起的内置旧代理,避免留孤儿进程</summary>
private void 关闭内置旧代理()
{
try
{
if (_代理进程 != null && !_代理进程.HasExited) _代理进程.Kill();
}
catch { }
}
/// <summary>所有可用的种子目录:工具内置副本+根目录原件(预热缓存)+元件库网页 data(现成真价,含原始 t)。</summary>
private static string[] 旧代理缓存目录们()
{
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string[] 候选 = {
Path.Combine(baseDir, @"旧代理\proxy_cache"), // 工具内置副本
Path.Combine(baseDir, @"..\..\..\旧服务-python代理\src\proxy_cache"), // 根目录原件(预热流程)
Path.Combine(baseDir, @"..\..\..\成套报价软件\bin\Debug\元件库网页\data\dx2_webGetPrice"), // 新服务现成真价(开发机)
Path.Combine(baseDir, @"元件库网页\data\dx2_webGetPrice"), // 安装布局
};
return Array.FindAll(候选, p => Directory.Exists(p));
}
/// <summary>清空旧数据:抓取输出两目录(树/系列包+价格)+两处旧代理缓存(proxy_cache)。
/// 旧代理缓存会被直接回放成旧响应(等于抓到的还是旧价),要拿全新数据就得先清。在启动代理前执行。</summary>
private int 清空旧数据()
{
int n = 0;
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string[] 目录们 = {
Path.Combine(工作根, @"dian\electricData_zips"),
Path.Combine(工作根, @"dx2_webGetPrice"),
Path.Combine(baseDir, @"旧代理\proxy_cache"), // 工具内置副本
Path.Combine(baseDir, @"..\..\..\旧服务-python代理\src\proxy_cache"), // 根目录原件
};
foreach (string d in 目录们)
{
try
{
if (!Directory.Exists(d)) continue;
int 个数 = Directory.GetFiles(d, "*", SearchOption.AllDirectories).Length;
Directory.Delete(d, true);
Directory.CreateDirectory(d);
n++;
UI日志(" 已清空 " + 个数 + " 个文件: " + d);
}
catch (Exception ex) { UI日志(" ! 清空失败 " + d + ": " + ex.Message); }
}
return n;
}
private void 检测旧代理()
{
if (InvokeRequired) { BeginInvoke((Action)(检测旧代理)); return; }
bool 在线 = 端口通(代理端口);
lbl代理.Text = 在线 ? "旧代理:在线 ✓" : "旧代理:离线";
lbl代理.ForeColor = 在线 ? System.Drawing.Color.Green : System.Drawing.Color.Firebrick;
}
private void chk代理_CheckedChanged(object sender, EventArgs e)
{
if (chk代理.Checked) 检测旧代理();
else lbl代理.Text = "旧代理:未使用";
}
// ---------- 厂家清单:元件库网页\data(开发/安装布局)→exe旁→内置 f.zip 都无则提示 ----------
private void 加载厂家清单()
{
string fzip = null;
string baseDir = AppDomain.CurrentDomain.BaseDirectory;
string[] 候选 = {
Path.Combine(baseDir, @"..\..\..\成套报价软件\bin\Debug\元件库网页\data\dian\electricData_zips\f.zip"),
Path.Combine(baseDir, @"..\..\..\..\..\..\成套报价软件\bin\Debug\元件库网页\data\dian\electricData_zips\f.zip"),
Path.Combine(baseDir, @"元件库网页\data\dian\electricData_zips\f.zip"),
Path.Combine(baseDir, "f.zip"),
};
foreach (string p in 候选)
if (File.Exists(p)) { fzip = p; break; }
if (fzip == null)
{
MessageBox.Show(this, "找不到厂家清单 f.zip。\r\n请把工具放在 元件库网页\\ 目录旁,或把 f.zip 拷到工具旁。",
"元件库数据工具", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
string 文;
using (var z = ZipFile.OpenRead(fzip))
using (var r = new StreamReader(z.Entries[0].Open(), System.Text.Encoding.UTF8))
文 = r.ReadToEnd();
var 见过 = new HashSet<string>();
foreach (Match m in Regex.Matches(文, @"\{[^{}]*?""f""\s*:\s*(\d+)[^{}]*?""name""\s*:\s*""([^""]+)""[^{}]*?\}"))
{
string id = m.Groups[1].Value;
if (id == "0" || 见过.Contains(id)) continue;
见过.Add(id);
全部厂家.Add(new 厂家项 { 树id = id, 名称 = m.Groups[2].Value });
}
// f 在 name 前的变体
if (全部厂家.Count == 0)
{
foreach (Match m in Regex.Matches(文, @"\{[^{}]*?""name""\s*:\s*""([^""]+)""[^{}]*?""f""\s*:\s*(\d+)[^{}]*?\}"))
{
string id = m.Groups[2].Value;
if (id == "0" || 见过.Contains(id)) continue;
见过.Add(id);
全部厂家.Add(new 厂家项 { 树id = id, 名称 = m.Groups[1].Value });
}
}
填列表("");
lbl统计.Text = "厂家 " + 全部厂家.Count + " 家";
}
catch (Exception ex)
{
MessageBox.Show(this, "读取 f.zip 失败: " + ex.Message, "元件库数据工具");
}
}
private void 填列表(string 过滤)
{
lst厂家.BeginUpdate();
lst厂家.Items.Clear();
foreach (var f in 全部厂家)
{
if (过滤 != "" && f.名称.IndexOf(过滤, StringComparison.OrdinalIgnoreCase) < 0) continue;
var it = lst厂家.Items.Add(f.名称);
it.Checked = false;
it.Tag = f;
}
lst厂家.EndUpdate();
}
private void txt搜索_TextChanged(object sender, EventArgs e)
{
填列表(txt搜索.Text.Trim());
}
private void btn全选_Click(object sender, EventArgs e)
{
foreach (ListViewItem it in lst厂家.Items) it.Checked = true;
}
private void btn反选_Click(object sender, EventArgs e)
{
foreach (ListViewItem it in lst厂家.Items) it.Checked = !it.Checked;
}
// ---------- UI 线程调度 ----------
private void UI日志(string s)
{
if (InvokeRequired) { BeginInvoke((Action)(() => UI日志(s))); return; }
rtb日志.AppendText("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + s + "\r\n");
}
private void UI进度(int 厂完成, int 厂总数)
{
if (InvokeRequired) { BeginInvoke((Action)(() => UI进度(厂完成, 厂总数))); return; }
if (厂总数 > 0) progress.Value = Math.Min(progress.Maximum, 厂完成 * 100 / 厂总数);
lbl进度.Text = 厂完成 + " / " + 厂总数;
}
private void btn开始_Click(object sender, EventArgs e)
{
if (运行中) { 抓.停止 = true; btn开始.Text = "正在停止…"; return; }
var 选中 = lst厂家.Items.Cast<ListViewItem>().Where(i => i.Checked).Select(i => (厂家项)i.Tag).ToList();
if (选中.Count == 0)
{
MessageBox.Show(this, "请先勾选要抓取的厂家。", "元件库数据工具");
return;
}
工作根 = txt输出.Text.Trim();
Directory.CreateDirectory(Path.Combine(工作根, "dian", "electricData_zips"));
Directory.CreateDirectory(Path.Combine(工作根, "dx2_webGetPrice"));
抓 = new 抓取器(工作根) { 日志 = UI日志 };
抓.经旧代理 = chk代理.Checked;
运行中 = true;
btn开始.Text = "停止";
progress.Maximum = 100; progress.Value = 0;
int 线程 = (int)num线程.Value;
UI日志("开始抓取 " + 选中.Count + " 家,线程 " + 线程 + ",输出 " + 工作根 + (抓.经旧代理 ? ",价格走旧代理" : ",价格直连"));
int 总系 = 0, 总价 = 0;
ThreadPool.QueueUserWorkItem(_ =>
{
// 先清旧数据(用户要求:旧代理缓存会回放旧响应、抓取输出留旧文件,要全新数据先清干净)
if (chk清理.Checked)
{
UI日志("清空旧数据…");
清空旧数据();
}
// 代理仅在勾选时启动(终版机制直连+种子 t 即可命中,不依赖代理)
if (抓.经旧代理) 确保旧代理运行();
// ★ 种子加载与代理无关,必须无条件执行:种子(系列有效时刻 t)决定价格能不能查,
// 不加载种子则所有系列按"无 t"跳过查价 → 0 价格
string[] 缓存们 = 旧代理缓存目录们();
if (缓存们.Length > 0)
{
int n种 = 0;
foreach (string 缓存 in 缓存们) n种 = 抓.加载种子(缓存); // 多处种子合并
UI日志("已加载种子: " + n种 + " 个系列的有效时刻(来自 " + 缓存们.Length + " 处目录)");
if (n种 == 0)
UI日志("! 种子为 0:价格将全部跳过。先在预热页面浏览目标厂家系列,或确认元件库网页 data 目录存在");
}
else
UI日志("! 未找到种子目录(价格将全部跳过)");
var sw = Stopwatch.StartNew();
try
{
for (int i = 0; i < 选中.Count && !抓.停止; i++)
{
var kv = 抓.抓厂家(选中[i].树id, 选中[i].名称, 线程);
总系 += kv.Key; 总价 += kv.Value;
UI进度(i + 1, 选中.Count);
}
UI日志((抓.停止 ? "已停止: " : "抓取完成: ") + "系列 " + 总系 + ", 价格组合 " + 总价 +
", 用时 " + (int)sw.Elapsed.TotalMinutes + " 分钟。可点【打包数据包】。");
}
catch (Exception ex)
{
UI日志("! 抓取中断: " + ex);
}
BeginInvoke((Action)(() => { 运行中 = false; btn开始.Text = "开始抓取"; }));
});
}
// ---------- 打包 ----------
private void btn打包_Click(object sender, EventArgs e)
{
if (运行中) { MessageBox.Show(this, "抓取进行中,请先停止。"); return; }
if (!Directory.Exists(工作根))
{
MessageBox.Show(this, "输出目录不存在,先抓取。"); return;
}
using (var dlg = new SaveFileDialog
{
Title = "打包数据包",
Filter = "元件库数据包 (*.zip)|*.zip",
FileName = "厂家数据包_" + DateTime.Now.ToString("yyyyMMdd_HHmm") + ".zip",
InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
})
{
if (dlg.ShowDialog(this) != DialogResult.OK) return;
try
{
int n = 0;
using (var zip = ZipFile.Open(dlg.FileName, ZipArchiveMode.Create))
{
foreach (string f in Directory.GetFiles(工作根, "*", SearchOption.AllDirectories))
{
if (f.EndsWith(".json")) continue; // 树缓存伴随文件不入包
string rel = f.Substring(工作根.Length + 1).Replace('\\', '/');
zip.CreateEntryFromFile(f, rel, CompressionLevel.Optimal);
n++;
}
}
MessageBox.Show(this, "打包完成: " + n + " 个文件\r\n" + dlg.FileName +
"\r\n\r\n把 zip 放进主程序 元件库网页\\ 目录,重启程序即自动导入。", "元件库数据工具");
}
catch (Exception ex)
{
MessageBox.Show(this, "打包失败: " + ex.Message);
}
}
}
}
}
-30
View File
@@ -1,30 +0,0 @@
using System;
using System.Windows.Forms;
namespace yjktool
{
static class Program
{
[STAThread]
static void Main()
{
// 全局异常兜底:任何未捕获异常弹窗而不是闪退
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
Application.ThreadException += (s, e) => 弹(e.Exception);
AppDomain.CurrentDomain.UnhandledException += (s, e) => 弹(e.ExceptionObject as Exception);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
private static void 弹(Exception ex)
{
try
{
MessageBox.Show("程序异常(可继续):\n\n" + (ex == null ? "?" : ex.ToString()),
"元件库数据工具", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
catch { }
}
}
}
-47
View File
@@ -1,47 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{8A1E5C72-9D3B-4E7A-A0C1-5F6E7D8B9E01}</ProjectGuid>
<ProjectTypeGuids>{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
<RootNamespace>yjktool</RootNamespace>
<AssemblyName>元件库数据工具</AssemblyName>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="MainForm.cs" />
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="抓取器.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
-422
View File
@@ -1,422 +0,0 @@
// 抓取器:抓厂家树/系列规格/价格,按新服务布局落盘(断点续抓,多线程安全)
// 两种价格通道:直连 dq123(默认) / 经内置旧代理 localhost:8081(带会话伪装,命中率高——工具自动启动它)
// 8081 是工具专用端口:node 新服务(元件库网页)占了 8080,两者须能同时跑
// 种子模式:从旧代理 proxy_cache 提取真实查询过的组合(sid→bg 列表),优先按种子形状抓价(重放+单变化)
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
namespace yjktool
{
internal class 抓取器
{
// 域名映射照旧 python 代理
private const string 电数据 = "https://dian.dq123.com/electricData?v=";
private const string 价格口 = "https://dx2.dhub.com.cn/pcprice/default/dx2/interface/webGetPrice?infoJson=";
// 经旧代理(路径同源,代理按前缀转发到真实域名并注入会话头)
private const string 代电数据 = "http://127.0.0.1:8081/electricData?v=";
private const string 代价格口 = "http://127.0.0.1:8081/dx2/pcprice/default/dx2/interface/webGetPrice?infoJson=";
public string 输出根 { get; private set; }
private string ZipDir { get { return Path.Combine(输出根, "dian", "electricData_zips"); } }
private string 价Dir { get { return Path.Combine(输出根, "dx2_webGetPrice"); } }
/// <summary>价格请求是否经旧代理(8081)。树/系列包恒直连(静态资源无会话要求)。</summary>
public bool 经旧代理;
/// <summary>种子组合:旧代理缓存里真实查询过的 (系列→组合串列表),价格抓取优先按种子形状。</summary>
/// <summary>种子表:sid → [bg组合串, t历史时间戳] 列表。
/// 终版机制(实测):命中 = 系列在有效时刻 t 查过(服务器按 sid+t 记录) AND 组合是真实型号——
/// 系列只要有一个种子的 t,即可解锁它全部规格组组合的价格查询;t 用当前时间必返空。</summary>
private Dictionary<string, List<string[]>> 种子 = new Dictionary<string, List<string[]>>();
private int 无t系列数;
private int 无t提示过;
// 进度/日志回调(UI 线程调度由调用方处理)
public Action<string> 日志 { get; set; }
public Action<int, int> 进度 { get; set; } // (当前,总数)
public volatile bool 停止;
public 抓取器(string 输出目录)
{
输出根 = 输出目录;
Directory.CreateDirectory(ZipDir);
Directory.CreateDirectory(价Dir);
// net48 下显式启用 TLS1.2(dq123 全站 https,不设会握手失败)
try { ServicePointManager.SecurityProtocol = ServicePointManager.SecurityProtocol | SecurityProtocolType.Tls12; }
catch { }
ServicePointManager.DefaultConnectionLimit = 32;
}
/// <summary>从缓存/数据目录加载种子(webGetPrice 响应里的 bg 组合串+原始 t 时间戳)。
/// 可多处调用合并(旧代理缓存+元件库网页 data 的现成真价都吃)。返回种子系列数。</summary>
public int 加载种子(string 目录)
{
if (种子 == null) 种子 = new Dictionary<string, List<string[]>>();
try
{
foreach (string f in Directory.GetFiles(目录, "*webGetPrice*.data"))
{
try
{
string body = File.ReadAllText(f);
foreach (System.Text.RegularExpressions.Match m in
System.Text.RegularExpressions.Regex.Matches(body, "\"content\"\\s*:\\s*\"([A-Za-z0-9+/=]+)\""))
{
string decoded;
try { decoded = Encoding.UTF8.GetString(Convert.FromBase64String(m.Groups[1].Value)); }
catch { continue; }
if (string.IsNullOrEmpty(decoded) || decoded.Trim() == "[]") continue;
// ★ JavaScriptSerializer.Deserialize<object> 对顶层数组返回 Object[](不是 ArrayList),
// 按 IEnumerable 遍历两者通吃——之前 as ArrayList 恒 null,种子从来没加载成功过
System.Collections.IEnumerable 条集 = 解析器.Deserialize<object>(decoded) as System.Collections.IEnumerable;
if (条集 == null) continue;
foreach (object o in 条集)
{
var it = o as Dictionary<string, object>;
if (it == null || !it.ContainsKey("sid")) continue;
string sid = Convert.ToString(it["sid"]);
string bg = it.ContainsKey("bg") ? Convert.ToString(it["bg"]) : "";
// ★ t 是 13 位毫秒时间戳:JavaScriptSerializer 把 JSON 整数解析成 double,
// Convert.ToString(double) 会变成科学计数法(1.785401168E+12)拼进 time 服务器不认——
// 必须经 ToDouble→ToInt64 还原成纯数字串
string t = "";
object tv;
if (it.TryGetValue("t", out tv) && tv != null)
{
try { t = Convert.ToInt64(Convert.ToDouble(tv)).ToString(); }
catch { }
}
if (string.IsNullOrEmpty(sid) || string.IsNullOrEmpty(bg) || bg.IndexOf('-') < 0) continue;
if (string.IsNullOrEmpty(t)) continue; // 没 t 的种子重放不了(当前时间必空),跳过
List<string[]> l;
if (!种子.TryGetValue(sid, out l)) { l = new List<string[]>(); 种子[sid] = l; }
if (!l.Any(e => e[0] == bg)) l.Add(new[] { bg, t });
}
}
}
catch { }
}
}
catch { }
return 种子.Count;
}
private void L(string s) { if (日志 != null) 日志(s); }
// ---------- HTTP(简单重试) ----------
private byte[] Get(string url, int timeoutMs)
{
for (int 试 = 0; 试 < 3 && !停止; 试++)
{
try
{
var req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
req.Timeout = timeoutMs;
req.ReadWriteTimeout = timeoutMs;
req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0";
req.Referer = "https://www.dq123.com/";
req.Proxy = null;
using (var r = (HttpWebResponse)req.GetResponse())
using (var ms = new MemoryStream())
{
r.GetResponseStream().CopyTo(ms);
return ms.ToArray();
}
}
catch (WebException we)
{
var hr = we.Response as HttpWebResponse;
if (hr != null && (int)hr.StatusCode >= 400 && (int)hr.StatusCode < 500)
return null; // 4xx(404 无此包)不重试,快速跳过
Thread.Sleep(600);
}
catch (Exception) { return null; }
}
return null;
}
// ---------- v 参数(base64 逻辑名去 padding) ----------
private static string V参数(string 逻辑名)
{
string b = Convert.ToBase64String(Encoding.UTF8.GetBytes(逻辑名));
return b.TrimEnd('=');
}
/// <summary>读 ZIP 字节数组里的首个文件文本(JSON)。失败返回 null。</summary>
private static string 读Zip内文(byte[] zip)
{
try
{
using (var ms = new MemoryStream(zip))
using (var z = new ZipArchive(ms))
{
var e = z.Entries[0];
using (var r = new StreamReader(e.Open(), Encoding.UTF8))
return r.ReadToEnd();
}
}
catch { return null; }
}
// ---------- JSON 反序列化(JavaScriptSerializer) ----------
private static readonly System.Web.Script.Serialization.JavaScriptSerializer 解析器 =
new System.Web.Script.Serialization.JavaScriptSerializer { MaxJsonLength = 64 * 1024 * 1024 };
/// <summary>系列包 → 主规格组有序表(aq顺序号→as选项列表)。
/// ★ 实测规则(1122 对照页面真实组合 337-350-15-9-29-30-37 破解):
/// 参与组合的组 = 顶层 c 键里 bc==0 且 p==2 的项;段顺序 = aq 字段升序;
/// bc!=0 / p!=2 的组(附件名称、延时类型等)不参与组合。
/// 系列包名 = 4/z_p/{系列id}.jss(不是 z_seri)。</summary>
private static SortedDictionary<int, List<int>> 规格组(string 系文)
{
var g = new SortedDictionary<int, List<int>>();
try
{
var root = 解析器.Deserialize<Dictionary<string, object>>(系文);
object co;
if (root == null || !root.TryGetValue("c", out co)) return g;
var cArr = co as System.Collections.ArrayList;
if (cArr == null) return g;
foreach (object o in cArr)
{
var 组 = o as Dictionary<string, object>;
if (组 == null) continue;
// ★ 终版规则(SDK Ke 过滤器:z 数组=an==1;两厂实测 725/1122 真实组合段 100% 命中):
// p 各家不同(正泰=1 德力西=2),不能加 p 条件
if (Convert.ToInt32(组.ContainsKey("an") ? 组["an"] : 0) != 1) continue;
int aq = Convert.ToInt32(组.ContainsKey("aq") ? 组["aq"] : 0);
var ar = 组.ContainsKey("ar") ? 组["ar"] as System.Collections.ArrayList : null;
if (ar == null || ar.Count == 0) continue;
var l = new List<int>();
foreach (object oo in ar)
{
var 选项 = oo as Dictionary<string, object>;
if (选项 == null || !选项.ContainsKey("as")) continue;
l.Add(Convert.ToInt32(选项["as"]));
}
if (l.Count > 0 && !g.ContainsKey(aq)) g[aq] = l;
}
}
catch { }
return g;
}
// ---------- 最小 JSON 取值(避免引第三方库;仅取固定结构字段) ----------
private static System.Text.RegularExpressions.MatchCollection 正则匹配(string json, string pattern)
{
return System.Text.RegularExpressions.Regex.Matches(json, pattern);
}
/// <summary>解析厂家树 ZIP 文本 → 叶子系列号(s 字段非 0)列表。</summary>
public static List<string> 树系列(string 树文)
{
var r = new List<string>();
foreach (System.Text.RegularExpressions.Match m in 正则匹配(树文, "\"s\"\\s*:\\s*(\\d+)"))
{
string v = m.Groups[1].Value;
if (v != "0" && !r.Contains(v)) r.Add(v);
}
return r;
}
/// <summary>组合策略(照 preheat 脚本):默认组合 + 每组每选项单独变化。</summary>
private static List<string> 组合(SortedDictionary<int, List<int>> g)
{
if (g.Count == 0) return new List<string>();
var 默认 = g.Values.Select(l => l[0].ToString()).ToList();
var r = new List<string> { string.Join("-", 默认) };
for (int i = 0; i < g.Count; i++)
{
foreach (int ab in g.Values.ElementAt(i).Skip(1))
{
var c = new List<string>(默认) { };
c[i] = ab.ToString();
r.Add(string.Join("-", c));
}
}
return r;
}
// ---------- webGetPrice 哈希(复刻 python json.dumps 分隔符) ----------
private static string PyDumps(string json)
{
// 本场景 JSON 只含 ASCII 字符串/数字/数组/对象,手工重排分隔符即可:
// 把 "," 与 ":" 后补空格(仅结构符,字符串内部不会出现裸的这些符号——base64 内容安全)
var sb = new StringBuilder(json.Length * 2);
bool 引号内 = false;
for (int i = 0; i < json.Length; i++)
{
char c = json[i];
sb.Append(c);
if (c == '"') 引号内 = !引号内;
else if (!引号内 && (c == ',' || c == ':'))
{
char 后 = i + 1 < json.Length ? json[i + 1] : ' ';
if (后 != ' ') sb.Append(' ');
}
}
return sb.ToString();
}
public static string 价格哈希(string infoJsonB64)
{
string json = Encoding.UTF8.GetString(Convert.FromBase64String(infoJsonB64));
// 剥 time 字段("time":123,) —— 手工正则
json = System.Text.RegularExpressions.Regex.Replace(json, "\"time\"\\s*:\\s*\\d+\\s*,?\\s*", "");
json = json.Replace(",}", "}").Replace(",]", "]");
string 稳定 = "infoJson=" + Convert.ToBase64String(Encoding.UTF8.GetBytes(PyDumps(json)));
using (var md5 = MD5.Create())
return BitConverter.ToString(md5.ComputeHash(Encoding.UTF8.GetBytes(稳定))).Replace("-", "").ToLower().Substring(0, 8);
}
// ---------- 抓取主流程 ----------
/// <summary>抓一个厂家:树+全部系列+全部组合价格。返回 (系列数, 价格数)。任何异常不外抛(记日志返回 0)。</summary>
public KeyValuePair<int, int> 抓厂家(string 树id, string 厂名, int 线程数)
{
try
{
return 抓厂家内部(树id, 厂名, 线程数);
}
catch (Exception ex)
{
L("! 厂家 " + 厂名 + " 抓取异常: " + ex.Message);
return new KeyValuePair<int, int>(0, 0);
}
}
private KeyValuePair<int, int> 抓厂家内部(string 树id, string 厂名, int 线程数)
{
// 1) 厂家树(断点:已存在直接读)
string 树zip路径 = Path.Combine(ZipDir, 树id + ".zip");
string 树文 = null;
if (File.Exists(树zip路径))
{
树文 = 读Zip内文(File.ReadAllBytes(树zip路径));
}
if (树文 == null)
{
byte[] z = Get(电数据 + V参数("z_seri/" + 树id + ".jss") + "&t=" + 时间戳(), 20000);
if (z == null || z.Length < 100) { L("× 厂家 " + 厂名 + " 树拉取失败"); return new KeyValuePair<int, int>(0, 0); }
File.WriteAllBytes(树zip路径, z);
树文 = 读Zip内文(z);
Thread.Sleep(50);
}
if (树文 == null) { L("× 厂家 " + 厂名 + " 树解析失败"); return new KeyValuePair<int, int>(0, 0); }
var 系列 = 树系列(树文);
L("▶ " + 厂名 + ": " + 系列.Count + " 个系列");
无t系列数 = 0; 无t提示过 = 0;
// 2) 并发抓系列
var 队列 = new ConcurrentQueue<string>(系列);
var 计数 = new int[2];
var 线程 = new List<Thread>();
for (int i = 0; i < Math.Max(1, 线程数); i++)
{
var t = new Thread(delegate()
{
string sid;
while (!停止 && 队列.TryDequeue(out sid))
{
int 局系 = 0, 局价 = 0;
string szPath = Path.Combine(ZipDir, sid + ".zip");
string 系文 = null;
try
{
系文 = File.Exists(szPath) ? 读Zip内文(File.ReadAllBytes(szPath)) : null;
if (系文 == null)
{
byte[] z = Get(电数据 + V参数("4/z_p/" + sid + ".jss") + "&t=" + 时间戳(), 20000);
if (z != null && z.Length > 100) { File.WriteAllBytes(szPath, z); 系文 = 读Zip内文(z); Thread.Sleep(20); }
}
if (系文 != null && 系文.IndexOf("\"c\"") >= 0)
{
局系 = 1;
// ★ 终版机制(实测):命中 = 系列在有效时刻 t 查过 AND 组合是真实型号。
// 每个系列只要有一个种子的 t,就能解锁它全部规格组组合;无 t 的系列必空,跳过查价。
List<string[]> sd;
bool 有种子 = 种子.TryGetValue(sid, out sd) && sd.Count > 0;
if (!有种子)
{
Interlocked.Increment(ref 无t系列数);
if (无t提示过 == 0)
{
int n = Interlocked.Increment(ref 无t提示过);
if (n == 1)
L("· 提示: 无有效时刻(t)的系列跳过价格查询(服务器对没查过的系列+当前时间必返空)——已跳过 " + sid + " 等");
}
}
else
{
string t种 = sd[0][1]; // 系列任一种子的 t(系列级会话标识,只配自己系列)
// ★ 组合恒用当前系列包规格组生成(默认+单变化):编号与页面渲染同源,查到的价页面必能命中。
// 种子 bg(旧版本编号)不再作基底——跨版本编号混合的组合页面永远点不出来(725 教训:75条仅1条可用)。
var cs = 组合(规格组(系文));
foreach (string c in cs)
{
string info = 构造infoJson(sid, c, t种);
string h = 价格哈希(info);
string 价path = Path.Combine(价Dir, "dx2_pcprice_default_dx2_interface_webGetPrice_" + h + ".data");
if (!File.Exists(价path))
{
string 口 = 经旧代理 ? 代价格口 : 价格口;
byte[] body = Get(口 + info, 20000);
// ★ 空结果不落盘:content="W10="(base64("[]"))或 content="" 都表示该组合厂家无报价,
// 存了也是废数据(旧代理靠运行时合成兜底,新服务只需要真价格)
string 文 = body == null ? null : Encoding.UTF8.GetString(body);
bool 有价 = 文 != null && 文.Length > 30 && 文.Length < 300000
&& 文.IndexOf("\"content\":\"W10=\"") < 0
&& 文.IndexOf("\"content\": \"W10=\"") < 0
&& 文.IndexOf("\"content\":\"\"") < 0
&& 文.IndexOf("\"content\": \"\"") < 0;
if (有价)
{
File.WriteAllBytes(价path, body);
var mb = System.Text.RegularExpressions.Regex.Match(文, "\"bh\"\\s*:\\s*\"?([0-9.]+)");
L(" ¥ 系列" + sid + " 命中真价" + (mb.Success ? " " + mb.Groups[1].Value + " 元" : "") + ": " + c);
}
Thread.Sleep(20);
}
局价++;
}
}
}
}
catch (Exception ex_series)
{
L("· 系列 " + sid + " 异常: " + ex_series.Message);
}
Interlocked.Add(ref 计数[0], 局系);
Interlocked.Add(ref 计数[1], 局价);
if (进度 != null) 进度(0, 0);
}
});
t.IsBackground = true;
线程.Add(t); t.Start();
}
foreach (var t in 线程) t.Join();
if (无t系列数 > 0)
L("· " + 厂名 + ": " + 无t系列数 + " 个系列无有效时刻(t),已跳过价格查询(可先在预热页面浏览这些系列再抓)");
return new KeyValuePair<int, int>(计数[0], 计数[1]);
}
private static long 时间戳() { return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds; }
/// <summary>构造 infoJson 的 base64。t 必须传历史时间戳(种子的原始 t 或兜底 t):
/// 实测服务器只对「真实查过的组合+历史时间戳」返回真价,当前时间必空。</summary>
private static string 构造infoJson(string 系列, string 组合串, string t)
{
// {"s": "1122", "options": ["337-350"], "time": 123, "from": "dx2jsapi"} —— 键序照 SDK
string json = "{\"s\": \"" + 系列 + "\", \"options\": [\"" + 组合串 + "\"], \"time\": " + t + ", \"from\": \"dx2jsapi\"}";
return Convert.ToBase64String(Encoding.UTF8.GetBytes(json));
}
}
}
-19
View File
@@ -1,19 +0,0 @@
using System;
namespace yjktool
{
static class 测试入口
{
[STAThread]
static int Main(string[] args)
{
string 树id = args.Length > 0 ? args[0] : "10";
Console.OutputEncoding = System.Text.Encoding.UTF8;
var g = new 抓取器(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "抓取输出"))
{ 日志 = s => Console.WriteLine(s) };
var kv = g.抓厂家(树id, "(测试厂" + 树id + ")", 4);
Console.WriteLine("== 结果: 系列 {0}, 价格 {1}", kv.Key, kv.Value);
return 0;
}
}
}
-135
View File
@@ -1,135 +0,0 @@
{
"37141": [
"5-10-14-15-19-21-23"
],
"1506": [
"10-15-19-21-460-26-44",
"8-15-19-21-460-26-44",
"230-15-19-21-460-26-39",
"230-331-19-21-460-446-39",
"11-15-19-21-460-26-48",
"182-313",
"11-17-19-21-460-27-50",
"11-17-19-21-460-27-48",
"9-12-19-21-460-26-28",
"7-15-19-21-460-26-39",
"10-15-19-21-460-26-48",
"11-17-19-21-460-26-48",
"11-329-19-21-460-26-48",
"159-285",
"230-14-19-21-460-26-39",
"119-279",
"7-331-19-21-460-446-28",
"114-115-267",
"11-330-19-21-460-26-48",
"8-15-19-21-460-26-39",
"382-384"
],
"46805": [
"5-7-14"
],
"725": [
"7-13-22-15-17-18-19-25-74-20-46-27-82-83-96-84-353",
"8-13-22-15-17-18-19-25-74-20-46-27-82-83-96-84-353",
"56-24-22-15-17-18-19-25-74-20-33-27-82-83-96-84-353",
"23-24-22-15-17-18-19-25-74-20-85-27-82-83-96-84-353",
"7-13-22-15-17-18-19-25-74-20-41-27-82-83-96-84-353",
"6-12-22-15-17-18-19-25-74-20-39-27-82-83-96-84-353",
"341-13-22-15-17-18-19-25-74-20-48-27-82-83-96-84-352",
"56-24-22-28-17-18-19-25-74-20-85-27-82-83-96-84-353",
"23-24-22-15-17-18-19-25-74-20-35-27-82-83-96-84-353",
"56-24-22-15-17-18-59-25-75-20-29-27-82-83-96-84-353",
"319-12-22-28-17-18-19-25-74-20-29-27-82-83-96-84-352",
"5-12-22-28-17-18-19-25-74-20-29-27-82-83-96-84-353",
"56-24-22-15-17-18-59-25-74-20-29-27-82-83-96-84-353",
"6-12-22-15-17-18-19-25-74-20-37-27-82-83-96-84-353",
"56-24-22-15-17-18-19-25-74-20-85-27-82-83-96-84-353",
"23-24-22-28-17-18-19-25-74-20-85-27-82-83-96-84-353",
"56-24-22-28-17-18-19-25-74-20-85-27-82-83-96-84-350",
"330-13-22-15-17-18-19-25-74-20-46-27-82-83-96-84-352",
"6-12-22-15-17-18-19-25-74-20-36-27-82-83-96-84-353"
],
"47762": [
"5-6-8-9-10"
],
"42825": [
"5-11-14",
"5-6-13",
"5-10-14",
"5-12-15"
],
"3205": [
"5-11-15-27",
"10-13-15-27"
],
"56242": [
"5-10-14-19-20-22-29-31-32"
],
"1401": [
"5-6-8-12-16"
],
"2486": [
"5-8-6-936-14-46-35-33"
],
"1245": [
"5-7-16-17"
],
"10586": [
"6-12"
],
"48269": [
"5-807-22-37-58-60-17-67-810"
],
"47084": [
"5-6-12-16-20"
],
"1122": [
"337-350-15-9-29-30-37",
"6-13-18-10-28-30-37"
],
"40": [
"5-8"
],
"23641": [
"7-163-10-12-14-164-19-21"
],
"757": [
"5-11-66-17-20-21-22-23-25-27-68-67-91-90-96-92-134"
],
"1825": [
"5-18-26-9-15-8"
],
"733": [
"18-37-32-39"
],
"59163": [
"5-11-13-16-19-21",
"5-11-15-17-20-27"
],
"32339": [
"7-124-8-34"
],
"1427": [
"5-7-24-17"
],
"604": [
"16-5-12-15",
"16-5-12-14"
],
"71": [
"5-15-50-154"
],
"47960": [
"5-12-10-20-23-26-37-63"
],
"791": [
"5-7-11-13"
],
"1086": [
"10-6-30",
"12-6-30"
],
"735": [
"5-7-17-12-13-15-16-119"
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff