diff --git a/.node-red-data/projects/zsy/flows.json b/.node-red-data/projects/zsy/flows.json index c7d50d3..ca66123 100644 --- a/.node-red-data/projects/zsy/flows.json +++ b/.node-red-data/projects/zsy/flows.json @@ -7,10 +7,18 @@ "info": "", "env": [] }, + { + "id": "2bbc1a949095492c", + "type": "tab", + "label": "CRUD子流程", + "disabled": false, + "info": "", + "env": [] + }, { "id": "78d15f59dee4b6d8", "type": "tab", - "label": "流程 2", + "label": "接口", "disabled": false, "info": "", "env": [] @@ -1134,6 +1142,887 @@ "y": 220, "wires": [] }, + { + "id": "6b82573f9ffd406c", + "type": "http request", + "z": "2bbc1a949095492c", + "name": "创建井", + "method": "POST", + "ret": "txt", + "paytoqs": "ignore", + "url": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "", + "senderr": false, + "headers": [], + "x": 1030, + "y": 480, + "wires": [ + [ + "4de04763f97579e6", + "dff6a9719efe6bb8", + "b18ba558db58cd2c" + ] + ] + }, + { + "id": "fd19275e55b06039", + "type": "inject", + "z": "2bbc1a949095492c", + "name": "创建", + "props": [ + { + "p": "payload" + }, + { + "p": "headers", + "v": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "vt": "json" + }, + { + "p": "rejectUnauthorized", + "v": "false", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"version\":\"1.0.0\",\"act\":-1,\"data\":[{\"dsid\":\"testid2\",\"wellId\":\"WELL-zzlhTEST-002\",\"wellCommonName\":\"zzlh测试用井名\",\"wellLegalName\":\"zzlh-test-01\",\"wellPurpose\":\"开发井\",\"wellType\":\"直井\",\"dataRegion\":\"ZZLH\",\"projectId\":\"PROJ-ZZLH-001\",\"projectName\":\"zzlh测试地质单元\",\"orgId\":\"ORG-ZZLH-01\",\"orgName\":\"zzlh采油厂\",\"bsflag\":1,\"wellState\":\"生产中\",\"spudDate\":\"2024-01-15\",\"completionDate\":\"2024-05-20\",\"prodDate\":\"2024-06-01\",\"egl\":145.5,\"kbd\":5.2,\"kb\":150.7,\"actualXAxis\":550123.45,\"actualYAxis\":4998765.32,\"coordinateSystemName\":\"zzlh测试坐标系\",\"geoDescription\":\"位于zzlh测试区域\",\"remarks\":\"这是一口用于系统测试的生产井。\",\"createUserId\":\"testuser001\",\"createDate\":\"2025-09-12T10:00:00Z\",\"updateUserId\":\"testuser001\",\"updateDate\":\"2025-09-12T10:00:00Z\"}]}", + "payloadType": "json", + "x": 850, + "y": 320, + "wires": [ + [ + "af408af17987663d" + ] + ] + }, + { + "id": "4de04763f97579e6", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "创建结果", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 1180, + "y": 360, + "wires": [] + }, + { + "id": "9d308d75e615a2b1", + "type": "http request", + "z": "2bbc1a949095492c", + "name": "更新井", + "method": "PUT", + "ret": "txt", + "paytoqs": "ignore", + "url": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "", + "senderr": false, + "headers": [], + "x": 270, + "y": 280, + "wires": [ + [ + "53b9ebee8b3ad17f" + ] + ] + }, + { + "id": "7b342ce3a2bf48c1", + "type": "inject", + "z": "2bbc1a949095492c", + "name": "更新", + "props": [ + { + "p": "payload" + }, + { + "p": "headers", + "v": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "vt": "json" + }, + { + "p": "rejectUnauthorized", + "v": "false", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"version\":\"1.0.0\",\"act\":-1,\"data\":[{\"dsid\":\"testid2\",\"wellId\":\"WELL-zzlhTEST-002\",\"wellCommonName\":\"zzlh测试用井名\",\"wellLegalName\":\"zzlh-test-01\",\"wellPurpose\":\"开发井---更新16\",\"wellType\":\"直井\",\"dataRegion\":\"ZZLH\",\"projectId\":\"PROJ-ZZLH-001\",\"projectName\":\"zzlh测试地质单元\",\"orgId\":\"ORG-ZZLH-01\",\"orgName\":\"zzlh采油厂\",\"bsflag\":1,\"wellState\":\"生产中\",\"spudDate\":\"2024-01-15\",\"completionDate\":\"2024-05-20\",\"prodDate\":\"2024-06-01\",\"egl\":145.5,\"kbd\":5.2,\"kb\":150.7,\"actualXAxis\":550123.45,\"actualYAxis\":4998765.32,\"coordinateSystemName\":\"zzlh测试坐标系\",\"geoDescription\":\"位于zzlh测试区域\",\"remarks\":\"这是一口用于系统测试的生产井。\",\"createUserId\":\"testuser001\",\"createDate\":\"2025-09-12T10:00:00Z\",\"updateUserId\":\"testuser001\",\"updateDate\":\"2025-09-12T10:00:00Z\"}]}", + "payloadType": "json", + "x": 110, + "y": 260, + "wires": [ + [ + "9d308d75e615a2b1" + ] + ] + }, + { + "id": "53b9ebee8b3ad17f", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "更新结果", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 460, + "y": 260, + "wires": [] + }, + { + "id": "cfd7ae558fdd3340", + "type": "inject", + "z": "2bbc1a949095492c", + "name": "查询列表", + "props": [ + { + "p": "headers", + "v": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "vt": "json" + }, + { + "p": "rejectUnauthorized", + "v": "false", + "vt": "str" + }, + { + "p": "url", + "v": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well/1.0.0", + "vt": "str" + }, + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{}", + "payloadType": "json", + "x": 120, + "y": 400, + "wires": [ + [ + "1c0decb86a5b16bc" + ] + ] + }, + { + "id": "54b7e6f656002a74", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "查询", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 490, + "y": 400, + "wires": [] + }, + { + "id": "1c0decb86a5b16bc", + "type": "http request", + "z": "2bbc1a949095492c", + "name": "查询井列表", + "method": "POST", + "ret": "txt", + "paytoqs": "ignore", + "url": "", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "", + "senderr": false, + "headers": [], + "x": 290, + "y": 420, + "wires": [ + [ + "54b7e6f656002a74", + "c226f4cb78c4eeda" + ] + ] + }, + { + "id": "c226f4cb78c4eeda", + "type": "function", + "z": "2bbc1a949095492c", + "name": "function 6", + "func": "try {\n \n const payload = JSON.parse(msg.payload);\n if (payload && payload.data && Array.isArray(payload.data.list)) {\n msg.isEmpty = payload.data.list.length === 0;\n } else {\n msg.isEmpty = false; \n }\n} catch (e) {\n \n \n msg.isEmpty = false\n}\n\n\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 300, + "y": 520, + "wires": [ + [ + "8c029cbbaf7a4083" + ] + ] + }, + { + "id": "8c029cbbaf7a4083", + "type": "switch", + "z": "2bbc1a949095492c", + "name": "", + "property": "isEmpty", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "true", + "vt": "jsonata" + }, + { + "t": "neq", + "v": "true", + "vt": "jsonata" + } + ], + "checkall": "true", + "repair": false, + "outputs": 2, + "x": 470, + "y": 500, + "wires": [ + [ + "58738307f84d7063", + "af408af17987663d" + ], + [ + "0d33ba7f9e75ba14" + ] + ] + }, + { + "id": "0d33ba7f9e75ba14", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 12", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "\"初始不为空,错误\"", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 490, + "y": 600, + "wires": [] + }, + { + "id": "58738307f84d7063", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 13", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "\"初始为空,正确\"", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 690, + "y": 560, + "wires": [] + }, + { + "id": "af408af17987663d", + "type": "change", + "z": "2bbc1a949095492c", + "name": "", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "{\"version\":\"1.0.0\",\"act\":-1,\"data\":[{\"dsid\":\"testid2\",\"wellId\":\"WELL-zzlhTEST-002\",\"wellCommonName\":\"zzlh测试用井名\",\"wellLegalName\":\"zzlh-test-01\",\"wellPurpose\":\"开发井\",\"wellType\":\"直井\",\"dataRegion\":\"ZZLH\",\"projectId\":\"PROJ-ZZLH-001\",\"projectName\":\"zzlh测试地质单元\",\"orgId\":\"ORG-ZZLH-01\",\"orgName\":\"zzlh采油厂\",\"bsflag\":1,\"wellState\":\"生产中\",\"spudDate\":\"2024-01-15\",\"completionDate\":\"2024-05-20\",\"prodDate\":\"2024-06-01\",\"egl\":145.5,\"kbd\":5.2,\"kb\":150.7,\"actualXAxis\":550123.45,\"actualYAxis\":4998765.32,\"coordinateSystemName\":\"zzlh测试坐标系\",\"geoDescription\":\"位于zzlh测试区域\",\"remarks\":\"这是一口用于系统测试的生产井。\",\"createUserId\":\"testuser001\",\"createDate\":\"2025-09-12T10:00:00Z\",\"updateUserId\":\"testuser001\",\"updateDate\":\"2025-09-12T10:00:00Z\"}]}", + "tot": "json" + }, + { + "t": "set", + "p": "headers", + "pt": "msg", + "to": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "tot": "json" + }, + { + "t": "set", + "p": "rejectUnauthorized", + "pt": "msg", + "to": "false", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 880, + "y": 480, + "wires": [ + [ + "6b82573f9ffd406c" + ] + ] + }, + { + "id": "eae40b8b1740da9d", + "type": "switch", + "z": "2bbc1a949095492c", + "name": "", + "property": "isCreated", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "true", + "vt": "jsonata" + }, + { + "t": "eq", + "v": "false", + "vt": "jsonata" + } + ], + "checkall": "true", + "repair": false, + "outputs": 2, + "x": 1330, + "y": 540, + "wires": [ + [ + "7f25bc1c56632834", + "7e2390487c525c25" + ], + [ + "b32a8f9b0f2cd01b" + ] + ] + }, + { + "id": "dff6a9719efe6bb8", + "type": "function", + "z": "2bbc1a949095492c", + "name": "function 7", + "func": "try {\n const payloadObject = JSON.parse(msg.payload);\n msg.isCreated = (payloadObject.code === 0);\n\n} catch (e) {\n msg.isCreated = false;\n}\n\n// 返回更新后的 msg 对象\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1160, + "y": 540, + "wires": [ + [ + "eae40b8b1740da9d" + ] + ] + }, + { + "id": "7f25bc1c56632834", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 14", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "\"创建成功\"", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 1390, + "y": 380, + "wires": [] + }, + { + "id": "b32a8f9b0f2cd01b", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 15", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "创建失败", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 1410, + "y": 660, + "wires": [] + }, + { + "id": "b18ba558db58cd2c", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 16", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "msg", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 1000, + "y": 600, + "wires": [] + }, + { + "id": "1c609e3fa4938dc3", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 17", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "false", + "statusVal": "", + "statusType": "auto", + "x": 800, + "y": 660, + "wires": [] + }, + { + "id": "6b971983d782d570", + "type": "http request", + "z": "2bbc1a949095492c", + "name": "删除井", + "method": "DELETE", + "ret": "txt", + "paytoqs": "ignore", + "url": "", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "", + "senderr": false, + "headers": [], + "x": 1770, + "y": 580, + "wires": [ + [ + "449b2760f19c65ef", + "588b71ddf9f6ad2a" + ] + ] + }, + { + "id": "449b2760f19c65ef", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "删除结果", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 1960, + "y": 460, + "wires": [] + }, + { + "id": "8534db3f11cc613a", + "type": "inject", + "z": "2bbc1a949095492c", + "name": "删除", + "props": [ + { + "p": "headers", + "v": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "vt": "json" + }, + { + "p": "rejectUnauthorized", + "v": "false", + "vt": "str" + }, + { + "p": "url", + "v": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well", + "vt": "str" + }, + { + "p": "payload" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"version\":\"1.0.0\",\"data\":[\"testid2\"]}", + "payloadType": "json", + "x": 1710, + "y": 400, + "wires": [ + [ + "6b971983d782d570" + ] + ] + }, + { + "id": "7e2390487c525c25", + "type": "change", + "z": "2bbc1a949095492c", + "name": "", + "rules": [ + { + "t": "set", + "p": "payload", + "pt": "msg", + "to": "{\"version\":\"1.0.0\",\"data\":[\"testid2\"]}", + "tot": "json" + }, + { + "t": "set", + "p": "headers", + "pt": "msg", + "to": "{\"Content-Type\":\"application/json\",\"Authorization\":\"1\",\"Dataregion\":\"ZZLH\"}", + "tot": "json" + }, + { + "t": "set", + "p": "rejectUnauthorized", + "pt": "msg", + "to": "false", + "tot": "str" + }, + { + "t": "set", + "p": "url", + "pt": "msg", + "to": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well", + "tot": "str" + } + ], + "action": "", + "property": "", + "from": "", + "to": "", + "reg": false, + "x": 1580, + "y": 540, + "wires": [ + [ + "6b971983d782d570" + ] + ] + }, + { + "id": "87da5039b77ae777", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 18", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "\"删除成功\"", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 2170, + "y": 460, + "wires": [] + }, + { + "id": "466bd32fcc7164c2", + "type": "switch", + "z": "2bbc1a949095492c", + "name": "", + "property": "isDeleted", + "propertyType": "msg", + "rules": [ + { + "t": "eq", + "v": "true", + "vt": "jsonata" + }, + { + "t": "eq", + "v": "false", + "vt": "jsonata" + } + ], + "checkall": "true", + "repair": false, + "outputs": 2, + "x": 2110, + "y": 620, + "wires": [ + [ + "87da5039b77ae777", + "6ce191ad8e5a407e" + ], + [ + "b41e21ee453d29d7" + ] + ] + }, + { + "id": "b41e21ee453d29d7", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 19", + "active": true, + "tosidebar": true, + "console": true, + "tostatus": false, + "complete": "删除失败", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 2190, + "y": 740, + "wires": [] + }, + { + "id": "588b71ddf9f6ad2a", + "type": "function", + "z": "2bbc1a949095492c", + "name": "function 8", + "func": "try {\n const payloadObject = JSON.parse(msg.payload);\n msg.isDeleted = (payloadObject.code === 0);\n\n} catch (e) {\n msg.isDeleted = false;\n}\n\n// 返回更新后的 msg 对象\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 1920, + "y": 620, + "wires": [ + [ + "466bd32fcc7164c2", + "5b1fd3727096c31d" + ] + ] + }, + { + "id": "5b1fd3727096c31d", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "debug 20", + "active": false, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "msg", + "targetType": "jsonata", + "statusVal": "", + "statusType": "auto", + "x": 2000, + "y": 680, + "wires": [] + }, + { + "id": "cada8d4a6105ea2d", + "type": "function", + "z": "2bbc1a949095492c", + "name": "function 9", + "func": "msg.headers = { \"Content-Type\": \"application/json\", \"Authorization\": \"1\", \"Dataregion\": \"ZZLH\" }\nmsg.body={}\nmsg.rejectUnauthorized=false\nmsg.url = \"https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well/1.0.0\"\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 100, + "y": 500, + "wires": [ + [ + "1c0decb86a5b16bc" + ] + ] + }, + { + "id": "21d47918f0e5a611", + "type": "http in", + "z": "2bbc1a949095492c", + "name": "", + "url": "/test", + "method": "get", + "upload": false, + "skipBodyParsing": false, + "swaggerDoc": "", + "x": 80, + "y": 580, + "wires": [ + [ + "cada8d4a6105ea2d" + ] + ] + }, + { + "id": "608d38ac3750e9a9", + "type": "http response", + "z": "2bbc1a949095492c", + "name": "", + "statusCode": "", + "headers": {}, + "x": 2370, + "y": 620, + "wires": [] + }, + { + "id": "6ce191ad8e5a407e", + "type": "function", + "z": "2bbc1a949095492c", + "name": "function 10", + "func": "msg.payload = { \"code\": 0, \"message\": \"井创建删除流程测试成功\",}\nreturn msg;", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 2260, + "y": 560, + "wires": [ + [ + "608d38ac3750e9a9" + ] + ] + }, + { + "id": "954bc3b915b9ad93", + "type": "inject", + "z": "2bbc1a949095492c", + "name": "创建", + "props": [ + { + "p": "payload" + }, + { + "p": "headers", + "v": "{\"Content-Type\":\"application/json\",\"Dataregion\":\"ZZLH\"}", + "vt": "json" + }, + { + "p": "rejectUnauthorized", + "v": "false", + "vt": "str" + } + ], + "repeat": "", + "crontab": "", + "once": false, + "onceDelay": 0.1, + "topic": "", + "payload": "{\"version\":\"1.0.0\",\"act\":-1,\"data\":[{\"dsid\":\"testid2\",\"wellId\":\"WELL-zzlhTEST-002\",\"wellCommonName\":\"zzlh测试用井名\",\"wellLegalName\":\"zzlh-test-01\",\"wellPurpose\":\"开发井\",\"wellType\":\"直井\",\"dataRegion\":\"ZZLH\",\"projectId\":\"PROJ-ZZLH-001\",\"projectName\":\"zzlh测试地质单元\",\"orgId\":\"ORG-ZZLH-01\",\"orgName\":\"zzlh采油厂\",\"bsflag\":1,\"wellState\":\"生产中\",\"spudDate\":\"2024-01-15\",\"completionDate\":\"2024-05-20\",\"prodDate\":\"2024-06-01\",\"egl\":145.5,\"kbd\":5.2,\"kb\":150.7,\"actualXAxis\":550123.45,\"actualYAxis\":4998765.32,\"coordinateSystemName\":\"zzlh测试坐标系\",\"geoDescription\":\"位于zzlh测试区域\",\"remarks\":\"这是一口用于系统测试的生产井。\",\"createUserId\":\"testuser001\",\"createDate\":\"2025-09-12T10:00:00Z\",\"updateUserId\":\"testuser001\",\"updateDate\":\"2025-09-12T10:00:00Z\"}]}", + "payloadType": "json", + "x": 850, + "y": 80, + "wires": [ + [ + "05975bc9c72aea39" + ] + ] + }, + { + "id": "05975bc9c72aea39", + "type": "http request", + "z": "2bbc1a949095492c", + "name": "创建井", + "method": "POST", + "ret": "txt", + "paytoqs": "ignore", + "url": "https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1/cd_well", + "tls": "", + "persist": true, + "proxy": "", + "insecureHTTPParser": false, + "authType": "", + "senderr": false, + "headers": [], + "x": 990, + "y": 20, + "wires": [ + [ + "0144f7e3d85b8e7e" + ] + ] + }, + { + "id": "0144f7e3d85b8e7e", + "type": "debug", + "z": "2bbc1a949095492c", + "name": "创建结果", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 1080, + "y": 140, + "wires": [] + }, + { + "id": "6c06fbe60248c14c", + "type": "link in", + "z": "2bbc1a949095492c", + "name": "crud子流程linkin", + "links": [], + "x": 175, + "y": 340, + "wires": [ + [ + "1c0decb86a5b16bc" + ] + ] + }, { "id": "fd3672b8ebb314ee", "type": "http in", @@ -1168,21 +2057,21 @@ "type": "function", "z": "78d15f59dee4b6d8", "name": "dms转化为oas", - "func": "'use strict';\n\nconst DEFAULT_OPENAPI_VERSION = '3.0.1';\nconst DEFAULT_API_VERSION = '1.0.0';\n\nlet schema;\ntry {\n // 优先使用 HTTP In 提供的 req.body.schema,缺省时回退到 msg.payload。\n const schemaInput = extractSchemaInput(msg);\n schema = parseSchema(schemaInput);\n} catch (error) {\n node.error(`DMS -> Swagger 解析失败:${error.message}`, msg);\n msg.error = error.message;\n return msg;\n}\n\nconst resourceTitle = typeof schema.title === 'string' && schema.title.trim()\n ? schema.title.trim()\n : 'DMS Resource';\n\nconst resourceName = pascalCase(resourceTitle);\nconst collectionName = pluralize(kebabCase(resourceTitle));\nconst identityField = Array.isArray(schema.identityId) && schema.identityId.length > 0\n ? String(schema.identityId[0])\n : 'id';\n\nconst schemaComponent = buildComponentSchema(resourceName, schema);\nconst identitySchema = schemaComponent.properties && schemaComponent.properties[identityField]\n ? clone(schemaComponent.properties[identityField])\n : { type: 'string' };\n\nconst openApiDocument = {\n openapi: DEFAULT_OPENAPI_VERSION,\n info: {\n title: `${resourceTitle} API`,\n version: DEFAULT_API_VERSION,\n description: schema.description || `${schema.$id || ''}`.trim(),\n 'x-dms-sourceId': schema.$id || undefined,\n },\n paths: buildCrudPaths({\n collectionName,\n resourceName,\n identityField,\n identitySchema,\n }),\n components: {\n schemas: {\n [resourceName]: schemaComponent,\n },\n },\n};\n\nmsg.oas_def = openApiDocument;\nmsg.payload = openApiDocument;\nreturn msg;\n\nfunction extractSchemaInput(message) {\n if (message && message.req && message.req.body && typeof message.req.body === 'object') {\n if (message.req.body.schema !== undefined) {\n return message.req.body.schema;\n }\n }\n\n if (message && message.payload !== undefined) {\n return message.payload;\n }\n\n throw new Error('未找到schema,请在请求体的schema字段或msg.payload中提供');\n}\n\nfunction parseSchema(source) {\n if (typeof source === 'string') {\n try {\n return JSON.parse(source);\n } catch (error) {\n throw new Error(`JSON 解析失败:${error.message}`);\n }\n }\n\n if (!source || typeof source !== 'object') {\n throw new Error('schema 必须是 DMS 定义对象或 JSON 字符串');\n }\n\n return source;\n}\n\nfunction buildComponentSchema(resourceName, dmsSchema) {\n const { properties = {}, required = [], groupView, identityId, naturalKey, defaultShow } = dmsSchema;\n const openApiProps = {};\n\n for (const [propName, propSchema] of Object.entries(properties)) {\n openApiProps[propName] = mapProperty(propSchema);\n }\n\n return {\n type: 'object',\n required: Array.isArray(required) ? required.slice() : [],\n properties: openApiProps,\n description: dmsSchema.description || dmsSchema.title || resourceName,\n 'x-dms-groupView': groupView || undefined,\n 'x-dms-identityId': identityId || undefined,\n 'x-dms-naturalKey': naturalKey || undefined,\n 'x-dms-defaultShow': defaultShow || undefined,\n };\n}\n\nfunction mapProperty(propSchema) {\n if (!propSchema || typeof propSchema !== 'object') {\n return { type: 'string' };\n }\n\n const result = {};\n\n const type = normalizeType(propSchema.type);\n result.type = type.type;\n if (type.format) {\n result.format = type.format;\n }\n if (type.items) {\n result.items = type.items;\n }\n\n if (propSchema.description) {\n result.description = propSchema.description;\n } else if (propSchema.title) {\n result.description = propSchema.title;\n }\n\n if (propSchema.enum) {\n result.enum = propSchema.enum.slice();\n }\n\n if (propSchema.default !== undefined) {\n result.default = propSchema.default;\n }\n\n if (propSchema.mask) {\n result['x-dms-mask'] = propSchema.mask;\n }\n if (propSchema.geom) {\n result['x-dms-geom'] = propSchema.geom;\n }\n if (propSchema.title) {\n result['x-dms-title'] = propSchema.title;\n }\n if (propSchema.type) {\n result['x-dms-originalType'] = propSchema.type;\n }\n\n return result;\n}\n\nfunction normalizeType(typeValue) {\n const normalized = typeof typeValue === 'string' ? typeValue.toLowerCase() : undefined;\n\n switch (normalized) {\n case 'number':\n case 'integer':\n case 'long':\n case 'float':\n case 'double':\n return { type: 'number' };\n case 'boolean':\n return { type: 'boolean' };\n case 'array':\n return { type: 'array', items: { type: 'string' } };\n case 'date':\n return { type: 'string', format: 'date' };\n case 'date-time':\n return { type: 'string', format: 'date-time' };\n case 'object':\n return { type: 'object' };\n case 'string':\n default:\n return { type: 'string' };\n }\n}\n\nfunction buildCrudPaths({ collectionName, resourceName, identityField, identitySchema }) {\n const ref = `#/components/schemas/${resourceName}`;\n const collectionPath = `/${collectionName}`;\n const itemPath = `/${collectionName}/{${identityField}}`;\n\n return {\n [collectionPath]: {\n get: {\n operationId: `list${resourceName}s`,\n summary: `List ${resourceName} resources`,\n responses: {\n 200: {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: { $ref: ref },\n },\n },\n },\n },\n },\n },\n \n post: {\n operationId: `create${resourceName}`,\n summary: `Create a ${resourceName}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n responses: {\n 201: {\n description: 'Created',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n },\n },\n \n },\n [itemPath]: {\n parameters: [\n {\n name: identityField,\n in: 'path',\n required: true,\n schema: identitySchema,\n },\n ],\n get: {\n operationId: `get${resourceName}`,\n summary: `Get a single ${resourceName}`,\n responses: {\n 200: {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n 404: { description: `${resourceName} not found` },\n },\n },\n \n put: {\n operationId: `update${resourceName}`,\n summary: `Update a ${resourceName}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n responses: {\n 200: {\n description: 'Successful update',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n },\n },\n delete: {\n operationId: `delete${resourceName}`,\n summary: `Delete a ${resourceName}`,\n responses: {\n 204: { description: 'Deleted' },\n },\n },\n \n },\n };\n}\n\nfunction pascalCase(input) {\n return input\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .split(' ')\n .filter(Boolean)\n .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join('') || 'Resource';\n}\n\nfunction kebabCase(input) {\n return input\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase() || 'resource';\n}\n\nfunction pluralize(word) {\n if (word.endsWith('s')) {\n return word;\n }\n if (word.endsWith('y')) {\n return word.slice(0, -1) + 'ies';\n }\n return `${word}s`;\n}\n\nfunction clone(value) {\n return JSON.parse(JSON.stringify(value));\n}\n", + "func": "'use strict';\n\nconst DEFAULT_OPENAPI_VERSION = '3.0.1';\nconst DEFAULT_API_VERSION = '1.0.0';\nconst FALLBACK_BASE_URL = 'https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1';\nconst FALLBACK_HEADERS = {\n 'Content-Type': 'application/json',\n 'Authorization': '1',\n 'Dataregion': 'ZZLH',\n};\n\nlet schema;\ntry {\n // 优先使用 HTTP In 提供的 req.body.schema,缺省时回退到 msg.payload。\n const schemaInput = extractSchemaInput(msg);\n schema = parseSchema(schemaInput);\n} catch (error) {\n node.error(`DMS -> Swagger 解析失败:${error.message}`, msg);\n msg.error = error.message;\n return msg;\n}\n\nconst resourceTitle = typeof schema.title === 'string' && schema.title.trim()\n ? schema.title.trim()\n : 'DMS Resource';\n\nconst resourceName = pascalCase(resourceTitle);\nconst collectionName = pluralize(kebabCase(resourceTitle));\nconst identityField = Array.isArray(schema.identityId) && schema.identityId.length > 0\n ? String(schema.identityId[0])\n : 'id';\n\nconst schemaComponent = buildComponentSchema(resourceName, schema);\nconst identitySchema = schemaComponent.properties && schemaComponent.properties[identityField]\n ? clone(schemaComponent.properties[identityField])\n : { type: 'string' };\n\nconst openApiDocument = {\n openapi: DEFAULT_OPENAPI_VERSION,\n info: {\n title: `${resourceTitle} API`,\n version: DEFAULT_API_VERSION,\n description: schema.description || `${schema.$id || ''}`.trim(),\n 'x-dms-sourceId': schema.$id || undefined,\n },\n paths: buildCrudPaths({\n collectionName,\n resourceName,\n identityField,\n identitySchema,\n }),\n components: {\n schemas: {\n [resourceName]: schemaComponent,\n },\n },\n};\n\nconst crudConfig = Object.assign({}, msg.crudConfig || {});\n\nif (!crudConfig.baseUrl) {\n crudConfig.baseUrl = FALLBACK_BASE_URL;\n}\n\nconst headers = Object.assign({}, FALLBACK_HEADERS, crudConfig.headers || {});\nconst dataRegionValue = extractDataRegion(schema, headers.Dataregion);\n\nif (dataRegionValue) {\n headers.Dataregion = dataRegionValue;\n crudConfig.dataRegion = dataRegionValue;\n}\n\ncrudConfig.headers = headers;\ncrudConfig.identityField = crudConfig.identityField || identityField;\n\nmsg.crudConfig = crudConfig;\nmsg.headers = Object.assign({}, headers);\n\nmsg.oas_def = openApiDocument;\nmsg.payload = openApiDocument;\nreturn msg;\n\nfunction extractDataRegion(dmsSchema, fallback) {\n if (!dmsSchema || typeof dmsSchema !== 'object') {\n return fallback;\n }\n\n if (typeof dmsSchema.dataRegion === 'string' && dmsSchema.dataRegion.trim()) {\n return dmsSchema.dataRegion.trim();\n }\n\n if (dmsSchema.defaultShow && Array.isArray(dmsSchema.defaultShow)) {\n const candidate = dmsSchema.defaultShow.find(item => item && typeof item === 'string' && item.toLowerCase().includes('dataregion'));\n if (candidate) {\n return fallback;\n }\n }\n\n const props = dmsSchema.properties;\n if (props && typeof props === 'object' && props.dataRegion) {\n if (typeof props.dataRegion.default === 'string' && props.dataRegion.default.trim()) {\n return props.dataRegion.default.trim();\n }\n }\n\n return fallback;\n}\n\nfunction extractSchemaInput(message) {\n if (message && message.req && message.req.body && typeof message.req.body === 'object') {\n if (message.req.body.schema !== undefined) {\n return message.req.body.schema;\n }\n }\n\n if (message && message.payload !== undefined) {\n return message.payload;\n }\n\n throw new Error('未找到schema,请在请求体的schema字段或msg.payload中提供');\n}\n\nfunction parseSchema(source) {\n if (typeof source === 'string') {\n try {\n return JSON.parse(source);\n } catch (error) {\n throw new Error(`JSON 解析失败:${error.message}`);\n }\n }\n\n if (!source || typeof source !== 'object') {\n throw new Error('schema 必须是 DMS 定义对象或 JSON 字符串');\n }\n\n return source;\n}\n\nfunction buildComponentSchema(resourceName, dmsSchema) {\n const { properties = {}, required = [], groupView, identityId, naturalKey, defaultShow } = dmsSchema;\n const openApiProps = {};\n\n for (const [propName, propSchema] of Object.entries(properties)) {\n openApiProps[propName] = mapProperty(propSchema);\n }\n\n return {\n type: 'object',\n required: Array.isArray(required) ? required.slice() : [],\n properties: openApiProps,\n description: dmsSchema.description || dmsSchema.title || resourceName,\n 'x-dms-groupView': groupView || undefined,\n 'x-dms-identityId': identityId || undefined,\n 'x-dms-naturalKey': naturalKey || undefined,\n 'x-dms-defaultShow': defaultShow || undefined,\n };\n}\n\nfunction mapProperty(propSchema) {\n if (!propSchema || typeof propSchema !== 'object') {\n return { type: 'string' };\n }\n\n const result = {};\n\n const type = normalizeType(propSchema.type);\n result.type = type.type;\n if (type.format) {\n result.format = type.format;\n }\n if (type.items) {\n result.items = type.items;\n }\n\n if (propSchema.description) {\n result.description = propSchema.description;\n } else if (propSchema.title) {\n result.description = propSchema.title;\n }\n\n if (propSchema.enum) {\n result.enum = propSchema.enum.slice();\n }\n\n if (propSchema.default !== undefined) {\n result.default = propSchema.default;\n }\n\n if (propSchema.mask) {\n result['x-dms-mask'] = propSchema.mask;\n }\n if (propSchema.geom) {\n result['x-dms-geom'] = propSchema.geom;\n }\n if (propSchema.title) {\n result['x-dms-title'] = propSchema.title;\n }\n if (propSchema.type) {\n result['x-dms-originalType'] = propSchema.type;\n }\n\n return result;\n}\n\nfunction normalizeType(typeValue) {\n const normalized = typeof typeValue === 'string' ? typeValue.toLowerCase() : undefined;\n\n switch (normalized) {\n case 'number':\n case 'integer':\n case 'long':\n case 'float':\n case 'double':\n return { type: 'number' };\n case 'boolean':\n return { type: 'boolean' };\n case 'array':\n return { type: 'array', items: { type: 'string' } };\n case 'date':\n return { type: 'string', format: 'date' };\n case 'date-time':\n return { type: 'string', format: 'date-time' };\n case 'object':\n return { type: 'object' };\n case 'string':\n default:\n return { type: 'string' };\n }\n}\n\nfunction buildCrudPaths({ collectionName, resourceName, identityField, identitySchema }) {\n const ref = `#/components/schemas/${resourceName}`;\n const collectionPath = `/${collectionName}`;\n const itemPath = `/${collectionName}/{${identityField}}`;\n\n return {\n [collectionPath]: {\n get: {\n operationId: `list${resourceName}s`,\n summary: `List ${resourceName} resources`,\n responses: {\n 200: {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: {\n type: 'array',\n items: { $ref: ref },\n },\n },\n },\n },\n },\n },\n \n post: {\n operationId: `create${resourceName}`,\n summary: `Create a ${resourceName}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n responses: {\n 201: {\n description: 'Created',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n },\n },\n \n },\n [itemPath]: {\n parameters: [\n {\n name: identityField,\n in: 'path',\n required: true,\n schema: identitySchema,\n },\n ],\n get: {\n operationId: `get${resourceName}`,\n summary: `Get a single ${resourceName}`,\n responses: {\n 200: {\n description: 'Successful response',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n 404: { description: `${resourceName} not found` },\n },\n },\n \n put: {\n operationId: `update${resourceName}`,\n summary: `Update a ${resourceName}`,\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n responses: {\n 200: {\n description: 'Successful update',\n content: {\n 'application/json': {\n schema: { $ref: ref },\n },\n },\n },\n },\n },\n delete: {\n operationId: `delete${resourceName}`,\n summary: `Delete a ${resourceName}`,\n responses: {\n 204: { description: 'Deleted' },\n },\n },\n \n },\n };\n}\n\nfunction pascalCase(input) {\n return input\n .replace(/[^a-zA-Z0-9]+/g, ' ')\n .split(' ')\n .filter(Boolean)\n .map(part => part.charAt(0).toUpperCase() + part.slice(1).toLowerCase())\n .join('') || 'Resource';\n}\n\nfunction kebabCase(input) {\n return input\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[^a-zA-Z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .toLowerCase() || 'resource';\n}\n\nfunction pluralize(word) {\n if (word.endsWith('s')) {\n return word;\n }\n if (word.endsWith('y')) {\n return word.slice(0, -1) + 'ies';\n }\n return `${word}s`;\n}\n\nfunction clone(value) {\n return JSON.parse(JSON.stringify(value));\n}\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], - "x": 320, - "y": 220, + "x": 280, + "y": 200, "wires": [ [ "dfe6ed572461c4a5", "5231ed8a796d6f17", "6ab9403df07fcefa", - "60ce224bd2ed8e69" + "9c84414e55654e6a" ] ] }, @@ -1276,8 +2165,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 480, - "y": 320, + "x": 500, + "y": 240, "wires": [ [ "dfe6ed572461c4a5", @@ -1323,7 +2212,7 @@ "topic": "", "payload": "", "payloadType": "date", - "x": 210, + "x": 130, "y": 320, "wires": [ [ @@ -1380,8 +2269,8 @@ "initialize": "", "finalize": "", "libs": [], - "x": 450, - "y": 540, + "x": 350, + "y": 640, "wires": [ [ "540a5771113ca5dd" @@ -1421,7 +2310,8 @@ "y": 520, "wires": [ [ - "e87c2057c28d5eee" + "e87c2057c28d5eee", + "31d5f84e4c6f69f6" ] ] }, @@ -1441,12 +2331,107 @@ "authType": "", "senderr": false, "headers": [], - "x": 600, + "x": 580, "y": 600, "wires": [ [ - "20818ab4243934bf" + "20818ab4243934bf", + "44fc6e2d405c2a78" ] ] + }, + { + "id": "44fc6e2d405c2a78", + "type": "debug", + "z": "78d15f59dee4b6d8", + "name": "请求", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 750, + "y": 620, + "wires": [] + }, + { + "id": "9c84414e55654e6a", + "type": "function", + "z": "78d15f59dee4b6d8", + "name": "构建CRUD计划", + "func": "'use strict';\n\n/**\n * 构建 CRUD 执行动作所需的指令集合,保存于 msg.crudFlow。\n * 约定 operationId 采用 dms→oas 转换后默认的命名:\n * lists / create / delete\n * 允许使用 msg.crudConfig.* 进行覆盖。\n */\nconst FALLBACK_BASE_URL = 'https://www.dev.ideas.cnpc/api/dms/well_kd_wellbore_ideas01/v1';\nconst DEFAULT_LIST_PAYLOAD = {\n version: '1.0.0',\n data: [],\n pageNo: 1,\n pageSize: 20,\n isSearchCount: true,\n};\nconst DEFAULT_CREATE_SAMPLE = {\n version: '1.0.0',\n act: -1,\n data: [\n {\n dsid: 'testid2',\n wellId: 'WELL-zzlhTEST-002',\n wellCommonName: 'zzlh测试用井名',\n wellLegalName: 'zzlh-test-01',\n wellPurpose: '开发井',\n wellType: '直井',\n dataRegion: 'ZZLH',\n projectId: 'PROJ-ZZLH-001',\n projectName: 'zzlh测试地质单元',\n orgId: 'ORG-ZZLH-01',\n orgName: 'zzlh采油厂',\n bsflag: 1,\n wellState: '生产中',\n spudDate: '2024-01-15',\n completionDate: '2024-05-20',\n prodDate: '2024-06-01',\n egl: 145.5,\n kbd: 5.2,\n kb: 150.7,\n actualXAxis: 550123.45,\n actualYAxis: 4998765.32,\n coordinateSystemName: 'zzlh测试坐标系',\n geoDescription: '位于zzlh测试区域',\n remarks: '这是一口用于系统测试的生产井。',\n createUserId: 'testuser001',\n createDate: '2025-09-12T10:00:00Z',\n updateUserId: 'testuser001',\n updateDate: '2025-09-12T10:00:00Z',\n },\n ],\n};\nconst DEFAULT_DELETE_TEMPLATE = {\n version: '1.0.0',\n data: ['{{primaryKey}}'],\n};\n\nreturn buildCrudPlan(msg, node);\n\nfunction buildCrudPlan(message, node) {\n const requestBody = getRequestBody(message);\n const crudConfig = mergeDeep({}, requestBody.crudConfig || {}, message.crudConfig || {});\n const apiDoc = normaliseOpenApi(message, crudConfig, requestBody, node);\n const operations = collectOperations(apiDoc);\n\n const listOp = pickOperation('list', operations, crudConfig);\n const createOp = pickOperation('create', operations, crudConfig);\n const deleteOp = pickOperation('delete', operations, crudConfig);\n\n if (!listOp || !createOp || !deleteOp) {\n const missing = [\n !listOp ? 'list' : null,\n !createOp ? 'create' : null,\n !deleteOp ? 'delete' : null,\n ].filter(Boolean).join(', ');\n const errMsg = `未能在 OpenAPI 文档中找到必要的 CRUD 操作:${missing}`;\n node.error(errMsg, message);\n message.error = errMsg;\n return null;\n }\n\n const resourceName = determineResourceName([createOp, listOp, deleteOp]) || 'Resource';\n const identityField = crudConfig.identityField ||\n requestBody.identityField ||\n selectIdentityField(apiDoc, crudConfig) ||\n 'dsid';\n const baseUrl = trimTrailingSlash(\n crudConfig.baseUrl ||\n requestBody.baseUrl ||\n message.baseUrl ||\n FALLBACK_BASE_URL\n );\n const headers = mergeDeep({}, requestBody.headers || {}, crudConfig.headers || {});\n\n const listConfig = mergeDeep(\n {},\n { payload: clone(DEFAULT_LIST_PAYLOAD) },\n requestBody.list || {},\n crudConfig.list || {}\n );\n const createConfig = mergeDeep(\n {},\n { payload: clone(DEFAULT_CREATE_SAMPLE) },\n requestBody.create || {},\n crudConfig.create || {}\n );\n const deleteConfig = mergeDeep(\n {},\n { payloadTemplate: clone(DEFAULT_DELETE_TEMPLATE) },\n requestBody.delete || {},\n crudConfig.delete || {}\n );\n\n if (requestBody.dataRegion) {\n headers.Dataregion = requestBody.dataRegion;\n }\n\n message.identityField = identityField;\n message.crudFlow = {\n resourceName,\n identityField,\n baseUrl,\n headers,\n list: Object.assign({\n operationId: listOp.operationId,\n method: listOp.method,\n path: listOp.path,\n }, listConfig),\n create: Object.assign({\n operationId: createOp.operationId,\n method: createOp.method,\n path: createOp.path,\n samplePayload: clone(DEFAULT_CREATE_SAMPLE),\n }, createConfig),\n delete: Object.assign({\n operationId: deleteOp.operationId,\n method: deleteOp.method,\n path: deleteOp.path,\n }, deleteConfig),\n openapi: apiDoc,\n };\n\n message.oas_def = apiDoc;\n delete message.error;\n return message;\n}\n\nfunction normaliseOpenApi(message, crudConfig, requestBody, node) {\n let candidate =\n crudConfig.openapi ||\n requestBody.openapi ||\n message.oas_def ||\n message.swagger ||\n message.payload;\n if (typeof candidate === 'string') {\n try {\n candidate = JSON.parse(candidate);\n } catch (err) {\n throw new Error(`OpenAPI JSON 解析失败:${err.message}`);\n }\n }\n if (!candidate || typeof candidate !== 'object') {\n throw new Error('未提供合法的 OpenAPI 文档');\n }\n if (!candidate.paths || typeof candidate.paths !== 'object' || Object.keys(candidate.paths).length === 0) {\n throw new Error('OpenAPI 文档缺少 paths 定义');\n }\n return candidate;\n}\n\nfunction collectOperations(apiDoc) {\n const operations = [];\n const allowed = ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'trace'];\n for (const path of Object.keys(apiDoc.paths)) {\n const pathItem = apiDoc.paths[path];\n if (!pathItem || typeof pathItem !== 'object') {\n continue;\n }\n for (const method of Object.keys(pathItem)) {\n if (!allowed.includes(method.toLowerCase())) {\n continue;\n }\n const operation = pathItem[method];\n if (!operation || typeof operation !== 'object') {\n continue;\n }\n operations.push({\n operationId: operation.operationId || '',\n summary: operation.summary || '',\n description: operation.description || '',\n method: method.toUpperCase(),\n path,\n operation,\n });\n }\n }\n return operations;\n}\n\nfunction pickOperation(kind, operations, crudConfig) {\n const overrideId =\n (crudConfig[kind] && crudConfig[kind].operationId) ||\n crudConfig[`${kind}OperationId`];\n if (overrideId) {\n return operations.find(op => op.operationId === overrideId);\n }\n\n const matcher = getDefaultMatcher(kind);\n let matched = operations.find(op => matcher.test(op.operationId));\n if (matched) {\n return matched;\n }\n\n // 兜底策略\n switch (kind) {\n case 'list':\n return operations.find(op => op.method === 'GET') || null;\n case 'create':\n return operations.find(op => op.method === 'POST') || null;\n case 'delete':\n return operations.find(op => op.method === 'DELETE') ||\n operations.find(op => op.method === 'POST' && /delete/i.test(op.operationId)) ||\n null;\n default:\n return null;\n }\n}\n\nfunction getDefaultMatcher(kind) {\n switch (kind) {\n case 'list':\n return /^list[A-Z].*s$/;\n case 'create':\n return /^create[A-Z].*/;\n case 'delete':\n return /^delete[A-Z].*/;\n default:\n return /^$/;\n }\n}\n\nfunction determineResourceName(candidates) {\n for (const item of candidates) {\n const opId = item && item.operationId ? item.operationId : '';\n let match;\n if ((match = opId.match(/^list([A-Z].*)s$/))) {\n return match[1];\n }\n if ((match = opId.match(/^create([A-Z].*)$/))) {\n return match[1];\n }\n if ((match = opId.match(/^delete([A-Z].*)$/))) {\n return match[1];\n }\n }\n return null;\n}\n\nfunction selectIdentityField(apiDoc, crudConfig) {\n if (crudConfig.identityField) {\n return crudConfig.identityField;\n }\n if (apiDoc.components && apiDoc.components.schemas) {\n for (const schemaName of Object.keys(apiDoc.components.schemas)) {\n const schema = apiDoc.components.schemas[schemaName];\n if (!schema || typeof schema !== 'object') {\n continue;\n }\n const identity = Array.isArray(schema['x-dms-identityId']) ? schema['x-dms-identityId'][0] : null;\n if (identity) {\n return identity;\n }\n }\n }\n if (apiDoc.components && apiDoc.components.schemas) {\n for (const schemaName of Object.keys(apiDoc.components.schemas)) {\n const schema = apiDoc.components.schemas[schemaName];\n if (schema && schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, 'dsid')) {\n return 'dsid';\n }\n }\n }\n return 'dsid';\n}\n\nfunction trimTrailingSlash(url) {\n if (!url) {\n return '';\n }\n return url.replace(/\\/+$/, '');\n}\n\nfunction getRequestBody(message) {\n if (message && message.req && message.req.body && typeof message.req.body === 'object') {\n return message.req.body;\n }\n return {};\n}\n\nfunction clone(value) {\n return value == null ? value : JSON.parse(JSON.stringify(value));\n}\n\nfunction mergeDeep(target, ...sources) {\n for (const source of sources) {\n if (!isPlainObject(source)) {\n continue;\n }\n for (const key of Object.keys(source)) {\n const value = source[key];\n if (value === undefined) {\n continue;\n }\n if (isPlainObject(value)) {\n const base = isPlainObject(target[key]) ? target[key] : {};\n target[key] = mergeDeep({}, base, value);\n } else {\n target[key] = clone(value);\n }\n }\n }\n return target;\n}\n\nfunction isPlainObject(value) {\n return Object.prototype.toString.call(value) === '[object Object]';\n}\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 320, + "y": 340, + "wires": [ + [ + "76358bc84ac6e3e1" + ] + ] + }, + { + "id": "76358bc84ac6e3e1", + "type": "function", + "z": "78d15f59dee4b6d8", + "name": "设置create上下文", + "func": "'use strict';\n\n/**\n * 为参数生成器 / LLM 设定目标的 operationId/path,并清理 msg.mock。\n */\n\nreturn setCreateContext(msg, node);\n\nfunction setCreateContext(message, node) {\n if (!message.crudFlow || !message.crudFlow.create) {\n const err = '缺少 crudFlow.create 配置,无法准备创建操作';\n node.error(err, message);\n message.error = err;\n return null;\n }\n\n const create = message.crudFlow.create;\n message.operationId = create.operationId;\n message.method = create.method || 'POST';\n message.path = create.path;\n message.mock = {};\n\n if (create.prompt) {\n message.prompt = create.prompt;\n }\n if (!message.oas_def && message.crudFlow.openapi) {\n message.oas_def = message.crudFlow.openapi;\n }\n\n delete message.error;\n return message;\n}\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 270, + "y": 560, + "wires": [ + [ + "60ce224bd2ed8e69" + ] + ] + }, + { + "id": "31d5f84e4c6f69f6", + "type": "function", + "z": "78d15f59dee4b6d8", + "name": "缓存create结果", + "func": "'use strict';\n\n/**\n * 将 LLM 生成的创建请求体写回 crudFlow,提取主键供删除步骤使用。\n */\n\nreturn storeCreateResult(msg, node);\n\nfunction storeCreateResult(message, node) {\n if (!message.crudFlow || !message.crudFlow.create) {\n return message;\n }\n\n const identityField = message.crudFlow.identityField || message.identityField || 'dsid';\n const mockBody = extractMockBody(message);\n\n if (mockBody) {\n message.crudFlow.create.payload = clone(mockBody);\n } else if (!message.crudFlow.create.payload) {\n node.warn('未从模型生成创建参数,继续使用默认样例', message);\n message.crudFlow.create.payload = clone(message.crudFlow.create.samplePayload || {});\n }\n\n const payload = message.crudFlow.create.payload || {};\n const primaryKeyValue = payload[identityField];\n if (primaryKeyValue !== undefined) {\n message.primaryKeyValue = primaryKeyValue;\n message.crudFlow.delete = message.crudFlow.delete || {};\n message.crudFlow.delete.actualKey = primaryKeyValue;\n }\n\n delete message.mock;\n message.payload = message.crudFlow;\n\n return message;\n}\n\nfunction extractMockBody(message) {\n if (message && message.mock && typeof message.mock === 'object' && message.mock.body && typeof message.mock.body === 'object') {\n return message.mock.body;\n }\n if (message && message.payload && typeof message.payload === 'object' && !Array.isArray(message.payload)) {\n return message.payload;\n }\n return null;\n}\n\nfunction clone(value) {\n return value == null ? value : JSON.parse(JSON.stringify(value));\n}\n", + "outputs": 1, + "timeout": 0, + "noerr": 0, + "initialize": "", + "finalize": "", + "libs": [], + "x": 940, + "y": 520, + "wires": [ + [ + "cfa3c9b06af4840e" + ] + ] + }, + { + "id": "cfa3c9b06af4840e", + "type": "debug", + "z": "78d15f59dee4b6d8", + "name": "缓存结果", + "active": true, + "tosidebar": true, + "console": false, + "tostatus": false, + "complete": "payload", + "targetType": "msg", + "statusVal": "", + "statusType": "auto", + "x": 1060, + "y": 460, + "wires": [] } ] \ No newline at end of file diff --git a/.node-red-data/projects/zsy/flows_cred.json b/.node-red-data/projects/zsy/flows_cred.json index 4e83ccf..55bc246 100644 --- a/.node-red-data/projects/zsy/flows_cred.json +++ b/.node-red-data/projects/zsy/flows_cred.json @@ -6,5 +6,6 @@ "ae5c8d27d69b77ed": {}, "0d437a2a77570c57": {}, "5921574867140eb3": {}, - "551a78c76ae2bccf": {} + "551a78c76ae2bccf": {}, + "540a5771113ca5dd": {} } \ No newline at end of file