From 0ba5cede73bfb5e2b2e0ec52dd06da4550be13cd Mon Sep 17 00:00:00 2001 From: haoliang <821644@qq.com> Date: Tue, 28 Apr 2026 17:26:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=90=AD=E5=BB=BAVS2017=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E6=96=B9=E6=A1=88=E9=AA=A8=E6=9E=B6=EF=BC=888?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE+=E5=89=8D=E7=AB=AF=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A4=B9=EF=BC=89=EF=BC=8C=E7=BC=96=E8=AF=91=E9=80=9A=E8=BF=87?= =?UTF-8?q?0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CncDataSystem.sln: 4层源码项目 + 4测试项目 + frontend解决方案文件夹 - CncModels: ApiResponse/PagedResult/PagedQuery/ErrorCode 基础类 - CncRepository: BaseRepository 双库连接管理(BusinessRepository/LogRepository) - CncService: BusinessException 业务异常基类 - CncWebApi: WebApiConfig路由配置/GlobalExceptionFilter/HealthController/Web.config - 测试项目: xUnit + Moq + Microsoft.NET.Test.Sdk - NuGet: Dapper + MySqlConnector + Newtonsoft.Json + log4net + JWT - 编译: dotnet build 8项目全部通过 --- .gitignore | 6 + AGENTS.md | 44 +++- CncDataSystem.sln | 72 ++++++ frontend/.gitignore | 24 ++ frontend/README.md | 5 + frontend/_screen_part1.vue | 77 +++++++ frontend/_screen_part2.vue | 191 ++++++++++++++++ frontend/_screen_part3.vue | 207 ++++++++++++++++++ frontend/env.d.ts | 18 ++ frontend/gen-screen.cjs | 9 + frontend/gen1.cjs | 104 +++++++++ frontend/gen2.cjs | 188 ++++++++++++++++ frontend/gen3.cjs | 158 +++++++++++++ frontend/generate-pages.cjs | 107 +++++++++ frontend/scripts/fix_any.cjs | 41 ++++ frontend/scripts/refactor_inline_styles.js | 66 ++++++ src/CncModels/CncModels.csproj | 20 ++ src/CncModels/Constants/ErrorCode.cs | 31 +++ src/CncModels/Dto/ApiResponse.cs | 53 +++++ src/CncModels/Dto/PagedQuery.cs | 34 +++ src/CncModels/Dto/PagedResult.cs | 27 +++ src/CncModels/Properties/AssemblyInfo.cs | 19 ++ src/CncRepository/Base/BaseRepository.cs | 39 ++++ src/CncRepository/Base/RepositoryBases.cs | 24 ++ src/CncRepository/CncRepository.csproj | 24 ++ src/CncRepository/Properties/AssemblyInfo.cs | 14 ++ src/CncService/BusinessException.cs | 24 ++ src/CncService/CncService.csproj | 21 ++ src/CncService/Properties/AssemblyInfo.cs | 14 ++ src/CncWebApi/App_Start/WebApiConfig.cs | 38 ++++ src/CncWebApi/CncWebApi.csproj | 44 ++++ src/CncWebApi/Controllers/HealthController.cs | 28 +++ .../Filters/GlobalExceptionFilter.cs | 42 ++++ src/CncWebApi/Global.asax | 1 + src/CncWebApi/Global.asax.cs | 22 ++ src/CncWebApi/Properties/AssemblyInfo.cs | 14 ++ src/CncWebApi/Web.config | 45 ++++ tests/CncModels.Tests/CncModels.Tests.csproj | 24 ++ .../CncRepository.Tests.csproj | 26 +++ .../CncService.Tests/CncService.Tests.csproj | 26 +++ tests/CncWebApi.Tests/CncWebApi.Tests.csproj | 30 +++ 41 files changed, 1989 insertions(+), 12 deletions(-) create mode 100644 CncDataSystem.sln create mode 100644 frontend/.gitignore create mode 100644 frontend/README.md create mode 100644 frontend/_screen_part1.vue create mode 100644 frontend/_screen_part2.vue create mode 100644 frontend/_screen_part3.vue create mode 100644 frontend/env.d.ts create mode 100644 frontend/gen-screen.cjs create mode 100644 frontend/gen1.cjs create mode 100644 frontend/gen2.cjs create mode 100644 frontend/gen3.cjs create mode 100644 frontend/generate-pages.cjs create mode 100644 frontend/scripts/fix_any.cjs create mode 100644 frontend/scripts/refactor_inline_styles.js create mode 100644 src/CncModels/CncModels.csproj create mode 100644 src/CncModels/Constants/ErrorCode.cs create mode 100644 src/CncModels/Dto/ApiResponse.cs create mode 100644 src/CncModels/Dto/PagedQuery.cs create mode 100644 src/CncModels/Dto/PagedResult.cs create mode 100644 src/CncModels/Properties/AssemblyInfo.cs create mode 100644 src/CncRepository/Base/BaseRepository.cs create mode 100644 src/CncRepository/Base/RepositoryBases.cs create mode 100644 src/CncRepository/CncRepository.csproj create mode 100644 src/CncRepository/Properties/AssemblyInfo.cs create mode 100644 src/CncService/BusinessException.cs create mode 100644 src/CncService/CncService.csproj create mode 100644 src/CncService/Properties/AssemblyInfo.cs create mode 100644 src/CncWebApi/App_Start/WebApiConfig.cs create mode 100644 src/CncWebApi/CncWebApi.csproj create mode 100644 src/CncWebApi/Controllers/HealthController.cs create mode 100644 src/CncWebApi/Filters/GlobalExceptionFilter.cs create mode 100644 src/CncWebApi/Global.asax create mode 100644 src/CncWebApi/Global.asax.cs create mode 100644 src/CncWebApi/Properties/AssemblyInfo.cs create mode 100644 src/CncWebApi/Web.config create mode 100644 tests/CncModels.Tests/CncModels.Tests.csproj create mode 100644 tests/CncRepository.Tests/CncRepository.Tests.csproj create mode 100644 tests/CncService.Tests/CncService.Tests.csproj create mode 100644 tests/CncWebApi.Tests/CncWebApi.Tests.csproj diff --git a/.gitignore b/.gitignore index 51fbc9d..5688e86 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,9 @@ npm-debug.log* # TypeScript cache *.tsbuildinfo + +# === 后端编译输出 === +src/**/bin/ +src/**/obj/ +tests/**/bin/ +tests/**/obj/ diff --git a/AGENTS.md b/AGENTS.md index 51874f4..619ef74 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,22 +5,35 @@ ## 概述 -多品牌CNC机床统一化数据采集系统的产品设计文档库。技术栈:Vue3前端 + ASP.NET Web API 2后端 + Windows Service采集服务 + MariaDB数据库。本地IIS部署,局域网场景。 +多品牌CNC机床统一化数据采集系统。技术栈:Vue3前端 + ASP.NET Web API 2后端 + Windows Service采集服务 + MariaDB数据库。本地IIS部署,局域网场景。 ## 项目结构 ``` . -├── docs/ # 全部设计文档 +├── CncDataSystem.sln ← VS2017 解决方案(4层+3测试项目+前端文件夹) +├── src/ ← 后端源码 +│ ├── CncModels/ ← 数据模型层(Entity + Dto + Enum + Constants) +│ ├── CncRepository/ ← 数据访问层(Dapper + MariaDB双库) +│ ├── CncService/ ← 业务逻辑层(接口 + 实现) +│ └── CncWebApi/ ← Web API 主项目(Controllers + Filters + Infrastructure) +├── tests/ ← 测试项目(xUnit + Moq,100%方法覆盖 ≥95%分支覆盖) +│ ├── CncModels.Tests/ +│ ├── CncRepository.Tests/ +│ ├── CncService.Tests/ +│ └── CncWebApi.Tests/ +├── database/ ← 数据库脚本(幂等DDL+预置数据) +├── docs/ ← 全部设计文档 │ ├── 00-需求与设计文档.md # 核心需求、架构决策、技术选型 -│ ├── 01-数据库设计.md # 双库设计(业务库+日志库),17张表DDL +│ ├── 01-数据库设计.md # 双库设计(业务库+日志库),20张表DDL(已定稿) │ ├── 02-功能清单/ # 按模块拆分的功能清单 -│ │ ├── 02-文件夹创建规范.md # ⚠️ 文档结构规范,新增模块必读 -│ │ ├── 02-前端全局规范.md # 前端全局规范+CRUD必填项+模块进度+工程开发规范 -│ │ ├── 03-界面变更执行规范.md # ⚠️ AI助手执行界面变更时必读 +│ │ ├── 02-文件夹创建规范.md # ⚠️ 文档结构规范,新增模块必读 +│ │ ├── 02-前端全局规范.md # 前端全局规范+CRUD必填项+模块进度+工程开发规范 +│ │ ├── 03-界面变更执行规范.md # ⚠️ AI助手执行界面变更时必读 │ │ ├── 大屏/ # 大屏看板模块 │ │ └── 管理后台/ # 12个子模块(登录/仪表盘/设备/品牌/采集地址/员工/产量/告警/系统/车间/操作日志/大屏配置) -│ └── ... +│ ├── 03-API接口设计.md # 13模块83端点,含Mock映射+DB表对照 +│ └── 04-后端开发规范.md # ⚠️ 后端必读:技术栈/项目结构/命名/注释/测试/分层/依赖注入规范 ├── frontend/ # 前端工程(Vue3+Vite+TypeScript+Element Plus) │ ├── mock/ # Mock数据定义(按模块拆分) │ ├── src/ # 源码(路由/组件/样式/类型) @@ -38,6 +51,8 @@ | 前端工程开发规范 | `docs/02-前端全局规范.md` → 前端工程开发规范章节 | 技术栈/Mock方案/目录结构/CSS规范 | | 新增功能模块文档 | `docs/02-功能清单/02-文件夹创建规范.md` | 目录结构/命名/内容模板规范 | | AI助手执行界面变更 | `docs/02-功能清单/03-界面变更执行规范.md` | ⚠️ 必读:最小必读文件+变更清单+联动同步规则 | +| 后端开发规范 | `docs/04-后端开发规范.md` | ⚠️ 后端必读:技术栈/项目结构/命名/注释/测试/分层/依赖注入 | +| API接口设计 | `docs/03-API接口设计.md` | 13模块83端点,含Mock映射+DB表对照 | | 品牌采集数据格式 | `发那科系统采集示例.txt` | FANUC品牌JSON结构示例 | | 管理后台某模块设计 | `docs/02-功能清单/管理后台/{编号}-{模块名}/` | 每模块含索引+规范+页面文件 | | 大屏看板设计 | `docs/02-功能清单/大屏/` | 索引+规范+页面 | @@ -85,10 +100,15 @@ ## 待设计模块 -- API接口设计(后置,界面全部确认后启动) -- 采集服务核心逻辑设计(后置,界面全部确认后启动) -- 前端管理后台设计(✅ 已完成,见 `02-前端全局规范.md` + `02-功能清单/管理后台/`) -- 大屏看板设计(✅ 已完成,见 `02-功能清单/大屏/`) +- 采集服务核心逻辑设计(后置,后端API完成后启动) + +## 已完成模块 + +- ✅ 前端管理后台设计(见 `02-前端全局规范.md` + `02-功能清单/管理后台/`) +- ✅ 大屏看板设计(见 `02-功能清单/大屏/`) +- ✅ 数据库设计定稿(见 `01-数据库设计.md`,20张表已落地MariaDB) +- ✅ API接口设计(见 `03-API接口设计.md`,13模块83端点) +- ✅ 后端开发规范(见 `04-后端开发规范.md`) ## 强制要求(必须遵守) @@ -125,6 +145,6 @@ ## 注意事项 - 部分索引/规范文件内容为空(尚未填写)→ 已全部填写 -- 数据库设计为草案状态(状态:草案),界面确认后定稿 +- 数据库设计已定稿(状态:定稿),20张表已落地MariaDB - 前端界面设计全部完成(2026-04-26),13个模块16个页面均已设计 - 品牌预置:FANUC已预置,其他品牌手动添加 diff --git a/CncDataSystem.sln b/CncDataSystem.sln new file mode 100644 index 0000000..8e5989b --- /dev/null +++ b/CncDataSystem.sln @@ -0,0 +1,72 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17.VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncModels", "src\CncModels\CncModels.csproj", "{898BBE60-B7CB-4602-BFC6-7651B062F986}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncRepository", "src\CncRepository\CncRepository.csproj", "{534CA636-CA2C-4038-B02E-5258981479D3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncService", "src\CncService\CncService.csproj", "{8B105015-DFDF-4BFC-B0BA-471E0FA1AAC8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncWebApi", "src\CncWebApi\CncWebApi.csproj", "{A39DE219-F8CB-44CD-9907-8FCAA3766C8B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncModels.Tests", "tests\CncModels.Tests\CncModels.Tests.csproj", "{9AAF88A1-B04C-403E-A559-7622B13F9872}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncRepository.Tests", "tests\CncRepository.Tests\CncRepository.Tests.csproj", "{D581A6D4-25A1-4143-8155-2A895AC52E5E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncService.Tests", "tests\CncService.Tests\CncService.Tests.csproj", "{BD63C81D-29E3-4B53-A41A-F10A04ED1052}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CncWebApi.Tests", "tests\CncWebApi.Tests\CncWebApi.Tests.csproj", "{4DAE1DA8-E028-4025-AA80-1E698976F74C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "frontend", "frontend", "{D099B5F2-7E64-4A0A-B9ED-D085421E996E}" + ProjectSection(SolutionItems) = preProject + frontend\package.json = frontend\package.json + frontend\vite.config.ts = frontend\vite.config.ts + frontend\tsconfig.json = frontend\tsconfig.json + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {898BBE60-B7CB-4602-BFC6-7651B062F986}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {898BBE60-B7CB-4602-BFC6-7651B062F986}.Debug|Any CPU.Build.0 = Debug|Any CPU + {898BBE60-B7CB-4602-BFC6-7651B062F986}.Release|Any CPU.ActiveCfg = Release|Any CPU + {898BBE60-B7CB-4602-BFC6-7651B062F986}.Release|Any CPU.Build.0 = Release|Any CPU + {534CA636-CA2C-4038-B02E-5258981479D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {534CA636-CA2C-4038-B02E-5258981479D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {534CA636-CA2C-4038-B02E-5258981479D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {534CA636-CA2C-4038-B02E-5258981479D3}.Release|Any CPU.Build.0 = Release|Any CPU + {8B105015-DFDF-4BFC-B0BA-471E0FA1AAC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B105015-DFDF-4BFC-B0BA-471E0FA1AAC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B105015-DFDF-4BFC-B0BA-471E0FA1AAC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B105015-DFDF-4BFC-B0BA-471E0FA1AAC8}.Release|Any CPU.Build.0 = Release|Any CPU + {A39DE219-F8CB-44CD-9907-8FCAA3766C8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A39DE219-F8CB-44CD-9907-8FCAA3766C8B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A39DE219-F8CB-44CD-9907-8FCAA3766C8B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A39DE219-F8CB-44CD-9907-8FCAA3766C8B}.Release|Any CPU.Build.0 = Release|Any CPU + {9AAF88A1-B04C-403E-A559-7622B13F9872}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9AAF88A1-B04C-403E-A559-7622B13F9872}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9AAF88A1-B04C-403E-A559-7622B13F9872}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9AAF88A1-B04C-403E-A559-7622B13F9872}.Release|Any CPU.Build.0 = Release|Any CPU + {D581A6D4-25A1-4143-8155-2A895AC52E5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D581A6D4-25A1-4143-8155-2A895AC52E5E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D581A6D4-25A1-4143-8155-2A895AC52E5E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D581A6D4-25A1-4143-8155-2A895AC52E5E}.Release|Any CPU.Build.0 = Release|Any CPU + {BD63C81D-29E3-4B53-A41A-F10A04ED1052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD63C81D-29E3-4B53-A41A-F10A04ED1052}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD63C81D-29E3-4B53-A41A-F10A04ED1052}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD63C81D-29E3-4B53-A41A-F10A04ED1052}.Release|Any CPU.Build.0 = Release|Any CPU + {4DAE1DA8-E028-4025-AA80-1E698976F74C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4DAE1DA8-E028-4025-AA80-1E698976F74C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4DAE1DA8-E028-4025-AA80-1E698976F74C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4DAE1DA8-E028-4025-AA80-1E698976F74C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + EndGlobalSection +EndGlobal diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..33895ab --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,5 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` diff --git a/frontend/_screen_part3.vue b/frontend/_screen_part3.vue new file mode 100644 index 0000000..9c22264 --- /dev/null +++ b/frontend/_screen_part3.vue @@ -0,0 +1,207 @@ + + diff --git a/frontend/env.d.ts b/frontend/env.d.ts new file mode 100644 index 0000000..c401dad --- /dev/null +++ b/frontend/env.d.ts @@ -0,0 +1,18 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} + +declare module 'vite-plugin-mock' { + import type { Plugin } from 'vite' + interface ViteMockOptions { + mockDir?: string + localEnabled?: boolean + prodEnabled?: boolean + injectCode?: string + } + export function viteMockServe(options: ViteMockOptions): Plugin +} diff --git a/frontend/gen-screen.cjs b/frontend/gen-screen.cjs new file mode 100644 index 0000000..ab3323f --- /dev/null +++ b/frontend/gen-screen.cjs @@ -0,0 +1,9 @@ +const fs = require("fs"); +const path = require("path"); +const target = path.join(__dirname, "src/views/screen/ScreenPage.vue"); +const parts = []; +parts.push(fs.readFileSync(path.join(__dirname, "_screen_part1.vue"), "utf8")); +parts.push(fs.readFileSync(path.join(__dirname, "_screen_part2.vue"), "utf8")); +parts.push(fs.readFileSync(path.join(__dirname, "_screen_part3.vue"), "utf8")); +fs.writeFileSync(target, parts.join(""), "utf8"); +console.log("ScreenPage.vue generated successfully"); diff --git a/frontend/gen1.cjs b/frontend/gen1.cjs new file mode 100644 index 0000000..1857e1d --- /dev/null +++ b/frontend/gen1.cjs @@ -0,0 +1,104 @@ +// 批量生成所有页面组件 - 第1部分 +const fs = require('fs'); +const path = require('path'); +const b = 'D:/opencode/haoliang/frontend/src/views'; + +function w(d, f, c) { + const p = path.join(b, d, f); + fs.writeFileSync(p, c, 'utf8'); + console.log('OK: ' + d + '/' + f); +} + +// ==================== 品牌列表 ==================== +w('brand', 'BrandListPage.vue', ` + + + 新增品牌 + + + + + {{row.isEnabled?'启用':'停用'}} + + + 编辑 + {{row.isEnabled?'禁用':'启用'}} + 删除 + + + + +`); + +// ==================== 品牌编辑 ==================== +w('brand', 'BrandEditPage.vue', ` + + + 返回 + {{ isEdit ? '编辑品牌' : '新增品牌' }} + + + + + + + + + + 字段映射列表+ 新增映射 + + + + + + + 删除 + + + + 取消 + 保存 + + + +`); + +console.log('Part 1 done: brand pages'); diff --git a/frontend/gen2.cjs b/frontend/gen2.cjs new file mode 100644 index 0000000..81bc4f5 --- /dev/null +++ b/frontend/gen2.cjs @@ -0,0 +1,188 @@ +const fs = require('fs'); +const path = require('path'); +const b = 'D:/opencode/haoliang/frontend/src/views'; +function w(d, f, c) { fs.writeFileSync(path.join(b, d, f), c, 'utf8'); console.log('OK: ' + d + '/' + f); } + +// MachineDetailPage +w('machine', 'MachineDetailPage.vue', ` + + + 返回 + 机床详情:{{detail.name}} + + + 基本信息 + + {{detail.name}} + {{detail.deviceCode}} + {{detail.workshopName}} + {{detail.brandName}} + {{detail.ipAddress}} + {{detail.workerName||'-'}} + {{detail.isOnline?'在线':'离线'}} + {{detail.isEnabled?'启用':'停用'}} + + + 实时状态 + + {{status.programName||'-'}} + {{status.partCount??'-'}} + {{status.runStatus||'-'}} + {{status.operateMode||'-'}} + {{status.spindleSpeedSet??'-'}} + {{status.feedSpeedSet??'-'}} + {{status.spindleSpeedActual??'-'}} + {{status.spindleLoad??'-'}}% + + + + + 今日产量 + + + + + 7天产量趋势 + + + + 最近采集记录 + + + + + + +`); + +// CollectAddressListPage +w('collect-address', 'CollectAddressListPage.vue', ` + + + 新增地址 + + + 查询重置 + + + {{row.name}} + + + + {{row.isEnabled?'启用':'停用'}} + + + + 编辑 + 删除 + + + + + + + + + + 取消保存 + + + +`); + +// CollectAddressDetailPage +w('collect-address', 'CollectAddressDetailPage.vue', ` + + + 返回 + 采集地址详情:{{detail.name}} + + 基本信息 + + {{detail.name}} + {{detail.url}} + {{detail.brandName}} + {{detail.collectInterval}}秒 + {{detail.isEnabled?'启用':'停用'}} + {{detail.lastCollectTime||'-'}} + + + 关联机床 + + + {{row.isOnline?'在线':'离线'}} + + + + 最近采集记录 + + + {{row.isSuccess?'成功':'失败'}} + + + + + +`); + +console.log('gen2 done: machine detail, collect-address list+detail'); diff --git a/frontend/gen3.cjs b/frontend/gen3.cjs new file mode 100644 index 0000000..e2d444d --- /dev/null +++ b/frontend/gen3.cjs @@ -0,0 +1,158 @@ +const fs = require('fs'); +const path = require('path'); +const b = 'D:/opencode/haoliang/frontend/src/views'; +function w(d, f, c) { fs.writeFileSync(path.join(b, d, f), c, 'utf8'); console.log('OK: ' + d + '/' + f); } + +// WorkerListPage +w('worker', 'WorkerListPage.vue', ` + + + 新增工人 + + + + 查询重置 + + + + + {{row.name}} + {{row.isEnabled?'启用':'停用'}} + + + + 编辑 + 删除 + + + + 已选{{selectedRows.length}}项 批量启用批量停用 + + + + + + + + 取消保存 + + + +`); + +// WorkerDetailPage +w('worker', 'WorkerDetailPage.vue', ` + + + 返回 + 工人详情:{{detail.name}} + + + 基本信息 + + {{detail.code}} + {{detail.name}} + {{detail.isEnabled?'启用':'停用'}} + {{detail.machineCount||0}} + + + 7天产量趋势 + + + + 绑定机床 + + + {{row.isOnline?'在线':'离线'}} + + + + 今日产量 + + + + + + +`); + +// ProductionPage +w('production', 'ProductionPage.vue', ` + + + 总产量{{summary.totalQuantity?.toLocaleString()}} + 运行机床{{summary.activeMachineCount}} + 切削总时{{summary.totalCuttingTime}} + 平均产量{{summary.avgQuantityPerMachine}} + + + + {{row.dataStatus==='data_missing'?'-':row.quantity}} + + {{row.dataStatus==='normal'?'正常':row.dataStatus==='offline'?'离线':'缺失'}} + {{row.isAdjusted?'✓':'-'}} + 修正 + + + + + + + + + 取消确认修正 + + + +`); + +console.log('gen3 done: worker list+detail, production'); diff --git a/frontend/generate-pages.cjs b/frontend/generate-pages.cjs new file mode 100644 index 0000000..5a96657 --- /dev/null +++ b/frontend/generate-pages.cjs @@ -0,0 +1,107 @@ +const fs = require('fs'); +const path = require('path'); +const base = 'D:/opencode/haoliang/frontend/src/views'; + +function w(dir, file, content) { + const p = path.join(base, dir, file); + fs.writeFileSync(p, content, 'utf8'); + console.log('Created: ' + p); +} + +// ===== MachineDetailPage ===== +w('machine', 'MachineDetailPage.vue', ` + + + 返回 + 机床详情:{{ detail.name }} + + + + 基本信息 + + {{ detail.name }} + {{ detail.deviceCode }} + {{ detail.workshopName }} + {{ detail.brandName }} + {{ detail.ipAddress }} + {{ detail.workerName || '-' }} + {{ detail.isOnline ? '在线' : '离线' }} + {{ detail.isEnabled ? '启用' : '停用' }} + + + + + 实时状态 + + {{ status.programName || '-' }} + {{ status.partCount ?? '-' }} + {{ status.runStatus || '-' }} + {{ status.operateMode || '-' }} + {{ status.spindleSpeedSet ?? '-' }} + {{ status.feedSpeedSet ?? '-' }} + {{ status.spindleSpeedActual ?? '-' }} + {{ status.spindleLoad ?? '-' }}% + + + + + + + 今日产量 + + + + + + + 7天产量趋势 + + + + + 最近采集记录 + + + + + + + + +`); + +console.log('All detail pages created'); diff --git a/frontend/scripts/fix_any.cjs b/frontend/scripts/fix_any.cjs new file mode 100644 index 0000000..db477a3 --- /dev/null +++ b/frontend/scripts/fix_any.cjs @@ -0,0 +1,41 @@ +const fs = require('fs'); +const path = require('path'); +const d = 'E:/opencode/haoliang/frontend/src/views'; + +const fixes = [ + ['(rows: any[])', '(rows: Record[])'], + ['(record: any)', '(record: Record)'], + ['const params: any =', 'const params: Record ='], + ['(r: any) => r.id', '(r: {id:number}) => r.id'], + ['function onFileChange(file: any)', 'function onFileChange(file: Record)'], + ['params: { row: any; rowIndex', 'params: { row: Record; rowIndex'], + ['const payload: any =', 'const payload: Record ='], + ['(c: any) => c.configKey.toLowerCase().includes(kw) || c.description.t', + '(c: {configKey:string;description:string}) => c.configKey.toLowerCase().includes(kw) || c.description.t'], + ['_rule: any, value: string, callback: any', '_rule: unknown, value: string, callback: (err?:Error)=>void'], + ['rule: any, value: any, callback: any', 'rule: unknown, value: string, callback: (err?:Error)=>void'], +]; + +let total = 0; +fs.readdirSync(d).forEach(sub => { + const subDir = path.join(d, sub); + if (!fs.statSync(subDir).isDirectory()) return; + fs.readdirSync(subDir).forEach(f => { + if (!f.endsWith('.vue')) return; + const fp = path.join(subDir, f); + let c = fs.readFileSync(fp, 'utf8'); + let n = 0; + fixes.forEach(([from, to]) => { + if (c.includes(from)) { + c = c.split(from).join(to); + n++; + } + }); + if (n > 0) { + fs.writeFileSync(fp, c, 'utf8'); + console.log(f + ': ' + n); + total += n; + } + }); +}); +console.log('Total fixed: ' + total); diff --git a/frontend/scripts/refactor_inline_styles.js b/frontend/scripts/refactor_inline_styles.js new file mode 100644 index 0000000..e179340 --- /dev/null +++ b/frontend/scripts/refactor_inline_styles.js @@ -0,0 +1,66 @@ +// Simple, targeted refactor: replace common inline styles with CSS utility classes +// Only handles exact pattern matches and only when the tag doesn't already have a class attribute. +// This is a safe, incremental step. Run this script from the project root: `node frontend/scripts/refactor_inline_styles.js` + +const fs = require('fs'); +const path = require('path'); + +function walkVueFiles(dir) { + const res = []; + const items = fs.readdirSync(dir, { withFileTypes: true }); + for (const it of items) { + const full = path.join(dir, it.name); + if (it.isDirectory()) { + res.push(...walkVueFiles(full)); + } else if (it.isFile() && full.endsWith('.vue')) { + res.push(full); + } + } + return res; +} + +const projectRoot = path.resolve(__dirname, '..'); +const targetDir = path.resolve(projectRoot, 'src', 'views'); +const files = walkVueFiles(targetDir); + +const replacements = [ + { find: 'style="margin-bottom:16px"', replace: 'class="mb-16"' }, + { find: "style='margin-bottom:16px'", replace: "class='mb-16'" }, + { find: 'style="margin-top:20px"', replace: 'class="mt-20"' }, + { find: "style='margin-top:20px'", replace: "class='mt-20'" }, + { find: 'style="display:flex;align-items:center;gap:12px"', replace: 'class="flex-gap"' }, + { find: "style='display:flex;align-items:center;gap:12px'", replace: "class='flex-gap'" }, + { find: 'style="font-size:16px;font-weight:bold"', replace: 'class="page-title"' }, + { find: "style='font-size:16px;font-weight:bold'", replace: "class='page-title'" }, + { find: 'style="color: var(--el-color-primary); cursor: pointer; text-decoration: none;"', replace: 'class="link-text"' }, + { find: "style='color: var(--el-color-primary); cursor: pointer; text-decoration: none;'", replace: "class='link-text'" }, +]; + +let totalReplacements = 0; +let totalFilesLaunched = 0; + +for (const file of files) { + let content = fs.readFileSync(file, 'utf8'); + let modified = false; + const lines = content.split(/\r?\n/); + for (let i = 0; i < lines.length; i++) { + let line = lines[i]; + // Quick skip if line already has a class attribute + if (line.includes('style=') && !line.includes('class=')) { + for (const r of replacements) { + if (line.includes(r.find)) { + line = line.replace(r.find, r.replace); + modified = true; + totalReplacements++; + } + } + } + lines[i] = line; + } + if (modified) { + totalFilesLaunched++; + fs.writeFileSync(file, lines.join('\n'), 'utf8'); + } +} + +console.log(`refactor_inline_styles.js: applied ${totalReplacements} replacements across ${totalFilesLaunched} files.`); diff --git a/src/CncModels/CncModels.csproj b/src/CncModels/CncModels.csproj new file mode 100644 index 0000000..d85d7e0 --- /dev/null +++ b/src/CncModels/CncModels.csproj @@ -0,0 +1,20 @@ + + + + net472 + x64 + CncModels + CncModels + true + + false + + + + + + + + + + diff --git a/src/CncModels/Constants/ErrorCode.cs b/src/CncModels/Constants/ErrorCode.cs new file mode 100644 index 0000000..b1a7e46 --- /dev/null +++ b/src/CncModels/Constants/ErrorCode.cs @@ -0,0 +1,31 @@ +using System; + +namespace CncModels.Constants +{ + /// + /// 全局错误码 + /// 编号规则:5位数字,前2位为模块,后3位为具体错误 + /// + public static class ErrorCode + { + // ======== 通用错误(40xxx)======== + + /// 请求参数错误 + public const int BadRequest = 40000; + + /// 未认证(Token缺失或无效) + public const int Unauthorized = 40101; + + /// 资源不存在 + public const int NotFound = 40002; + + /// 数据冲突(唯一性校验失败) + public const int Conflict = 40003; + + /// 数据已被引用,不允许操作 + public const int DataReferenced = 40001; + + /// 服务器内部错误 + public const int InternalError = 50001; + } +} diff --git a/src/CncModels/Dto/ApiResponse.cs b/src/CncModels/Dto/ApiResponse.cs new file mode 100644 index 0000000..9a342b9 --- /dev/null +++ b/src/CncModels/Dto/ApiResponse.cs @@ -0,0 +1,53 @@ +using System; + +namespace CncModels.Dto +{ + /// + /// 统一API响应包装类 + /// 前端约定:code=0 表示成功,非0表示失败 + /// + /// 业务数据类型 + public class ApiResponse + { + /// 错误码,0=成功 + public int Code { get; set; } + + /// 提示信息 + public string Message { get; set; } + + /// 业务数据 + public T Data { get; set; } + + /// + /// 构建成功响应 + /// + /// 业务数据 + /// 提示信息,默认 "success" + /// 成功响应 + public static ApiResponse Success(T data, string message = "success") + { + return new ApiResponse + { + Code = 0, + Message = message, + Data = data + }; + } + + /// + /// 构建失败响应 + /// + /// 错误码(非0) + /// 错误信息 + /// 失败响应 + public static ApiResponse Fail(int code, string message) + { + return new ApiResponse + { + Code = code, + Message = message, + Data = default(T) + }; + } + } +} diff --git a/src/CncModels/Dto/PagedQuery.cs b/src/CncModels/Dto/PagedQuery.cs new file mode 100644 index 0000000..0067f93 --- /dev/null +++ b/src/CncModels/Dto/PagedQuery.cs @@ -0,0 +1,34 @@ +using System; + +namespace CncModels.Dto +{ + /// + /// 分页查询参数基类 + /// 默认值:page=1, pageSize=20 + /// 约束:pageSize最大100,page最小1 + /// + public class PagedQuery + { + private int _page = 1; + private int _pageSize = 20; + + /// 页码(从1开始),小于1自动修正为1 + public int Page + { + get => _page; + set => _page = value < 1 ? 1 : value; + } + + /// 每页条数,范围1-100,超出自动修正 + public int PageSize + { + get => _pageSize; + set => _pageSize = value < 1 ? 20 : (value > 100 ? 100 : value); + } + + /// + /// 计算SQL偏移量(OFFSET) + /// + public int Offset => (Page - 1) * PageSize; + } +} diff --git a/src/CncModels/Dto/PagedResult.cs b/src/CncModels/Dto/PagedResult.cs new file mode 100644 index 0000000..e1500f4 --- /dev/null +++ b/src/CncModels/Dto/PagedResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; + +namespace CncModels.Dto +{ + /// + /// 分页结果 + /// + /// 数据项类型 + public class PagedResult + { + /// 数据列表 + public List Items { get; set; } = new List(); + + /// 总记录数 + public int Total { get; set; } + + /// 当前页码(从1开始) + public int Page { get; set; } + + /// 每页条数 + public int PageSize { get; set; } + + /// 总页数 + public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)Total / PageSize) : 0; + } +} diff --git a/src/CncModels/Properties/AssemblyInfo.cs b/src/CncModels/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1cdeaaf --- /dev/null +++ b/src/CncModels/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 通用信息 +[assembly: AssemblyTitle("CncModels")] +[assembly: AssemblyDescription("CNC机床数据采集系统 - 数据模型层")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CncDataSystem")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// COM 可见性 +[assembly: ComVisible(false)] + +// 版本号 +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CncRepository/Base/BaseRepository.cs b/src/CncRepository/Base/BaseRepository.cs new file mode 100644 index 0000000..e42ee17 --- /dev/null +++ b/src/CncRepository/Base/BaseRepository.cs @@ -0,0 +1,39 @@ +using System; +using System.Data; +using MySqlConnector; + +namespace CncRepository.Base +{ + /// + /// 仓储基类,提供数据库连接管理 + /// 每个仓储方法应 using(CreateConnection()) 自动释放连接 + /// + public abstract class BaseRepository + { + private readonly string _connectionString; + + /// + /// 初始化仓储基类 + /// + /// 数据库连接字符串 + protected BaseRepository(string connectionString) + { + _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); + } + + /// + /// 创建新的数据库连接 + /// 调用方需使用 using 语句确保连接释放 + /// + /// + /// using (var conn = CreateConnection()) + /// { + /// return conn.QueryFirstOrDefault<Machine>("SELECT * FROM cnc_machine WHERE id = @Id", new { Id = id }); + /// } + /// + protected IDbConnection CreateConnection() + { + return new MySqlConnection(_connectionString); + } + } +} diff --git a/src/CncRepository/Base/RepositoryBases.cs b/src/CncRepository/Base/RepositoryBases.cs new file mode 100644 index 0000000..0184ea8 --- /dev/null +++ b/src/CncRepository/Base/RepositoryBases.cs @@ -0,0 +1,24 @@ +using System; +using System.Data; +using MySqlConnector; + +namespace CncRepository.Base +{ + /// + /// 业务库仓储基类(cnc_business) + /// 所有操作业务库的仓储继承此类 + /// + public class BusinessRepository : BaseRepository + { + public BusinessRepository(string connectionString) : base(connectionString) { } + } + + /// + /// 日志库仓储基类(cnc_log) + /// 所有操作日志库的仓储继承此类 + /// + public class LogRepository : BaseRepository + { + public LogRepository(string connectionString) : base(connectionString) { } + } +} diff --git a/src/CncRepository/CncRepository.csproj b/src/CncRepository/CncRepository.csproj new file mode 100644 index 0000000..2678ffb --- /dev/null +++ b/src/CncRepository/CncRepository.csproj @@ -0,0 +1,24 @@ + + + + net472 + x64 + CncRepository + CncRepository + true + false + + + + + + + + + + + + + + + diff --git a/src/CncRepository/Properties/AssemblyInfo.cs b/src/CncRepository/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..eb55c10 --- /dev/null +++ b/src/CncRepository/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("CncRepository")] +[assembly: AssemblyDescription("CNC机床数据采集系统 - 数据访问层")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CncDataSystem")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CncService/BusinessException.cs b/src/CncService/BusinessException.cs new file mode 100644 index 0000000..eae572a --- /dev/null +++ b/src/CncService/BusinessException.cs @@ -0,0 +1,24 @@ +using System; + +namespace CncService +{ + /// + /// 业务异常 + /// Service层抛出此异常,由全局异常过滤器统一捕获并转换为ApiResponse + /// + public class BusinessException : Exception + { + /// 业务错误码(非0) + public int Code { get; } + + /// + /// 创建业务异常 + /// + /// 错误码,参见 CncModels.Constants.ErrorCode + /// 错误信息,会返回给前端展示 + public BusinessException(int code, string message) : base(message) + { + Code = code; + } + } +} diff --git a/src/CncService/CncService.csproj b/src/CncService/CncService.csproj new file mode 100644 index 0000000..2296ca9 --- /dev/null +++ b/src/CncService/CncService.csproj @@ -0,0 +1,21 @@ + + + + net472 + x64 + CncService + CncService + true + false + + + + + + + + + + + + diff --git a/src/CncService/Properties/AssemblyInfo.cs b/src/CncService/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5e42518 --- /dev/null +++ b/src/CncService/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("CncService")] +[assembly: AssemblyDescription("CNC机床数据采集系统 - 业务逻辑层")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CncDataSystem")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CncWebApi/App_Start/WebApiConfig.cs b/src/CncWebApi/App_Start/WebApiConfig.cs new file mode 100644 index 0000000..ebeb7dd --- /dev/null +++ b/src/CncWebApi/App_Start/WebApiConfig.cs @@ -0,0 +1,38 @@ +using System.Web.Http; +using System.Web.Http.Cors; + +namespace CncWebApi.App_Start +{ + /// + /// Web API 路由和过滤器配置 + /// 在 Global.asax Application_Start 中调用 + /// + public static class WebApiConfig + { + /// + /// 注册Web API配置 + /// + /// HTTP配置对象 + public static void Register(HttpConfiguration config) + { + // 跨域配置(局域网场景,允许所有来源) + config.EnableCors(new EnableCorsAttribute("*", "*", "*")); + + // 路由注册 + // 默认路由模板:api/{controller}/{id} + // 各Controller使用 [RoutePrefix] + [Route] 属性路由覆盖此默认 + config.MapHttpAttributeRoutes(); + + // 全局异常过滤器 + config.Filters.Add(new Filters.GlobalExceptionFilter()); + + // 统一JSON序列化设置 + config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = + Newtonsoft.Json.NullValueHandling.Ignore; + config.Formatters.JsonFormatter.SerializerSettings.DateFormatString = + "yyyy-MM-dd HH:mm:ss"; + // 移除XML格式器,统一使用JSON + config.Formatters.Remove(config.Formatters.XmlFormatter); + } + } +} diff --git a/src/CncWebApi/CncWebApi.csproj b/src/CncWebApi/CncWebApi.csproj new file mode 100644 index 0000000..35e8a8b --- /dev/null +++ b/src/CncWebApi/CncWebApi.csproj @@ -0,0 +1,44 @@ + + + + net472 + x64 + CncWebApi + CncWebApi + true + false + + Library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/CncWebApi/Controllers/HealthController.cs b/src/CncWebApi/Controllers/HealthController.cs new file mode 100644 index 0000000..cd9996e --- /dev/null +++ b/src/CncWebApi/Controllers/HealthController.cs @@ -0,0 +1,28 @@ +using System; +using System.Web.Http; + +namespace CncWebApi.Controllers +{ + /// + /// 健康检查控制器 + /// 用于验证API服务是否正常运行 + /// + [RoutePrefix("api")] + public class HealthController : ApiController + { + /// + /// 健康检查端点 + /// GET /api/health + /// + [HttpGet] + [Route("health")] + public IHttpActionResult Check() + { + return Ok(new + { + status = "healthy", + timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + }); + } + } +} diff --git a/src/CncWebApi/Filters/GlobalExceptionFilter.cs b/src/CncWebApi/Filters/GlobalExceptionFilter.cs new file mode 100644 index 0000000..87aa70b --- /dev/null +++ b/src/CncWebApi/Filters/GlobalExceptionFilter.cs @@ -0,0 +1,42 @@ +using System.Net; +using System.Net.Http; +using System.Web.Http; +using System.Web.Http.Filters; +using CncModels.Dto; +using CncService; + +namespace CncWebApi.Filters +{ + /// + /// 全局异常过滤器 + /// 统一捕获所有未处理异常,转换为标准ApiResponse格式 + /// Controller层不需要 try-catch,异常会自动被此过滤器捕获 + /// + public class GlobalExceptionFilter : ExceptionFilterAttribute + { + /// + /// 异常发生时自动调用 + /// + /// 异常上下文 + public override void OnException(HttpActionExecutedContext context) + { + if (context.Exception is BusinessException bex) + { + // 业务异常:返回对应的错误码和消息 + var response = ApiResponse.Fail(bex.Code, bex.Message); + context.Response = context.Request.CreateResponse( + HttpStatusCode.OK, response); + } + else + { + // 未预期异常:记录日志,返回通用错误 + // TODO: 接入 log4net 记录完整异常堆栈 + var response = ApiResponse.Fail( + CncModels.Constants.ErrorCode.InternalError, + "服务器内部错误"); + context.Response = context.Request.CreateResponse( + HttpStatusCode.InternalServerError, response); + } + } + } +} diff --git a/src/CncWebApi/Global.asax b/src/CncWebApi/Global.asax new file mode 100644 index 0000000..a1a7732 --- /dev/null +++ b/src/CncWebApi/Global.asax @@ -0,0 +1 @@ +<%@ Application Codebehind="Global.asax.cs" Inherits="CncWebApi.WebApiApplication" Language="C#" %> diff --git a/src/CncWebApi/Global.asax.cs b/src/CncWebApi/Global.asax.cs new file mode 100644 index 0000000..03f137f --- /dev/null +++ b/src/CncWebApi/Global.asax.cs @@ -0,0 +1,22 @@ +using System; +using System.Web; +using System.Web.Http; +using CncWebApi.App_Start; + +namespace CncWebApi +{ + /// + /// Web API 应用程序入口 + /// IIS 启动时自动调用 Application_Start + /// + public class WebApiApplication : HttpApplication + { + /// + /// 应用启动时执行,注册路由和全局配置 + /// + protected void Application_Start() + { + GlobalConfiguration.Configure(WebApiConfig.Register); + } + } +} diff --git a/src/CncWebApi/Properties/AssemblyInfo.cs b/src/CncWebApi/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7852f09 --- /dev/null +++ b/src/CncWebApi/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("CncWebApi")] +[assembly: AssemblyDescription("CNC机床数据采集系统 - Web API 主项目")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CncDataSystem")] +[assembly: AssemblyCopyright("Copyright © 2026")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: ComVisible(false)] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/CncWebApi/Web.config b/src/CncWebApi/Web.config new file mode 100644 index 0000000..7cbd851 --- /dev/null +++ b/src/CncWebApi/Web.config @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/CncModels.Tests/CncModels.Tests.csproj b/tests/CncModels.Tests/CncModels.Tests.csproj new file mode 100644 index 0000000..dd17d4c --- /dev/null +++ b/tests/CncModels.Tests/CncModels.Tests.csproj @@ -0,0 +1,24 @@ + + + + net472 + x64 + CncModels.Tests + CncModels.Tests + false + + false + + + + + + + + + + + + + + diff --git a/tests/CncRepository.Tests/CncRepository.Tests.csproj b/tests/CncRepository.Tests/CncRepository.Tests.csproj new file mode 100644 index 0000000..48765eb --- /dev/null +++ b/tests/CncRepository.Tests/CncRepository.Tests.csproj @@ -0,0 +1,26 @@ + + + + net472 + x64 + CncRepository.Tests + CncRepository.Tests + false + false + + + + + + + + + + + + + + + + + diff --git a/tests/CncService.Tests/CncService.Tests.csproj b/tests/CncService.Tests/CncService.Tests.csproj new file mode 100644 index 0000000..d3c9f16 --- /dev/null +++ b/tests/CncService.Tests/CncService.Tests.csproj @@ -0,0 +1,26 @@ + + + + net472 + x64 + CncService.Tests + CncService.Tests + false + false + + + + + + + + + + + + + + + + + diff --git a/tests/CncWebApi.Tests/CncWebApi.Tests.csproj b/tests/CncWebApi.Tests/CncWebApi.Tests.csproj new file mode 100644 index 0000000..2337030 --- /dev/null +++ b/tests/CncWebApi.Tests/CncWebApi.Tests.csproj @@ -0,0 +1,30 @@ + + + + net472 + x64 + CncWebApi.Tests + CncWebApi.Tests + false + false + + + + + + + + + + + + + + + + + + + + +