commit a2f22988805aff296f9b9e28e8f3a603045d764e Author: lixiang <504331699@qq.com> Date: Mon Aug 4 16:50:54 2025 +0800 feat: 提交 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..55b3403 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.tgz +node_modules/* +*.yaml +dist/* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..81638bc --- /dev/null +++ b/README.md @@ -0,0 +1,111 @@ +# @mes-processors/libs + +这是一个用于处理MES(制造执行系统)相关工作流的处理器类库。 + +## 安装 + +在内网环境下执行以下脚本进行安装 + +```sh +pnpm add http://gitea.cf/MES-FE/mes-packages/releases/download/0.1/mes-processors-libs-0.1.0.tgz +``` + +> [!CAUTION] +> 在安装库之前,请确认以下信息: +> +> - 该库发布于内网gitea仓库的release中,所以你需要提前在gitea中进行登录,并确保你有该仓库的访问权限。 +> - 库的版本需要手动进行控制,注意上述链接中的版本信息,在安装前需要主动修改版本号,请前往来确认最新版本。 + +## 使用 + +该库提供了MES/iMES公用的处理器,并已配置为导出项,请参考以下Typescript代码进行使用: + +```ts +// 引入矩形优化处理器 +import { RectLayoutProcConfig } from 'cut-abstractions'; +import { RectLayoutProc } from '@mes-processors/libs'; + +// 实例化处理器 +const proc = new RectLayoutProc(); +// 构建上下文f proc.exec>[0] = { + input: testObj, + params: new RectLayoutProcConfig() +}; +// 异步执行 +const ctx: Parameters [!NOTE] +> 发布前记得更改版本号 + +### 约定 + +**目录** + +``` +src +├── modules 项目模块分组 +├── processors 处理器 +└── utils 公用的工具类 +``` + +**导出和打包** + +- 编写的处理器请在`src/index.ts`中进行导出 +- 编写的工具类请在`src/utils/index.ts`中进行导出 +- 在打包时项目仅会对`src/index.ts`进行打包,工具类相关模块不会进行打包 +- 关于打包相关明细请自行查看相关文件 + - [package.json](package.json) + - [vite.config.ts](vite.config.ts) + +> [!WARNING] +> 在该工作区中编写模块时,禁止使用绝对路径进行导入,禁止在`tsconfig.json`或`vite.config.ts`中添加"@"别名,所有导入语句请使用相对路径进行引入,否则会因monorepo内部导入混乱导致模块解析失败。 + +### 测试 + +项目使用[Vitest](http://vitest.dev/)作为单元测试框架,若要对TS文件编写单元测试,请在文件的同目录下创建`<文件名>.test.ts`文件,并遵循Vitest规范编写单元测试。 + +要执行单元测试,请运行下面的命令: +```sh +pnpm test +``` diff --git a/package.json b/package.json new file mode 100644 index 0000000..a2365ae --- /dev/null +++ b/package.json @@ -0,0 +1,38 @@ +{ + "name": "@imes-holeToModel/libs", + "version": "0.1.2", + "description": "", + "type": "module", + "scripts": { + "build": "vite build", + "test": "vitest", + "check": "tsc --noEmit --skipLibCheck -p tsconfig.app.json" + }, + "files": [ + "dist", + "package.json", + "src", + "tsconfig.json", + "tsconfig.app.json", + "tsconfig.node.json" + ], + "exports": { + ".": "./src/index.ts", + "./utils": "./src/utils/index.ts" + }, + "dependencies": { + "cut-abstractions": "http://gitea.cf/MES-FE/cut-abstractions/releases/download/0.2/cut-abstractions-0.2.1.tgz" + }, + "devDependencies": { + "@types/node": "^24.0.10", + "typescript": "~5.8.3", + "vite": "^7.0.0", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-node-polyfills": "^0.24.0", + "vite-plugin-resolve": "^2.5.2", + "vitest": "^3.2.4" + }, + "keywords": [], + "author": "", + "license": "ISC" +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..3ce9a3d --- /dev/null +++ b/src/index.ts @@ -0,0 +1,2 @@ +// holeToModel +export * from "./processors/holeToModel/holeToModel"; \ No newline at end of file diff --git a/src/processors/holeToModel/holeToModel.test.ts b/src/processors/holeToModel/holeToModel.test.ts new file mode 100644 index 0000000..9a1efd1 --- /dev/null +++ b/src/processors/holeToModel/holeToModel.test.ts @@ -0,0 +1,63 @@ +import { test } from "vitest"; +import { HoleToModelInput, HoleToModelProc, HoleToModelProcConfig, HoleToModelProcessingItem } from "./holeToModel"; + +const data = [ + { + "id": "1", + "faceType": 0, + "holeType": 10, + "startX": 8, + "startY": 549, + "radius": 3, + "depth": 13.5, + "knifeRadius": 1 + }, + { + "id": "2", + "faceType": 0, + "holeType": 10, + "startX": 8, + "startY": 49, + "radius": 3, + "depth": 13.5, + "knifeRadius": 2.5 + }, + { + "id": "2", + "faceType": 0, + "holeType": 10, + "startX": 8, + "startY": 209, + "radius": 3, + "depth": 18, + "knifeRadius": 1 + } +] +test('holeToModelTest', async () => { + let holeData: HoleToModelProcessingItem[] = [] + data.forEach(e => { + let temp: HoleToModelProcessingItem = { + radius: e.radius, + depth: e.depth, + pts: [{ x: e.startX, y: e.startY }], + buls: [0], + knifeRadius: e.knifeRadius + } + holeData.push(temp) + }) + + let conf: HoleToModelProcConfig = {} + let input: HoleToModelInput = { + thickness: 18, + holeData + } + + let proc = new HoleToModelProc() + let context = { + input, + params: conf + } + await proc.exec(context) + + console.log(context); +}) \ No newline at end of file diff --git a/src/processors/holeToModel/holeToModel.ts b/src/processors/holeToModel/holeToModel.ts new file mode 100644 index 0000000..830c3c1 --- /dev/null +++ b/src/processors/holeToModel/holeToModel.ts @@ -0,0 +1,218 @@ +import { ConfigBase, ProcessorBase, ProcessorContext } from "cut-abstractions"; + +/** + * 孔转造型 + */ +export class HoleToModelProc extends ProcessorBase { + get name(): string { + return 'holeToModel'; + } + get version(): string { + return '1.0.0'; + } + exec(context: ProcessorContext): Promise | any | void { + return new Promise(async (resolve, reject) => { + try { + let res: HoleToModelOutput | string = '' + if (!context.input) { + res = 'holeToModel: input is undefined!' + reject(res) + return res + } + + if (Array.isArray(context.input.holeData)) { + let thickness = context.input.thickness + + let modelData: HoleToModelProcessingItem[] = [] + let noHandleItem: noHandleItemType[] = [] + for (const hole of context.input.holeData) { + let data = this.toModel(thickness, hole) + if (data.code == 1) { + modelData.push(data.item) + } else { + noHandleItem.push({ + info: data.info, + holeData: hole + }) + } + } + let output: HoleToModelOutput = { + modelData, + noHandleItem + } + context.output = output + } else { + res = 'holeToModel: input.holeData is invalid!' + reject(res) + return res + } + + + resolve(res) + } catch (error) { + reject(error); + } + }); + } + /** + * @param t 板件的厚度 + * @param hole 孔的 加工项 + */ + private toModel(t: number, hole: HoleToModelProcessingItem) { + let depth = hole.depth + let radius = hole.radius + let knifeRadius = hole.knifeRadius + let resData: any = { + code: -1, + item: null, + info: '' + } + + if (radius == knifeRadius) { + resData.code = -1 + resData.item = hole + resData.info = 'HoleToModel =》toModel : transform fail,radius is same as knifeRadius,do not need handle.' + return resData + } else if (radius < knifeRadius) { + resData.code = -1 + resData.item = hole + resData.info = 'HoleToModel =》toModel : transform fail,knifeRadius is more then radius,can not handle.' + return resData + } else if (radius > knifeRadius) { + let p = hole.pts[0] + if (p == undefined) { + resData.code = -1 + resData.item = hole + resData.info = 'HoleToModel =》toModel : transform fail,hole.pts has no data,can not handle.' + return resData + } else { + let model: HoleToModelProcessingItem = { + depth: depth, + radius: knifeRadius, + pts: [], + buls: [], + knifeRadius: knifeRadius, + } + /** 圆点 x */ + let cx = p.x + /** 圆点 y */ + let cy = p.y + + let r0 = hole.radius - hole.knifeRadius + /** 最外层走一圈 */ + let bul = 0.41421356237309503 + model.pts.push({ x: cx - r0, y: cy }) + model.buls.push(-bul) + + model.pts.push({ x: cx, y: cy + r0 }) + model.buls.push(-bul) + + model.pts.push({ x: cx + r0, y: cy }) + model.buls.push(-bul) + + model.pts.push({ x: cx, y: cy - r0 }) + model.buls.push(-bul) + + model.pts.push({ x: cx - r0, y: cy }) + model.buls.push(0) + + if (depth >= t - 0.001) { + // 挖穿 输出结果 + resData.code = 1 + resData.item = model + resData.info = 'success' + return resData + } else { + // 非挖穿 需要铣 + r0 = r0 - knifeRadius + while (r0 > 0) { + + model.pts.push({ x: cx - r0, y: cy }) + model.buls.push(bul) + + model.pts.push({ x: cx, y: cy - r0 }) + model.buls.push(bul) + + model.pts.push({ x: cx + r0, y: cy }) + model.buls.push(bul) + + model.pts.push({ x: cx, y: cy + r0 }) + model.buls.push(bul) + + model.pts.push({ x: cx, y: cy + r0 }) + model.buls.push(0) + r0 = r0 - knifeRadius + } + + // 移动到圆心 + model.pts.push({ x: cx, y: cy }) + model.buls.push(0) + + resData.code = 1 + resData.item = model + resData.info = 'success' + return resData + } + } + + + + } + + + + } +} +/** 处理器输入 -孔转造型*/ +export type HoleToModelInput = { + /** 孔信息 */ + holeData: HoleToModelProcessingItem[], + /** 孔所在板件的优化后的坐标 X (可选)*/ + placeX?: number, + /** 孔所在板件的优化后的坐标 Y (可选)*/ + placeY?: number, + /** 孔所在板件的 厚度 */ + thickness: number +} +/** 处理器输出-- 获取造型在大板的刀路 */ +export type HoleToModelOutput = { + /** 孔转造型 后的 造型数据 */ + modelData: HoleToModelProcessingItem[], + /** 未处理的孔数据 以及信息 */ + noHandleItem: noHandleItemType[] +} +export type noHandleItemType = { + /** 未处理的孔信息 */ + holeData: HoleToModelProcessingItem, + /** 未处理 说明 */ + info: string +} +/** 处理器配置-- 获取造型在大板的刀路 */ +export declare class HoleToModelProcConfig extends ConfigBase { + +} + +/** + * 点阵数据 加工项 + */ +export interface IProcessingItem { + /** + * 加工点数组 + */ + pts: IPoint[]; + /** + * 凸度数组 + */ + buls: number[]; + /** 半径 (孔) */ + radius: number, + /** 深度 */ + depth: number +} +/** 加工项的类型 */ +export type HoleToModelProcessingItem = IProcessingItem & { + /** 使用刀具的刀半径 */ + knifeRadius: number +} + +export interface IPoint { x: number, y: number; } \ No newline at end of file diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..ae94125 --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,39 @@ +{ + // TODO: Warn: 在进行TS类型检查的时候会检查到workflow工作区中的文件,原因未知 + "compilerOptions": { + "lib": [ + "ES2020", + "ES2021", + "ESNext", + "DOM", + "DOM.Iterable" + ], + "noEmit": true, + "target": "esnext", + "module": "ESNext", + "moduleResolution": "Bundler", + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "baseUrl": ".", + "paths": { + // 为了保证导入不与被引入项目冲突,不应该配置'@/*'别名 + "@libs/*": [ + "./src/*" + ] + }, + /* Linting */ + "strict": true, + "erasableSyntaxOnly": false, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "composite": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + ], + "exclude": [ + "src/**/__tests__/*", + "dist", + "node_modules/**" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..dcf15c3 --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2023", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..a488e90 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,34 @@ +/// +import { defineConfig } from 'vite' +import { nodePolyfills } from 'vite-plugin-node-polyfills'; +import { resolve } from 'node:path'; +import dts from 'vite-plugin-dts'; + +let basePath = process.env.basePath ?? ''; + +// https://vite.dev/config/ +export default defineConfig({ + base: basePath, + plugins: [ + nodePolyfills(), + dts({rollupTypes: true, tsconfigPath: './tsconfig.app.json',insertTypesEntry: true}), + ], + build: { + modulePreload: { + resolveDependencies() { + return []; + } + }, + lib: { + entry: resolve(__dirname, 'src/index.ts'), + name: 'MesCutorder', + fileName(format) { + return `mes-cutorder.${format}.js` + }, + formats: ['es', 'umd', 'iife'] + } + }, + esbuild: { + drop: process.env.NODE_ENV === 'production' ? ['console', 'debugger'] : [], + }, +}) \ No newline at end of file