Compare commits
9
Commits
v2026.10.01-2
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86fc8e5c28 | ||
|
|
48eab1da2c | ||
|
|
71d960ba67 | ||
|
|
193035acfb | ||
|
|
e7f25a8ceb | ||
|
|
5e2493fdf4 | ||
|
|
fdf1de774b | ||
|
|
048144b7e0 | ||
|
|
2f0ee71093 |
@@ -59,6 +59,21 @@ description: SharpDevelop 5.x WinForms 设计器**全部工具箱**(5 分类 8
|
||||
- **依赖清单**:所需引用的资源文件(图标/图片/resx)、组件库与依赖程序集(Designer.cs 用到增强控件时,同一次改动先写 csproj 引用,见第 3 条);
|
||||
- **数据接口**:窗口与其他系统模块(主窗口/数据库/停靠布局/外部进程)的数据交互方式与调用入口。
|
||||
窗口一律采用双文件结构:`窗口名.Designer.cs`(纯布局与属性,SD 设计器能正确打开并继续编辑微调)+ `窗口名.cs`(交互逻辑与业务代码),Designer.cs 里绝不写业务代码;窗口文件记得同步注册进 csproj(Compile Include + Designer.cs 加 `<DependentUpon>`)。
|
||||
7. **版本号铁律(用户强制 2026-10-01):每次发版必须递增版本号**。每次打安装包/发 Gitea Release 前,必须先跑 `tools\递增版本号.ps1`(默认修订号 +1,如 1.0.3→1.0.4;大改动可传参指定如 1.1.0)。规则:
|
||||
- **唯一事实源** = `成套报价软件\Properties\AssemblyInfo.cs` 的 `AssemblyVersion`(固定三段式 `主.次.修订.0`,**禁用 `1.0.*` 自动号**——每次编译都变,无法对应发布的安装包);
|
||||
- 「关于软件」窗口运行时自动读程序集版本显示(不在 Designer 写死);
|
||||
- `release\成套报价软件\setup.iss` 的 `AppVersion` 与 `OutputBaseFilename=成套报价软件_Setup_版本` 由脚本同步;
|
||||
- Gitea Release 的 tag 与版本号一致(如 `v1.0.4`);
|
||||
- 发版链固定为:递增版本号 → 编译 → make_package → ISCC → 更新包 → git 提交推送 → Release。跳过递增 = 两个不同功能的安装包同版本号,用户分不清、回滚排障全乱。
|
||||
8. **git 推送流程与故障排查(2026-10-01 实战沉淀,用户强制写入)**。日常流程:改动 → `git add -A` → `git commit -m "中文消息"` → `git push`(remote 已内嵌用户令牌自动认证,无需弹窗)。Release 附件(安装包/更新包)走 Gitea 附件存储**只在发版时上传一次**,`git push` 只推源码文本,两者互不相干——不要混淆"推送源码"与"重传安装包"。常见失败与处置:
|
||||
- **`Failed to authenticate user` / 认证失败**:令牌失效或被撤销。让用户去 Gitea 网页 头像→设置→应用 生成新令牌(勾 repository 读写),然后 `git remote set-url origin http://0999we:<新令牌>@192.168.9.43:3000/0999we/ctbjrj.git`。同令牌也用于 Gitea REST API(`Authorization: token <令牌>` 头,建 Release/传附件用)。
|
||||
- **`! [rejected] (fetch first)`**:远程有本地没有的提交(通常是用户自己在 Gitea 网页上传过文件)。处置:`git fetch` → `git log HEAD..origin/master --oneline` 看远程新增 → `git pull --rebase` 整合 → `git push`。**绝不 force push**(会抹掉用户网页上传的东西)。
|
||||
- **GCM 弹窗/OAuth 凭据残留**:本项目不靠 GCM(remote 内嵌令牌)。若 cmdkey 里出现 `git:http://refresh_token.192.168.9.43:3000` 之类失效条目,`cmdkey /list | findstr 192.168` 找到后 `cmdkey /delete <条目名>` 清掉。
|
||||
- **`另一个程序正在使用此文件`**:git add/checkout 撞上运行中的 node/AI 引擎/主程序占用。先 `Get-CimInstance Win32_Process` 查占用进程(看 CommandLine 路径),Stop-Process 结束开发目录侧的进程再操作(安装目录 C:\成套报价软件 下的不动)。
|
||||
- **`.gitignore` 否定规则陷阱**:父目录被排除时深层 `!` 否定无效(`!release/成套报价软件/setup.iss` 配 `release/*` 不生效)。必须逐层放行:`!release/` → `release/*` → `!release/成套报价软件` → `release/成套报价软件/*` → `!release/成套报价软件/setup.iss`。改完用 `git status --short` 验证目标文件真的 staged(`A` 状态)。
|
||||
- **中文路径显示八进制转义**(`\346\210\220...`):git 默认 quotepath,排查时加 `-c core.quotepath=false`,如 `git -c core.quotepath=false ls-tree -r --name-only HEAD`。
|
||||
- **LF→CRLF warning**:无害,忽略。
|
||||
- **push 后验证**:`git ls-remote origin` 的 HEAD 与本地 `git log -1` 哈希一致才算成功。
|
||||
|
||||
## 一、项目前提(缺一不可)
|
||||
|
||||
|
||||
@@ -51,3 +51,10 @@ selftest_result.txt
|
||||
!成套报价软件/lib/*.dll
|
||||
# 例外:tools\ 下的 WebView2 引导程序是打包必需件
|
||||
!tools/MicrosoftEdgeWebview2Setup.exe
|
||||
# 例外:release 里的 Inno Setup 脚本是手工维护的打包正本,必须进版本控制
|
||||
# (gitignore 否定规则限制:父目录被排除时无法重新包含深层文件,须逐层放行)
|
||||
!release/
|
||||
release/*
|
||||
!release/成套报价软件
|
||||
release/成套报价软件/*
|
||||
!release/成套报价软件/setup.iss
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
# 成套报价软件
|
||||
|
||||
电气成套设备报价桌面软件:报价三表(图号/箱号/元件)+ CAD/PDF 图纸扒图 + 元件库选型 + 公式计算 + 甲方报表,单机 SQLite 存储,可选 AI 助手与云端会员服务。
|
||||
|
||||
> **改代码前必读**:[代码索引.md](代码索引.md)(所有功能的文件/方法级定位 + 修改铁律)
|
||||
> **组件属性手册**:`.agents\skills\sd-enhanced-components\SKILL.md`(WinForms 控件白名单、设计器规则、版本号铁律、git 推送排查手册)
|
||||
|
||||
## 功能概览
|
||||
|
||||
- **项目管理**:新建/修改/删除/复制项目,zip 项目包导入导出,最近项目自动恢复
|
||||
- **报价三表**:图号/箱号/元件三级联动,虚拟模式万行秒开,编辑实时落库;公式自动计算(成本价/报出价/利润/毛利率,公式可自定义);批量粘贴/删除/撤销、费用模板行
|
||||
- **CAD 扒图**:内嵌网页 CAD 查看器(mlightcad)打开 DWG/DXF;框选扒图号/箱号/元件,表格点行定位图上蒙版,F1/F2/F3 元件合并
|
||||
- **PDF 扒图**:pdfium 渲染 + 框选 OCR(百度/智谱 GLM/千帆/UApiPro/Umi-OCR 本地五引擎),自动纠正文本方向,入库/合并/定位同 CAD
|
||||
- **元件库与选型**:厂家/系列/价格网页选型,收藏跳转,方案库独立库文件,用户库/柜体库管理与 CSV 导入导出
|
||||
- **计算与报表**:GCS 母排计算与铜排推荐、批量调系数、元件排序、甲方报表 Excel 导出
|
||||
- **其它**:停靠布局保存恢复、数据备份恢复、登录门禁、可选 AI 助手(ZCode 引擎)
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 框架 | WinForms,.NET Framework 4.8,x86(SharpDevelop 5.x 工具链) |
|
||||
| 数据库 | SQLite(WAL + Pooling + BusyTimeout=5000),连接串统一见 `成套报价软件\数据库连接.cs` |
|
||||
| 内嵌网页 | WebView2(元件库/CAD 查看器/AI 助手面板) |
|
||||
| PDF/OCR | pdfium 渲染 + 多引擎 OCR(`扒图\` 下为唯一源码,pdfbt 链接共享) |
|
||||
| Excel | NPOI(甲方报表/导入导出) |
|
||||
| UI 组件 | Smart.CustomComponents(自研)、WeifenLuo Docking、AdvancedDataGridView |
|
||||
|
||||
## 仓库结构
|
||||
|
||||
```
|
||||
成套报价软件\ 主程序源码(MainForm 拆 14 个 partial;xiangmu/shezhi/ku 子模块窗体)
|
||||
└ 扒图\ 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)
|
||||
```
|
||||
|
||||
(已退役:独立 cadbt.exe/pdfbt.exe 扒图程序、ghj/yjktool 试验小工具、cadcj 旧 AutoCAD 插件——扒图功能全部由主程序内嵌窗口承载。)
|
||||
|
||||
**数据目录**(运行时,均不进 git):`sjk\bjb\项目<编号>.db` 每项目一库;`sjk\fak.db` 公式库;`sjk\方案库\*.db` 一方案一库;`shezhi\` 用户配置;`xiangmu\` 报表模板。
|
||||
|
||||
## 构建与验证
|
||||
|
||||
```powershell
|
||||
# 主程序(工作目录必须是 成套报价软件\ 子目录!rsp 相对路径基于它)
|
||||
cd 成套报价软件
|
||||
& "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" "@..\tools\verify_build.rsp" /warn:1
|
||||
|
||||
# pdfbt 独立程序(链接共享主项目扒图\ 源码,改 OCR 相关先确认两项目都编译)
|
||||
& "C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe" pdfbt\pdfbt.csproj /t:Build /p:Configuration=Debug
|
||||
```
|
||||
|
||||
注意:编译前杀掉运行中的主程序(exe 被锁报 CS0016);rsp 默认 `/warn:0` 压警告,排查时加 `/warn:1`。
|
||||
|
||||
## 版本号与发版流程
|
||||
|
||||
版本号唯一事实源 = `成套报价软件\Properties\AssemblyInfo.cs` 的 `AssemblyVersion`(固定三段式 `主.次.修订.0`,禁用 `1.0.*` 自动号);关于软件窗口运行时自动读它显示;安装包文件名带版本号。
|
||||
|
||||
```powershell
|
||||
# 每次发版必须先递增版本号(规则详见技能"版本号铁律")
|
||||
powershell -File tools\递增版本号.ps1 # 修订号+1;大版本: tools\递增版本号.ps1 1.1.0
|
||||
|
||||
# 发版链(顺序固定)
|
||||
递增版本号 → 编译 → python tools\make_package.py → ISCC release\成套报价软件\setup.iss
|
||||
→ python tools\make_update_package.py → git add/commit/push → Gitea Release(tag=v版本号,附件=安装包+更新包)
|
||||
```
|
||||
|
||||
## 常用工具脚本(tools\)
|
||||
|
||||
| 脚本 | 用途 |
|
||||
|---|---|
|
||||
| `递增版本号.ps1` | 版本号一键递增,同步 AssemblyInfo + setup.iss |
|
||||
| `make_package.py` | 组装发布目录(exe+DLL+数据目录+cadbt+pdfbt+AI 助手) |
|
||||
| `make_update_package.py` | 生成覆盖式更新包(exe+说明.txt+zip) |
|
||||
| `扒图同步检查.ps1` | Cad/Pdf Form3.cs 双胞胎漂移护栏(超基线报警) |
|
||||
| `perf_load.py` | 性能加载测试 |
|
||||
|
||||
## 版本控制与远程
|
||||
|
||||
- 远程:`http://192.168.9.43:3000/0999we/ctbjrj`(Gitea,remote URL 内嵌访问令牌自动认证)
|
||||
- 节奏:每轮改动 `git add -A → commit(中文消息)→ push`;Release 附件只在发版时上传一次
|
||||
- 故障排查(认证失败/rebase 整合/文件占用/gitignore 陷阱等 7 类场景):见技能"git 推送流程与故障排查"
|
||||
- 发版历史:Gitea Releases(含安装包与更新包附件)
|
||||
|
||||
## 开源组件致谢
|
||||
|
||||
软件内嵌的开源组件(WeifenLuo Docking、ADGV、NPOI、DotNetZip、SharpZipLib、ReoGrid、System.Data.SQLite、pdfium、WebView2、Node.js、ZCode、mlightcad CAD-Viewer、Umi-OCR、Lucide)的版权与许可声明见软件"关于→开源致谢"页及安装目录 `licenses\`。
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
-69
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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.*")]
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -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>
|
||||
@@ -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.
@@ -1,350 +0,0 @@
|
||||
// ============================================================
|
||||
// CAD 2018 插件入口(cadcj.dll)
|
||||
// · 实现 IExtensionApplication,在 CAD 启动时自动加载
|
||||
// · 注册命令 "CADCJ" 打开 Form3 报价窗口
|
||||
// · 使用 PaletteSet 把 Form3 嵌成 CAD 可停靠工具栏窗口
|
||||
// 启动时自动贴靠到 CAD 左侧,用户可拖到右/上/下边或浮动
|
||||
// · 编译:/target:library /platform:x64
|
||||
// · 加载:在 CAD 里 NETLOAD 选择 cadcj.dll,然后输入 CADCJ 命令
|
||||
// ============================================================
|
||||
using System;
|
||||
using Autodesk.AutoCAD.Runtime;
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.Windows;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
|
||||
|
||||
[assembly: CommandClass(typeof(MyApp.CadPlugin))]
|
||||
[assembly: ExtensionApplication(typeof(MyApp.CadPlugin))]
|
||||
|
||||
namespace MyApp
|
||||
{
|
||||
/// <summary>
|
||||
/// CAD 2018 插件入口。CAD 启动时自动初始化,注册 CADCJ 命令打开报价窗口。
|
||||
/// 报价窗口用 PaletteSet 承载,可像 CAD 工具选项板一样停靠/浮动。
|
||||
/// </summary>
|
||||
public class CadPlugin : IExtensionApplication
|
||||
{
|
||||
// PaletteSet 单例:CAD 里常驻,可停靠
|
||||
private static PaletteSet _ps = null;
|
||||
// Form3 单例(作为 PaletteSet 的内容)
|
||||
private static Form3 _form3 = null;
|
||||
// ★ 宿主容器:PaletteSet 只加 Panel,Form3 塞进去(规避主题同步崩溃)
|
||||
private static System.Windows.Forms.Panel _hostPanel = null;
|
||||
|
||||
#region IExtensionApplication 成员
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// ★ 最简单的文件日志,不依赖任何外部代码,确认 Initialize 是否被调用
|
||||
try
|
||||
{
|
||||
string logPath = System.IO.Path.Combine(
|
||||
System.IO.Path.GetDirectoryName(
|
||||
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath),
|
||||
"cadcj_load.log");
|
||||
System.IO.File.WriteAllText(logPath,
|
||||
"[" + System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "] Initialize 被调用" + System.Environment.NewLine);
|
||||
}
|
||||
catch { }
|
||||
|
||||
// ★ 解决 CAD 安全提示:把插件目录添加到 TRUSTEDPATHS,并关闭 SECURELOAD
|
||||
// 这样 CAD 不会每次都弹"始终加载/加载一次"的安全提示
|
||||
try
|
||||
{
|
||||
string pluginDir = System.IO.Path.GetDirectoryName(
|
||||
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
|
||||
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null)
|
||||
{
|
||||
// ★ 关闭 SECURELOAD(0=不检查可执行文件签名)
|
||||
try
|
||||
{
|
||||
object sl = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("SECURELOAD");
|
||||
if (sl == null || Convert.ToInt32(sl) != 0)
|
||||
{
|
||||
Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("SECURELOAD", 0);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// ★ 把插件目录添加到 TRUSTEDPATHS
|
||||
object cur = Autodesk.AutoCAD.ApplicationServices.Application.GetSystemVariable("TRUSTEDPATHS");
|
||||
string curPaths = cur == null ? "" : cur.ToString();
|
||||
bool found = false;
|
||||
string[] parts = curPaths.Split(';');
|
||||
foreach (string p in parts)
|
||||
{
|
||||
if (string.Equals(p.Trim(), pluginDir.Trim(), System.StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
string newPaths = string.IsNullOrEmpty(curPaths) ? pluginDir : curPaths + ";" + pluginDir;
|
||||
Autodesk.AutoCAD.ApplicationServices.Application.SetSystemVariable("TRUSTEDPATHS", newPaths);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc0 = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc0 != null) doc0.Editor.WriteMessage("\n[CADCJ] 设置可信路径失败: " + ex.Message);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null)
|
||||
{
|
||||
doc.Editor.WriteMessage("\n[CADCJ] 成套报价插件已加载,报价窗口将随文档自动打开。");
|
||||
}
|
||||
// ★ 监听文档创建/激活事件:每次新建/打开文件时自动显示报价窗口
|
||||
AcAp.DocumentManager.DocumentCreated += OnDocumentCreated;
|
||||
|
||||
// ★ 关键修复:acaddoc.lsp 的 NETLOAD 发生在文档已打开之后,
|
||||
// DocumentCreated 事件早已错过;且 Idle 事件在挂接时若 CAD 已空闲
|
||||
// 可能永不触发 → 改为直接显示(Initialize 在命令上下文里可安全创建 UI)
|
||||
if (AcAp.DocumentManager.MdiActiveDocument != null && _ps == null && _form3 == null)
|
||||
{
|
||||
PluginLog("[Initialize] 直接调用 OpenForm3");
|
||||
OpenForm3();
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex2)
|
||||
{
|
||||
PluginLog("[Initialize] ⚠ 直接打开失败: " + ex2.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>文档创建时自动打开/显示报价窗口(停靠左侧)。</summary>
|
||||
private void OnDocumentCreated(object sender, DocumentCollectionEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 延迟到 Idle 时执行,避免在文档创建过程中操作 UI
|
||||
AcAp.Idle -= OnCadIdleShowPalette;
|
||||
AcAp.Idle += OnCadIdleShowPalette;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>Idle 时显示报价窗口(只执行一次后取消订阅)。</summary>
|
||||
private void OnCadIdleShowPalette(object sender, EventArgs e)
|
||||
{
|
||||
AcAp.Idle -= OnCadIdleShowPalette;
|
||||
try
|
||||
{
|
||||
OpenForm3();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_ps != null)
|
||||
{
|
||||
_ps.Visible = false;
|
||||
_ps = null;
|
||||
}
|
||||
if (_form3 != null && !_form3.IsDisposed)
|
||||
{
|
||||
_form3.Dispose();
|
||||
_form3 = null;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
|
||||
/// <summary>CADCJ 命令:打开/激活报价窗口(PaletteSet,可停靠)。</summary>
|
||||
[CommandMethod("CADCJ", CommandFlags.Modal)]
|
||||
public void OpenForm3()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 已有 PaletteSet 则激活显示并重新停靠到左侧
|
||||
if (_ps != null)
|
||||
{
|
||||
_ps.Visible = true;
|
||||
try
|
||||
{
|
||||
_ps.DockEnabled = DockSides.Left;
|
||||
_ps.Dock = DockSides.Left;
|
||||
}
|
||||
catch { }
|
||||
return;
|
||||
}
|
||||
|
||||
PluginLog("[CADCJ] OpenForm3 开始");
|
||||
|
||||
// 新建 Form3,转成子控件模式嵌入容器
|
||||
_form3 = new Form3();
|
||||
_form3.TopLevel = false;
|
||||
_form3.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
|
||||
_form3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
_form3.Visible = true;
|
||||
PluginLog("[CADCJ] Form3 就绪");
|
||||
|
||||
// ★ 根治 ResyncToTheme 崩溃:PaletteSet 只加 UserControl 容器,
|
||||
// 不直接加 Form(CAD 主题同步强改 Form.BackColor 会抛
|
||||
// "控件不支持透明的背景色")。Form3 塞进 Panel 再加。
|
||||
_hostPanel = new System.Windows.Forms.Panel();
|
||||
_hostPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
_hostPanel.BackColor = System.Drawing.SystemColors.Control;
|
||||
_hostPanel.Controls.Add(_form3);
|
||||
|
||||
// 新建 PaletteSet
|
||||
_ps = new PaletteSet("扒图", new System.Guid("A3F2B5C1-7D8E-4A6B-9C0D-1E2F3A4B5C6D"));
|
||||
PluginLog("[CADCJ] PaletteSet 创建成功");
|
||||
|
||||
_ps.Style = PaletteSetStyles.Snappable
|
||||
| PaletteSetStyles.UsePaletteNameAsTitleForSingle;
|
||||
_ps.Add("扒图", _hostPanel);
|
||||
PluginLog("[CADCJ] Add 成功");
|
||||
|
||||
// ★ 启动时自动贴靠到 CAD 左侧,并设置足够尺寸
|
||||
_ps.Size = new System.Drawing.Size(540, 800);
|
||||
_ps.MinimumSize = new System.Drawing.Size(300, 400);
|
||||
|
||||
// ★ 先显示,再设置停靠(CAD PaletteSet 的特殊行为)
|
||||
_ps.Visible = true;
|
||||
PluginLog("[CADCJ] Visible=true 完成");
|
||||
|
||||
// ★ 启用左侧停靠 + 强制停靠到左侧
|
||||
_ps.DockEnabled = DockSides.Left;
|
||||
_ps.Dock = DockSides.Left;
|
||||
PluginLog("[CADCJ] OpenForm3 全部完成 ✓");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
PluginLog("[CADCJ] ⚠ 打开窗口失败: " + ex);
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null)
|
||||
{
|
||||
doc.Editor.WriteMessage("\n[CADCJ] 打开窗口失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>插件级文件日志(写 cadcj 目录 diag.log,独立于 Form3)。</summary>
|
||||
private static void PluginLog(string msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
string dir = System.IO.Path.GetDirectoryName(
|
||||
new System.Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath);
|
||||
System.IO.File.AppendAllText(System.IO.Path.Combine(dir, "diag.log"),
|
||||
DateTime.Now.ToString("HH:mm:ss.fff") + " " + msg + System.Environment.NewLine);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 扒图号/扒箱号/扒元件 命令
|
||||
// · 由 Form3 的按钮通过 SendStringToExecute 触发
|
||||
// · 只允许框选 DBText/MText(过滤掉线条)
|
||||
// · 选中文本用半透明颜色高亮
|
||||
// · 选中的文本传回 Form3 插入到对应表格
|
||||
// ============================================================
|
||||
|
||||
/// <summary>扒图号命令:CADPATU</summary>
|
||||
[CommandMethod("CADPATU", CommandFlags.Modal)]
|
||||
public void PaTuhaoCommand()
|
||||
{
|
||||
ExecutePaCommand(MyApp.PaMode.Tuhao);
|
||||
}
|
||||
|
||||
/// <summary>扒箱号命令:CADPAXH</summary>
|
||||
[CommandMethod("CADPAXH", CommandFlags.Modal)]
|
||||
public void PaXianghaoCommand()
|
||||
{
|
||||
ExecutePaCommand(MyApp.PaMode.Xianghao);
|
||||
}
|
||||
|
||||
/// <summary>扒元件命令:CADPAYJ</summary>
|
||||
[CommandMethod("CADPAYJ", CommandFlags.Modal)]
|
||||
public void PaYuanjianCommand()
|
||||
{
|
||||
ExecutePaCommand(MyApp.PaMode.Yuanjian);
|
||||
}
|
||||
|
||||
/// <summary>清除所有高亮颜色命令:CADPACL</summary>
|
||||
[CommandMethod("CADPACL", CommandFlags.Modal)]
|
||||
public void PaClearCommand()
|
||||
{
|
||||
try
|
||||
{
|
||||
PaTextSelector.ClearAllHighlight();
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 已清除所有染色文本。");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 清除失败: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>执行扒数据命令的核心逻辑(连续框选模式)。</summary>
|
||||
private void ExecutePaCommand(PaMode mode)
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc == null) return;
|
||||
var ed = doc.Editor;
|
||||
try
|
||||
{
|
||||
// 订阅事件:每次框选完一批文本,立即通过 Invoke 调用 Form3 的插入方法
|
||||
PaTextSelector.BatchTextsPicked -= OnPaBatchTextsPicked;
|
||||
PaTextSelector.BatchTextsPicked += OnPaBatchTextsPicked;
|
||||
|
||||
// 进入连续框选循环(直到用户按 ESC)
|
||||
PaTextSelector.PickTextsContinuous(mode);
|
||||
|
||||
// 用户按 ESC 退出后,触发一次最终的"完成"提示(可选)
|
||||
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
|
||||
|
||||
// 取消订阅
|
||||
PaTextSelector.BatchTextsPicked -= OnPaBatchTextsPicked;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
ed.WriteMessage("\n[扒数据] 异常: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>PaTextSelector 事件回调:把一批文本+框Handle传给 Form3 插入到表格。</summary>
|
||||
private void OnPaBatchTextsPicked(PaMode mode, System.Collections.Generic.List<PaTextResult> results)
|
||||
{
|
||||
if (_form3 == null || _form3.IsDisposed) return;
|
||||
try
|
||||
{
|
||||
_form3.Invoke(new System.Action(() =>
|
||||
{
|
||||
try { _form3.OnPaTextsPicked(mode, results); }
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 插入数据异常: " + ex.Message);
|
||||
}
|
||||
}));
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,34 +0,0 @@
|
||||
// ============================================================
|
||||
// Form3 依赖清单
|
||||
// 此文件记录窗体所使用的控件及其运行时依赖。
|
||||
// ============================================================
|
||||
|
||||
// NuGet 包依赖:
|
||||
// ----------------
|
||||
// System.Data.SQLite.Core (版本 1.0.119.0)
|
||||
// 安装命令: dotnet add package System.Data.SQLite.Core --version 1.0.119.0
|
||||
// 或在 Visual Studio 中: 右键项目 → 管理 NuGet 包 → 搜索 System.Data.SQLite.Core
|
||||
|
||||
// DLL 文件依赖:
|
||||
// ----------------
|
||||
// 来自 未知:
|
||||
// - AdvancedDataGridView.dll (托管 DLL)
|
||||
// 来自 System.Data.SQLite.Core:
|
||||
// - System.Data.SQLite.dll (托管 DLL)
|
||||
|
||||
// 编译说明:
|
||||
// ----------------
|
||||
// 1. 确保 NuGet 包已安装到项目
|
||||
// 2. 编译时使用正确的 CPU 架构(x64 或 x86)
|
||||
// 3. 运行时确保所有 DLL 文件与 exe 在同一目录
|
||||
// 4. ★ 推荐用同目录下的 build.bat 一键编译(已自动配置 response file 和 manifest)
|
||||
// manifest 的 DPI 策略与设计器一致(dpiAware=unaware),保证所见即所得
|
||||
|
||||
// 编译命令示例(x64):
|
||||
// csc /target:winexe /platform:x64 /out:Form3.exe
|
||||
// /win32manifest:app.manifest
|
||||
// /r:System.Windows.Forms.dll /r:System.Drawing.dll
|
||||
// /r:"AdvancedDataGridView.dll"
|
||||
// /r:"System.Data.SQLite.dll"
|
||||
// Form3.cs Form3.ui.cs
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,830 +0,0 @@
|
||||
// ============================================================
|
||||
// 扒图号/扒箱号/扒元件 - CAD文本框选交互
|
||||
// · 直接框选一次完成(无需点完成按钮)
|
||||
// · 只框选 DBText/MText(线条自动过滤)
|
||||
// · 不改文字颜色,而是在每个文字周围画彩色矩形框
|
||||
// (图号=红色框, 箱号=绿色框, 元件=蓝色框)
|
||||
// · 清除时删除所有彩色矩形框
|
||||
// ============================================================
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Autodesk.AutoCAD.DatabaseServices;
|
||||
using Autodesk.AutoCAD.EditorInput;
|
||||
using Autodesk.AutoCAD.ApplicationServices;
|
||||
using Autodesk.AutoCAD.Geometry;
|
||||
using Autodesk.AutoCAD.Colors;
|
||||
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
|
||||
|
||||
namespace MyApp
|
||||
{
|
||||
/// <summary>
|
||||
/// 扒数据模式:图号/箱号/元件
|
||||
/// </summary>
|
||||
public enum PaMode
|
||||
{
|
||||
Tuhao, // 扒图号
|
||||
Xianghao, // 扒箱号
|
||||
Yuanjian // 扒元件
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扒图结果:一条文本 + 它对应的彩色框的 Handle(句柄字符串)
|
||||
/// 用于关联表格数据行与 CAD 框实体,实现点击行定位、删除行删框。
|
||||
/// ★ TextHandle:源文本实体自身的 Handle,用于判断"是否同一个文本"
|
||||
/// (不同位置的相同内容文本 Handle 不同,不算重复)。
|
||||
/// </summary>
|
||||
public class PaTextResult
|
||||
{
|
||||
public string Text;
|
||||
public string FrameHandle;
|
||||
public string TextHandle = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CAD 文本框选交互:框选一次即完成,在文字周围画彩色矩形框(不改文字颜色)。
|
||||
/// </summary>
|
||||
public static class PaTextSelector
|
||||
{
|
||||
// 三种模式对应不同的矩形框颜色(ACI:3=绿,4=青,1=红)
|
||||
private const short TuhaoColorIndex = 3; // 图号=绿
|
||||
private const short XianghaoColorIndex = 4; // 箱号=青
|
||||
private const short YuanjianColorIndex = 1; // 元件=红
|
||||
|
||||
// 矩形框图层名(便于批量清除)
|
||||
public const string PaLayerName = "__CADCJ_PA_FRAME";
|
||||
|
||||
/// <summary>
|
||||
/// 连续扒数据事件:每次框选完成(松开鼠标)就触发一次,把这一批文本+框Handle送给调用方。
|
||||
/// 调用方在 Form3 里把数据插入到表格,然后控制流回到 PickTexts 继续下一次框选。
|
||||
/// </summary>
|
||||
public static event System.Action<PaMode, List<PaTextResult>> BatchTextsPicked;
|
||||
|
||||
/// <summary>
|
||||
/// 连续框选模式:用户点一次按钮进入,可以连续框选多次,每次框选立即送出一批文本。
|
||||
/// 按回车/空格完成当前批次,ESC 退出连续模式。
|
||||
/// 方向决定行为:
|
||||
/// · 左上→右下(正向框选):每个文本一条记录
|
||||
/// · 右下→左上(反向框选,CAD里称为"交叉框选"):多条文本合并为一条
|
||||
/// </summary>
|
||||
/// <param name="mode">扒数据模式(决定矩形框颜色)</param>
|
||||
public static void PickTextsContinuous(PaMode mode)
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc == null) return;
|
||||
var ed = doc.Editor;
|
||||
|
||||
// ★ 强制开启透明度显示(TRANSPARENCYDISPLAY=1)
|
||||
// 否则 Hatch.Transparency 在某些电脑上不生效,蒙版显示为不透明
|
||||
try { AcAp.SetSystemVariable("TRANSPARENCYDISPLAY", 1); } catch { }
|
||||
|
||||
// ★ 当前模式(允许右键切换,所以用变量保存当前模式)
|
||||
PaMode currentMode = mode;
|
||||
|
||||
try
|
||||
{
|
||||
var typeValues = new TypedValue[]
|
||||
{
|
||||
new TypedValue(-4, "<OR"),
|
||||
new TypedValue((int)DxfCode.Start, "TEXT"),
|
||||
new TypedValue((int)DxfCode.Start, "MTEXT"),
|
||||
new TypedValue(-4, "OR>")
|
||||
};
|
||||
var filter = new SelectionFilter(typeValues);
|
||||
|
||||
// ★ 连续循环:每次框选完立即触发事件,直到用户按 ESC
|
||||
while (true)
|
||||
{
|
||||
// 根据当前模式获取颜色和名称
|
||||
short colorIndex;
|
||||
string modeName;
|
||||
switch (currentMode)
|
||||
{
|
||||
case PaMode.Tuhao: colorIndex = TuhaoColorIndex; modeName = "图号"; break;
|
||||
case PaMode.Xianghao: colorIndex = XianghaoColorIndex; modeName = "箱号"; break;
|
||||
default: colorIndex = YuanjianColorIndex; modeName = "元件"; break;
|
||||
}
|
||||
|
||||
// 第一角点
|
||||
// ★ AllowNone=true:右键会返回 None,用来切换模式;ESC 返回 Cancel 退出
|
||||
var po1 = new PromptPointOptions("\n框选【" + modeName + "】起点(右键切换模式,ESC结束): ");
|
||||
po1.AllowNone = true;
|
||||
var pres1 = ed.GetPoint(po1);
|
||||
if (pres1.Status == PromptStatus.Cancel) break; // ESC 退出
|
||||
if (pres1.Status == PromptStatus.None)
|
||||
{
|
||||
// ★ 右键:切换到下一个模式(图号→箱号→元件→退出)
|
||||
PaMode next = GetNextMode(currentMode);
|
||||
if (next == currentMode)
|
||||
{
|
||||
// 元件模式右键 → 退出
|
||||
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
|
||||
break;
|
||||
}
|
||||
currentMode = next;
|
||||
ed.WriteMessage("\n[扒数据] 切换到【" + GetModeName(currentMode) + "】模式。");
|
||||
continue;
|
||||
}
|
||||
if (pres1.Status != PromptStatus.OK) break;
|
||||
Point3d pt1 = pres1.Value;
|
||||
|
||||
// 对角点
|
||||
// ★ AllowNone=true:右键也允许切换模式(回到第一角点重新开始)
|
||||
var co = new PromptCornerOptions("\n对角点: ", pt1);
|
||||
co.AllowNone = true;
|
||||
var cres = ed.GetCorner(co);
|
||||
if (cres.Status == PromptStatus.Cancel) break; // ESC 退出
|
||||
if (cres.Status == PromptStatus.None)
|
||||
{
|
||||
// ★ 右键:切换到下一个模式,回到第一角点
|
||||
PaMode next = GetNextMode(currentMode);
|
||||
if (next == currentMode)
|
||||
{
|
||||
ed.WriteMessage("\n[扒数据] 已退出连续模式。");
|
||||
break;
|
||||
}
|
||||
currentMode = next;
|
||||
ed.WriteMessage("\n[扒数据] 切换到【" + GetModeName(currentMode) + "】模式。");
|
||||
continue;
|
||||
}
|
||||
if (cres.Status != PromptStatus.OK) break;
|
||||
Point3d pt2 = cres.Value;
|
||||
|
||||
// ★ 关键:判断方向(任意一项反向即为"交叉框选"=合并模式)
|
||||
// pt1.X > pt2.X = 从右往左框选(pt1 在 pt2 右边)
|
||||
// pt1.Y < pt2.Y = 从下往上框选(pt1 在 pt2 下方)
|
||||
// 任一条件满足都视为反向框选 → 多文本合并为一条
|
||||
bool isCrossing = (pt1.X > pt2.X) || (pt1.Y < pt2.Y);
|
||||
|
||||
double minX = Math.Min(pt1.X, pt2.X);
|
||||
double maxX = Math.Max(pt1.X, pt2.X);
|
||||
double minY = Math.Min(pt1.Y, pt2.Y);
|
||||
double maxY = Math.Max(pt1.Y, pt2.Y);
|
||||
Point3d minPt = new Point3d(minX, minY, 0);
|
||||
Point3d maxPt = new Point3d(maxX, maxY, 0);
|
||||
|
||||
// ★ 统一用交叉窗口选择:只要框碰到文字(部分重叠)即选中,
|
||||
// 不再要求把文字完全框住(旧版正向框选用 SelectWindow 必须全包,漏选严重)。
|
||||
// 框选方向只决定业务模式(正向=逐条,反向=合并),不再影响选择方式。
|
||||
PromptSelectionResult res = ed.SelectCrossingWindow(minPt, maxPt, filter);
|
||||
|
||||
if (res.Status != PromptStatus.OK) continue; // 这一次没选中,继续下一次
|
||||
ObjectId[] ids = res.Value.GetObjectIds();
|
||||
if (ids.Length == 0) continue;
|
||||
|
||||
// 收集文本
|
||||
var items = new List<TextItem>();
|
||||
using (var tr = doc.Database.TransactionManager.StartTransaction())
|
||||
{
|
||||
foreach (ObjectId id in ids)
|
||||
{
|
||||
var ent = tr.GetObject(id, OpenMode.ForRead) as Entity;
|
||||
if (ent == null) continue;
|
||||
string text = "";
|
||||
Point3d pos = Point3d.Origin;
|
||||
Extents3d? bounds = null;
|
||||
var dt = ent as DBText;
|
||||
var mt = ent as MText;
|
||||
if (dt != null)
|
||||
{
|
||||
text = dt.TextString;
|
||||
try
|
||||
{
|
||||
// ★ 用 CAD 自身的 GeometricExtents 获取文本框边界
|
||||
// 宽度通常准确,高度包含字体预留空间偏大
|
||||
// 所以高度用字高重新估算,宽度用 GeometricExtents
|
||||
bounds = dt.GeometricExtents;
|
||||
if (bounds.HasValue)
|
||||
{
|
||||
double h = dt.Height;
|
||||
if (h > 0)
|
||||
{
|
||||
// ★ 宽度:直接用 GeometricExtents 的宽度(CAD 自身文本框宽度)
|
||||
double left = bounds.Value.MinPoint.X;
|
||||
double right = bounds.Value.MaxPoint.X;
|
||||
// ★ 高度:用字高紧凑估算(底部=baseline下0.2h,顶部=baseline上1.0h)
|
||||
double bottom = dt.Position.Y - h * 0.2;
|
||||
double top = dt.Position.Y + h * 1.0;
|
||||
bounds = new Extents3d(
|
||||
new Point3d(left, bottom, 0),
|
||||
new Point3d(right, top, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
// ★ 用文字中心点作为排序基准
|
||||
if (bounds.HasValue)
|
||||
pos = new Point3d(
|
||||
(bounds.Value.MinPoint.X + bounds.Value.MaxPoint.X) / 2.0,
|
||||
(bounds.Value.MinPoint.Y + bounds.Value.MaxPoint.Y) / 2.0,
|
||||
0);
|
||||
else
|
||||
pos = dt.Position;
|
||||
}
|
||||
else if (mt != null)
|
||||
{
|
||||
text = mt.Text;
|
||||
try { bounds = mt.GeometricExtents; } catch { }
|
||||
if (bounds.HasValue)
|
||||
pos = new Point3d(
|
||||
(bounds.Value.MinPoint.X + bounds.Value.MaxPoint.X) / 2.0,
|
||||
(bounds.Value.MinPoint.Y + bounds.Value.MaxPoint.Y) / 2.0,
|
||||
0);
|
||||
else
|
||||
pos = mt.Location;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
items.Add(new TextItem
|
||||
{
|
||||
Text = text.Trim(),
|
||||
Position = pos,
|
||||
Bounds = bounds,
|
||||
ObjectId = id,
|
||||
TextHandle = ent.Handle.ToString()
|
||||
});
|
||||
}
|
||||
}
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
if (items.Count == 0) continue;
|
||||
|
||||
// ★ 按列分组排序:先从左到右分列,列内从上到下
|
||||
// 用户需求示例:1在上 2在下(左列) 3在上 4在下(右列)
|
||||
// 期望顺序:1、2、3、4(先左列从上到下,再右列从上到下)
|
||||
// 算法:
|
||||
// 1. 按X左边界升序
|
||||
// 2. 扫描分列:X范围有重叠的归为同一列(垂直方向对齐的文字)
|
||||
// 3. 每列内按Y降序(上在前)
|
||||
// 4. 列间按X升序(左在前)合并
|
||||
{
|
||||
System.Func<TextItem, double> getLeft = it =>
|
||||
it.Bounds.HasValue ? it.Bounds.Value.MinPoint.X : it.Position.X;
|
||||
System.Func<TextItem, double> getRight = it =>
|
||||
it.Bounds.HasValue ? it.Bounds.Value.MaxPoint.X : it.Position.X;
|
||||
System.Func<TextItem, double> getCenterY = it =>
|
||||
it.Bounds.HasValue ? (it.Bounds.Value.MinPoint.Y + it.Bounds.Value.MaxPoint.Y) / 2.0 : it.Position.Y;
|
||||
|
||||
// 1. 按X左边界升序
|
||||
items.Sort((a, b) => getLeft(a).CompareTo(getLeft(b)));
|
||||
|
||||
// 2. 扫描分列:X范围有重叠的归为同一列
|
||||
var columns = new List<List<TextItem>>();
|
||||
double curMaxRight = double.NegativeInfinity;
|
||||
List<TextItem> curCol = null;
|
||||
foreach (var it in items)
|
||||
{
|
||||
double left = getLeft(it);
|
||||
double right = getRight(it);
|
||||
if (curCol == null || left > curMaxRight)
|
||||
{
|
||||
// 新列
|
||||
curCol = new List<TextItem>();
|
||||
columns.Add(curCol);
|
||||
curMaxRight = right;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 加入当前列,更新右边界
|
||||
if (right > curMaxRight) curMaxRight = right;
|
||||
}
|
||||
curCol.Add(it);
|
||||
}
|
||||
|
||||
// 3. 每列内按Y降序(上在前)
|
||||
foreach (var col in columns)
|
||||
{
|
||||
col.Sort((a, b) => getCenterY(b).CompareTo(getCenterY(a)));
|
||||
}
|
||||
|
||||
// 4. 合并(列间已按X升序)
|
||||
items.Clear();
|
||||
foreach (var col in columns) items.AddRange(col);
|
||||
}
|
||||
|
||||
var result = new List<PaTextResult>();
|
||||
if (isCrossing && items.Count > 1)
|
||||
{
|
||||
// ★ 反向框选 + 多条文本:合并模式
|
||||
// 画一个大框,所有文本共用这个框Handle
|
||||
// 每个文本作为独立的 PaTextResult 传出(共用同一个框Handle),
|
||||
// 让 Form3 能检查每个文本是否已存在并自动合并已存在的元件
|
||||
string mergedHandle = DrawMergedFrame(items, colorIndex);
|
||||
foreach (var it in items)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(it.Text))
|
||||
{
|
||||
result.Add(new PaTextResult
|
||||
{
|
||||
Text = it.Text.Trim(),
|
||||
FrameHandle = mergedHandle,
|
||||
TextHandle = it.TextHandle
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (currentMode == PaMode.Yuanjian)
|
||||
{
|
||||
// 元件模式(正向框选或单条):每个文字一条,每个文字一个框
|
||||
var handles = DrawTextFrames(items, colorIndex);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
string h = i < handles.Count ? handles[i] : "";
|
||||
result.Add(new PaTextResult
|
||||
{
|
||||
Text = items[i].Text,
|
||||
FrameHandle = h,
|
||||
TextHandle = items[i].TextHandle
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 图号/箱号(正向框选或单条):去重(同名只算一条),框对应
|
||||
var seen = new HashSet<string>();
|
||||
var seenTextHandles = new HashSet<string>();
|
||||
var handles = DrawTextFrames(items, colorIndex);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
// ★ 用文本实体Handle去重(同一个文本实体只算一条),
|
||||
// 不同位置的相同内容文本算两条
|
||||
if (seenTextHandles.Add(items[i].TextHandle) && seen.Add(items[i].Text))
|
||||
{
|
||||
string h = i < handles.Count ? handles[i] : "";
|
||||
result.Add(new PaTextResult
|
||||
{
|
||||
Text = items[i].Text,
|
||||
FrameHandle = h,
|
||||
TextHandle = items[i].TextHandle
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ★ 立即把这一批数据(文本+框Handle)送给调用方(插入到表格)
|
||||
if (result.Count > 0)
|
||||
{
|
||||
var handler = BatchTextsPicked;
|
||||
if (handler != null)
|
||||
{
|
||||
try { handler(currentMode, result); } catch { }
|
||||
}
|
||||
|
||||
// ★ 扒完一批后自动切换到下一个模式(图号→箱号→元件)
|
||||
// 元件模式扒完后保持元件模式不变(继续扒下一个箱号的元件)
|
||||
if (currentMode == PaMode.Tuhao)
|
||||
{
|
||||
currentMode = PaMode.Xianghao;
|
||||
ed.WriteMessage("\n[扒数据] 图号已扒完,自动切换到【箱号】模式。");
|
||||
}
|
||||
else if (currentMode == PaMode.Xianghao)
|
||||
{
|
||||
currentMode = PaMode.Yuanjian;
|
||||
ed.WriteMessage("\n[扒数据] 箱号已扒完,自动切换到【元件】模式。");
|
||||
}
|
||||
}
|
||||
// 继续下一次框选
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
try { ed.WriteMessage("\n[扒数据] 异常: " + ex.Message); } catch { }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取右键切换的下一个扒图模式。
|
||||
/// 顺序:图号 → 箱号 → 元件 → 退出(返回当前模式表示退出)。
|
||||
/// </summary>
|
||||
private static PaMode GetNextMode(PaMode current)
|
||||
{
|
||||
switch (current)
|
||||
{
|
||||
case PaMode.Tuhao: return PaMode.Xianghao;
|
||||
case PaMode.Xianghao: return PaMode.Yuanjian;
|
||||
default: return PaMode.Yuanjian; // 元件右键 → 返回自身,外层判断退出
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>获取模式的中文名称(用于切换提示)。</summary>
|
||||
private static string GetModeName(PaMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case PaMode.Tuhao: return "图号";
|
||||
case PaMode.Xianghao: return "箱号";
|
||||
default: return "元件";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 反向框选合并时:计算所有文字的总边界,画一个大框包住所有文字。
|
||||
/// 返回:大框的 Handle 字符串(失败返回空字符串)。
|
||||
/// </summary>
|
||||
private static string DrawMergedFrame(List<TextItem> items, short colorIndex)
|
||||
{
|
||||
string handle = "";
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc == null) return handle;
|
||||
var db = doc.Database;
|
||||
|
||||
// 先计算所有文字的合并 Extents
|
||||
double? minX = null, minY = null, maxX = null, maxY = null;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Bounds == null) continue;
|
||||
Extents3d ext = item.Bounds.Value;
|
||||
if (minX == null || ext.MinPoint.X < minX.Value) minX = ext.MinPoint.X;
|
||||
if (minY == null || ext.MinPoint.Y < minY.Value) minY = ext.MinPoint.Y;
|
||||
if (maxX == null || ext.MaxPoint.X > maxX.Value) maxX = ext.MaxPoint.X;
|
||||
if (maxY == null || ext.MaxPoint.Y > maxY.Value) maxY = ext.MaxPoint.Y;
|
||||
}
|
||||
if (minX == null) return handle;
|
||||
|
||||
using (var tr = db.TransactionManager.StartTransaction())
|
||||
{
|
||||
// 确保专用图层存在
|
||||
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
|
||||
ObjectId layerId;
|
||||
if (lt.Has(PaLayerName))
|
||||
{
|
||||
layerId = lt[PaLayerName];
|
||||
}
|
||||
else
|
||||
{
|
||||
lt.UpgradeOpen();
|
||||
var layerDef = new LayerTableRecord { Name = PaLayerName };
|
||||
layerId = lt.Add(layerDef);
|
||||
tr.AddNewlyCreatedDBObject(layerDef, true);
|
||||
}
|
||||
|
||||
var ms = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
|
||||
|
||||
// ★ 先删除这批文字之前已有的旧框(避免小框和大框同时存在)
|
||||
// 遍历当前空间,找出 __CADCJ_PA_FRAME 图层上与这批文字 Bounds 相交的实体,
|
||||
// 通过 EraseGroupForEntity 删除整个组(边框+蒙版一起删)
|
||||
var idsToDelete = new List<ObjectId>();
|
||||
foreach (ObjectId entId in ms)
|
||||
{
|
||||
var ent = tr.GetObject(entId, OpenMode.ForRead, false, true) as Entity;
|
||||
if (ent == null) continue;
|
||||
if (ent.LayerId != layerId) continue;
|
||||
if (ent.IsErased) continue;
|
||||
Extents3d? entExt = null;
|
||||
try { entExt = ent.GeometricExtents; } catch { }
|
||||
if (!entExt.HasValue) continue;
|
||||
// 检查是否与任何文字 item 的 Bounds 相交
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Bounds == null) continue;
|
||||
if (BoundsIntersect(entExt.Value, item.Bounds.Value))
|
||||
{
|
||||
idsToDelete.Add(entId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (ObjectId id in idsToDelete)
|
||||
{
|
||||
// ★ 先删除同组的其他实体(Hatch),再删除主实体
|
||||
EraseGroupForEntity(tr, id);
|
||||
var ent = tr.GetObject(id, OpenMode.ForWrite);
|
||||
if (!ent.IsErased) ent.Erase();
|
||||
}
|
||||
|
||||
// ★ 边距极小:总宽高的 2%,最小 0.5
|
||||
double totalW = maxX.Value - minX.Value;
|
||||
double totalH = maxY.Value - minY.Value;
|
||||
double padX = Math.Max(totalW * 0.02, 0.5);
|
||||
double padY = Math.Max(totalH * 0.02, 0.5);
|
||||
|
||||
// 大框四角点(带边距,X和Y方向各自按比例)
|
||||
Point3d p1 = new Point3d(minX.Value - padX, minY.Value - padY, 0);
|
||||
Point3d p2 = new Point3d(maxX.Value + padX, minY.Value - padY, 0);
|
||||
Point3d p3 = new Point3d(maxX.Value + padX, maxY.Value + padY, 0);
|
||||
Point3d p4 = new Point3d(minX.Value - padX, maxY.Value + padY, 0);
|
||||
|
||||
var pl = new Polyline();
|
||||
pl.AddVertexAt(0, new Point2d(p1.X, p1.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(1, new Point2d(p2.X, p2.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(2, new Point2d(p3.X, p3.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(3, new Point2d(p4.X, p4.Y), 0, 0, 0);
|
||||
pl.Closed = true;
|
||||
pl.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
|
||||
pl.LayerId = layerId;
|
||||
pl.LineWeight = LineWeight.LineWeight070;
|
||||
|
||||
ms.AppendEntity(pl);
|
||||
tr.AddNewlyCreatedDBObject(pl, true);
|
||||
// ★ 记录大框的 Handle
|
||||
handle = pl.Handle.ToString();
|
||||
|
||||
// ★ 添加半透明填充蒙版(用 Hatch 实体,支持透明度)
|
||||
var hatch = new Hatch();
|
||||
hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
|
||||
hatch.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
|
||||
hatch.Transparency = new Transparency(65); // 65% 透明度
|
||||
hatch.LayerId = layerId;
|
||||
ms.AppendEntity(hatch);
|
||||
tr.AddNewlyCreatedDBObject(hatch, true);
|
||||
|
||||
ObjectIdCollection hatchLoopIds = new ObjectIdCollection();
|
||||
hatchLoopIds.Add(pl.Id);
|
||||
hatch.AppendLoop(HatchLoopTypes.Default, hatchLoopIds);
|
||||
|
||||
// ★ 把 Polyline 和 Hatch 创建为一个组(整体选中/整体删除)
|
||||
MakeFrameGroup(db, tr, pl.Id, hatch.Id);
|
||||
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
doc.Editor.UpdateScreen();
|
||||
doc.Editor.Regen();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 画合并框失败: " + ex.Message);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查两个 Extents3d 是否相交(用于删除旧框时判断范围重叠)。
|
||||
/// </summary>
|
||||
private static bool BoundsIntersect(Extents3d a, Extents3d b)
|
||||
{
|
||||
// X 方向不相交
|
||||
if (a.MaxPoint.X < b.MinPoint.X || a.MinPoint.X > b.MaxPoint.X) return false;
|
||||
// Y 方向不相交
|
||||
if (a.MaxPoint.Y < b.MinPoint.Y || a.MinPoint.Y > b.MaxPoint.Y) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ★ 把 Polyline(边框) 和 Hatch(蒙版) 创建为一个命名组,
|
||||
/// 这样用户在 CAD 里选中/删除其中一个时,整个组(边框+蒙版)会一起被选中/删除。
|
||||
/// </summary>
|
||||
private static void MakeFrameGroup(Database db, Transaction tr, ObjectId plId, ObjectId hatchId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var groupDict = (DBDictionary)tr.GetObject(db.GroupDictionaryId, OpenMode.ForWrite);
|
||||
// 组名用 Polyline 的 Handle 保证唯一
|
||||
string groupName = "CADCJ_PA_FRAME_" + plId.Handle.ToString();
|
||||
var group = new Group(groupName, true); // true = 可选中
|
||||
group.Append(new ObjectIdCollection(new[] { plId, hatchId }));
|
||||
groupDict.SetAt(groupName, group);
|
||||
tr.AddNewlyCreatedDBObject(group, true);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ★ 删除包含指定实体的所有 Group 内的所有实体(连同 Group 本身一起删除)。
|
||||
/// 用于"删除框时自动删除关联的蒙版"。
|
||||
/// </summary>
|
||||
public static void EraseGroupForEntity(Transaction tr, ObjectId entId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ent = tr.GetObject(entId, OpenMode.ForRead) as Entity;
|
||||
if (ent == null) return;
|
||||
// 获取实体的所有 PersistentReactor(Group 会作为 reactor 记录)
|
||||
ObjectIdCollection reactors = ent.GetPersistentReactorIds();
|
||||
var idsToErase = new List<ObjectId>();
|
||||
var groupsToErase = new List<ObjectId>();
|
||||
foreach (ObjectId reactorId in reactors)
|
||||
{
|
||||
var grp = tr.GetObject(reactorId, OpenMode.ForRead) as Group;
|
||||
if (grp == null) continue;
|
||||
// 收集 Group 内所有实体
|
||||
foreach (ObjectId memberId in grp.GetAllEntityIds())
|
||||
{
|
||||
if (!idsToErase.Contains(memberId)) idsToErase.Add(memberId);
|
||||
}
|
||||
groupsToErase.Add(reactorId);
|
||||
}
|
||||
// 删除 Group 内所有实体
|
||||
foreach (ObjectId memberId in idsToErase)
|
||||
{
|
||||
if (memberId == entId) continue; // 主实体由调用方删除
|
||||
try
|
||||
{
|
||||
var member = tr.GetObject(memberId, OpenMode.ForWrite);
|
||||
if (!member.IsErased) member.Erase();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
// 删除 Group 本身
|
||||
foreach (ObjectId groupId in groupsToErase)
|
||||
{
|
||||
try
|
||||
{
|
||||
var grp = tr.GetObject(groupId, OpenMode.ForWrite);
|
||||
if (!grp.IsErased) grp.Erase();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在每个文字周围画一个彩色矩形框(LWPolyline),不改文字本身的颜色。
|
||||
/// 所有矩形框放在专用图层 __CADCJ_PA_FRAME 上,方便批量清除。
|
||||
/// 返回:每个 item 对应的框 Handle 字符串列表(和 items 顺序一致;无 Bounds 的为空字符串)。
|
||||
/// </summary>
|
||||
private static List<string> DrawTextFrames(List<TextItem> items, short colorIndex)
|
||||
{
|
||||
var handles = new List<string>();
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc == null) return handles;
|
||||
var db = doc.Database;
|
||||
|
||||
using (var tr = db.TransactionManager.StartTransaction())
|
||||
{
|
||||
// 确保专用图层存在(如果不存在就创建)
|
||||
LayerTable lt = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
|
||||
ObjectId layerId;
|
||||
if (lt.Has(PaLayerName))
|
||||
{
|
||||
layerId = lt[PaLayerName];
|
||||
}
|
||||
else
|
||||
{
|
||||
lt.UpgradeOpen();
|
||||
var layerDef = new LayerTableRecord { Name = PaLayerName };
|
||||
layerId = lt.Add(layerDef);
|
||||
tr.AddNewlyCreatedDBObject(layerDef, true);
|
||||
}
|
||||
|
||||
// 获取当前空间(模型空间或图纸空间)
|
||||
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
|
||||
var ms = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Bounds == null) { handles.Add(""); continue; }
|
||||
Extents3d ext = item.Bounds.Value;
|
||||
|
||||
// ★ 用文字的实际位置和高度估算更紧凑的范围
|
||||
// GeometricExtents 可能包含字体预留的 ascent/descent 空间,
|
||||
// 这里用文字中心点和估算的宽高来定义框,使其更贴合文字
|
||||
double textW, textH;
|
||||
if (ext.MaxPoint.Y - ext.MinPoint.Y > ext.MaxPoint.X - ext.MinPoint.X * 3)
|
||||
{
|
||||
// 如果高度远大于宽度(多行或特殊情况),用 GeometricExtents
|
||||
textW = ext.MaxPoint.X - ext.MinPoint.X;
|
||||
textH = ext.MaxPoint.Y - ext.MinPoint.Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 单行文字:用中心点和估算尺寸
|
||||
textW = ext.MaxPoint.X - ext.MinPoint.X;
|
||||
textH = ext.MaxPoint.Y - ext.MinPoint.Y;
|
||||
}
|
||||
|
||||
// ★ 边距极小:文字宽高的 3%,最小 0.3
|
||||
double padX = Math.Max(textW * 0.03, 0.3);
|
||||
double padY = Math.Max(textH * 0.03, 0.3);
|
||||
|
||||
// 矩形四角点(带极小边距)
|
||||
Point3d p1 = new Point3d(ext.MinPoint.X - padX, ext.MinPoint.Y - padY, 0);
|
||||
Point3d p2 = new Point3d(ext.MaxPoint.X + padX, ext.MinPoint.Y - padY, 0);
|
||||
Point3d p3 = new Point3d(ext.MaxPoint.X + padX, ext.MaxPoint.Y + padY, 0);
|
||||
Point3d p4 = new Point3d(ext.MinPoint.X - padX, ext.MaxPoint.Y + padY, 0);
|
||||
|
||||
// 创建 LWPolyline 矩形
|
||||
var pl = new Polyline();
|
||||
pl.AddVertexAt(0, new Point2d(p1.X, p1.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(1, new Point2d(p2.X, p2.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(2, new Point2d(p3.X, p3.Y), 0, 0, 0);
|
||||
pl.AddVertexAt(3, new Point2d(p4.X, p4.Y), 0, 0, 0);
|
||||
pl.Closed = true;
|
||||
|
||||
// 设置颜色和图层
|
||||
pl.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
|
||||
pl.LayerId = layerId;
|
||||
// 线宽更粗,看得清
|
||||
pl.LineWeight = LineWeight.LineWeight070;
|
||||
|
||||
ms.AppendEntity(pl);
|
||||
tr.AddNewlyCreatedDBObject(pl, true);
|
||||
// ★ 记录框的 Handle,用于关联表格数据行
|
||||
handles.Add(pl.Handle.ToString());
|
||||
|
||||
// ★ 添加半透明填充蒙版(用 Hatch 实体,支持透明度)
|
||||
var hatch = new Hatch();
|
||||
hatch.SetHatchPattern(HatchPatternType.PreDefined, "SOLID");
|
||||
hatch.Color = Color.FromColorIndex(ColorMethod.ByAci, colorIndex);
|
||||
hatch.Transparency = new Transparency(65); // 65% 透明度
|
||||
hatch.LayerId = layerId;
|
||||
ms.AppendEntity(hatch);
|
||||
tr.AddNewlyCreatedDBObject(hatch, true);
|
||||
|
||||
ObjectIdCollection hatchLoopIds = new ObjectIdCollection();
|
||||
hatchLoopIds.Add(pl.Id);
|
||||
hatch.AppendLoop(HatchLoopTypes.Default, hatchLoopIds);
|
||||
|
||||
// ★ 把 Polyline 和 Hatch 创建为一个组(整体选中/整体删除)
|
||||
MakeFrameGroup(db, tr, pl.Id, hatch.Id);
|
||||
}
|
||||
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
// 刷新显示
|
||||
doc.Editor.UpdateScreen();
|
||||
doc.Editor.Regen();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 画框失败: " + ex.Message);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
return handles;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清除所有扒数据时画的彩色矩形框(删除 __CADCJ_PA_FRAME 图层上的所有对象)。
|
||||
/// 不动文字本身,文字保持原色。
|
||||
/// </summary>
|
||||
public static void ClearAllHighlight()
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc == null) return;
|
||||
var db = doc.Database;
|
||||
|
||||
using (var tr = db.TransactionManager.StartTransaction())
|
||||
{
|
||||
var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
|
||||
// 遍历所有块定义(模型空间+所有布局),删除目标图层上的对象
|
||||
foreach (ObjectId btrId in bt)
|
||||
{
|
||||
var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
|
||||
var ids = new List<ObjectId>();
|
||||
foreach (ObjectId entId in btr)
|
||||
{
|
||||
var ent = tr.GetObject(entId, OpenMode.ForRead, false, true) as Entity;
|
||||
if (ent == null) continue;
|
||||
if (ent.Layer == PaLayerName)
|
||||
{
|
||||
ids.Add(entId);
|
||||
}
|
||||
}
|
||||
if (ids.Count > 0)
|
||||
{
|
||||
btr.UpgradeOpen();
|
||||
foreach (ObjectId id in ids)
|
||||
{
|
||||
// ★ 先删除同组的其他实体,再删除主实体
|
||||
EraseGroupForEntity(tr, id);
|
||||
var ent = tr.GetObject(id, OpenMode.ForWrite);
|
||||
if (!ent.IsErased) ent.Erase();
|
||||
}
|
||||
}
|
||||
}
|
||||
tr.Commit();
|
||||
}
|
||||
|
||||
doc.Editor.UpdateScreen();
|
||||
doc.Editor.Regen();
|
||||
|
||||
try { doc.Editor.WriteMessage("\n[扒数据] 已清除所有标记框。"); } catch { }
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var doc = AcAp.DocumentManager.MdiActiveDocument;
|
||||
if (doc != null) doc.Editor.WriteMessage("\n[扒数据] 清除失败: " + ex.Message);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private class TextItem
|
||||
{
|
||||
public string Text;
|
||||
public Point3d Position;
|
||||
public Extents3d? Bounds;
|
||||
public ObjectId ObjectId;
|
||||
public string TextHandle = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10/11 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">unaware</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
@@ -1,19 +0,0 @@
|
||||
@echo off
|
||||
REM ============================================
|
||||
REM Auto-generated build script
|
||||
REM All non-ASCII paths are in build.rsp (UTF-8)
|
||||
REM Keep this .bat file ASCII-only to avoid cmd codepage issues
|
||||
REM ============================================
|
||||
|
||||
cd /d "%~dp0"
|
||||
|
||||
"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe" @build.rsp
|
||||
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo Build OK. Launching...
|
||||
powershell -NoProfile -Command "Start-Process -FilePath ('%~dp0' + (Select-String -Path build.rsp -Pattern '^/out:(.+)$').Matches.Groups[1].Value)"
|
||||
) else (
|
||||
echo Build FAILED - see messages above
|
||||
pause
|
||||
)
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# Auto-generated csc response file
|
||||
/target:library
|
||||
/platform:x64
|
||||
/utf8output
|
||||
/out:cadcj.dll
|
||||
/win32manifest:app.manifest
|
||||
/r:System.Windows.Forms.dll
|
||||
/r:System.Drawing.dll
|
||||
/r:System.dll
|
||||
/r:System.Data.dll
|
||||
/r:System.Core.dll
|
||||
/r:System.Xml.dll
|
||||
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\PresentationCore.dll"
|
||||
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\WindowsBase.dll"
|
||||
/r:System.IO.Compression.dll
|
||||
/r:System.IO.Compression.FileSystem.dll
|
||||
/r:"AdvancedDataGridView.dll"
|
||||
/r:"System.Data.SQLite.dll"
|
||||
/r:"E:\cad2\AutoCAD 2018\acdbmgd.dll"
|
||||
/r:"E:\cad2\AutoCAD 2018\acmgd.dll"
|
||||
/r:"E:\cad2\AutoCAD 2018\accoremgd.dll"
|
||||
CadPlugin.cs
|
||||
Form3.cs
|
||||
Form3.ui.cs
|
||||
PaTextSelector.cs
|
||||
新建项目.cs
|
||||
新建项目.ui.cs
|
||||
@@ -1,25 +0,0 @@
|
||||
/target:library
|
||||
/platform:x64
|
||||
/utf8output
|
||||
/out:cadcj_v2.dll
|
||||
/r:System.Windows.Forms.dll
|
||||
/r:System.Drawing.dll
|
||||
/r:System.dll
|
||||
/r:System.Data.dll
|
||||
/r:System.Core.dll
|
||||
/r:System.Xml.dll
|
||||
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\PresentationCore.dll"
|
||||
/r:"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\WindowsBase.dll"
|
||||
/r:System.IO.Compression.dll
|
||||
/r:System.IO.Compression.FileSystem.dll
|
||||
/r:"AdvancedDataGridView.dll"
|
||||
/r:"System.Data.SQLite.dll"
|
||||
/r:"D:\ProgramData\cad\AutoCAD 2018\acdbmgd.dll"
|
||||
/r:"D:\ProgramData\cad\AutoCAD 2018\acmgd.dll"
|
||||
/r:"D:\ProgramData\cad\AutoCAD 2018\accoremgd.dll"
|
||||
CadPlugin.cs
|
||||
Form3.cs
|
||||
Form3.ui.cs
|
||||
PaTextSelector.cs
|
||||
新建项目.cs
|
||||
新建项目.ui.cs
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"ApiKey": "sk-65b3963488ab420aa9df3e4dafa02768",
|
||||
"BaseUrl": "https://api.deepseek.com",
|
||||
"Model": "deepseek-v4-flash",
|
||||
"Enabled": false,
|
||||
"WebSearch": true
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
@echo off
|
||||
chcp 936 >nul
|
||||
title 成套报价 CAD 插件卸载程序
|
||||
|
||||
REM 切换到批处理文件所在目录(支持从任意位置运行)
|
||||
cd /d "%~dp0"
|
||||
|
||||
REM 检查 PowerShell 脚本是否存在
|
||||
if not exist "卸载CAD插件.ps1" (
|
||||
echo [错误] 未找到 卸载CAD插件.ps1
|
||||
echo 请确保本批处理文件与 卸载CAD插件.ps1 在同一目录。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 以管理员身份运行 PowerShell 脚本(避免 HKLM 删除提权弹窗中断)
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%~dp0卸载CAD插件.ps1' -Verb RunAs -Wait"
|
||||
|
||||
REM 若用户取消提权,则非提权运行(HKLM 删除会自动提权,acaddoc.lsp 和 TRUSTEDPATHS 无需管理员)
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo [提示] 管理员提权被取消,尝试非提权运行...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "卸载CAD插件.ps1"
|
||||
)
|
||||
|
||||
pause
|
||||
@@ -1,263 +0,0 @@
|
||||
# ===========================================================================
|
||||
# 成套报价 CAD 插件 - 通用卸载脚本
|
||||
# 自动检测 AutoCAD 并移除所有安装时写入的配置
|
||||
# 用法:以管理员身份运行,或在 PowerShell 中执行本脚本
|
||||
# ===========================================================================
|
||||
|
||||
# --- 0. 环境与自检 ---
|
||||
$ErrorActionPreference = 'Stop'
|
||||
# $PSScriptRoot 在 -File 模式下可靠返回脚本所在目录(PS 3.0+)
|
||||
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||
$scriptDir = $scriptDir.TrimEnd('\') # 统一去除尾部反斜杠,便于比较
|
||||
|
||||
# 检测是否管理员(写 HKLM 需要)
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "[提示] 当前未以管理员身份运行,HKLM 注册表删除将自动提权。" -ForegroundColor Yellow
|
||||
Write-Host " acaddoc.lsp 和 TRUSTEDPATHS 无需管理员权限。" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host " 成套报价 CAD 插件卸载程序" -ForegroundColor Cyan
|
||||
Write-Host " 插件目录: $scriptDir" -ForegroundColor Cyan
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# --- 1. 检测已安装的 AutoCAD 版本 ---
|
||||
Write-Host "[1/4] 检测 AutoCAD 安装..." -ForegroundColor Green
|
||||
|
||||
$acadInstalls = @()
|
||||
$regRoots = @(
|
||||
'HKLM:\SOFTWARE\Autodesk\AutoCAD',
|
||||
'HKLM:\SOFTWARE\WOW6432Node\Autodesk\AutoCAD'
|
||||
)
|
||||
|
||||
foreach ($root in $regRoots) {
|
||||
if (-not (Test-Path $root)) { continue }
|
||||
Get-ChildItem $root -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^R\d+\.0$' } | ForEach-Object {
|
||||
$verKey = $_.PSPath
|
||||
$verNum = $_.PSChildName
|
||||
Get-ChildItem $verKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^ACAD-\d+:\d+$' } | ForEach-Object {
|
||||
$langKey = $_.PSPath
|
||||
$props = Get-ItemProperty -Path $langKey -ErrorAction SilentlyContinue
|
||||
$loc = $props.AcadLocation
|
||||
$prod = $props.ProductName
|
||||
if ($loc -and (Test-Path $loc)) {
|
||||
$acadInstalls += [PSCustomObject]@{
|
||||
Version = $verNum
|
||||
LangKey = $_.PSChildName
|
||||
Location = $loc
|
||||
Product = $prod
|
||||
HKLMKey = $langKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($acadInstalls.Count -eq 0) {
|
||||
Write-Host "[警告] 未检测到已安装的 AutoCAD,无法清理注册表。" -ForegroundColor Yellow
|
||||
Write-Host " 如有手动残留的 acaddoc.lsp,请手动检查。" -ForegroundColor Yellow
|
||||
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
|
||||
exit 0
|
||||
}
|
||||
|
||||
Write-Host "找到 $($acadInstalls.Count) 个 AutoCAD 安装:" -ForegroundColor Green
|
||||
for ($i = 0; $i -lt $acadInstalls.Count; $i++) {
|
||||
$a = $acadInstalls[$i]
|
||||
Write-Host (" [{0}] {1} ({2}) - {3}" -f $i, $a.Product, $a.Version, $a.Location) -ForegroundColor White
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# 若有多个,让用户选择
|
||||
$target = $acadInstalls[0]
|
||||
if ($acadInstalls.Count -gt 1) {
|
||||
if ($env:CADCJ_SILENT) {
|
||||
Write-Host "[静默模式] 检测到多个 AutoCAD,默认选择第一个: $($target.Product)" -ForegroundColor Yellow
|
||||
} else {
|
||||
do {
|
||||
$sel = Read-Host "请选择要卸载的 AutoCAD 序号 (0-$($acadInstalls.Count - 1)),默认 0"
|
||||
if ([string]::IsNullOrWhiteSpace($sel)) { $sel = '0' }
|
||||
} until ($sel -match '^\d+$' -and [int]$sel -lt $acadInstalls.Count)
|
||||
$target = $acadInstalls[[int]$sel]
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ("目标: {0} ({1})" -f $target.Product, $target.Version) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# --- 2. 删除 HKLM 注册表 CADCJ 节点 ---
|
||||
Write-Host "[2/4] 删除 HKLM 自动加载注册表..." -ForegroundColor Green
|
||||
|
||||
$hklmPath = $target.HKLMKey -replace '^HKLM:\\', ''
|
||||
$appsPath = "HKLM:\$hklmPath\Apps\CADCJ"
|
||||
|
||||
if (-not (Test-Path $appsPath)) {
|
||||
Write-Host " HKLM 中无 CADCJ 节点,跳过" -ForegroundColor DarkGray
|
||||
} else {
|
||||
if ($isAdmin) {
|
||||
Remove-Item -Path $appsPath -Recurse -Force -ErrorAction SilentlyContinue
|
||||
if (-not (Test-Path $appsPath)) {
|
||||
Write-Host " 已删除 HKLM 注册表节点" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [警告] 删除失败,请检查权限" -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
# 提权删除
|
||||
$tmpPs1 = Join-Path $env:TEMP "cadcj_uninstall_hklm.ps1"
|
||||
$tmpContent = @"
|
||||
`$ErrorActionPreference = 'Stop'
|
||||
`$path = '$appsPath'
|
||||
if (Test-Path `$path) { Remove-Item -Path `$path -Recurse -Force }
|
||||
if (-not (Test-Path `$path)) { Write-Host ' HKLM 注册表节点已删除' } else { Write-Host ' [警告] 删除失败' }
|
||||
"@
|
||||
$tmpContent | Out-File -FilePath $tmpPs1 -Encoding UTF8 -Force
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File",$tmpPs1 -Verb RunAs -Wait -PassThru
|
||||
if ($p.ExitCode -eq 0) {
|
||||
Write-Host " 已删除 HKLM 注册表节点" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [警告] HKLM 删除失败(用户取消提权?)" -ForegroundColor Yellow
|
||||
}
|
||||
Remove-Item $tmpPs1 -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 3. 从所有 TRUSTEDPATHS 移除插件目录 ---
|
||||
Write-Host "[3/4] 移除受信任路径(TRUSTEDPATHS)..." -ForegroundColor Green
|
||||
|
||||
$hkcuRoot = "HKCU:\SOFTWARE\Autodesk\AutoCAD\$($target.Version)\$($target.LangKey)"
|
||||
|
||||
$targets = @()
|
||||
$topVar = Join-Path $hkcuRoot 'Variables'
|
||||
if (Test-Path $topVar) { $targets += $topVar }
|
||||
$profRoot = Join-Path $hkcuRoot 'Profiles'
|
||||
if (Test-Path $profRoot) {
|
||||
Get-ChildItem $profRoot -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$pv = Join-Path $_.PSPath 'Variables'
|
||||
if (Test-Path $pv) { $targets += $pv }
|
||||
}
|
||||
}
|
||||
|
||||
$removedCount = 0
|
||||
foreach ($t in $targets) {
|
||||
$cur = (Get-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue).TRUSTEDPATHS
|
||||
if (-not $cur) { continue }
|
||||
# 分割后去除每段首尾空白,统一比较
|
||||
$allParts = $cur.Split(';') | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
|
||||
$keepParts = $allParts | Where-Object { -not $_.Equals($scriptDir, [StringComparison]::OrdinalIgnoreCase) }
|
||||
$hasOurs = ($allParts | Where-Object { $_.Equals($scriptDir, [StringComparison]::OrdinalIgnoreCase) }).Count -gt 0
|
||||
$shortName = $t -replace '.*\\Profiles\\','Profile\' -replace '\\Variables',''
|
||||
if (-not $hasOurs) {
|
||||
Write-Host " 未包含: $shortName 跳过" -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
if ($keepParts.Count -eq 0) {
|
||||
# 全部都是本目录,删除整个值
|
||||
Remove-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue
|
||||
Write-Host " 已清空: $shortName" -ForegroundColor Green
|
||||
} else {
|
||||
$newVal = $keepParts -join ';'
|
||||
Set-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -Value $newVal -Type String -Force
|
||||
Write-Host " 已移除: $shortName" -ForegroundColor Green
|
||||
}
|
||||
$removedCount++
|
||||
}
|
||||
if ($removedCount -eq 0) {
|
||||
Write-Host " 无需修改(TRUSTEDPATHS 中未包含本目录)" -ForegroundColor DarkGray
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 4. 清理 acaddoc.lsp 中的 CADCJ 加载逻辑 ---
|
||||
Write-Host "[4/4] 清理 acaddoc.lsp 自动加载脚本..." -ForegroundColor Green
|
||||
|
||||
$acadDirName = Split-Path $target.Location -Leaf
|
||||
$roamingBase = Join-Path $env:APPDATA "Autodesk\$acadDirName\$($target.Version)\chs\Support"
|
||||
$installSupport = Join-Path $target.Location "Support"
|
||||
|
||||
$candidateDirs = @($roamingBase, $installSupport) | Select-Object -Unique
|
||||
$supDir = $null
|
||||
foreach ($d in $candidateDirs) {
|
||||
if (Test-Path $d) { $supDir = $d; break }
|
||||
}
|
||||
|
||||
if (-not $supDir) {
|
||||
Write-Host " 未找到 Support 目录,跳过" -ForegroundColor DarkGray
|
||||
} else {
|
||||
$lspPath = Join-Path $supDir 'acaddoc.lsp'
|
||||
if (-not (Test-Path $lspPath)) {
|
||||
Write-Host " acaddoc.lsp 不存在,跳过" -ForegroundColor DarkGray
|
||||
} else {
|
||||
# 读取(尝试 GB2312,失败则用默认编码)
|
||||
$content = $null
|
||||
try {
|
||||
$content = [System.IO.File]::ReadAllText($lspPath, [System.Text.Encoding]::GetEncoding('GB2312'))
|
||||
} catch {
|
||||
$content = Get-Content $lspPath -Raw -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if (-not $content) {
|
||||
Write-Host " acaddoc.lsp 为空或无法读取,跳过" -ForegroundColor DarkGray
|
||||
} elseif ($content -notmatch 'CADCJ|cadcj') {
|
||||
Write-Host " acaddoc.lsp 中无 CADCJ 加载逻辑,跳过" -ForegroundColor DarkGray
|
||||
} else {
|
||||
# 判断是否为纯 CADCJ 文件(以 ;;; CADCJ 开头或整个文件就是 CADCJ 块)
|
||||
# 移除 CADCJ 加载块(从 ;;; CADCJ 标记开始到 (princ) 结束)
|
||||
$pattern = '(?s)\s*;;; CADCJ.*?\(princ\)\s*'
|
||||
$newContent = [regex]::Replace($content, $pattern, "`r`n")
|
||||
# 清理多余空行
|
||||
$newContent = $newContent -replace "(`r`n){3,}", "`r`n`r`n"
|
||||
$newContent = $newContent.TrimEnd()
|
||||
|
||||
try {
|
||||
if ([string]::IsNullOrWhiteSpace($newContent)) {
|
||||
# 文件清空了,删除文件
|
||||
Remove-Item $lspPath -Force
|
||||
Write-Host " 已删除: $lspPath(文件仅含 CADCJ 内容)" -ForegroundColor Green
|
||||
} else {
|
||||
# 保留其他内容,只移除 CADCJ 块
|
||||
[System.IO.File]::WriteAllText($lspPath, $newContent + "`r`n", [System.Text.Encoding]::GetEncoding('GB2312'))
|
||||
Write-Host " 已清理 CADCJ 加载逻辑,保留其他内容: $lspPath" -ForegroundColor Green
|
||||
}
|
||||
} catch {
|
||||
# 写入失败时提权
|
||||
Write-Host " 写入失败,尝试提权: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
$tmpLsp = Join-Path $env:TEMP 'cadcj_acaddoc_clean.lsp'
|
||||
if ([string]::IsNullOrWhiteSpace($newContent)) {
|
||||
$delCmd = "Remove-Item '$lspPath' -Force -ErrorAction SilentlyContinue"
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$delCmd -Verb RunAs -Wait -PassThru
|
||||
if ($p.ExitCode -eq 0) {
|
||||
Write-Host " 已删除(提权): $lspPath" -ForegroundColor Green
|
||||
}
|
||||
} else {
|
||||
[System.IO.File]::WriteAllText($tmpLsp, $newContent + "`r`n", [System.Text.Encoding]::GetEncoding('GB2312'))
|
||||
$copyCmd = "Copy-Item '$tmpLsp' '$lspPath' -Force"
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$copyCmd -Verb RunAs -Wait -PassThru
|
||||
if ($p.ExitCode -eq 0) {
|
||||
Write-Host " 已清理(提权): $lspPath" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
Remove-Item $tmpLsp -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 完成 ---
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host " 卸载完成!" -ForegroundColor Green
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "卸载摘要:" -ForegroundColor White
|
||||
Write-Host " AutoCAD: $($target.Product) ($($target.Version))" -ForegroundColor White
|
||||
Write-Host " HKLM 注册: 已删除 CADCJ 节点" -ForegroundColor White
|
||||
Write-Host " TRUSTEDPATHS: 已移除 $scriptDir" -ForegroundColor White
|
||||
Write-Host " acaddoc.lsp: 已清理 CADCJ 加载逻辑" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "插件文件本身未删除(cadcj.dll 等),如需彻底删除请手动移除目录:" -ForegroundColor Yellow
|
||||
Write-Host " $scriptDir" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
|
||||
@@ -1,26 +0,0 @@
|
||||
@echo off
|
||||
chcp 936 >nul
|
||||
title 成套报价 CAD 插件安装程序
|
||||
|
||||
REM 切换到批处理文件所在目录(支持从任意位置运行)
|
||||
cd /d "%~dp0"
|
||||
|
||||
REM 检查 PowerShell 脚本是否存在
|
||||
if not exist "安装CAD插件.ps1" (
|
||||
echo [错误] 未找到 安装CAD插件.ps1
|
||||
echo 请确保本批处理文件与 安装CAD插件.ps1 在同一目录。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM 以管理员身份运行 PowerShell 脚本(避免 HKLM 写入提权弹窗中断)
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process powershell -ArgumentList '-NoProfile','-ExecutionPolicy','Bypass','-File','%~dp0安装CAD插件.ps1' -Verb RunAs -Wait"
|
||||
|
||||
REM 若用户取消提权,则非提权运行(HKLM 写入会自动提权,acaddoc.lsp 和 TRUSTEDPATHS 无需管理员)
|
||||
if errorlevel 1 (
|
||||
echo.
|
||||
echo [提示] 管理员提权被取消,尝试非提权运行...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -File "安装CAD插件.ps1"
|
||||
)
|
||||
|
||||
pause
|
||||
@@ -1,309 +0,0 @@
|
||||
# ===========================================================================
|
||||
# 成套报价 CAD 插件 - 通用安装脚本
|
||||
# 适用于任何电脑、任何已安装的 AutoCAD 版本(2010+)
|
||||
# 用法:以管理员身份运行,或在 PowerShell 中执行本脚本
|
||||
# ===========================================================================
|
||||
|
||||
# --- 0. 环境与自检 ---
|
||||
$ErrorActionPreference = 'Stop'
|
||||
# $PSScriptRoot 在 -File 模式下可靠返回脚本所在目录(PS 3.0+)
|
||||
$scriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }
|
||||
$scriptDir = $scriptDir.TrimEnd('\') # 统一去除尾部反斜杠,便于比较
|
||||
$dllPath = Join-Path $scriptDir 'cadcj.dll'
|
||||
|
||||
if (-not (Test-Path $dllPath)) {
|
||||
Write-Host "[错误] 未找到 cadcj.dll,请确保脚本与 cadcj.dll 在同一目录。" -ForegroundColor Red
|
||||
Write-Host " 当前目录: $scriptDir" -ForegroundColor Yellow
|
||||
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 检测是否管理员(写 HKLM 需要)
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "[提示] 当前未以管理员身份运行,HKLM 注册表写入将自动提权。" -ForegroundColor Yellow
|
||||
Write-Host " acaddoc.lsp 和 TRUSTEDPATHS 无需管理员权限。" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host " 成套报价 CAD 插件安装程序" -ForegroundColor Cyan
|
||||
Write-Host " 插件目录: $scriptDir" -ForegroundColor Cyan
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# --- 1. 检测已安装的 AutoCAD 版本 ---
|
||||
Write-Host "[1/4] 检测 AutoCAD 安装..." -ForegroundColor Green
|
||||
|
||||
# 同时检测 64 位和 32 位注册表视图
|
||||
$acadInstalls = @()
|
||||
$regRoots = @(
|
||||
'HKLM:\SOFTWARE\Autodesk\AutoCAD',
|
||||
'HKLM:\SOFTWARE\WOW6432Node\Autodesk\AutoCAD'
|
||||
)
|
||||
|
||||
foreach ($root in $regRoots) {
|
||||
if (-not (Test-Path $root)) { continue }
|
||||
# 遍历每个 Rxx.0 版本(如 R22.0=2018, R23.0=2020, R24.0=2022...)
|
||||
Get-ChildItem $root -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^R\d+\.0$' } | ForEach-Object {
|
||||
$verKey = $_.PSPath
|
||||
$verNum = $_.PSChildName # 如 R22.0
|
||||
# 遍历该版本下的语言变体(如 ACAD-1001:804)
|
||||
Get-ChildItem $verKey -ErrorAction SilentlyContinue | Where-Object { $_.PSChildName -match '^ACAD-\d+:\d+$' } | ForEach-Object {
|
||||
$langKey = $_.PSPath
|
||||
$props = Get-ItemProperty -Path $langKey -ErrorAction SilentlyContinue
|
||||
$loc = $props.AcadLocation
|
||||
$prod = $props.ProductName
|
||||
if ($loc -and (Test-Path $loc)) {
|
||||
$acadInstalls += [PSCustomObject]@{
|
||||
Version = $verNum
|
||||
LangKey = $_.PSChildName
|
||||
Location = $loc
|
||||
Product = $prod
|
||||
RegRoot = $root
|
||||
HKLMKey = $langKey
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($acadInstalls.Count -eq 0) {
|
||||
Write-Host "[错误] 未检测到已安装的 AutoCAD。" -ForegroundColor Red
|
||||
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "找到 $($acadInstalls.Count) 个 AutoCAD 安装:" -ForegroundColor Green
|
||||
for ($i = 0; $i -lt $acadInstalls.Count; $i++) {
|
||||
$a = $acadInstalls[$i]
|
||||
Write-Host (" [{0}] {1} ({2}) - {3}" -f $i, $a.Product, $a.Version, $a.Location) -ForegroundColor White
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# 若有多个,让用户选择
|
||||
$target = $acadInstalls[0]
|
||||
if ($acadInstalls.Count -gt 1) {
|
||||
if ($env:CADCJ_SILENT) {
|
||||
# 静默模式:默认选第一个,不交互
|
||||
Write-Host "[静默模式] 检测到多个 AutoCAD,默认选择第一个: $($target.Product)" -ForegroundColor Yellow
|
||||
} else {
|
||||
do {
|
||||
$sel = Read-Host "请选择要安装的 AutoCAD 序号 (0-$($acadInstalls.Count - 1)),默认 0"
|
||||
if ([string]::IsNullOrWhiteSpace($sel)) { $sel = '0' }
|
||||
} until ($sel -match '^\d+$' -and [int]$sel -lt $acadInstalls.Count)
|
||||
$target = $acadInstalls[[int]$sel]
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ("目标: {0} ({1})" -f $target.Product, $target.Version) -ForegroundColor Cyan
|
||||
Write-Host ("路径: {0}" -f $target.Location) -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# --- 2. 修正 MODULE 路径到 HKLM ---
|
||||
Write-Host "[2/4] 注册 AutoCAD 自动加载(HKLM)..." -ForegroundColor Green
|
||||
|
||||
# HKLM 路径(去除 HKLM: 前缀,得到 SOFTWARE\Autodesk\AutoCAD\Rxx.0\ACAD-xxxx:xxx\Apps\CADCJ)
|
||||
$hklmPath = $target.HKLMKey -replace '^HKLM:\\', ''
|
||||
$appsPath = "HKLM:\$hklmPath\Apps\CADCJ"
|
||||
|
||||
# 写入函数(管理员直接写,非管理员生成临时 ps1 提权执行)
|
||||
function Write-HklmReg {
|
||||
param($Path, $Dll)
|
||||
if (-not (Test-Path $Path)) { New-Item -Path $Path -Force | Out-Null }
|
||||
Set-ItemProperty -Path $Path -Name 'DESCRIPTION' -Value '成套报价插件' -Type String -Force
|
||||
Set-ItemProperty -Path $Path -Name 'LOADCTRLS' -Value 2 -Type DWord -Force
|
||||
Set-ItemProperty -Path $Path -Name 'MANAGED' -Value 1 -Type DWord -Force
|
||||
Set-ItemProperty -Path $Path -Name 'MODULE' -Value $Dll -Type String -Force
|
||||
}
|
||||
|
||||
if ($isAdmin) {
|
||||
Write-HklmReg -Path $appsPath -Dll $dllPath
|
||||
Write-Host " HKLM 注册完成" -ForegroundColor Green
|
||||
} else {
|
||||
# 生成临时 ps1 提权执行(避免字符串嵌套转义问题)
|
||||
$tmpPs1 = Join-Path $env:TEMP "cadcj_install_hklm.ps1"
|
||||
$tmpContent = @"
|
||||
`$ErrorActionPreference = 'Stop'
|
||||
`$path = '$appsPath'
|
||||
`$dll = '$dllPath'
|
||||
if (-not (Test-Path `$path)) { New-Item -Path `$path -Force | Out-Null }
|
||||
Set-ItemProperty -Path `$path -Name 'DESCRIPTION' -Value '成套报价插件' -Type String -Force
|
||||
Set-ItemProperty -Path `$path -Name 'LOADCTRLS' -Value 2 -Type DWord -Force
|
||||
Set-ItemProperty -Path `$path -Name 'MANAGED' -Value 1 -Type DWord -Force
|
||||
Set-ItemProperty -Path `$path -Name 'MODULE' -Value `$dll -Type String -Force
|
||||
Write-Host ' HKLM 注册完成'
|
||||
"@
|
||||
$tmpContent | Out-File -FilePath $tmpPs1 -Encoding UTF8 -Force
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-ExecutionPolicy","Bypass","-File",$tmpPs1 -Verb RunAs -Wait -PassThru
|
||||
if ($p.ExitCode -ne 0) {
|
||||
Write-Host "[警告] HKLM 写入失败(用户取消提权?)。不影响后续安装,acaddoc.lsp 会自动加载。" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host " HKLM 注册完成" -ForegroundColor Green
|
||||
}
|
||||
Remove-Item $tmpPs1 -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 3. 添加 TRUSTEDPATHS 到所有用户配置(HKCU) ---
|
||||
Write-Host "[3/4] 添加受信任路径(TRUSTEDPATHS)..." -ForegroundColor Green
|
||||
|
||||
# 确定 HKCU 根路径
|
||||
$hkcuRoot = "HKCU:\SOFTWARE\Autodesk\AutoCAD\$($target.Version)\$($target.LangKey)"
|
||||
|
||||
$targets = @()
|
||||
# 顶层 Variables
|
||||
$topVar = Join-Path $hkcuRoot 'Variables'
|
||||
if (Test-Path $topVar) { $targets += $topVar }
|
||||
# 各 Profile 下的 Variables
|
||||
$profRoot = Join-Path $hkcuRoot 'Profiles'
|
||||
if (Test-Path $profRoot) {
|
||||
Get-ChildItem $profRoot -ErrorAction SilentlyContinue | ForEach-Object {
|
||||
$pv = Join-Path $_.PSPath 'Variables'
|
||||
if (Test-Path $pv) { $targets += $pv }
|
||||
}
|
||||
}
|
||||
|
||||
$addedCount = 0
|
||||
foreach ($t in $targets) {
|
||||
$cur = (Get-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -ErrorAction SilentlyContinue).TRUSTEDPATHS
|
||||
if ($cur -and ($cur.Split(';') -contains $scriptDir)) {
|
||||
Write-Host " 已存在: $($t -replace '.*\\Profiles\\','Profile\') 跳过" -ForegroundColor DarkGray
|
||||
continue
|
||||
}
|
||||
if ($cur) {
|
||||
$newVal = "$cur;$scriptDir"
|
||||
} else {
|
||||
$newVal = $scriptDir
|
||||
}
|
||||
try {
|
||||
New-ItemProperty -Path $t -Name 'TRUSTEDPATHS' -Value $newVal -PropertyType String -Force | Out-Null
|
||||
$shortName = $t -replace '.*\\Profiles\\','Profile\' -replace '\\Variables',''
|
||||
Write-Host " 已添加: $shortName" -ForegroundColor Green
|
||||
$addedCount++
|
||||
} catch {
|
||||
Write-Host " 失败: $t - $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
if ($addedCount -eq 0 -and $targets.Count -gt 0) {
|
||||
Write-Host " 所有配置已包含本目录,无需修改" -ForegroundColor DarkGray
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 4. 创建 acaddoc.lsp 自动加载(核心机制) ---
|
||||
Write-Host "[4/4] 创建 acaddoc.lsp 自动加载脚本..." -ForegroundColor Green
|
||||
|
||||
# 确定 Support 目录(优先用户漫游目录,其次 AutoCAD 安装目录)
|
||||
# 漫游目录路径模式:%APPDATA%\Autodesk\AutoCAD 20XX\Rxx.0\chs\Support
|
||||
$acadDirName = Split-Path $target.Location -Leaf # 如 "AutoCAD 2018"
|
||||
$roamingBase = Join-Path $env:APPDATA "Autodesk\$acadDirName\$($target.Version)\chs\Support"
|
||||
$installSupport = Join-Path $target.Location "Support"
|
||||
|
||||
$candidateDirs = @($roamingBase, $installSupport) | Select-Object -Unique
|
||||
$supDir = $null
|
||||
foreach ($d in $candidateDirs) {
|
||||
if (Test-Path $d) { $supDir = $d; break }
|
||||
}
|
||||
if (-not $supDir) {
|
||||
# 创建漫游目录
|
||||
$supDir = $roamingBase
|
||||
New-Item -ItemType Directory -Path $supDir -Force | Out-Null
|
||||
Write-Host " 创建目录: $supDir" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
$lspPath = Join-Path $supDir 'acaddoc.lsp'
|
||||
|
||||
# LISP 代码(路径用双反斜杠转义)
|
||||
$dllPathEscaped = $dllPath -replace '\\','\\\\'
|
||||
$lispCode = @"
|
||||
;;; CADCJ 自动加载 - 由安装脚本生成
|
||||
;;; 每会话首次打开文档时通过 NETLOAD 加载成套报价插件
|
||||
;;; 使用内存全局变量,进程退出后自动清除,避免持久化导致跳过加载
|
||||
(vl-load-com)
|
||||
(if (not *cadcj-loaded*)
|
||||
(progn
|
||||
(setq *cadcj-loaded* t)
|
||||
(setq #cadcj-fd (getvar "FILEDIA"))
|
||||
(setvar "FILEDIA" 0)
|
||||
(vl-catch-all-apply
|
||||
'(lambda ()
|
||||
(command "NETLOAD" "$dllPathEscaped")
|
||||
)
|
||||
)
|
||||
(setvar "FILEDIA" #cadcj-fd)
|
||||
(vl-propagate '*cadcj-loaded*)
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
"@
|
||||
|
||||
# 检查是否已有 acaddoc.lsp(避免覆盖用户现有内容)
|
||||
$needMerge = $false
|
||||
if (Test-Path $lspPath) {
|
||||
$existing = Get-Content $lspPath -Raw -ErrorAction SilentlyContinue
|
||||
if ($existing -and ($existing -match 'CADCJ|cadcj')) {
|
||||
Write-Host " acaddoc.lsp 已包含 CADCJ 加载逻辑,跳过" -ForegroundColor DarkGray
|
||||
} elseif ($existing) {
|
||||
$needMerge = $true
|
||||
Write-Host " 检测到现有 acaddoc.lsp,将追加 CADCJ 加载逻辑" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if ($needMerge) {
|
||||
# 追加到现有文件末尾
|
||||
$existing + "`r`n" + $lispCode | Out-File -FilePath $lspPath -Encoding Default -Append -Force
|
||||
} else {
|
||||
# GB2312 编码写入(AutoCAD 正确读取中文路径)
|
||||
[System.IO.File]::WriteAllText($lspPath, $lispCode, [System.Text.Encoding]::GetEncoding('GB2312'))
|
||||
}
|
||||
Write-Host " 已创建: $lspPath" -ForegroundColor Green
|
||||
} catch {
|
||||
# AppData 写入失败时提权
|
||||
Write-Host " 写入失败,尝试提权: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
$tmpLsp = Join-Path $env:TEMP 'cadcj_acaddoc.lsp'
|
||||
[System.IO.File]::WriteAllText($tmpLsp, $lispCode, [System.Text.Encoding]::GetEncoding('GB2312'))
|
||||
$copyCmd = "Copy-Item '$tmpLsp' '$lspPath' -Force"
|
||||
$p = Start-Process -FilePath "powershell.exe" -ArgumentList "-NoProfile","-Command",$copyCmd -Verb RunAs -Wait -PassThru
|
||||
if ($p.ExitCode -eq 0) {
|
||||
Write-Host " 已创建(提权): $lspPath" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " [错误] 无法创建 acaddoc.lsp" -ForegroundColor Red
|
||||
}
|
||||
Remove-Item $tmpLsp -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
Write-Host ""
|
||||
|
||||
# --- 5. 同步更新 .reg 文件(便于记录) ---
|
||||
$regFile = Join-Path $scriptDir '注册CAD自动加载.reg'
|
||||
$regKeyHklm = $appsPath -replace '^HKLM:\\','HKEY_LOCAL_MACHINE\'
|
||||
$regContent = @"
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[$regKeyHklm]
|
||||
"DESCRIPTION"="成套报价插件"
|
||||
"LOADCTRLS"=dword:00000002
|
||||
"MANAGED"=dword:00000001
|
||||
"MODULE"="$($dllPath -replace '\\','\\')"
|
||||
"@
|
||||
try {
|
||||
$regContent | Out-File -FilePath $regFile -Encoding Default -Force
|
||||
Write-Host " 已更新: $regFile" -ForegroundColor DarkGray
|
||||
} catch {}
|
||||
Write-Host ""
|
||||
|
||||
# --- 完成 ---
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host " 安装完成!" -ForegroundColor Green
|
||||
Write-Host "======================================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "安装摘要:" -ForegroundColor White
|
||||
Write-Host " AutoCAD: $($target.Product) ($($target.Version))" -ForegroundColor White
|
||||
Write-Host " 插件DLL: $dllPath" -ForegroundColor White
|
||||
Write-Host " LSP文件: $lspPath" -ForegroundColor White
|
||||
Write-Host " 加载方式: acaddoc.lsp (NETLOAD)" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "现在启动 AutoCAD 并打开任意图纸,插件会自动加载。" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
if (-not $env:CADCJ_SILENT) { Read-Host "按回车退出" }
|
||||
@@ -1,71 +0,0 @@
|
||||
@echo off
|
||||
chcp 65001 >nul
|
||||
REM ============================================
|
||||
REM 成套报价 CAD 插件 - 就地安装脚本
|
||||
REM 功能:把【本脚本所在目录】的 cadcj.dll 注册为 CAD 自动加载
|
||||
REM 原则:在哪个目录运行,就安装哪个目录(测试目录/安装目录通用)
|
||||
REM 用法:双击运行(无需管理员权限,写的是用户级注册表 HKCU)
|
||||
REM 更新 DLL 后:先关 CAD → 替换本目录 cadcj.dll → 再运行本脚本不需要,
|
||||
REM 注册表已指向本目录,直接重启 CAD 即加载新版
|
||||
REM ============================================
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM 取脚本所在目录(去掉尾部反斜杠)
|
||||
set "INSTDIR=%~dp0"
|
||||
if "%INSTDIR:~-1%"=="\" set "INSTDIR=%INSTDIR:~0,-1%"
|
||||
set "DLLPATH=%INSTDIR%\cadcj.dll"
|
||||
|
||||
REM 检查本目录是否有 cadcj.dll
|
||||
if not exist "%DLLPATH%" (
|
||||
echo [错误] 本目录没有 cadcj.dll,无法安装。
|
||||
echo 当前目录: %INSTDIR%
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ==============================================
|
||||
echo 成套报价 CAD 插件 - 就地安装
|
||||
echo 插件目录: %INSTDIR%
|
||||
echo ==============================================
|
||||
echo.
|
||||
|
||||
REM 检查 CAD 是否在运行(在运行也能写注册表,但新DLL要重启CAD才生效)
|
||||
tasklist /FI "IMAGENAME eq acad.exe" 2>nul | find /I "acad.exe" >nul
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo [提示] AutoCAD 正在运行:注册完成后请重启 CAD 才能生效。
|
||||
echo.
|
||||
)
|
||||
|
||||
REM 枚举所有已安装的 AutoCAD 版本(HKCU 用户级,无需管理员)
|
||||
REM ★ findstr "^HKEY_" 只取子键行,过滤掉 CurVer 这类值行
|
||||
set FOUND=0
|
||||
for /f "delims=" %%K in ('reg query "HKCU\SOFTWARE\Autodesk\AutoCAD" 2^>nul ^| findstr /I /C:"HKEY_"') do (
|
||||
for /f "delims=" %%P in ('reg query "%%K" 2^>nul ^| findstr /I /C:"HKEY_" ^| findstr /I "ACAD-"') do (
|
||||
set "APPSKEY=%%P\Apps\CADCJ"
|
||||
reg add "!APPSKEY!" /v LOADCTRLS /t REG_DWORD /d 2 /f >nul
|
||||
reg add "!APPSKEY!" /v MANAGED /t REG_DWORD /d 1 /f >nul
|
||||
reg add "!APPSKEY!" /v MODULE /t REG_SZ /d "%DLLPATH%" /f >nul
|
||||
reg add "!APPSKEY!" /v DESCRIPTION /t REG_SZ /d "ChengTao BaoJia Plugin" /f >nul
|
||||
echo [OK] 已注册: !APPSKEY!
|
||||
echo MODULE = %DLLPATH%
|
||||
set FOUND=1
|
||||
)
|
||||
)
|
||||
|
||||
if %FOUND% EQU 0 (
|
||||
echo [错误] 未检测到已安装的 AutoCAD(R22.0=2018 等)。
|
||||
echo 请确认 AutoCAD 已安装后重试。
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo.
|
||||
echo ==============================================
|
||||
echo 安装完成!
|
||||
echo CAD 自动加载: %DLLPATH%
|
||||
echo 用户库CSV : 本目录下最新的 用户库_*.csv
|
||||
echo 数据库sjk : 本目录 sjk\ 下
|
||||
echo 重启 AutoCAD 即生效。
|
||||
echo ==============================================
|
||||
pause
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -1,7 +0,0 @@
|
||||
Windows Registry Editor Version 5.00
|
||||
|
||||
[HKEY_LOCAL_MACHINE\Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Autodesk\AutoCAD\R22.0\ACAD-1001:804\Apps\CADCJ]
|
||||
"DESCRIPTION"="成套报价插件"
|
||||
"LOADCTRLS"=dword:00000002
|
||||
"MANAGED"=dword:00000001
|
||||
"MODULE"="C:\\Users\\099978\\Documents\\SharpDevelop Projects\\成套报价软件\\成套报价软件\\cadcj\\cadcj.dll"
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Generated
-47
@@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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.*")]
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Generated
-71
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
Generated
-1321
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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>
|
||||
@@ -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 = "";
|
||||
}
|
||||
}
|
||||
Generated
-609
@@ -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项目总价;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.*")]
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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.
@@ -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>
|
||||
@@ -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
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
; ============================================================
|
||||
; 成套报价软件 安装包脚本 — Inno Setup 6
|
||||
; 文件必须保存为 UTF-8 with BOM 编码(中文才能正确显示)
|
||||
; ============================================================
|
||||
|
||||
[Code]
|
||||
// ★ WebView2 运行时检测(2026-09-21 新装机实测:精简系统没装过 Edge 时所有内嵌网页窗口全黑)
|
||||
// 三处注册表任一存在有效版本即视为已装(64位系统机器级/32位视图/当前用户级)
|
||||
// (标识符必须 ASCII——Inno 的 Check 表达式解析不接受中文函数名)
|
||||
function WebView2RegOk(Root: Integer; SubKey: String): Boolean;
|
||||
var
|
||||
v: String;
|
||||
begin
|
||||
Result := RegQueryStringValue(Root, SubKey, 'pv', v) and (Length(v) > 2) and (Pos('0.0.0.0', v) = 0);
|
||||
end;
|
||||
|
||||
function NeedWebView2(): Boolean;
|
||||
begin
|
||||
Result := not (
|
||||
WebView2RegOk(HKEY_LOCAL_MACHINE, 'SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}') or
|
||||
WebView2RegOk(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}') or
|
||||
WebView2RegOk(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}')
|
||||
);
|
||||
end;
|
||||
|
||||
// 升级安装:清理旧版遗留的 cadcj(旧 AutoCAD 插件)与 libredwg 目录(2026-09-04 退役)
|
||||
procedure CurStepChanged(CurStep: TSetupStep);
|
||||
begin
|
||||
if CurStep = ssInstall then
|
||||
begin
|
||||
if DirExists(ExpandConstant('{app}\cadcj')) then
|
||||
DelTree(ExpandConstant('{app}\cadcj'), True, True, True);
|
||||
if DirExists(ExpandConstant('{app}\libredwg-0.13.4.8043-win64')) then
|
||||
DelTree(ExpandConstant('{app}\libredwg-0.13.4.8043-win64'), True, True, True);
|
||||
end;
|
||||
end;
|
||||
|
||||
[Setup]
|
||||
AppName=成套报价软件
|
||||
; ★ 版本号与 AssemblyInfo.cs 的 AssemblyVersion 同步(tools\递增版本号.ps1 统一递增)
|
||||
AppVersion=1.0.3
|
||||
AppPublisher=成套报价软件
|
||||
AppId={{8F3A7C21-6B54-4E2D-9A71-5C8B20260825}
|
||||
DefaultDirName=C:\成套报价软件
|
||||
DefaultGroupName=成套报价软件
|
||||
DisableProgramGroupPage=yes
|
||||
OutputDir=Output
|
||||
; ★ 安装包文件名带版本号(多版本下载不混淆),与 AppVersion 同步
|
||||
OutputBaseFilename=成套报价软件_Setup_1.0.3
|
||||
Compression=lzma2
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
; 程序为 x86(32位)编译,但可在 64 位 Windows 上运行
|
||||
ArchitecturesAllowed=x64 x86
|
||||
PrivilegesRequired=admin
|
||||
|
||||
; ★ 支持直接覆盖安装升级:
|
||||
; CloseApplications=yes —— 安装时检测到本软件正在运行,提示一键关闭后再继续,
|
||||
; 避免旧 exe/DLL 被占用导致替换失败(表现为"装了新版但还是旧功能");
|
||||
; RestartApplications=no —— 不用重启延迟替换,当场完成替换。
|
||||
CloseApplications=yes
|
||||
RestartApplications=no
|
||||
|
||||
; 安装包自身与卸载项图标
|
||||
SetupIconFile=app.ico
|
||||
UninstallDisplayIcon={app}\app.ico
|
||||
UninstallDisplayName=成套报价软件
|
||||
|
||||
[Languages]
|
||||
Name: "chinesesimp"; MessagesFile: "compiler:Languages\ChineseSimplified.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "创建桌面快捷方式(&D)"; GroupDescription: "附加图标:"
|
||||
Name: "importdata"; Description: "安装 GCS 铜排计算工具(&M)"; GroupDescription: "可选组件(仅铜排壳体计算需要):"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
; ★ WebView2 运行时官方引导程序(仅安装期用,装进 {tmp} 不落安装目录):
|
||||
; 新电脑缺运行时(元件库/CAD扒图/AI助手等所有内嵌网页窗口的底层)时静默安装,
|
||||
; 引导程序联网从微软 CDN 下载——不依赖 GitHub;已装过则整个跳过
|
||||
Source: "MicrosoftEdgeWebview2Setup.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
|
||||
; 主程序 + 配置 + 图标
|
||||
Source: "成套报价软件.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "成套报价软件.exe.config"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "app.ico"; DestDir: "{app}"; Flags: ignoreversion
|
||||
; 功能区按钮图标
|
||||
Source: "icons\*"; DestDir: "{app}\icons"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; 开源许可证全文(关于窗口「查看许可证全文」用,亦是协议义务的随附声明)
|
||||
Source: "licenses\*"; DestDir: "{app}\licenses"; Flags: ignoreversion
|
||||
; 元件库网页(node 纯本地静态服务数据,替代旧 python 代理)
|
||||
Source: "元件库网页\*"; DestDir: "{app}\元件库网页"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
|
||||
; 依赖 DLL
|
||||
Source: "AdvancedDataGridView.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "Smart.CustomComponents.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "WeifenLuo.WinFormsUI.Docking.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "System.Data.SQLite.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "System.Resources.Extensions.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "System.Memory.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "System.Numerics.Vectors.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "System.Runtime.CompilerServices.Unsafe.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "Microsoft.Web.WebView2.Core.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "Microsoft.Web.WebView2.WinForms.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "WebView2Loader.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
; ★ 2026-09-11 补:主程序扒图 PdfiumNative P/Invoke 根目录 pdfium.dll,上包(9-10)漏装,装机能用仅因手动同步过安装目录
|
||||
Source: "pdfium.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "NPOI.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "NPOI.OOXML.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "NPOI.OpenXml4Net.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "NPOI.OpenXmlFormats.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "DotNetZip.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "ICSharpCode.SharpZipLib.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "unvell.ReoGrid.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
Source: "CJZZ.Controls.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
; 核心数据目录(项目库/用户库/柜体库/母排规格库等程序必需文件,必装)
|
||||
Source: "sjk\*"; DestDir: "{app}\sjk"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "shezhi\*"; DestDir: "{app}\shezhi"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; 甲方报表 Excel 模板(按图号/按箱号/按箱号+箱体面积/按箱类型)
|
||||
Source: "xiangmu\*"; DestDir: "{app}\xiangmu"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; CAD 网页引擎运行时(node+CAD-Viewer;2026-10-01 独立 cadbt.exe 退役,主程序内嵌扒图窗口用)
|
||||
Source: "cadbt\*"; DestDir: "{app}\cadbt"; 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,部署套件单独交付)
|
||||
Source: "GCS铜排壳体计算\*"; DestDir: "{app}\GCS铜排壳体计算"; Flags: ignoreversion recursesubdirs createallsubdirs; Tasks: importdata
|
||||
|
||||
[Dirs]
|
||||
; 各项目报价库存放目录(空目录,程序运行时在里面建库)
|
||||
Name: "{app}\sjk\bjb"
|
||||
|
||||
[InstallDelete]
|
||||
; ★ 覆盖安装升级前,先删掉旧版主程序和依赖 DLL,保证不会残留旧功能文件。
|
||||
; 只清安装根目录({app})下的程序文件:通配符不含子目录,
|
||||
; cadcj/libredwg/GCS铜排壳体计算 等工具目录不受影响;
|
||||
; 用户数据都在子目录里(sjk 项目库、shezhi 企业信息、停靠布局等),全部保留。
|
||||
Type: files; Name: "{app}\成套报价软件.exe"
|
||||
Type: files; Name: "{app}\*.dll"
|
||||
|
||||
[Icons]
|
||||
; 开始菜单
|
||||
Name: "{group}\成套报价软件"; Filename: "{app}\成套报价软件.exe"; IconFilename: "{app}\app.ico"; Comment: "电气成套设备报价软件"
|
||||
Name: "{group}\卸载 成套报价软件"; Filename: "{uninstallexe}"
|
||||
; 桌面快捷方式
|
||||
Name: "{commondesktop}\成套报价软件"; Filename: "{app}\成套报价软件.exe"; IconFilename: "{app}\app.ico"; Tasks: desktopicon
|
||||
|
||||
[Run]
|
||||
; ★ WebView2 运行时缺失时先静默装好再启动软件(所有内嵌网页窗口的底层;
|
||||
; 已装过的机器 Check 返回 False 整条跳过,不联网不弹窗)
|
||||
Filename: "{tmp}\MicrosoftEdgeWebview2Setup.exe"; Parameters: "/silent /install"; StatusMsg: "正在安装 WebView2 运行时(内嵌网页功能必需)..."; Flags: runhidden waituntilterminated; Check: NeedWebView2
|
||||
Filename: "{app}\成套报价软件.exe"; Description: "立即启动 成套报价软件"; Flags: nowait postinstall skipifsilent
|
||||
|
||||
[UninstallDelete]
|
||||
; 卸载时彻底清理安装目录(含运行时生成的数据库/备份/日志)
|
||||
Type: filesandordirs; Name: "{app}"
|
||||
+2
-17
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
+10
-10
@@ -1,4 +1,4 @@
|
||||
# csc 编译验证(UTF-8)
|
||||
# csc 编译验证(UTF-8)
|
||||
/target:winexe
|
||||
/platform:x86
|
||||
/utf8output
|
||||
@@ -37,15 +37,15 @@ MainForm.cs
|
||||
MainForm.Designer.cs
|
||||
Program.cs
|
||||
Properties\AssemblyInfo.cs
|
||||
主窗口.cs
|
||||
主窗口.菜单与库.cs
|
||||
主窗口.公式重算.cs
|
||||
主窗口.母排与备份.cs
|
||||
MainForm.主窗口.cs
|
||||
MainForm.菜单与库.cs
|
||||
MainForm.公式重算.cs
|
||||
MainForm.母排与备份.cs
|
||||
备份目标选择.cs
|
||||
会员安全客户端.cs
|
||||
主窗口.状态栏.cs
|
||||
主窗口.项目导入导出.cs
|
||||
主窗口.SQLite加载.cs
|
||||
MainForm.状态栏.cs
|
||||
MainForm.项目导入导出.cs
|
||||
MainForm.SQLite加载.cs
|
||||
MainForm.控件别名.cs
|
||||
MainForm.旧页签兼容.cs
|
||||
MainForm.停靠布局.cs
|
||||
@@ -107,9 +107,9 @@ AI助手设置.Designer.cs
|
||||
扒图\PdfQuoteWindow.cs
|
||||
扒图\PdfQuoteWindow.Designer.cs
|
||||
扒图\Cad\Form3.cs
|
||||
扒图\Cad\Form3.ui.cs
|
||||
扒图\Cad\Form3.Designer.cs
|
||||
扒图\Cad\新建项目.cs
|
||||
扒图\Cad\新建项目.ui.cs
|
||||
扒图\Cad\新建项目.Designer.cs
|
||||
扒图\Pdf\Form3.cs
|
||||
扒图\Pdf\Form3.Designer.cs
|
||||
扒图\Pdf\新建项目.cs
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
109
|
||||
4450
|
||||
|
||||
+25
-11
@@ -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)) {
|
||||
if (-not (Test-Path $f)) { Write-Host "[FAIL] 缺少文件: $f" -ForegroundColor Red; exit 2 }
|
||||
# ★ 2026-10-01 扩充:从只查 Form3.cs 扩展到全部 Cad/Pdf 双胞胎文件对
|
||||
# (新建项目.cs 与两对 Designer/ui.cs 此前是漂移盲区)
|
||||
$pairs = @(
|
||||
@('成套报价软件\扒图\Cad\Form3.cs', '成套报价软件\扒图\Pdf\Form3.cs'),
|
||||
@('成套报价软件\扒图\Cad\新建项目.cs', '成套报价软件\扒图\Pdf\新建项目.cs'),
|
||||
@('成套报价软件\扒图\Cad\Form3.Designer.cs', '成套报价软件\扒图\Pdf\Form3.Designer.cs'),
|
||||
@('成套报价软件\扒图\Cad\新建项目.Designer.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) {
|
||||
$parts = (@($numstat)[0]) -split "`t"
|
||||
if ($parts.Count -ge 2) { $added = [int]$parts[0]; $deleted = [int]$parts[1] }
|
||||
"" | 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] }
|
||||
}
|
||||
}
|
||||
$drift = $added + $deleted
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# ============================================================
|
||||
# 递增版本号.ps1 —— 版本号一键递增并三处同步
|
||||
# ============================================================
|
||||
# 唯一事实源: 成套报价软件\Properties\AssemblyInfo.cs 的 AssemblyVersion
|
||||
# 同步点: ① AssemblyInfo.cs (AssemblyVersion + AssemblyFileVersion)
|
||||
# ② release\成套报价软件\setup.iss (AppVersion + OutputBaseFilename)
|
||||
# 关于软件窗口自动读程序集版本,无需同步。
|
||||
# 用法:
|
||||
# powershell -File tools\递增版本号.ps1 # 修订号 +1 (1.0.3 → 1.0.4)
|
||||
# powershell -File tools\递增版本号.ps1 1.1.0 # 直接指定版本
|
||||
# 发版流程: 本脚本 → 编译 → make_package → ISCC → 更新包 → git 提交推送
|
||||
# → Gitea Release(tag 与版本号一致,如 v1.0.4)
|
||||
# ============================================================
|
||||
param([string]$SetVersion = "")
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$asm = Join-Path $root '成套报价软件\Properties\AssemblyInfo.cs'
|
||||
$iss = Join-Path $root 'release\成套报价软件\setup.iss'
|
||||
|
||||
# --- 读当前版本 ---
|
||||
$asmText = [System.IO.File]::ReadAllText($asm)
|
||||
if ($asmText -notmatch 'AssemblyVersion\("(\d+)\.(\d+)\.(\d+)') {
|
||||
Write-Host "[FAIL] AssemblyInfo.cs 里没找到三段式 AssemblyVersion" -ForegroundColor Red; exit 1
|
||||
}
|
||||
$cur = "{0}.{1}.{2}" -f $Matches[1], $Matches[2], $Matches[3]
|
||||
|
||||
# --- 算新版本 ---
|
||||
if ($SetVersion -eq "") {
|
||||
$new = "{0}.{1}.{2}" -f $Matches[1], $Matches[2], ([int]$Matches[3] + 1)
|
||||
} else {
|
||||
if ($SetVersion -notmatch '^\d+\.\d+\.\d+$') {
|
||||
Write-Host "[FAIL] 版本号格式须为 主.次.修订,如 1.1.0" -ForegroundColor Red; exit 1
|
||||
}
|
||||
$new = $SetVersion
|
||||
}
|
||||
|
||||
# --- ① AssemblyInfo: AssemblyVersion + AssemblyFileVersion ---
|
||||
$asmText = $asmText -replace 'AssemblyVersion\("\d+\.\d+\.\d+[\.\d]*"\)', "AssemblyVersion(`"$new.0`")"
|
||||
$asmText = $asmText -replace 'AssemblyFileVersion\("\d+\.\d+\.\d+[\.\d]*"\)', "AssemblyFileVersion(`"$new.0`")"
|
||||
[System.IO.File]::WriteAllText($asm, $asmText, (New-Object System.Text.UTF8Encoding $true))
|
||||
Write-Host "[OK] AssemblyInfo.cs: $cur -> $new"
|
||||
|
||||
# --- ② setup.iss: AppVersion + OutputBaseFilename ---
|
||||
$issText = [System.IO.File]::ReadAllText($iss)
|
||||
$issText = $issText -replace 'AppVersion=\d+\.\d+\.\d+', "AppVersion=$new"
|
||||
$issText = $issText -replace 'OutputBaseFilename=成套报价软件_Setup[_\d\.]*', "OutputBaseFilename=成套报价软件_Setup_$new"
|
||||
[System.IO.File]::WriteAllText($iss, $issText, (New-Object System.Text.UTF8Encoding $true))
|
||||
Write-Host "[OK] setup.iss: AppVersion=$new, 安装包名=成套报价软件_Setup_$new.exe"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "版本号已递增至 $new。后续步骤:"
|
||||
Write-Host " 1. 编译主项目(csc @tools\verify_build.rsp)"
|
||||
Write-Host " 2. python tools\make_package.py 组装发布目录"
|
||||
Write-Host " 3. ISCC 编译安装包(文件名自动带 $new)"
|
||||
Write-Host " 4. 更新包(make_update_package.py,目录名建议带版本)"
|
||||
Write-Host " 5. git add+commit+push"
|
||||
Write-Host " 6. Gitea Release: tag 用 v$new"
|
||||
Generated
-269
@@ -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清理;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user