已添加53个文件
已复制12个文件
已重命名47个文件
已删除16个文件
已修改84个文件
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:brainstorming"} |
| | | {"t":0,"agent":"a9501da","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a9501da","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":8663} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:writing-plans"} |
| | | {"t":0,"agent":"abb2829","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"abb2829","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":12576} |
| | | {"t":0,"agent":"system","event":"skill_invoked","skill_name":"superpowers:subagent-driven-development"} |
| | | {"t":0,"agent":"ab6a2d9","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ab6a2d9","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":55725} |
| | | {"t":0,"agent":"a3a7fd0","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a3a7fd0","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":11968} |
| | | {"t":0,"agent":"a0ed568","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a0ed568","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":84239} |
| | | {"t":0,"agent":"a32ad6a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a32ad6a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":155707} |
| | | {"t":0,"agent":"a4dd492","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a4dd492","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":17301} |
| | | {"t":0,"agent":"aefc20e","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aefc20e","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":180634} |
| | | {"t":0,"agent":"a18fadb","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a18fadb","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":92939} |
| | | {"t":0,"agent":"a379d3a","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a379d3a","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":19656} |
| | | {"t":0,"agent":"a7985a3","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a7985a3","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":79712} |
| | | {"t":0,"agent":"ab97ed1","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ab97ed1","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":57941} |
| | | {"t":0,"agent":"ad231d3","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ad231d3","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":119172} |
| | | {"t":0,"agent":"a7e494a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a7e494a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":53504} |
| | | {"t":0,"agent":"aba5116","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aba5116","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":94295} |
| | | {"t":0,"agent":"a8e5fbf","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a8e5fbf","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":192007} |
| | | {"t":0,"agent":"a9a1cc3","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a9a1cc3","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":29527} |
| | | {"t":0,"agent":"a581cc0","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a581cc0","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":35311} |
| | | {"t":0,"agent":"a6536cf","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a6536cf","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":154828} |
| | | {"t":0,"agent":"ab287b4","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"ab287b4","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":22379} |
| | | {"t":0,"agent":"a3bba61","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a3bba61","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":106152} |
| | | {"t":0,"agent":"a0a843a","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a0a843a","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":30220} |
| | | {"t":0,"agent":"afd8eac","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"afd8eac","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":167934} |
| | | {"t":0,"agent":"aa4ea81","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"aa4ea81","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":28896} |
| | | {"t":0,"agent":"a522225","agent_type":"superpowers:code-reviewer","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a522225","agent_type":"superpowers:code-reviewer","event":"agent_stop","success":true,"duration_ms":35164} |
| | | {"t":0,"agent":"ac7c987","agent_type":"unknown","event":"agent_stop","success":true} |
| | | {"t":0,"agent":"a405c70","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a405c70","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":59509} |
| | | {"t":0,"agent":"a0ff377","agent_type":"general-purpose","event":"agent_start","parent_mode":"none"} |
| | | {"t":0,"agent":"a0ff377","agent_type":"general-purpose","event":"agent_stop","success":true,"duration_ms":7226} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "created_at": "2026-04-12T13:52:50.251Z", |
| | | "trigger": "auto", |
| | | "active_modes": {}, |
| | | "todo_summary": { |
| | | "pending": 0, |
| | | "in_progress": 0, |
| | | "completed": 0 |
| | | }, |
| | | "wisdom_exported": false, |
| | | "background_jobs": { |
| | | "active": [], |
| | | "recent": [], |
| | | "stats": null |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "lastSentAt": "2026-04-12T12:35:52.350Z" |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "tool_name": "Read", |
| | | "tool_input_preview": "{\"file_path\":\"D:\\\\Git\\\\ShanMeiXinNengYuan\\\\Code\\\\WMS\\\\WIDESEA_WMSServer\\\\WIDESEA_WMSServer\\\\Controllers\\\\BatteryCellController.cs\"}", |
| | | "error": "File does not exist. Note: your current working directory is D:\\Git\\ShanMeiXinNengYuan\\Code.", |
| | | "timestamp": "2026-04-12T13:48:48.578Z", |
| | | "retry_count": 1 |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "updatedAt": "2026-04-12T13:54:45.455Z", |
| | | "missions": [ |
| | | { |
| | | "id": "session:9007b9ea-1eb6-4d24-8fe7-2c3a949eac88:none", |
| | | "source": "session", |
| | | "name": "none", |
| | | "objective": "Session mission", |
| | | "createdAt": "2026-04-12T13:05:45.505Z", |
| | | "updatedAt": "2026-04-12T13:54:45.455Z", |
| | | "status": "done", |
| | | "workerCount": 27, |
| | | "taskCounts": { |
| | | "total": 27, |
| | | "pending": 0, |
| | | "blocked": 0, |
| | | "inProgress": 0, |
| | | "completed": 27, |
| | | "failed": 0 |
| | | }, |
| | | "agents": [ |
| | | { |
| | | "name": "general-purpose:a9501da", |
| | | "role": "general-purpose", |
| | | "ownership": "a9501da36be20eb24", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:53:13.149Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:abb2829", |
| | | "role": "general-purpose", |
| | | "ownership": "abb28297f69440cf9", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:10:58.257Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ab6a2d9", |
| | | "role": "general-purpose", |
| | | "ownership": "ab6a2d9ed6f459274", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:13:25.065Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a3a7fd0", |
| | | "role": "general-purpose", |
| | | "ownership": "a3a7fd0c0829e5f0c", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:13:48.330Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:a0ed568", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "a0ed568f9e32bd5b0", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:17:47.626Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a32ad6a", |
| | | "role": "general-purpose", |
| | | "ownership": "a32ad6a96659ec279", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:24:23.170Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a4dd492", |
| | | "role": "general-purpose", |
| | | "ownership": "a4dd4923f28eeaea9", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:24:47.505Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:aefc20e", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "aefc20e8f3f9438f3", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:27:54.713Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a18fadb", |
| | | "role": "general-purpose", |
| | | "ownership": "a18fadb164b0dfdb8", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:29:34.186Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:a379d3a", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "a379d3a8646888a66", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:29:58.098Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a7985a3", |
| | | "role": "general-purpose", |
| | | "ownership": "a7985a337688f4971", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:31:36.395Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ab97ed1", |
| | | "role": "general-purpose", |
| | | "ownership": "ab97ed1012975ec79", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:32:42.067Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:ad231d3", |
| | | "role": "general-purpose", |
| | | "ownership": "ad231d3220b6ba05e", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:34:46.714Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a7e494a", |
| | | "role": "general-purpose", |
| | | "ownership": "a7e494aa6cfed7748", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:35:43.945Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:aba5116", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "aba5116eaa0ef6b17", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:37:25.682Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a8e5fbf", |
| | | "role": "general-purpose", |
| | | "ownership": "a8e5fbfad6a90c9c9", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:41:43.878Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a9a1cc3", |
| | | "role": "general-purpose", |
| | | "ownership": "a9a1cc30ce01dd110", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:42:18.517Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:a581cc0", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "a581cc05f79eed2ab", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:42:59.753Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a6536cf", |
| | | "role": "general-purpose", |
| | | "ownership": "a6536cf10ec91573d", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:45:40.542Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:ab287b4", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "ab287b483b80dd1ab", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:46:06.732Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a3bba61", |
| | | "role": "general-purpose", |
| | | "ownership": "a3bba6185e3ada31c", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:48:07.136Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a0a843a", |
| | | "role": "general-purpose", |
| | | "ownership": "a0a843ae77e400e58", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:48:41.191Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:afd8eac", |
| | | "role": "general-purpose", |
| | | "ownership": "afd8eacdfadd73310", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:51:34.998Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:aa4ea81", |
| | | "role": "general-purpose", |
| | | "ownership": "aa4ea817d9e391ac6", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:52:08.592Z" |
| | | }, |
| | | { |
| | | "name": "superpowers:code-reviewer:a522225", |
| | | "role": "superpowers:code-reviewer", |
| | | "ownership": "a5222258aed5f5f3d", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:52:49.666Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a405c70", |
| | | "role": "general-purpose", |
| | | "ownership": "a405c7090be2886ee", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:54:30.286Z" |
| | | }, |
| | | { |
| | | "name": "general-purpose:a0ff377", |
| | | "role": "general-purpose", |
| | | "ownership": "a0ff37729a29ea04f", |
| | | "status": "done", |
| | | "currentStep": null, |
| | | "latestUpdate": "completed", |
| | | "completedSummary": null, |
| | | "updatedAt": "2026-04-12T13:54:45.455Z" |
| | | } |
| | | ], |
| | | "timeline": [ |
| | | { |
| | | "id": "session-start:a405c7090be2886ee:2026-04-12T13:53:30.777Z", |
| | | "at": "2026-04-12T13:53:30.777Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a405c70", |
| | | "detail": "started general-purpose:a405c70", |
| | | "sourceKey": "session-start:a405c7090be2886ee" |
| | | }, |
| | | { |
| | | "id": "session-stop:a405c7090be2886ee:2026-04-12T13:54:30.286Z", |
| | | "at": "2026-04-12T13:54:30.286Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:a405c70", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a405c7090be2886ee" |
| | | }, |
| | | { |
| | | "id": "session-start:a0ff37729a29ea04f:2026-04-12T13:54:38.229Z", |
| | | "at": "2026-04-12T13:54:38.229Z", |
| | | "kind": "update", |
| | | "agent": "general-purpose:a0ff377", |
| | | "detail": "started general-purpose:a0ff377", |
| | | "sourceKey": "session-start:a0ff37729a29ea04f" |
| | | }, |
| | | { |
| | | "id": "session-stop:a0ff37729a29ea04f:2026-04-12T13:54:45.455Z", |
| | | "at": "2026-04-12T13:54:45.455Z", |
| | | "kind": "completion", |
| | | "agent": "general-purpose:a0ff377", |
| | | "detail": "completed", |
| | | "sourceKey": "session-stop:a0ff37729a29ea04f" |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "agents": [ |
| | | { |
| | | "agent_id": "a9501da36be20eb24", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:05:45.505Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:05:54.168Z", |
| | | "duration_ms": 8663 |
| | | }, |
| | | { |
| | | "agent_id": "abb28297f69440cf9", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:10:45.681Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:10:58.257Z", |
| | | "duration_ms": 12576 |
| | | }, |
| | | { |
| | | "agent_id": "ab6a2d9ed6f459274", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:12:29.340Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:13:25.065Z", |
| | | "duration_ms": 55725 |
| | | }, |
| | | { |
| | | "agent_id": "a3a7fd0c0829e5f0c", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:13:36.362Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:13:48.330Z", |
| | | "duration_ms": 11968 |
| | | }, |
| | | { |
| | | "agent_id": "a0ed568f9e32bd5b0", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:16:23.387Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:17:47.626Z", |
| | | "duration_ms": 84239 |
| | | }, |
| | | { |
| | | "agent_id": "a32ad6a96659ec279", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:21:47.463Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:24:23.170Z", |
| | | "duration_ms": 155707 |
| | | }, |
| | | { |
| | | "agent_id": "a4dd4923f28eeaea9", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:24:30.204Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:24:47.505Z", |
| | | "duration_ms": 17301 |
| | | }, |
| | | { |
| | | "agent_id": "aefc20e8f3f9438f3", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:24:54.079Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:27:54.713Z", |
| | | "duration_ms": 180634 |
| | | }, |
| | | { |
| | | "agent_id": "a18fadb164b0dfdb8", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:28:01.247Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:29:34.186Z", |
| | | "duration_ms": 92939 |
| | | }, |
| | | { |
| | | "agent_id": "a379d3a8646888a66", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:29:38.442Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:29:58.098Z", |
| | | "duration_ms": 19656 |
| | | }, |
| | | { |
| | | "agent_id": "a7985a337688f4971", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:30:16.683Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:31:36.395Z", |
| | | "duration_ms": 79712 |
| | | }, |
| | | { |
| | | "agent_id": "ab97ed1012975ec79", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:31:44.126Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:32:42.067Z", |
| | | "duration_ms": 57941 |
| | | }, |
| | | { |
| | | "agent_id": "ad231d3220b6ba05e", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:32:47.542Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:34:46.714Z", |
| | | "duration_ms": 119172 |
| | | }, |
| | | { |
| | | "agent_id": "a7e494aa6cfed7748", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:34:50.441Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:35:43.945Z", |
| | | "duration_ms": 53504 |
| | | }, |
| | | { |
| | | "agent_id": "aba5116eaa0ef6b17", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:35:51.387Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:37:25.682Z", |
| | | "duration_ms": 94295 |
| | | }, |
| | | { |
| | | "agent_id": "a8e5fbfad6a90c9c9", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:38:31.871Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:41:43.878Z", |
| | | "duration_ms": 192007 |
| | | }, |
| | | { |
| | | "agent_id": "a9a1cc30ce01dd110", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:41:48.990Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:42:18.517Z", |
| | | "duration_ms": 29527 |
| | | }, |
| | | { |
| | | "agent_id": "a581cc05f79eed2ab", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:42:24.442Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:42:59.753Z", |
| | | "duration_ms": 35311 |
| | | }, |
| | | { |
| | | "agent_id": "a6536cf10ec91573d", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:43:05.714Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:45:40.542Z", |
| | | "duration_ms": 154828 |
| | | }, |
| | | { |
| | | "agent_id": "ab287b483b80dd1ab", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:45:44.353Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:46:06.732Z", |
| | | "duration_ms": 22379 |
| | | }, |
| | | { |
| | | "agent_id": "a3bba6185e3ada31c", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:46:20.984Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:48:07.136Z", |
| | | "duration_ms": 106152 |
| | | }, |
| | | { |
| | | "agent_id": "a0a843ae77e400e58", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:48:10.971Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:48:41.191Z", |
| | | "duration_ms": 30220 |
| | | }, |
| | | { |
| | | "agent_id": "afd8eacdfadd73310", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:48:47.064Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:51:34.998Z", |
| | | "duration_ms": 167934 |
| | | }, |
| | | { |
| | | "agent_id": "aa4ea817d9e391ac6", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:51:39.696Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:52:08.592Z", |
| | | "duration_ms": 28896 |
| | | }, |
| | | { |
| | | "agent_id": "a5222258aed5f5f3d", |
| | | "agent_type": "superpowers:code-reviewer", |
| | | "started_at": "2026-04-12T13:52:14.502Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:52:49.666Z", |
| | | "duration_ms": 35164 |
| | | }, |
| | | { |
| | | "agent_id": "a405c7090be2886ee", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:53:30.777Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:54:30.286Z", |
| | | "duration_ms": 59509 |
| | | }, |
| | | { |
| | | "agent_id": "a0ff37729a29ea04f", |
| | | "agent_type": "general-purpose", |
| | | "started_at": "2026-04-12T13:54:38.229Z", |
| | | "parent_mode": "none", |
| | | "status": "completed", |
| | | "completed_at": "2026-04-12T13:54:45.455Z", |
| | | "duration_ms": 7226 |
| | | } |
| | | ], |
| | | "total_spawned": 27, |
| | | "total_completed": 27, |
| | | "total_failed": 0, |
| | | "last_updated": "2026-04-12T13:54:45.571Z" |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | {"reason":"idle timeout","timestamp":1776000741677} |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <h2>æé®æ¾ç¤ºä¸ç¶ææ§å¶</h2> |
| | | <p class="subtitle">æ ¹æ®åºåç¶ææ§å¶æä½æé®çæ¾ç¤º</p> |
| | | |
| | | <div class="section"> |
| | | <h3>åºæ¯åæ</h3> |
| | | <p class="subtitle">ä¸åç¶æçåºåå¯è½å
许æç¦æ¢æäºæä½</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">åºåç¶ææä¸¾</div> |
| | | <div class="mockup-body"> |
| | | <div class="status-list"> |
| | | <div class="status-item"> |
| | | <span class="status-badge status-badge-idle">å¾
å
¥åº</span> |
| | | <div class="status-desc">æçå·²å建ä½å°æªå®æå
¥åº</div> |
| | | </div> |
| | | <div class="status-item"> |
| | | <span class="status-badge status-badge-instock">å¨åº</span> |
| | | <div class="status-desc">æçæ£å¸¸å¨åºä¸</div> |
| | | </div> |
| | | <div class="status-item"> |
| | | <span class="status-badge status-badge-outbound">åºåºä¸</span> |
| | | <div class="status-desc">æçæ£å¨åºåºæµç¨ä¸</div> |
| | | </div> |
| | | <div class="status-item"> |
| | | <span class="status-badge status-badge-lock">éå®</span> |
| | | <div class="status-desc">æç被éå®ï¼ä¸å¯æä½</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>æé®æ¾ç¤ºçç¥éæ©</h3> |
| | | <p class="subtitle">ä¸åçç¥çç¨æ·ä½éªåå®ç°å¤æåº¦</p> |
| | | |
| | | <div class="options"> |
| | | <div class="option" data-choice="always" onclick="toggleSelect(this)"> |
| | | <div class="letter">A</div> |
| | | <div class="content"> |
| | | <h3>å§ç»æ¾ç¤º</h3> |
| | | <p>æææä½æé®å§ç»æ¾ç¤ºï¼ç¹å»åå¨å¼¹çªä¸æ ¡éªç¶æ</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>å®ç°ç®å</li><li>ç¨æ·æ¸
æ¥æåªäºåè½</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>å¯è½äº§çæ æç¹å»</li><li>ä½éªè¾å·®</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="dynamic" onclick="toggleSelect(this)"> |
| | | <div class="letter">B</div> |
| | | <div class="content"> |
| | | <h3>卿æ¾ç¤º</h3> |
| | | <p>æ ¹æ®åºåç¶æå¨ææ¾ç¤º/éèæé®</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>ç颿¸
æ°</li><li>åå°è¯¯æä½</li><li>ä½éªæ´å¥½</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>éè¦ç»´æ¤ç¶ææ å°</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="disable" onclick="toggleSelect(this)"> |
| | | <div class="letter">C</div> |
| | | <div class="content"> |
| | | <h3>æ¾ç¤ºå¹¶ç¦ç¨</h3> |
| | | <p>æææé®é½æ¾ç¤ºï¼ä½ä¸å¯ç¨çæ¾ç¤ºä¸ºç¦ç¨ç¶æ</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>ç¨æ·ç¥éææ¤åè½</li><li>æ¸
æ¥ä¸ºä½ä¸å¯ç¨</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>çé¢å¯è½æ¥æ¤</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>示ä¾ï¼å¨ææ¾ç¤ºææ</h3> |
| | | <p class="subtitle">ä¸åç¶æä¸çæé®æ¾ç¤ºæ
åµ</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼ä¸åç¶æçæé®æ¾ç¤º</div> |
| | | <div class="mockup-body"> |
| | | <table class="mock-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>æçç¼å·</th> |
| | | <th>åºåç¶æ</th> |
| | | <th>æä½æé®</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>P001</td> |
| | | <td><span class="status-badge status-badge-idle">å¾
å
¥åº</span></td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">è¿ç«</button> |
| | | <button class="mock-btn-inline mock-btn-disabled">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>P002</td> |
| | | <td><span class="status-badge status-badge-instock">å¨åº</span></td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-disabled">è¿ç«</button> |
| | | <button class="mock-btn-inline mock-btn-success">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>P003</td> |
| | | <td><span class="status-badge status-badge-lock">éå®</span></td> |
| | | <td> |
| | | <span class="text-muted">ææ å¯æ§è¡æä½</span> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <style> |
| | | .status-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | } |
| | | .status-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 12px; |
| | | background: #fafafa; |
| | | border-radius: 6px; |
| | | } |
| | | .status-badge { |
| | | padding: 4px 12px; |
| | | border-radius: 4px; |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | white-space: nowrap; |
| | | } |
| | | .status-badge-idle { |
| | | background: #e3f2fd; |
| | | color: #1976d2; |
| | | } |
| | | .status-badge-instock { |
| | | background: #e8f5e9; |
| | | color: #388e3c; |
| | | } |
| | | .status-badge-outbound { |
| | | background: #fff3e0; |
| | | color: #f57c00; |
| | | } |
| | | .status-badge-lock { |
| | | background: #ffebee; |
| | | color: #d32f2f; |
| | | } |
| | | .status-desc { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | .mock-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 13px; |
| | | } |
| | | .mock-table th, .mock-table td { |
| | | border: 1px solid #e0e0e0; |
| | | padding: 10px 12px; |
| | | text-align: left; |
| | | } |
| | | .mock-table th { |
| | | background: #f5f5f5; |
| | | font-weight: 600; |
| | | } |
| | | .mock-table tbody tr:nth-child(even) { |
| | | background: #fafafa; |
| | | } |
| | | .mock-btn-inline { |
| | | padding: 6px 14px; |
| | | font-size: 13px; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | background: white; |
| | | cursor: pointer; |
| | | margin-right: 8px; |
| | | } |
| | | .mock-btn-primary { |
| | | background: #1f5eff; |
| | | color: white; |
| | | border-color: #1f5eff; |
| | | } |
| | | .mock-btn-success { |
| | | background: #67c23a; |
| | | color: white; |
| | | border-color: #67c23a; |
| | | } |
| | | .mock-btn-disabled { |
| | | background: #f5f5f5; |
| | | color: #c0c4cc; |
| | | border-color: #e4e7ed; |
| | | cursor: not-allowed; |
| | | } |
| | | .text-muted { |
| | | color: #909399; |
| | | font-size: 13px; |
| | | } |
| | | .pros-cons { |
| | | display: flex; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | } |
| | | .pros, .cons { |
| | | flex: 1; |
| | | font-size: 13px; |
| | | } |
| | | .pros h4 { |
| | | color: #4caf50; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .cons h4 { |
| | | color: #f56c6c; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .pros ul, .cons ul { |
| | | margin: 0; |
| | | padding-left: 16px; |
| | | } |
| | | .pros li, .cons li { |
| | | margin-bottom: 4px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <h2>é误å¤çä¸åé¦</h2> |
| | | <p class="subtitle">MESæ¥å£è°ç¨å¤±è´¥æ¶çå¤çæ¹å¼</p> |
| | | |
| | | <div class="section"> |
| | | <h3>åºæ¯åæ</h3> |
| | | <p class="subtitle">MESæ¥å£å¯è½å ç½ç»ãMESç³»ç»å¼å¸¸ãåæ°é误çåå 失败</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">常è§é误类å</div> |
| | | <div class="mockup-body"> |
| | | <div class="error-list"> |
| | | <div class="error-item"> |
| | | <span class="error-icon error-icon-network">ð¡</span> |
| | | <div class="error-content"> |
| | | <div class="error-title">ç½ç»è¶
æ¶</div> |
| | | <div class="error-desc">MESæå¡å¨æ ååºæè¿æ¥è¶
æ¶</div> |
| | | </div> |
| | | </div> |
| | | <div class="error-item"> |
| | | <span class="error-icon error-icon-server">â ï¸</span> |
| | | <div class="error-content"> |
| | | <div class="error-title">MESä¸å¡é误</div> |
| | | <div class="error-desc">æçä¸åå¨ãçµè¯å·²ç»å®çä¸å¡æ ¡éªå¤±è´¥</div> |
| | | </div> |
| | | </div> |
| | | <div class="error-item"> |
| | | <span class="error-icon error-icon-auth">ð</span> |
| | | <div class="error-content"> |
| | | <div class="error-title">认è¯å¤±è´¥</div> |
| | | <div class="error-desc">MESæ¥å£è®¤è¯ä¿¡æ¯è¿æææ æ</div> |
| | | </div> |
| | | </div> |
| | | <div class="error-item"> |
| | | <span class="error-icon error-icon-unknown">â</span> |
| | | <div class="error-content"> |
| | | <div class="error-title">æªç¥é误</div> |
| | | <div class="error-desc">MESç³»ç»è¿åå¼å¸¸ææªé¢æçååº</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>é误å¤çæ¹å¼éæ©</h3> |
| | | <p class="subtitle">éæ©é忍ä¸å¡çå¤ççç¥</p> |
| | | |
| | | <div class="options"> |
| | | <div class="option" data-choice="simple" onclick="toggleSelect(this)"> |
| | | <div class="letter">A</div> |
| | | <div class="content"> |
| | | <h3>ç®åæç¤º</h3> |
| | | <p>è°ç¨å¤±è´¥åå¼¹åºé误æç¤ºï¼ç¨æ·èªè¡å³å®æ¯å¦éè¯</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>å®ç°ç®å</li><li>ç¨æ·å®å
¨æ§å¶</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>éè¦æå¨éè¯</li><li>容æéæ¼</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="auto-retry" onclick="toggleSelect(this)"> |
| | | <div class="letter">B</div> |
| | | <div class="content"> |
| | | <h3>èªå¨éè¯</h3> |
| | | <p>失败åèªå¨éè¯æå®æ¬¡æ°ï¼å¦3次ï¼ï¼ä»å¤±è´¥åæç¤ºç¨æ·</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>å¤ç临æ¶ç½ç»é®é¢</li><li>æé«æåç</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>å¯è½é夿§è¡ä¸å¡</li><li>å¢å ååºæ¶é´</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="queue" onclick="toggleSelect(this)"> |
| | | <div class="letter">C</div> |
| | | <div class="content"> |
| | | <h3>弿¥éå</h3> |
| | | <p>失败åå å
¥éè¯éåï¼åå°å®æ¶ä»»å¡èªå¨éè¯</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>ä¸é»å¡ç¨æ·æä½</li><li>å¯è¿½æº¯éè¯è®°å½</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>å®ç°å¤æ</li><li>éè¦é¢å¤çæ§</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>é误æç¤ºå±ç¤º</h3> |
| | | <p class="subtitle">ç¨æ·çå°çéè¯¯ä¿¡æ¯æ ·å¼</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼é误æç¤ºæ ·å¼</div> |
| | | <div class="mockup-body"> |
| | | <div class="error-toast error-toast-error"> |
| | | <span class="error-toast-icon">â</span> |
| | | <div class="error-toast-content"> |
| | | <div class="error-toast-title">æä½å¤±è´¥</div> |
| | | <div class="error-toast-message">MESæå¡å¨è¿æ¥è¶
æ¶ï¼è¯·æ£æ¥ç½ç»åéè¯</div> |
| | | </div> |
| | | <button class="error-toast-retry">éè¯</button> |
| | | </div> |
| | | <div style="height: 12px;"></div> |
| | | <div class="error-toast error-toast-warning"> |
| | | <span class="error-toast-icon">â </span> |
| | | <div class="error-toast-content"> |
| | | <div class="error-toast-title">ä¸å¡æ ¡éªå¤±è´¥</div> |
| | | <div class="error-toast-message">æç P001 å¨MESä¸ä¸åå¨ï¼è¯·å
å¨MESä¸å建</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <style> |
| | | .error-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 12px; |
| | | } |
| | | .error-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | gap: 12px; |
| | | padding: 12px; |
| | | background: #fafafa; |
| | | border-radius: 6px; |
| | | border: 1px solid #e0e0e0; |
| | | } |
| | | .error-icon { |
| | | font-size: 24px; |
| | | flex-shrink: 0; |
| | | } |
| | | .error-content { |
| | | flex: 1; |
| | | } |
| | | .error-title { |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | margin-bottom: 4px; |
| | | } |
| | | .error-desc { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | .pros-cons { |
| | | display: flex; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | } |
| | | .pros, .cons { |
| | | flex: 1; |
| | | font-size: 13px; |
| | | } |
| | | .pros h4 { |
| | | color: #4caf50; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .cons h4 { |
| | | color: #f56c6c; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .pros ul, .cons ul { |
| | | margin: 0; |
| | | padding-left: 16px; |
| | | } |
| | | .pros li, .cons li { |
| | | margin-bottom: 4px; |
| | | } |
| | | .error-toast { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 14px 16px; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0,0,0,0.1); |
| | | } |
| | | .error-toast-error { |
| | | background: #fef0f0; |
| | | border: 1px solid #fde2e2; |
| | | } |
| | | .error-toast-warning { |
| | | background: #fdf6ec; |
| | | border: 1px solid #f5dab1; |
| | | } |
| | | .error-toast-icon { |
| | | font-size: 20px; |
| | | flex-shrink: 0; |
| | | } |
| | | .error-toast-error .error-toast-icon { |
| | | color: #f56c6c; |
| | | } |
| | | .error-toast-warning .error-toast-icon { |
| | | color: #e6a23c; |
| | | } |
| | | .error-toast-content { |
| | | flex: 1; |
| | | } |
| | | .error-toast-title { |
| | | font-weight: 600; |
| | | font-size: 14px; |
| | | margin-bottom: 4px; |
| | | } |
| | | .error-toast-error .error-toast-title { |
| | | color: #f56c6c; |
| | | } |
| | | .error-toast-warning .error-toast-title { |
| | | color: #e6a23c; |
| | | } |
| | | .error-toast-message { |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | .error-toast-retry { |
| | | padding: 6px 16px; |
| | | background: #1f5eff; |
| | | color: white; |
| | | border: none; |
| | | border-radius: 4px; |
| | | font-size: 13px; |
| | | cursor: pointer; |
| | | flex-shrink: 0; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <h2>åºå页颿ä½å设计</h2> |
| | | <p class="subtitle">为åºåä¿¡æ¯ååºåæç»é¡µé¢æ·»å MESæ¥å£æä½æé®</p> |
| | | |
| | | <div class="section"> |
| | | <h3>1. åºåä¿¡æ¯é¡µé¢ - æççº§å«æä½</h3> |
| | | <p class="subtitle">å½å页颿¾ç¤ºæçç¼å·ãè´§ä½ç¼å·çä¿¡æ¯ï¼éè¦æ·»å è¿ç«/åºç«æä½</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼åºåä¿¡æ¯è¡¨æ ¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mock-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>æçç¼å·</th> |
| | | <th>è´§ä½ç¼å·</th> |
| | | <th>ä»åº</th> |
| | | <th>å建人</th> |
| | | <th class="op-col">æä½</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>P001</td> |
| | | <td>A01-01-01</td> |
| | | <td>ä¸å·ä»</td> |
| | | <td>å¼ ä¸</td> |
| | | <td class="op-col"> |
| | | <button class="mock-button mock-btn-sm">è¿ç«</button> |
| | | <button class="mock-button mock-btn-sm mock-btn-primary">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>P002</td> |
| | | <td>A01-01-02</td> |
| | | <td>ä¸å·ä»</td> |
| | | <td>æå</td> |
| | | <td class="op-col"> |
| | | <button class="mock-button mock-btn-sm">è¿ç«</button> |
| | | <button class="mock-button mock-btn-sm mock-btn-primary">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>2. åºåæç»é¡µé¢ - çµè¯çº§å«æä½</h3> |
| | | <p class="subtitle">å½å页颿¾ç¤ºç©æç¼å·ãçµè¯ç çä¿¡æ¯ï¼éè¦æ·»å ç»å®/è§£ç»/NG䏿¥æä½</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼åºåæç»è¡¨æ ¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mock-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>ç©æç¼å·</th> |
| | | <th>ç©æåç§°</th> |
| | | <th>çµè¯ç </th> |
| | | <th>åºåæ°é</th> |
| | | <th>ç¶æ</th> |
| | | <th class="op-col">æä½</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>M001</td> |
| | | <td>ä¸å
éçµæ± </td> |
| | | <td>SN20240101001</td> |
| | | <td>100</td> |
| | | <td><span class="mock-tag mock-tag-success">æ£å¸¸</span></td> |
| | | <td class="op-col"> |
| | | <button class="mock-button mock-btn-sm mock-btn-primary">ç»å®</button> |
| | | <button class="mock-button mock-btn-sm">è§£ç»</button> |
| | | <button class="mock-button mock-btn-sm mock-btn-danger">NG䏿¥</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>M001</td> |
| | | <td>ä¸å
éçµæ± </td> |
| | | <td>SN20240101002</td> |
| | | <td>100</td> |
| | | <td><span class="mock-tag mock-tag-warning">å¼å¸¸</span></td> |
| | | <td class="op-col"> |
| | | <button class="mock-button mock-btn-sm mock-btn-primary">ç»å®</button> |
| | | <button class="mock-button mock-btn-sm">è§£ç»</button> |
| | | <button class="mock-button mock-btn-sm mock-btn-danger">NG䏿¥</button> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>æé®æä½ç¡®è®¤é®é¢</h3> |
| | | <p class="subtitle">MESæ¥å£è°ç¨å¯è½å¤±è´¥æéè¦é¢å¤åæ°</p> |
| | | |
| | | <div class="options"> |
| | | <div class="option" data-choice="direct" onclick="toggleSelect(this)"> |
| | | <div class="letter">A</div> |
| | | <div class="content"> |
| | | <h3>ç´æ¥è°ç¨</h3> |
| | | <p>ç¹å»æé®ç´æ¥è°ç¨MESæ¥å£ï¼æå/失败åå¼¹åºæç¤º</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>æä½ç®åå¿«æ·</li><li>éåé«é¢æä½</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>æ æ³è¾å
¥é¢å¤åæ°</li><li>é误åé¾ä»¥éè¯</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="dialog" onclick="toggleSelect(this)"> |
| | | <div class="letter">B</div> |
| | | <div class="content"> |
| | | <h3>å¼¹çªç¡®è®¤</h3> |
| | | <p>ç¹å»åå¼¹åºç¡®è®¤å¯¹è¯æ¡ï¼æ¾ç¤ºåæ°å¹¶å¯ä¿®æ¹ï¼ç¡®è®¤åè°ç¨</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>å¯é¢è§/ä¿®æ¹åæ°</li><li>鲿¢è¯¯æä½</li><li>æ¾ç¤ºè¯¦ç»é误信æ¯</li></ul></div> |
| | | <div class="cons"><h4>缺ç¹</h4><ul><li>æä½æ¥éª¤å¤</li><li>å½±åæç</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <style> |
| | | .mock-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 13px; |
| | | } |
| | | .mock-table th, .mock-table td { |
| | | border: 1px solid #e0e0e0; |
| | | padding: 10px 12px; |
| | | text-align: left; |
| | | } |
| | | .mock-table th { |
| | | background: #f5f5f5; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .mock-table .op-col { |
| | | width: 180px; |
| | | text-align: center; |
| | | } |
| | | .mock-table tbody tr:nth-child(even) { |
| | | background: #fafafa; |
| | | } |
| | | .mock-btn-sm { |
| | | padding: 5px 12px; |
| | | font-size: 12px; |
| | | margin: 0 3px; |
| | | } |
| | | .mock-btn-primary { |
| | | background: #1f5eff; |
| | | color: white; |
| | | border: none; |
| | | } |
| | | .mock-btn-danger { |
| | | background: #f56c6c; |
| | | color: white; |
| | | border: none; |
| | | } |
| | | .mock-tag { |
| | | display: inline-block; |
| | | padding: 3px 8px; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | } |
| | | .mock-tag-success { |
| | | background: #e1f5e1; |
| | | color: #4caf50; |
| | | } |
| | | .mock-tag-warning { |
| | | background: #fff3e0; |
| | | color: #ff9800; |
| | | } |
| | | .pros-cons { |
| | | display: flex; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | } |
| | | .pros, .cons { |
| | | flex: 1; |
| | | font-size: 13px; |
| | | } |
| | | .pros h4 { |
| | | color: #4caf50; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .cons h4 { |
| | | color: #f56c6c; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .pros ul, .cons ul { |
| | | margin: 0; |
| | | padding-left: 16px; |
| | | } |
| | | .pros li, .cons li { |
| | | margin-bottom: 4px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <h2>æä½åå¸å±ä¼å</h2> |
| | | <p class="subtitle">æé®å¨å䏿æ¾ç¤ºï¼è®¾ç½®åºå®å®½åº¦é²æ¢çé¢åå½¢</p> |
| | | |
| | | <div class="section"> |
| | | <h3>1. åºåä¿¡æ¯é¡µé¢ - æççº§å«æä½</h3> |
| | | <p class="subtitle">æä½ååºå®å®½åº¦ï¼æé®æ¨ªåæå</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼åºåä¿¡æ¯è¡¨æ ¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mock-table"> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 120px;">æçç¼å·</th> |
| | | <th style="width: 150px;">è´§ä½ç¼å·</th> |
| | | <th style="width: 100px;">ä»åº</th> |
| | | <th style="width: 90px;">å建人</th> |
| | | <th style="width: 200px;">æä½</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>P001</td> |
| | | <td>A01-01-01</td> |
| | | <td>ä¸å·ä»</td> |
| | | <td>å¼ ä¸</td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">è¿ç«</button> |
| | | <button class="mock-btn-inline mock-btn-success">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>P002</td> |
| | | <td>A01-01-02</td> |
| | | <td>ä¸å·ä»</td> |
| | | <td>æå</td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">è¿ç«</button> |
| | | <button class="mock-btn-inline mock-btn-success">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>P003</td> |
| | | <td>B01-01-01</td> |
| | | <td>äºå·ä»</td> |
| | | <td>çäº</td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">è¿ç«</button> |
| | | <button class="mock-btn-inline mock-btn-success">åºç«</button> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>2. åºåæç»é¡µé¢ - çµè¯çº§å«æä½</h3> |
| | | <p class="subtitle">ä¸ä¸ªæé®æ¨ªåæåï¼æä½ååºå®å®½åº¦</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼åºåæç»è¡¨æ ¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mock-table"> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 100px;">ç©æç¼å·</th> |
| | | <th style="width: 140px;">ç©æåç§°</th> |
| | | <th style="width: 150px;">çµè¯ç </th> |
| | | <th style="width: 90px;">æ°é</th> |
| | | <th style="width: 80px;">ç¶æ</th> |
| | | <th style="width: 280px;">æä½</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>M001</td> |
| | | <td>ä¸å
éçµæ± </td> |
| | | <td>SN20240101001</td> |
| | | <td>100</td> |
| | | <td><span class="mock-tag mock-tag-success">æ£å¸¸</span></td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">ç»å®</button> |
| | | <button class="mock-btn-inline mock-btn-warning">è§£ç»</button> |
| | | <button class="mock-btn-inline mock-btn-danger">NG䏿¥</button> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td>M001</td> |
| | | <td>ä¸å
éçµæ± </td> |
| | | <td>SN20240101002</td> |
| | | <td>100</td> |
| | | <td><span class="mock-tag mock-tag-warning">å¼å¸¸</span></td> |
| | | <td> |
| | | <button class="mock-btn-inline mock-btn-primary">ç»å®</button> |
| | | <button class="mock-btn-inline mock-btn-warning">è§£ç»</button> |
| | | <button class="mock-btn-inline mock-btn-danger">NG䏿¥</button> |
| | | </td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>å¼¹çªç¡®è®¤äº¤äºæµç¨</h3> |
| | | <p class="subtitle">ç¹å»æé® â å¼¹åºç¡®è®¤å¯¹è¯æ¡ â 确认åè°ç¨MESæ¥å£</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">é¢è§ï¼ç¡®è®¤å¯¹è¯æ¡ç¤ºä¾</div> |
| | | <div class="mockup-body"> |
| | | <div class="mock-dialog"> |
| | | <div class="mock-dialog-header"> |
| | | <span class="mock-dialog-title">确认æä½</span> |
| | | <span class="mock-dialog-close">â</span> |
| | | </div> |
| | | <div class="mock-dialog-body"> |
| | | <p class="mock-dialog-text">æ¨å³å°æ§è¡ <strong>æçè¿ç«</strong> æä½</p> |
| | | <div class="mock-dialog-info"> |
| | | <div class="mock-info-row"> |
| | | <span class="mock-info-label">æçç ï¼</span> |
| | | <span class="mock-info-value">P001</span> |
| | | </div> |
| | | <div class="mock-info-row"> |
| | | <span class="mock-info-label">设å¤ç¼ç ï¼</span> |
| | | <span class="mock-info-value">WCS_001</span> |
| | | </div> |
| | | <div class="mock-info-row"> |
| | | <span class="mock-info-label">èµæºç¼ç ï¼</span> |
| | | <span class="mock-info-value">RESOURCE_001</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="mock-dialog-footer"> |
| | | <button class="mock-btn-inline mock-btn-default">åæ¶</button> |
| | | <button class="mock-btn-inline mock-btn-primary">确认æ§è¡</button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>ä¸ä¸ä¸ªé®é¢</h3> |
| | | <p class="subtitle">å
³äºMESæ¥å£è°ç¨çåæ°è·åæ¹å¼</p> |
| | | |
| | | <div class="options"> |
| | | <div class="option" data-choice="config" onclick="toggleSelect(this)"> |
| | | <div class="letter">A</div> |
| | | <div class="content"> |
| | | <h3>ç³»ç»é
ç½®</h3> |
| | | <p>设å¤ç¼ç ãèµæºç¼ç çåæ°ä»ç³»ç»é
ç½®ä¸è¯»åï¼ç¨æ·æ éè¾å
¥</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>æä½ç®å</li><li>åå°äººä¸ºé误</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="input" onclick="toggleSelect(this)"> |
| | | <div class="letter">B</div> |
| | | <div class="content"> |
| | | <h3>å¼¹çªè¾å
¥</h3> |
| | | <p>å¨ç¡®è®¤å¯¹è¯æ¡ä¸æ¾ç¤ºåæ°è¾å
¥æ¡ï¼å
è®¸ç¨æ·ä¿®æ¹é»è®¤å¼</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>çµæ´»æ§é«</li><li>éåºä¸ååºæ¯</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="hybrid" onclick="toggleSelect(this)"> |
| | | <div class="letter">C</div> |
| | | <div class="content"> |
| | | <h3>æ··åæ¨¡å¼</h3> |
| | | <p>å
³é®åæ°ä»é
置读åï¼å¯éåæ°å¨å¼¹çªä¸æä¾è¾å
¥</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>平衡ç®ä¾¿æ§åçµæ´»æ§</li><li>å¸¸è§æä½å¿«éï¼ç¹æ®åºæ¯å¯è°æ´</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <style> |
| | | .mock-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 13px; |
| | | table-layout: fixed; |
| | | } |
| | | .mock-table th, .mock-table td { |
| | | border: 1px solid #e0e0e0; |
| | | padding: 10px 12px; |
| | | text-align: left; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | .mock-table th { |
| | | background: #f5f5f5; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .mock-table tbody tr:nth-child(even) { |
| | | background: #fafafa; |
| | | } |
| | | .mock-table tbody tr:hover { |
| | | background: #f0f7ff; |
| | | } |
| | | .mock-btn-inline { |
| | | padding: 6px 14px; |
| | | font-size: 13px; |
| | | border: 1px solid #dcdfe6; |
| | | background: white; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | margin-right: 8px; |
| | | transition: all 0.2s; |
| | | } |
| | | .mock-btn-inline:last-child { |
| | | margin-right: 0; |
| | | } |
| | | .mock-btn-inline:hover { |
| | | opacity: 0.85; |
| | | } |
| | | .mock-btn-primary { |
| | | background: #1f5eff; |
| | | color: white; |
| | | border-color: #1f5eff; |
| | | } |
| | | .mock-btn-success { |
| | | background: #67c23a; |
| | | color: white; |
| | | border-color: #67c23a; |
| | | } |
| | | .mock-btn-warning { |
| | | background: #e6a23c; |
| | | color: white; |
| | | border-color: #e6a23c; |
| | | } |
| | | .mock-btn-danger { |
| | | background: #f56c6c; |
| | | color: white; |
| | | border-color: #f56c6c; |
| | | } |
| | | .mock-btn-default { |
| | | background: white; |
| | | color: #606266; |
| | | border-color: #dcdfe6; |
| | | } |
| | | .mock-tag { |
| | | display: inline-block; |
| | | padding: 3px 8px; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | } |
| | | .mock-tag-success { |
| | | background: #e1f5e1; |
| | | color: #4caf50; |
| | | } |
| | | .mock-tag-warning { |
| | | background: #fff3e0; |
| | | color: #ff9800; |
| | | } |
| | | .mock-dialog { |
| | | width: 420px; |
| | | margin: 20px auto; |
| | | border: 1px solid #e0e0e0; |
| | | border-radius: 8px; |
| | | box-shadow: 0 4px 12px rgba(0,0,0,0.1); |
| | | background: white; |
| | | } |
| | | .mock-dialog-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #e0e0e0; |
| | | background: #f8fafc; |
| | | } |
| | | .mock-dialog-title { |
| | | font-weight: 600; |
| | | font-size: 16px; |
| | | color: #303133; |
| | | } |
| | | .mock-dialog-close { |
| | | cursor: pointer; |
| | | color: #909399; |
| | | font-size: 18px; |
| | | } |
| | | .mock-dialog-body { |
| | | padding: 20px; |
| | | } |
| | | .mock-dialog-text { |
| | | margin: 0 0 16px 0; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | .mock-dialog-info { |
| | | background: #f8fafc; |
| | | border-radius: 6px; |
| | | padding: 12px 16px; |
| | | } |
| | | .mock-info-row { |
| | | display: flex; |
| | | margin-bottom: 10px; |
| | | font-size: 13px; |
| | | } |
| | | .mock-info-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | .mock-info-label { |
| | | color: #909399; |
| | | width: 80px; |
| | | } |
| | | .mock-info-value { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | .mock-dialog-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 12px; |
| | | padding: 16px 20px; |
| | | border-top: 1px solid #e0e0e0; |
| | | background: #f8fafc; |
| | | } |
| | | .pros-cons { |
| | | display: flex; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | } |
| | | .pros, .cons { |
| | | flex: 1; |
| | | font-size: 13px; |
| | | } |
| | | .pros h4 { |
| | | color: #4caf50; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .pros ul { |
| | | margin: 0; |
| | | padding-left: 16px; |
| | | } |
| | | .pros li { |
| | | margin-bottom: 4px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <h2>ç¶æä¸æä½æ å°è§å</h2> |
| | | <p class="subtitle">å®ä¹åªäºåºåç¶æä¸å
许æ§è¡åªäºMESæä½</p> |
| | | |
| | | <div class="section"> |
| | | <h3>åºåä¿¡æ¯é¡µé¢ - æç级å«</h3> |
| | | <p class="subtitle">è¿ç«/åºç«æä½çè§¦åæ¡ä»¶</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">ç¶ææ å°è¡¨ï¼è¯·å¨æµè§å¨ä¸éæ©ï¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mapping-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>åºåç¶æ</th> |
| | | <th>è¿ç«æä½</th> |
| | | <th>åºç«æä½</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><span class="status-tag status-idle">å¾
å
¥åº</span></td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | </tr> |
| | | <tr> |
| | | <td><span class="status-tag status-instock">å¨åº</span></td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | </tr> |
| | | <tr> |
| | | <td><span class="status-tag status-outbound">åºåºä¸</span></td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | </tr> |
| | | <tr> |
| | | <td><span class="status-tag status-lock">éå®</span></td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | <p class="hint">æç¤ºï¼ä»¥ä¸æ¯é»è®¤å»ºè®®ï¼è¯·å¨ç»ç«¯ä¸åè¯æéè¦è°æ´çå°æ¹</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>åºåæç»é¡µé¢ - çµè¯çº§å«</h3> |
| | | <p class="subtitle">ç»å®/è§£ç»/NG䏿¥æä½çè§¦åæ¡ä»¶</p> |
| | | |
| | | <div class="mockup"> |
| | | <div class="mockup-header">ç¶ææ å°è¡¨ï¼è¯·å¨æµè§å¨ä¸éæ©ï¼</div> |
| | | <div class="mockup-body"> |
| | | <table class="mapping-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>çµè¯ç¶æ</th> |
| | | <th>ç»å®æä½</th> |
| | | <th>è§£ç»æä½</th> |
| | | <th>NG䏿¥</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><span class="status-tag status-normal">æ£å¸¸</span></td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | </tr> |
| | | <tr> |
| | | <td><span class="status-tag status-exception">å¼å¸¸</span></td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | <td><input type="checkbox" checked> å
许</td> |
| | | </tr> |
| | | <tr> |
| | | <td><span class="status-tag status-locked">å·²éå®</span></td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | <td><input type="checkbox"> ç¦æ¢</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | <p class="hint">æç¤ºï¼ä»¥ä¸æ¯é»è®¤å»ºè®®ï¼è¯·å¨ç»ç«¯ä¸åè¯æéè¦è°æ´çå°æ¹</p> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section"> |
| | | <h3>ä¸ä¸ä¸ªé®é¢</h3> |
| | | <p class="subtitle">æ¯å¦éè¦è®°å½MESæ¥å£è°ç¨æ¥å¿ï¼</p> |
| | | |
| | | <div class="options"> |
| | | <div class="option" data-choice="log-full" onclick="toggleSelect(this)"> |
| | | <div class="letter">A</div> |
| | | <div class="content"> |
| | | <h3>宿´æ¥å¿</h3> |
| | | <p>è®°å½æ¯æ¬¡MESæ¥å£è°ç¨ç宿´ä¿¡æ¯ï¼è¯·æ±ãååºãèæ¶ãç»æï¼</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>便äºé®é¢ææ¥</li><li>æ¯æå®¡è®¡è¿½æº¯</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="log-simple" onclick="toggleSelect(this)"> |
| | | <div class="letter">B</div> |
| | | <div class="content"> |
| | | <h3>ç®åæ¥å¿</h3> |
| | | <p>ä»
è®°å½è°ç¨æå/å¤±è´¥ç¶æåé误信æ¯</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>åå¨å ç¨å°</li><li>æ»¡è¶³åºæ¬éæ±</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="option" data-choice="log-none" onclick="toggleSelect(this)"> |
| | | <div class="letter">C</div> |
| | | <div class="content"> |
| | | <h3>ä¸è®°å½</h3> |
| | | <p>ä¸åç¬è®°å½æ¥å¿ï¼ä»
ä¾èµç³»ç»æ¥å¿åMESç³»ç»æ¥å¿</p> |
| | | <div class="pros-cons"> |
| | | <div class="pros"><h4>ä¼ç¹</h4><ul><li>æ é¢å¤åå¨</li><li>å®ç°ç®å</li></ul></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <style> |
| | | .mapping-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 13px; |
| | | } |
| | | .mapping-table th, .mapping-table td { |
| | | border: 1px solid #e0e0e0; |
| | | padding: 10px 12px; |
| | | text-align: center; |
| | | } |
| | | .mapping-table th { |
| | | background: #f5f5f5; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | .mapping-table tbody tr:nth-child(even) { |
| | | background: #fafafa; |
| | | } |
| | | .mapping-table input[type="checkbox"] { |
| | | width: 16px; |
| | | height: 16px; |
| | | cursor: pointer; |
| | | } |
| | | .status-tag { |
| | | padding: 4px 10px; |
| | | border-radius: 4px; |
| | | font-size: 12px; |
| | | font-weight: 500; |
| | | } |
| | | .status-idle { |
| | | background: #e3f2fd; |
| | | color: #1976d2; |
| | | } |
| | | .status-instock { |
| | | background: #e8f5e9; |
| | | color: #388e3c; |
| | | } |
| | | .status-outbound { |
| | | background: #fff3e0; |
| | | color: #f57c00; |
| | | } |
| | | .status-lock { |
| | | background: #ffebee; |
| | | color: #d32f2f; |
| | | } |
| | | .status-normal { |
| | | background: #e8f5e9; |
| | | color: #388e3c; |
| | | } |
| | | .status-exception { |
| | | background: #fff3e0; |
| | | color: #f57c00; |
| | | } |
| | | .status-locked { |
| | | background: #ffebee; |
| | | color: #d32f2f; |
| | | } |
| | | .hint { |
| | | margin: 12px 0 0 0; |
| | | padding: 10px 12px; |
| | | background: #f0f7ff; |
| | | border-left: 3px solid #1f5eff; |
| | | font-size: 12px; |
| | | color: #606266; |
| | | } |
| | | .pros-cons { |
| | | display: flex; |
| | | gap: 16px; |
| | | margin-top: 12px; |
| | | } |
| | | .pros, .cons { |
| | | flex: 1; |
| | | font-size: 13px; |
| | | } |
| | | .pros h4 { |
| | | color: #4caf50; |
| | | margin: 0 0 6px 0; |
| | | } |
| | | .pros ul { |
| | | margin: 0; |
| | | padding-left: 16px; |
| | | } |
| | | .pros li { |
| | | margin-bottom: 4px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <div style="display:flex;align-items:center;justify-content:center;min-height:60vh"> |
| | | <p class="subtitle">æ£å¨çæè®¾è®¡æ¹æ¡...</p> |
| | | </div> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # CLAUDE.md |
| | | |
| | | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| | | |
| | | ## é¡¹ç®æ¦è¿° |
| | | |
| | | **WIDESEA** æ¯ä¸ä¸ªå·¥ä¸ä»å¨èªå¨åç³»ç»ï¼å
å«ä¸¤ä¸ªæ ¸å¿åç³»ç»ï¼ |
| | | |
| | | - **WCS**ï¼ä»åºæ§å¶ç³»ç»ï¼ï¼ç´æ¥æ§å¶å åæºãè¾éçº¿ãæºå¨äººãç©¿æ¢è½¦çç©ç设å¤ï¼ä¸ PLC éä¿¡ |
| | | - **WMS**ï¼ä»åºç®¡çç³»ç»ï¼ï¼ç®¡çåºåãå
¥åºãåºåºä»»å¡ãçç¹çä¸å¡é»è¾ |
| | | |
| | | 两个系ç»éè¿ HTTP API 交äºï¼WMS ä¾èµ WCS å®æè®¾å¤è°åº¦ã |
| | | |
| | | ## æå»ºå½ä»¤ |
| | | |
| | | ```bash |
| | | # WCS å端ï¼ç«¯å£ 9292ï¼ |
| | | dotnet build WCS/WIDESEAWCS_Server/WIDESEAWCS_Server.sln |
| | | dotnet run --project WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/WIDESEAWCS_Server.csproj |
| | | |
| | | # WMS å端ï¼ç«¯å£ 9291ï¼ |
| | | dotnet build WMS/WIDESEA_WMSServer/WIDESEA_WMSServer.sln |
| | | dotnet run --project WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/WIDESEA_WMSServer.csproj |
| | | |
| | | # WCS å端 |
| | | cd WCS/WIDESEAWCS_Client && npm run serve |
| | | |
| | | # WMS å端 |
| | | cd WMS/WIDESEA_WMSClient && npm run serve |
| | | |
| | | # S7 模æå¨ |
| | | cd æµè¯å·¥å
·/WIDESEAWCS_S7Simulator/WIDESEAWCS_S7Simulator.Web && npm run dev |
| | | ``` |
| | | |
| | | ## æ¶ææ¦è§ |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â WCS (ç«¯å£ 9292) â |
| | | â âââââââââââââââ ââââââââââââââââ ââââââââââââââââââââââ â |
| | | â â Quartz â â Communicator â â Redis L1+L2 â â |
| | | â â Jobs ââ â (PLCåè®®) â â Cache â â |
| | | â âââââââââââââââ ââââââââââââââââ ââââââââââââââââââââââ â |
| | | â â â |
| | | â âââââââââââââââââââââââââââââââââââââââââââââââââââââââ â |
| | | â â TcpSocketServer (ç«¯å£ 2000) / WebSocket (ç«¯å£ 9296) â â |
| | | â âââââââââââââââââââââââââââââââââââââââââââââââââââââââ â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â HTTP API |
| | | â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â WMS (ç«¯å£ 9291) â |
| | | â âââââââââââââââ ââââââââââââââââ ââââââââââââââââââââââ â |
| | | â â Tasks â â Stock â â Inbound/ â â |
| | | â â Service â â Service â â Outbound â â |
| | | â âââââââââââââââ ââââââââââââââââ ââââââââââââââââââââââ â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ## WCS 项ç®ç»æ |
| | | |
| | | | é¡¹ç® | ç¨é | |
| | | |------|------| |
| | | | `WIDESEAWCS_Server` | 主 API å
¥å£ï¼ç«¯å£ 9292ï¼ | |
| | | | `WIDESEAWCS_Core` | æ¡æ¶ï¼æ°æ®åºãç¼åãDIãæ¥å¿ï¼ | |
| | | | `WIDESEAWCS_Common` | 常éãæä¸¾ãRedis é® | |
| | | | `WIDESEAWCS_Model` | å®ä½æ¨¡å | |
| | | | `WIDESEAWCS_DTO` | æ°æ®ä¼ è¾å¯¹è±¡ | |
| | | | `WIDESEAWCS_Communicator` | å·¥ä¸åè®®ï¼ModbusãS7ãOmron çï¼ | |
| | | | `WIDESEAWCS_Tasks` | åå°è®¾å¤æ§å¶ä½ä¸ | |
| | | | `WIDESEAWCS_QuartzJob` | Quartz.NET è°åº¦ | |
| | | |
| | | **è¯¦ç» WCS è§è**ï¼è§ `WCS/WIDESEAWCS_Server/CLAUDE.md` |
| | | |
| | | ## WMS 项ç®ç»æ |
| | | |
| | | | é¡¹ç® | ç¨é | |
| | | |------|------| |
| | | | `WIDESEA_WMSServer` | 主 API å
¥å£ï¼ç«¯å£ 9291ï¼ | |
| | | | `WIDESEA_Core` | æ¡æ¶å·¥å
· | |
| | | | `WIDESEA_Common` | 常éãæä¸¾ | |
| | | | `WIDESEA_Model` | å®ä½æ¨¡å | |
| | | | `WIDESEA_*Service` | ä¸å¡é»è¾æå¡ | |
| | | |
| | | ## å
³é®è®¾è®¡ |
| | | |
| | | - **ORM**ï¼SqlSugarï¼æ¯æå¤æ°æ®åºï¼ |
| | | - **ä¾èµæ³¨å
¥**ï¼Autofacï¼éè¿ `AutofacModuleRegister` 注å |
| | | - **ç¼å**ï¼Redis L1ï¼å
åï¼+ L2ï¼Redisï¼æ··åç¼å |
| | | - **è°åº¦**ï¼Quartz.NET |
| | | - **宿¶éä¿¡**ï¼SignalR WebSocket |
| | | - **设å¤åè®®**ï¼åå¨å¨æ°æ®åº `Dt_DeviceProtocol` 表ï¼éé
ç½®æä»¶ |
| | | |
| | | ## ææ¯æ |
| | | |
| | | - **å端**ï¼.NET 6/8ï¼ASP.NET Coreï¼C# 12 |
| | | - **å端**ï¼Vue 3ï¼Element Plusï¼Viteï¼Pinia |
| | | - **æ°æ®åº**ï¼SQL Server |
| | | - **ç¼å**ï¼Redis |
| | | |
| | | ## 注éä¸ææ¡£ (强å¶) |
| | | |
| | | - **XML ææ¡£æ³¨é**: ææ `public` ç±»ãæ¥å£ãæ¹æ³ã屿§**å¿
é¡»**å
å« XML ææ¡£æ³¨é (`/// <summary>...</summary>`)ï¼è§£éå
¶ç¨éãåæ°åè¿åå¼ã |
| | | - **è¡å
注é**: 对äºå¤æçä¸å¡é»è¾ãç®æ³å®ç°æéç´è§ç代ç åï¼**å¿
é¡»**æ·»å `//` è¡å
注éè§£éâ为ä»ä¹è¿ä¹åâã |
| | | - **TODO æ è®°**: å¦æä»£ç æªå®æææä¸´æ¶æ¹æ¡ï¼å¿
é¡»ä½¿ç¨ `// TODO: 说æ` æ è®°ã |
| | | |
| | | ## éç¨è§è |
| | | |
| | | - **弿¥ç¼ç¨**: ææ I/O æä½å¿
é¡»ä½¿ç¨ `async/await`ãåºä»£ç è¯·ä½¿ç¨ `ConfigureAwait(false)`ã |
| | | |
| | | - **å½å**: |
| | | |
| | | - æ¥å£ä»¥ "I" å¼å¤´ (ä¾å¦: `IUserService`)ã |
| | | - ç±»åãæ¹æ³åä½¿ç¨ **PascalCase**ã |
| | | - ç§æåæ®µãå±é¨åéä½¿ç¨ **camelCase**ã |
| | | |
| | | - **å½å空é´**: ä½¿ç¨ **æä»¶ä½ç¨åå½å空é´** (`namespace MyApp.Api;`)ã |
| | | |
| | | - å½éè¦å¯¹ä¸¤ä¸ªæä»¥ä¸çæ°æ®åºæ§è¡ä¿®æ¹/æ·»å æä½å¹¶ä¿è¯äºå¡ä¸è´æ§æ¶ï¼è¯·ä½¿ç¨å·¥ä½åå
管çå¨ï¼`IUnitOfWorkManage`ï¼çäºå¡æ¹æ³ï¼ |
| | | |
| | | - **åæ¥åºæ¯**ï¼è°ç¨ `BeginTran(Func<WebResponseContent> func)`ï¼ä¼ å
¥åæ¥å§æã |
| | | - **弿¥åºæ¯**ï¼è°ç¨ `BeginTranAsync(Func<Task<WebResponseContent>> funcAsync)`ï¼ä¼ å
¥å¼æ¥å§æã |
| | | |
| | | **注æ**ï¼`IUnitOfWorkManage` ééè¿ä¾èµæ³¨å
¥ï¼DIï¼è·åãè¯¥æ¹æ³ä¼èªå¨ç®¡çäºå¡çæäº¤ä¸åæ»ï¼åªéç¡®ä¿æææ°æ®åºæä½å¨ä¼ å
¥çå§æå
宿ã |
| | | |
| | | ## ð« 严ç¦äºé¡¹ |
| | | |
| | | - **严ç¦** çææ²¡ææ³¨éç代ç (å°¤å
¶æ¯å
Œ
±æ¹æ³)ã |
| | | - **严ç¦** ä½¿ç¨ `Task.Result` æ `Task.Wait()`ã |
| | | - **严ç¦** å¨å¼æ¥ä¸ä¸æä¸ä½¿ç¨ `.ToList()` (å¿
é¡»ç¨ `.ToListAsync()`)ã |
| | | - **严ç¦** ç´æ¥æ´é²å®ä½ (Entity)ï¼å¿
é¡»ä½¿ç¨ DTOã |
| | | - **严ç¦** æè· `Exception` èä¸è®°å½æ¥å¿ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "lastSentAt": "2026-04-12T15:31:49.457Z" |
| | | } |
| | |
| | | }, |
| | | "devDependencies": { |
| | | "@vitejs/plugin-vue": "^4.0.0", |
| | | "@vitejs/plugin-vue-jsx": "^5.1.5", |
| | | "@vue/compiler-sfc": "^3.0.0", |
| | | "eslint": "^8.50.0", |
| | | "less": "^4.1.1", |
copy from Code/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocol.js
copy to Code/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocolDetail.jsx
copy from Code/WCS/WIDESEAWCS_Client/src/extension/quartzJob/deviceProtocol.js
copy to Code/WCS/WIDESEAWCS_Client/src/extension/quartzJob/dispatchInfo.jsx
copy from Code/WCS/WIDESEAWCS_Client/src/extension/taskinfo/robotTask.js
copy to Code/WCS/WIDESEAWCS_Client/src/extension/taskinfo/taskHty.jsx
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basicinfo/router.js"; |
| | | import extend from "@/extension/basicinfo/router.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/quartzJob/deviceInfo.js"; |
| | | import extend from "@/extension/quartzJob/deviceInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/quartzJob/deviceProtocol.js"; |
| | | import extend from "@/extension/quartzJob/deviceProtocol.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/quartzJob/deviceProtocolDetail.js"; |
| | | import extend from "@/extension/quartzJob/deviceProtocolDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/quartzJob/dispatchInfo.js"; |
| | | import extend from "@/extension/quartzJob/dispatchInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Dictionary.js"; |
| | | import extend from "@/extension/system/Sys_Dictionary.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import extend from "@/extension/system/Sys_DictionaryList.js"; |
| | | import extend from "@/extension/system/Sys_DictionaryList.jsx"; |
| | | var vueParam = { |
| | | data() { |
| | | return { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Log.js"; |
| | | import extend from "@/extension/system/Sys_Log.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Role.js"; |
| | | import extend from "@/extension/system/Sys_Role.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Role1.js"; |
| | | import extend from "@/extension/system/Sys_Role1.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Tenant.js"; |
| | | import extend from "@/extension/system/Sys_Tenant.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_User.js"; |
| | | import extend from "@/extension/system/Sys_User.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/system/Sys_Department.js"; |
| | | import extend from "@/extension/system/system/Sys_Department.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import extend from "@/extension/taskinfo/robotTask.js"; |
| | | import extend from "@/extension/taskinfo/robotTask.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/taskinfo/task.js"; |
| | | import extend from "@/extension/taskinfo/task.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/taskinfo/taskHty.js"; |
| | | import extend from "@/extension/taskinfo/taskHty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| ÎļþÃû´Ó Code/WCS/WIDESEAWCS_Client/vite.config.js ÐÞ¸Ä |
| | |
| | | import { defineConfig } from 'vite' |
| | | import vue from '@vitejs/plugin-vue' |
| | | import vue from '@vitejs/plugin-vue' |
| | | import vueJsx from '@vitejs/plugin-vue-jsx' |
| | | import { fileURLToPath, URL } from 'node:url' |
| | | |
| | | const __dirname = fileURLToPath(new URL('.', import.meta.url)) |
| | | |
| | | export default defineConfig({ |
| | | plugins: [vue()], |
| | | plugins: [vue(), vueJsx()], |
| | | |
| | | server: { |
| | | host: '0.0.0.0', |
| | |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | |
| | | namespace WIDESEAWCS_Core.BaseRepository |
| | | { |
| | |
| | | /// </summary> |
| | | /// <returns>SqlSugarClientæ°æ®åºå®¢æ·ç«¯å¯¹è±¡</returns> |
| | | SqlSugarClient GetDbClient(); |
| | | |
| | | int TranCount { get; } |
| | | |
| | | /// <summary> |
| | |
| | | /// å¼å§ä¸ä¸ªäºå¡ |
| | | /// </summary> |
| | | void BeginTran(); |
| | | |
| | | /// <summary> |
| | | /// å¼å§ä¸ä¸ªäºå¡ |
| | | /// </summary> |
| | | /// <param name="method">触åäºå¡çæ¹æ³ä¿¡æ¯</param> |
| | | void BeginTran(MethodInfo method); |
| | | |
| | | /// <summary> |
| | | /// å¼å§ä¸ä¸ªäºå¡ï¼å¹¶æ§è¡æä¾ç彿° |
| | | /// </summary> |
| | | /// <param name="func">å§ææ¹æ³</param> |
| | | /// <returns></returns> |
| | | WebResponseContent BeginTran(Func<WebResponseContent> func); |
| | | |
| | | /// <summary> |
| | | /// æäº¤å½åäºå¡ |
| | | /// </summary> |
| | | void CommitTran(); |
| | | |
| | | /// <summary> |
| | | /// æäº¤äºå¡ |
| | | /// </summary> |
| | | /// <param name="method">触åæäº¤äºå¡çæ¹æ³ä¿¡æ¯</param> |
| | | void CommitTran(MethodInfo method); |
| | | |
| | | /// <summary> |
| | | /// åæ»å½åäºå¡ |
| | | /// </summary> |
| | | void RollbackTran(); |
| | | |
| | | /// <summary> |
| | | /// åæ»å½åäºå¡ |
| | | /// </summary> |
| | | /// <param name="method">触ååæ»çæ¹æ³ä¿¡æ¯</param> |
| | | void RollbackTran(MethodInfo method); |
| | | } |
| | | } |
| | | } |
| | |
| | | using Microsoft.Extensions.Logging; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Concurrent; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Reflection; |
| | | using System.Text; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | using WIDESEAWCS_Core.Helper; |
| | | |
| | | namespace WIDESEAWCS_Core.BaseRepository |
| | |
| | | { |
| | | // å®ä¹æ¥å¿è®°å½å¨ |
| | | private readonly ILogger<UnitOfWorkManage> _logger; |
| | | |
| | | // å®ä¹SqlSugarClient |
| | | private readonly ISqlSugarClient _sqlSugarClient; |
| | | |
| | | // å®ä¹äºå¡è®¡æ°å¨ |
| | | private int _tranCount { get; set; } |
| | | |
| | | // å®ä¹äºå¡è®¡æ°å¨çåªè¯»å±æ§ |
| | | public int TranCount => _tranCount; |
| | | |
| | | // å®ä¹äºå¡æ |
| | | public readonly ConcurrentStack<string> TranStack = new(); |
| | | |
| | |
| | | return _sqlSugarClient as SqlSugarClient; |
| | | } |
| | | |
| | | |
| | | // å建UnitOfWork |
| | | public UnitOfWork CreateUnitOfWork() |
| | | { |
| | |
| | | |
| | | uow.Db.Open(); |
| | | uow.Tenant.BeginTran(); |
| | | |
| | | |
| | | _logger.LogDebug("UnitOfWork Begin"); |
| | | return uow; |
| | | } |
| | |
| | | } |
| | | return content; |
| | | } |
| | | catch(Exception ex) |
| | | catch (Exception ex) |
| | | { |
| | | RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | |
| | | { |
| | | spinner.SpinOnce(); |
| | | } |
| | | |
| | | |
| | | if (result == method.GetFullName()) |
| | | { |
| | |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEAWCS_DTO.TaskInfo |
| | | { |
| | | /// <summary> |
| | | /// WCSæ¥æ¶WMSä»»å¡çç»æDto |
| | | /// </summary> |
| | | public class ReceiveTaskResultDto |
| | | { |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | public bool Success { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯ |
| | | /// </summary> |
| | | public string Message { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ°å»ºç任塿°é |
| | | /// </summary> |
| | | public int CreatedCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éå¤/å·²åå¨çä»»å¡å表ï¼åªå
å«ä»»å¡å·åæçå·ï¼ |
| | | /// </summary> |
| | | public List<DuplicateTaskDto> DuplicateTasks { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éå¤ä»»å¡ä¿¡æ¯Dto |
| | | /// </summary> |
| | | public class DuplicateTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ç±»å |
| | | /// </summary> |
| | | public int TaskType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åç¶æ |
| | | /// </summary> |
| | | public int TaskStatus { get; set; } |
| | | } |
| | | } |
| | |
| | | /// newStatus - æ°ç¶æï¼å¿
填项ï¼ç¨äºæå®ä»»å¡çæ°ç¶æ |
| | | /// </summary> |
| | | public int NewStatus { get; set; } |
| | | |
| | | |
| | | /// <summary> |
| | | /// NextAddress - ä¸ä¸å°åï¼å¿
填项ï¼ç¨äºæå®ä»»å¡çä¸ä¸ä½ç½® |
| | | /// </summary> |
| | | public string? NextAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// currentAddress - å½åå°åï¼å¿
填项ï¼ç¨äºæå®ä»»å¡çå½åä½ç½® |
| | | /// </summary> |
| | | public string? CurrentAddress { get; set; } |
| | | } |
| | | } |
| | |
| | | WebResponseContent ReceiveWMSTask([NotNull] List<WMSTaskDTO> taskDTOs); |
| | | |
| | | /// <summary> |
| | | /// æ¥æ¶WMSæå¨å建çä»»å¡ï¼å建WCSä»»å¡ |
| | | /// </summary> |
| | | /// <param name="taskDTOs">WMSä»»å¡å¯¹è±¡éå</param> |
| | | /// <returns>è¿åå¤çç»æ</returns> |
| | | WebResponseContent ReceiveManualTask([NotNull] List<WMSTaskDTO> taskDTOs); |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢æå®èµ·ç¹å°åçæ°å»ºæå¨å
¥åºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="sourceAddress">èµ·ç¹å°å</param> |
| | | /// <returns>ä»»å¡å表</returns> |
| | | Dt_Task QueryManualInboundTask(string sourceAddress); |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®æçå·ãèµ·å§å°ååWMS请æ±ä»»å¡ |
| | | /// </summary> |
| | | /// <param name="palletCode">æçå·</param> |
| | |
| | | return Service.ReceiveWMSTask(taskDTOs); |
| | | } |
| | | |
| | | [HttpPost, Route("ReceiveManualTask"), AllowAnonymous] |
| | | public WebResponseContent ReceiveManualTask([FromBody] List<WMSTaskDTO> taskDTOs) |
| | | { |
| | | return Service.ReceiveManualTask(taskDTOs); |
| | | } |
| | | |
| | | [HttpPost, HttpGet(), Route("UpdateTaskExceptionMessage")] |
| | | public WebResponseContent UpdateTaskExceptionMessage(int taskNum, string message) |
| | | { |
| | |
| | | { |
| | | var result = _httpClientHelper.Post<WebResponseContent>( |
| | | nameof(ConfigKey.UpdateTaskByStatus), |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus }.ToJson()); |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus, NextAddress = task.NextAddress, CurrentAddress = task.CurrentAddress }.ToJson()); |
| | | |
| | | if (!result.IsSuccess || !result.Data.Status) |
| | | return WebResponseContent.Instance.Error($"è°ç¨WMSæ¥å£æ´æ°ä»»å¡ç¶æå¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,é误信æ¯:ã{result.Data?.Message}ã"); |
| | |
| | | using Newtonsoft.Json; |
| | | using Autofac; |
| | | using Newtonsoft.Json; |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Common.HttpEnum; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_Core.BaseRepository; |
| | | using WIDESEAWCS_Core.Enums; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_DTO; |
| | | using WIDESEAWCS_DTO.Stock; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | | using WIDESEAWCS_ITaskInfoRepository; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob.DTO; |
| | | using WIDESEAWCS_QuartzJob.Models; |
| | | using WIDESEAWCS_QuartzJob.Service; |
| | | |
| | |
| | | private readonly IRouterService _routerService; |
| | | private readonly HttpClientHelper _httpClientHelper; |
| | | private readonly IRobotTaskService _robotTaskService; |
| | | private readonly ITaskService _taskService; |
| | | private readonly ITaskRepository _taskRepository; |
| | | private readonly IComponentContext _componentContext; |
| | | private readonly IUnitOfWorkManage _unitOfWorkManage; |
| | | |
| | | /// <summary> |
| | | /// åå§ååºåºä»»å¡æµç¨æå¡ã |
| | |
| | | /// <param name="routerService">è·¯ç±æå¡ã</param> |
| | | /// <param name="httpClientHelper">WMSæ¥å£è°ç¨å¸®å©ç±»ã</param> |
| | | /// <param name="robotTaskService">æºæ¢°æä»»å¡æå¡ã</param> |
| | | /// <param name="taskService">任塿å¡ï¼ç¨äºæ¥æ¶å
¥åºä»»å¡ï¼ã</param> |
| | | /// <param name="taskRepository">ä»»å¡ä»å¨ï¼ç¨äºå é¤åºåºä»»å¡ï¼ã</param> |
| | | public OutboundTaskFlowService(IRouterService routerService, HttpClientHelper httpClientHelper, IRobotTaskService robotTaskService, ITaskService taskService, ITaskRepository taskRepository) |
| | | /// <param name="componentContext">Autofacç»ä»¶ä¸ä¸æï¼ç¨äºå»¶è¿è§£æITaskService以é¿å
循ç¯ä¾èµï¼ã</param> |
| | | public OutboundTaskFlowService(IRouterService routerService, HttpClientHelper httpClientHelper, IRobotTaskService robotTaskService, IComponentContext componentContext, IUnitOfWorkManage unitOfWorkManage) |
| | | { |
| | | _routerService = routerService; |
| | | _httpClientHelper = httpClientHelper; |
| | | _robotTaskService = robotTaskService; |
| | | _taskService = taskService; |
| | | _taskRepository = taskRepository; |
| | | _componentContext = componentContext; |
| | | _unitOfWorkManage = unitOfWorkManage; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å»¶è¿è§£æITaskService以é¿å
循ç¯ä¾èµ |
| | | /// </summary> |
| | | private ITaskService TaskService => _componentContext.Resolve<ITaskService>(); |
| | | |
| | | /// <summary> |
| | | /// æ¥æ¶WMS任塿¶åå§ååºåºä»»å¡ã |
| | |
| | | |
| | | if (inboundTaskDto != null) |
| | | { |
| | | // å
å 餿¬å°åºåºä»»å¡ï¼é¿å
æçå·å¯ä¸é®å²çª |
| | | _taskRepository.DeleteAndMoveIntoHty(task, OperateTypeEnum.èªå¨å®æ); |
| | | |
| | | // è°ç¨ReceiveWMSTaskå建æ¬å°å
¥åºä»»å¡ |
| | | var receiveResult = _taskService.ReceiveWMSTask(new List<WMSTaskDTO> { inboundTaskDto }); |
| | | if (!receiveResult.Status) |
| | | _unitOfWorkManage.BeginTran(() => |
| | | { |
| | | return content.Error($"å建æ¬å°å
¥åºä»»å¡å¤±è´¥: {receiveResult.Message}"); |
| | | } |
| | | // å
å 餿¬å°åºåºä»»å¡ï¼é¿å
æçå·å¯ä¸é®å²çª |
| | | bool isDeleted = TaskService.Repository.DeleteAndMoveIntoHty(task, OperateTypeEnum.èªå¨å®æ); |
| | | if (!isDeleted) |
| | | { |
| | | return content.Error($"å 餿¬å°åºåºä»»å¡å¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,æçå·:ã{task.PalletCode}ã"); |
| | | } |
| | | |
| | | // è°ç¨ReceiveWMSTaskå建æ¬å°å
¥åºä»»å¡ |
| | | var receiveResult = TaskService.ReceiveWMSTask(new List<WMSTaskDTO> { inboundTaskDto }); |
| | | if (!receiveResult.Status) |
| | | { |
| | | return content.Error($"å建æ¬å°å
¥åºä»»å¡å¤±è´¥: {receiveResult.Message}"); |
| | | } |
| | | return content.OK("å建æ¬å°å
¥åºä»»å¡æå"); |
| | | }); |
| | | } |
| | | } |
| | | |
| | |
| | | { |
| | | var result = _httpClientHelper.Post<WebResponseContent>( |
| | | nameof(ConfigKey.UpdateTaskByStatus), |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus }.ToJson()); |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus, NextAddress = task.NextAddress, CurrentAddress = task.CurrentAddress }.ToJson()); |
| | | |
| | | if (!result.IsSuccess || !result.Data.Status) |
| | | return WebResponseContent.Instance.Error($"è°ç¨WMSæ¥å£æ´æ°ä»»å¡ç¶æå¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,é误信æ¯:ã{result.Data?.Message}ã"); |
| | |
| | | return WebResponseContent.Instance.OK(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | var result = _httpClientHelper.Post<WebResponseContent>( |
| | | nameof(ConfigKey.UpdateTaskByStatus), |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus }.ToJson()); |
| | | new UpdateTaskDto { Id = task.TaskNum, NewStatus = task.TaskStatus, NextAddress = task.NextAddress, CurrentAddress = task.CurrentAddress }.ToJson()); |
| | | |
| | | if (!result.IsSuccess || !result.Data.Status) |
| | | return WebResponseContent.Instance.Error($"è°ç¨WMSæ¥å£æ´æ°ä»»å¡ç¶æå¤±è´¥,ä»»å¡å·:ã{task.TaskNum}ã,é误信æ¯:ã{result.Data?.Message}ã"); |
| | |
| | | using System.Diagnostics.CodeAnalysis; |
| | | using WIDESEAWCS_Common.TaskEnum; |
| | | using WIDESEAWCS_Core; |
| | | using WIDESEAWCS_Core.Helper; |
| | | using WIDESEAWCS_DTO.TaskInfo; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | |
| | | return WebResponseContent.Instance.OK(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | { |
| | | return BaseDal.QueryFirst(x => x.TaskNum == taskNum); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥æ¶WMSæå¨å建çä»»å¡ï¼å建WCSä»»å¡ |
| | | /// </summary> |
| | | /// <param name="taskDTOs">WMSä»»å¡å¯¹è±¡éå</param> |
| | | /// <returns>è¿åå¤çç»æ</returns> |
| | | public WebResponseContent ReceiveManualTask([NotNull] List<WMSTaskDTO> taskDTOs) |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | try |
| | | { |
| | | // æ¶ééå¤ä»»å¡çä¿¡æ¯ |
| | | var duplicateTasks = new List<DuplicateTaskDto>(); |
| | | // ååºéåï¼å®å
¨å é¤å¹¶æ¶é被移é¤ç项 |
| | | for (int i = taskDTOs.Count - 1; i >= 0; i--) |
| | | { |
| | | var item = taskDTOs[i]; |
| | | var exists = BaseDal.QueryFirst(x => x.TaskNum == item.TaskNum || x.PalletCode == item.PalletCode); |
| | | if (exists != null) |
| | | { |
| | | duplicateTasks.Add(new DuplicateTaskDto |
| | | { |
| | | TaskNum = exists.TaskNum, |
| | | PalletCode = exists.PalletCode, |
| | | TaskType = exists.TaskType, |
| | | TaskStatus = exists.TaskStatus |
| | | }); |
| | | taskDTOs.RemoveAt(i); |
| | | } |
| | | } |
| | | |
| | | // è°ç¨ ReceiveWMSTask å建 WCS ä»»å¡ |
| | | content = ReceiveWMSTask(taskDTOs); |
| | | |
| | | // 妿æéå¤ä»»å¡ï¼ä¿®æ¹è¿åç»æ |
| | | if (duplicateTasks.Count > 0 && content.Status) |
| | | { |
| | | var result = new ReceiveTaskResultDto |
| | | { |
| | | Success = true, |
| | | Message = content.Message + $"ï¼å
¶ä¸{duplicateTasks.Count}个任å¡å¨WCSä¸å·²åå¨", |
| | | CreatedCount = taskDTOs.Count, |
| | | DuplicateTasks = duplicateTasks |
| | | }; |
| | | content.Data = result; |
| | | } |
| | | |
| | | return content; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | content = WebResponseContent.Instance.Error($"æå¨ä»»å¡æ¥æ¶é误,é误信æ¯:{ex.Message}"); |
| | | return content; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢æå®èµ·ç¹å°åçæ°å»ºæå¨å
¥åºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="sourceAddress">èµ·ç¹å°å</param> |
| | | /// <returns>ä»»å¡å®ä½</returns> |
| | | public Dt_Task QueryManualInboundTask(string sourceAddress) |
| | | { |
| | | return BaseDal.QueryFirst(x => |
| | | x.TaskType == (int)TaskInboundTypeEnum.Inbound && |
| | | x.TaskStatus == (int)TaskInStatusEnum.InNew && |
| | | x.SourceAddress == sourceAddress); |
| | | } |
| | | } |
| | | |
| | | public enum ConveyorLineDBNameNew |
| | |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.Service; |
| | | using ManualInboundTaskHandler = WIDESEAWCS_Tasks.ConveyorLineNewJob.ManualInbound.ManualInboundTaskHandler; |
| | | |
| | | namespace WIDESEAWCS_Tasks |
| | | { |
| | |
| | | // 妿 WCS_ACK 为 1ï¼å
æ¸
é¤ï¼è¡¨ç¤ºå¤çè¿ä¸ä¸æ¬¡è¯·æ±ï¼ |
| | | if (command.WCS_ACK == 1) |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)0, childDeviceCode); |
| | | |
| | | // å¤çæå¨å
¥åºä»»å¡ï¼èµ·ç¹ä¸ºçº¿ä½ç¹ä½çä»»å¡ï¼ |
| | | try |
| | | { |
| | | var task = _taskService.QueryManualInboundTask(childDeviceCode); |
| | | if (task != null) |
| | | { |
| | | var handler = new ManualInboundTaskHandler(_taskService); |
| | | handler.WriteTaskToPlc(conveyorLine, childDeviceCode, task); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | _logger.LogError(ex, "å¤çæå¨å
¥åºä»»å¡å¼å¸¸"); |
| | | QuartzLogger.Error($"å¤çæå¨å
¥åºä»»å¡å¼å¸¸: {ex.Message}", "CommonConveyorLineNewJob", ex); |
| | | } |
| | | continue; |
| | | } |
| | | |
| | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µï¼é常æ¯å®æï¼ |
| | | if (_taskService.UpdateTaskStatusToNext(task).Status) |
| | | { |
| | | |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); |
| | | _logger.LogInformation("ConveyorLineInFinishï¼å
¥åºå®æï¼ä»»å¡å·: {TaskNum}ï¼å设å¤: {ChildDeviceCode}", task.TaskNum, childDeviceCode); |
| | | QuartzLogger.Info($"å
¥åºå®æï¼ä»»å¡å·: {task.TaskNum}", conveyorLine.DeviceCode); |
| | | } |
| | | |
| | | // åå¤ ACK 确认 |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); |
| | | |
| | | _logger.LogInformation("ConveyorLineInFinishï¼å
¥åºå®æï¼ä»»å¡å·: {TaskNum}ï¼å设å¤: {ChildDeviceCode}", task.TaskNum, childDeviceCode); |
| | | QuartzLogger.Info($"å
¥åºå®æï¼ä»»å¡å·: {task.TaskNum}", conveyorLine.DeviceCode); |
| | | } |
| | | } |
| | | |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | using WIDESEAWCS_ITaskInfoService; |
| | | using WIDESEAWCS_Model.Models; |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.ConveyorLine; |
| | | |
| | | namespace WIDESEAWCS_Tasks.ConveyorLineNewJob.ManualInbound |
| | | { |
| | | /// <summary> |
| | | /// æå¨å
¥åºä»»å¡å¤çå¨ |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// è´è´£å¤çæå¨å建çå
¥åºä»»å¡ï¼å½PLC请æ±å
¥åºæ¶ï¼æ ¹æ®childDeviceCodeæ¥æ¾ä»»å¡å¹¶åå
¥PLCã |
| | | /// </remarks> |
| | | public class ManualInboundTaskHandler |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡æå¡ |
| | | /// </summary> |
| | | private readonly ITaskService _taskService; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="taskService">任塿å¡</param> |
| | | public ManualInboundTaskHandler(ITaskService taskService) |
| | | { |
| | | _taskService = taskService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå
¥æå¨å
¥åºä»»å¡å°PLC |
| | | /// </summary> |
| | | /// <param name="conveyorLine">è¾é线设å¤å¯¹è±¡</param> |
| | | /// <param name="childDeviceCode">å设å¤ç¼ç </param> |
| | | /// <param name="task">ä»»å¡å®ä½</param> |
| | | public void WriteTaskToPlc(CommonConveyorLine conveyorLine, string childDeviceCode, Dt_Task task) |
| | | { |
| | | if (conveyorLine == null || string.IsNullOrEmpty(childDeviceCode) || task == null) |
| | | { |
| | | QuartzLogger.Error("ManualInboundTaskHandler.WriteTaskToPlc: åæ°ä¸ºç©º", "ManualInbound"); |
| | | return; |
| | | } |
| | | |
| | | try |
| | | { |
| | | // åå
¥ä»»å¡å· |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.TaskNo, (short)task.TaskNum, childDeviceCode); |
| | | // åå
¥èµ·å§å°å |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Source, short.Parse(task.SourceAddress ?? "0"), childDeviceCode); |
| | | // åå
¥ç®æ å°å |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.Target, short.Parse(task.NextAddress ?? "0"), childDeviceCode); |
| | | |
| | | // æ´æ°ä»»å¡ç¶æå°ä¸ä¸é¶æ®µ |
| | | var updateResult = _taskService.UpdateTaskStatusToNext(task); |
| | | if (!updateResult.Status) |
| | | { |
| | | QuartzLogger.Error($"ManualInboundTaskHandler: æ´æ°ä»»å¡ç¶æå¤±è´¥ï¼ä»»å¡å·ã{task.TaskNum}ãï¼é误信æ¯:{updateResult.Message}", conveyorLine.DeviceCode); |
| | | return; |
| | | } |
| | | |
| | | // åå
¥ACKæ å¿ |
| | | conveyorLine.SetValue(ConveyorLineDBNameNew.WCS_ACK, (short)1, childDeviceCode); |
| | | |
| | | QuartzLogger.Info($"ManualInboundTaskHandler: æå¨ä»»å¡åå
¥PLCæåï¼ä»»å¡å·ã{task.TaskNum}ãï¼æºå°åã{task.SourceAddress}ã", conveyorLine.DeviceCode); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | QuartzLogger.Error($"ManualInboundTaskHandler: åå
¥è¾é线任å¡å¼å¸¸ï¼é误信æ¯:{ex.Message}", "ManualInbound"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | "devDependencies": { |
| | | "@babel/plugin-syntax-dynamic-import": "^7.8.3", |
| | | "@vitejs/plugin-vue": "^4.0.0", |
| | | "@vitejs/plugin-vue-jsx": "^5.1.5", |
| | | "@vue/compiler-sfc": "^3.0.0", |
| | | "@vue/test-utils": "^2.0.0-0", |
| | | "chai": "^4.1.2", |
| | |
| | | '@vitejs/plugin-vue': |
| | | specifier: ^4.0.0 |
| | | version: 4.6.2(vite@5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1))(vue@3.5.30) |
| | | '@vitejs/plugin-vue-jsx': |
| | | specifier: ^5.1.5 |
| | | version: 5.1.5(vite@5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1))(vue@3.5.30) |
| | | '@vue/compiler-sfc': |
| | | specifier: ^3.0.0 |
| | | version: 3.5.30 |
| | |
| | | resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-annotate-as-pure@7.27.3': |
| | | resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-compilation-targets@7.28.6': |
| | | resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-create-class-features-plugin@7.28.6': |
| | | resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} |
| | | engines: {node: '>=6.9.0'} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0 |
| | | |
| | | '@babel/helper-globals@7.28.0': |
| | | resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-member-expression-to-functions@7.28.5': |
| | | resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-module-imports@7.28.6': |
| | |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0 |
| | | |
| | | '@babel/helper-optimise-call-expression@7.27.1': |
| | | resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-plugin-utils@7.28.6': |
| | | resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-replace-supers@7.28.6': |
| | | resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} |
| | | engines: {node: '>=6.9.0'} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0 |
| | | |
| | | '@babel/helper-skip-transparent-expression-wrappers@7.27.1': |
| | | resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} |
| | | engines: {node: '>=6.9.0'} |
| | | |
| | | '@babel/helper-string-parser@7.27.1': |
| | |
| | | |
| | | '@babel/plugin-syntax-dynamic-import@7.8.3': |
| | | resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | |
| | | '@babel/plugin-syntax-jsx@7.28.6': |
| | | resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} |
| | | engines: {node: '>=6.9.0'} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | |
| | | '@babel/plugin-syntax-typescript@7.28.6': |
| | | resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} |
| | | engines: {node: '>=6.9.0'} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | |
| | | '@babel/plugin-transform-typescript@7.28.6': |
| | | resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} |
| | | engines: {node: '>=6.9.0'} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | |
| | |
| | | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} |
| | | engines: {node: '>=14'} |
| | | |
| | | '@rolldown/pluginutils@1.0.0-rc.15': |
| | | resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} |
| | | |
| | | '@rollup/rollup-android-arm-eabi@4.60.0': |
| | | resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} |
| | | cpu: [arm] |
| | |
| | | '@types/web-bluetooth@0.0.20': |
| | | resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} |
| | | |
| | | '@vitejs/plugin-vue-jsx@5.1.5': |
| | | resolution: {integrity: sha512-jIAsvHOEtWpslLOI2MeElGFxH7M8pM83BU/Tor4RLyiwH0FM4nUW3xdvbw20EeU9wc5IspQwMq225K3CMnJEpA==} |
| | | engines: {node: ^20.19.0 || >=22.12.0} |
| | | peerDependencies: |
| | | vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 |
| | | vue: ^3.0.0 |
| | | |
| | | '@vitejs/plugin-vue@4.6.2': |
| | | resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} |
| | | engines: {node: ^14.18.0 || >=16.0.0} |
| | | peerDependencies: |
| | | vite: ^4.0.0 || ^5.0.0 |
| | | vue: ^3.2.25 |
| | | |
| | | '@vue/babel-helper-vue-transform-on@2.0.1': |
| | | resolution: {integrity: sha512-uZ66EaFbnnZSYqYEyplWvn46GhZ1KuYSThdT68p+am7MgBNbQ3hphTL9L+xSIsWkdktwhPYLwPgVWqo96jDdRA==} |
| | | |
| | | '@vue/babel-plugin-jsx@2.0.1': |
| | | resolution: {integrity: sha512-a8CaLQjD/s4PVdhrLD/zT574ZNPnZBOY+IhdtKWRB4HRZ0I2tXBi5ne7d9eCfaYwp5gU5+4KIyFTV1W1YL9xZA==} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | peerDependenciesMeta: |
| | | '@babel/core': |
| | | optional: true |
| | | |
| | | '@vue/babel-plugin-resolve-type@2.0.1': |
| | | resolution: {integrity: sha512-ybwgIuRGRRBhOU37GImDoWQoz+TlSqap65qVI6iwg/J7FfLTLmMf97TS7xQH9I7Qtr/gp161kYVdhr1ZMraSYQ==} |
| | | peerDependencies: |
| | | '@babel/core': ^7.0.0-0 |
| | | |
| | | '@vue/compiler-core@3.5.30': |
| | | resolution: {integrity: sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==} |
| | |
| | | '@jridgewell/trace-mapping': 0.3.31 |
| | | jsesc: 3.1.0 |
| | | |
| | | '@babel/helper-annotate-as-pure@7.27.3': |
| | | dependencies: |
| | | '@babel/types': 7.29.0 |
| | | |
| | | '@babel/helper-compilation-targets@7.28.6': |
| | | dependencies: |
| | | '@babel/compat-data': 7.29.0 |
| | |
| | | lru-cache: 5.1.1 |
| | | semver: 6.3.1 |
| | | |
| | | '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-annotate-as-pure': 7.27.3 |
| | | '@babel/helper-member-expression-to-functions': 7.28.5 |
| | | '@babel/helper-optimise-call-expression': 7.27.1 |
| | | '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) |
| | | '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 |
| | | '@babel/traverse': 7.29.0 |
| | | semver: 6.3.1 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/helper-globals@7.28.0': {} |
| | | |
| | | '@babel/helper-member-expression-to-functions@7.28.5': |
| | | dependencies: |
| | | '@babel/traverse': 7.29.0 |
| | | '@babel/types': 7.29.0 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/helper-module-imports@7.28.6': |
| | | dependencies: |
| | |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/helper-optimise-call-expression@7.27.1': |
| | | dependencies: |
| | | '@babel/types': 7.29.0 |
| | | |
| | | '@babel/helper-plugin-utils@7.28.6': {} |
| | | |
| | | '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-member-expression-to-functions': 7.28.5 |
| | | '@babel/helper-optimise-call-expression': 7.27.1 |
| | | '@babel/traverse': 7.29.0 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/helper-skip-transparent-expression-wrappers@7.27.1': |
| | | dependencies: |
| | | '@babel/traverse': 7.29.0 |
| | | '@babel/types': 7.29.0 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/helper-string-parser@7.27.1': {} |
| | | |
| | |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | |
| | | '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | |
| | | '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | |
| | | '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-annotate-as-pure': 7.27.3 |
| | | '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 |
| | | '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@babel/template@7.28.6': |
| | | dependencies: |
| | |
| | | '@pkgjs/parseargs@0.11.0': |
| | | optional: true |
| | | |
| | | '@rolldown/pluginutils@1.0.0-rc.15': {} |
| | | |
| | | '@rollup/rollup-android-arm-eabi@4.60.0': |
| | | optional: true |
| | | |
| | |
| | | |
| | | '@types/web-bluetooth@0.0.20': {} |
| | | |
| | | '@vitejs/plugin-vue-jsx@5.1.5(vite@5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1))(vue@3.5.30)': |
| | | dependencies: |
| | | '@babel/core': 7.29.0 |
| | | '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) |
| | | '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) |
| | | '@rolldown/pluginutils': 1.0.0-rc.15 |
| | | '@vue/babel-plugin-jsx': 2.0.1(@babel/core@7.29.0) |
| | | vite: 5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1) |
| | | vue: 3.5.30 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@vitejs/plugin-vue@4.6.2(vite@5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1))(vue@3.5.30)': |
| | | dependencies: |
| | | vite: 5.4.21(@types/node@25.5.0)(less@4.6.4)(sass@1.98.0)(stylus@0.54.8)(terser@5.46.1) |
| | | vue: 3.5.30 |
| | | |
| | | '@vue/babel-helper-vue-transform-on@2.0.1': {} |
| | | |
| | | '@vue/babel-plugin-jsx@2.0.1(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/helper-module-imports': 7.28.6 |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) |
| | | '@babel/template': 7.28.6 |
| | | '@babel/traverse': 7.29.0 |
| | | '@babel/types': 7.29.0 |
| | | '@vue/babel-helper-vue-transform-on': 2.0.1 |
| | | '@vue/babel-plugin-resolve-type': 2.0.1(@babel/core@7.29.0) |
| | | '@vue/shared': 3.5.30 |
| | | optionalDependencies: |
| | | '@babel/core': 7.29.0 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@vue/babel-plugin-resolve-type@2.0.1(@babel/core@7.29.0)': |
| | | dependencies: |
| | | '@babel/code-frame': 7.29.0 |
| | | '@babel/core': 7.29.0 |
| | | '@babel/helper-module-imports': 7.28.6 |
| | | '@babel/helper-plugin-utils': 7.28.6 |
| | | '@babel/parser': 7.29.2 |
| | | '@vue/compiler-sfc': 3.5.30 |
| | | transitivePeerDependencies: |
| | | - supports-color |
| | | |
| | | '@vue/compiler-core@3.5.30': |
| | | dependencies: |
| | | '@babel/parser': 7.29.2 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | /** |
| | | * MESæ¥å£API模å |
| | | * æä¾ä¸MESç³»ç»çäº¤äºæ¥å£ï¼å
æ¬æçè¿åºç«ãçµè¯ç»å®è§£ç»ãNG䏿¥çåè½ |
| | | */ |
| | | import http from '@/api/http.js'; |
| | | |
| | | const baseURL = '/api'; |
| | | |
| | | // åºåä¿¡æ¯ç¸å
³MESæ¥å£ |
| | | export const stockInfoMesApi = { |
| | | /** |
| | | * æçè¿ç« |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, stockId } |
| | | * @returns {Promise} |
| | | */ |
| | | inboundInContainer(data) { |
| | | return http.post(`${baseURL}/StockInfo/inboundInContainer`, data, false, { |
| | | headers: { 'Content-Type': 'application/json' } |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * æçåºç« |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, stockId, paramList } |
| | | * @returns {Promise} |
| | | */ |
| | | outboundInContainer(data) { |
| | | return http.post(`${baseURL}/StockInfo/outboundInContainer`, data, false, { |
| | | headers: { 'Content-Type': 'application/json' } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | // åºåæç»ç¸å
³MESæ¥å£ |
| | | export const stockDetailMesApi = { |
| | | /** |
| | | * æççµè¯ç»å® |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, sfcList, location, operationType } |
| | | * @returns {Promise} |
| | | */ |
| | | bindContainer(data) { |
| | | return http.post(`${baseURL}/StockInfoDetail/bindContainer`, data, false, { |
| | | headers: { 'Content-Type': 'application/json' } |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * æççµè¯è§£ç» |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, sfcList } |
| | | * @returns {Promise} |
| | | */ |
| | | unbindContainer(data) { |
| | | return http.post(`${baseURL}/StockInfoDetail/unbindContainer`, data, false, { |
| | | headers: { 'Content-Type': 'application/json' } |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * æçNGçµè¯ä¸æ¥ |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, ngSfcList } |
| | | * @returns {Promise} |
| | | */ |
| | | containerNgReport(data) { |
| | | return http.post(`${baseURL}/StockInfoDetail/containerNgReport`, data, false, { |
| | | headers: { 'Content-Type': 'application/json' } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | export default { |
| | | stockInfo: stockInfoMesApi, |
| | | stockDetail: stockDetailMesApi |
| | | }; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | :title="dialogTitle" |
| | | width="500px" |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | > |
| | | <div class="mes-confirm-content"> |
| | | <p class="operation-text">{{ operationText }}</p> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row" v-for="(item, index) in displayInfo" :key="index"> |
| | | <span class="info-label">{{ item.label }}:</span> |
| | | <span class="info-value">{{ item.value }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="errorMessage" class="error-message"> |
| | | <el-icon><Warning /></el-icon> |
| | | <span>{{ errorMessage }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="handleClose">åæ¶</el-button> |
| | | <el-button |
| | | type="primary" |
| | | :loading="loading" |
| | | @click="handleConfirm" |
| | | > |
| | | 确认æ§è¡ |
| | | </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | import { defineComponent, ref, computed, watch } from 'vue'; |
| | | import { Warning } from '@element-plus/icons-vue'; |
| | | |
| | | /** |
| | | * MESç¡®è®¤å¯¹è¯æ¡ç»ä»¶ |
| | | * ç¨äºå¨æ§è¡MESæä½ï¼è¿ç«/åºç«/ç»å®/è§£ç»/NG䏿¥ï¼åæ¾ç¤ºç¡®è®¤ä¿¡æ¯ |
| | | */ |
| | | export default defineComponent({ |
| | | name: 'MesConfirmDialog', |
| | | |
| | | components: { |
| | | Warning |
| | | }, |
| | | |
| | | props: { |
| | | modelValue: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | /** |
| | | * æä½ç±»å: inbound(è¿ç«) | outbound(åºç«) | bind(ç»å®) | unbind(è§£ç») | ngReport(NG䏿¥) |
| | | */ |
| | | operationType: { |
| | | type: String, |
| | | required: true |
| | | }, |
| | | /** |
| | | * æçç |
| | | */ |
| | | palletCode: { |
| | | type: String, |
| | | required: true |
| | | }, |
| | | /** |
| | | * åºåä¿¡æ¯å¯¹è±¡ï¼ç¨äºè¿ç«/åºç«æä½ï¼ |
| | | */ |
| | | stockInfo: { |
| | | type: Object, |
| | | default: null |
| | | }, |
| | | /** |
| | | * åºåæç»ä¿¡æ¯å¯¹è±¡ï¼ç¨äºç»å®/è§£ç»/NG䏿¥æä½ï¼ |
| | | */ |
| | | detailInfo: { |
| | | type: Object, |
| | | default: null |
| | | } |
| | | }, |
| | | |
| | | emits: ['update:modelValue', 'confirm'], |
| | | |
| | | setup(props, { emit }) { |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const errorMessage = ref(''); |
| | | |
| | | // çå¬modelValueååï¼åæ¥å°visible |
| | | watch( |
| | | () => props.modelValue, |
| | | (newVal) => { |
| | | visible.value = newVal; |
| | | // å¯¹è¯æ¡æå¼æ¶éç½®éè¯¯ä¿¡æ¯ |
| | | if (newVal) { |
| | | errorMessage.value = ''; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | // çå¬visibleååï¼åæ¥å°modelValue |
| | | watch(visible, (newVal) => { |
| | | emit('update:modelValue', newVal); |
| | | }); |
| | | |
| | | /** |
| | | * æä½ç±»åé
ç½®æ å° |
| | | */ |
| | | const operationConfig = { |
| | | inbound: { title: 'æçè¿ç«', text: 'æ¨å³å°æ§è¡æçè¿ç«æä½' }, |
| | | outbound: { title: 'æçåºç«', text: 'æ¨å³å°æ§è¡æçåºç«æä½' }, |
| | | bind: { title: 'çµè¯ç»å®', text: 'æ¨å³å°æ§è¡çµè¯ç»å®æä½' }, |
| | | unbind: { title: 'çµè¯è§£ç»', text: 'æ¨å³å°æ§è¡çµè¯è§£ç»æä½' }, |
| | | ngReport: { title: 'NG䏿¥', text: 'æ¨å³å°æ§è¡NGçµè¯ä¸æ¥æä½' } |
| | | }; |
| | | |
| | | /** |
| | | * å¯¹è¯æ¡æ é¢ |
| | | */ |
| | | const dialogTitle = computed(() => { |
| | | return operationConfig[props.operationType]?.title || '确认æä½'; |
| | | }); |
| | | |
| | | /** |
| | | * æä½æç¤ºææ¬ |
| | | */ |
| | | const operationText = computed(() => { |
| | | return operationConfig[props.operationType]?.text || ''; |
| | | }); |
| | | |
| | | /** |
| | | * æ¾ç¤ºçä¿¡æ¯å表 |
| | | */ |
| | | const displayInfo = computed(() => { |
| | | const info = [ |
| | | { label: 'æçç ', value: props.palletCode || '-' } |
| | | ]; |
| | | |
| | | // 妿ææç»ä¿¡æ¯ï¼æ¾ç¤ºçµè¯æ°é |
| | | if (props.detailInfo) { |
| | | info.push({ |
| | | label: 'çµè¯æ°é', |
| | | value: props.detailInfo.sfcCount !== undefined ? props.detailInfo.sfcCount : '-' |
| | | }); |
| | | } |
| | | |
| | | // 妿æåºåä¿¡æ¯ï¼å¯ä»¥æ¾ç¤ºåºä½çä¿¡æ¯ |
| | | if (props.stockInfo) { |
| | | info.push({ |
| | | label: 'åºä½', |
| | | value: props.stockInfo.location || '-' |
| | | }); |
| | | } |
| | | |
| | | return info; |
| | | }); |
| | | |
| | | /** |
| | | * å
³éå¯¹è¯æ¡ |
| | | */ |
| | | const handleClose = () => { |
| | | visible.value = false; |
| | | errorMessage.value = ''; |
| | | loading.value = false; |
| | | }; |
| | | |
| | | /** |
| | | * 确认æ§è¡æä½ |
| | | * 触åconfirmäºä»¶ï¼ä¼ éæä½åè°åé误å¤ç彿° |
| | | */ |
| | | const handleConfirm = () => { |
| | | loading.value = true; |
| | | errorMessage.value = ''; |
| | | |
| | | // 触åconfirmäºä»¶ï¼ä¼ éæä½åæ°ååè°å½æ° |
| | | emit('confirm', { |
| | | operationType: props.operationType, |
| | | palletCode: props.palletCode, |
| | | stockInfo: props.stockInfo, |
| | | detailInfo: props.detailInfo, |
| | | onSuccess: () => { |
| | | // æä½æåï¼å
³éå¯¹è¯æ¡å¹¶éç½®ç¶æ |
| | | visible.value = false; |
| | | loading.value = false; |
| | | errorMessage.value = ''; |
| | | }, |
| | | onError: (error) => { |
| | | // æä½å¤±è´¥ï¼æ¾ç¤ºé误信æ¯å¹¶ä¿æå¯¹è¯æ¡æå¼ |
| | | errorMessage.value = error || 'æä½å¤±è´¥ï¼è¯·éè¯'; |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | return { |
| | | visible, |
| | | loading, |
| | | errorMessage, |
| | | dialogTitle, |
| | | operationText, |
| | | displayInfo, |
| | | handleClose, |
| | | handleConfirm |
| | | }; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="less" scoped> |
| | | .mes-confirm-content { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .operation-text { |
| | | font-size: 14px; |
| | | color: #303133; |
| | | margin-bottom: 20px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .info-section { |
| | | background: #f8fafc; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 12px; |
| | | font-size: 14px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | color: #909399; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .error-message { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 12px; |
| | | background: #fef0f0; |
| | | border: 1px solid #fde2e2; |
| | | border-radius: 6px; |
| | | color: #f56c6c; |
| | | font-size: 14px; |
| | | |
| | | .el-icon { |
| | | font-size: 18px; |
| | | } |
| | | } |
| | | </style> |
copy from Code/WMS/WIDESEA_WMSClient/src/extension/basic/supplierInfo.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/basic/userInfo.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/check/checkOrder.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/check/checkOrderResult.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrderDetail.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrderDetail_Hty.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrder_Hty.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrder.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/inbound/purchaseOrder.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrderDetail_Hty.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/inbound/purchaseOrderDetail.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/inbound/inboundOrderDetail_Hty.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/inbound/receiveOrderDetail.jsx
copy from Code/WMS/WIDESEA_WMSClient/src/extension/outbound/outboundOrderDetail_Hty.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/outbound/outboundOrder_Hty.jsx
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | //æ¤jsæä»¶æ¯ç¨æ¥èªå®ä¹æ©å±ä¸å¡ä»£ç ï¼å¯ä»¥æ©å±ä¸äºèªå®ä¹é¡µé¢æè
éæ°é
ç½®çæç代ç |
| | | |
| | | let extension = { |
| | | components: { |
| | | //æ¥è¯¢ç颿©å±ç»ä»¶ |
| | | gridHeader: '', |
| | | gridBody: '', |
| | | gridFooter: '', |
| | | //æ°å»ºãç¼è¾å¼¹åºæ¡æ©å±ç»ä»¶ |
| | | modelHeader: '', |
| | | modelBody: '', |
| | | modelFooter: '' |
| | | }, |
| | | tableAction: '', |
| | | buttons: { view: [], box: [], detail: [] }, |
| | | methods: { |
| | | onInit() { |
| | | // æ·»å MESæä½å |
| | | this.columns.push({ |
| | | title: 'æä½', |
| | | field: 'æä½', |
| | | align: 'center', |
| | | width: 200, |
| | | fixed: 'right', |
| | | render: (h, { row, column, index }) => { |
| | | return ( |
| | | <div> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | onClick={($e) => { this.handleInbound(row); }} |
| | | >è¿ç«</el-button> |
| | | <el-button |
| | | type="success" |
| | | size="small" |
| | | style="margin-left: 8px" |
| | | onClick={($e) => { this.handleOutbound(row); }} |
| | | >åºç«</el-button> |
| | | </div> |
| | | ); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // æçè¿ç«æä½ |
| | | async handleInbound(row) { |
| | | try { |
| | | await this.$confirm(`确认æ§è¡æçè¿ç«æä½ï¼\næçç¼å·ï¼${row.palletCode}`, "è¿ç«ç¡®è®¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning" |
| | | }); |
| | | |
| | | const result = await this.http.post("/api/StockInfo/inboundInContainer", { |
| | | palletCode: row.palletCode, |
| | | stockId: row.id |
| | | }, "æ£å¨è°ç¨MESæ¥å£..."); |
| | | |
| | | if (result.status) { |
| | | this.$Message.success(result.message || "æçè¿ç«æå"); |
| | | this.$refs.table.load(); |
| | | } else { |
| | | this.$error(result.message || "æçè¿ç«å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | this.$error(error.message || "ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // æçåºç«æä½ |
| | | async handleOutbound(row) { |
| | | try { |
| | | await this.$confirm(`确认æ§è¡æçåºç«æä½ï¼\næçç¼å·ï¼${row.palletCode}`, "åºç«ç¡®è®¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning" |
| | | }); |
| | | |
| | | const result = await this.http.post("/api/StockInfo/outboundInContainer", { |
| | | palletCode: row.palletCode, |
| | | stockId: row.id |
| | | }, "æ£å¨è°ç¨MESæ¥å£..."); |
| | | |
| | | if (result.status) { |
| | | this.$Message.success(result.message || "æçåºç«æå"); |
| | | this.$refs.table.load(); |
| | | } else { |
| | | this.$error(result.message || "æçåºç«å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | this.$error(error.message || "ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | onInited() { |
| | | // æ¡æ¶åå§åé
ç½®å |
| | | }, |
| | | searchBefore(param) { |
| | | return true; |
| | | }, |
| | | searchAfter(result) { |
| | | return true; |
| | | }, |
| | | addBefore(formData) { |
| | | return true; |
| | | }, |
| | | updateBefore(formData) { |
| | | return true; |
| | | }, |
| | | rowClick({ row, column, event }) { |
| | | this.$refs.table.$refs.table.toggleRowSelection(row); |
| | | }, |
| | | modelOpenAfter(row) { |
| | | // ç¹å»ç¼è¾ãæ°å»ºæé®å¼¹åºæ¡å |
| | | } |
| | | } |
| | | }; |
| | | |
| | | export default extension; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | //æ¤jsæä»¶æ¯ç¨æ¥èªå®ä¹æ©å±ä¸å¡ä»£ç ï¼å¯ä»¥æ©å±ä¸äºèªå®ä¹é¡µé¢æè
éæ°é
ç½®çæç代ç |
| | | |
| | | let extension = { |
| | | components: { |
| | | //æ¥è¯¢ç颿©å±ç»ä»¶ |
| | | gridHeader: '', |
| | | gridBody: '', |
| | | gridFooter: '', |
| | | //æ°å»ºãç¼è¾å¼¹åºæ¡æ©å±ç»ä»¶ |
| | | modelHeader: '', |
| | | modelBody: '', |
| | | modelFooter: '' |
| | | }, |
| | | tableAction: '', |
| | | buttons: { view: [], box: [], detail: [] }, |
| | | methods: { |
| | | onInit() { |
| | | // æ·»å MESæä½å |
| | | this.columns.push({ |
| | | title: 'æä½', |
| | | field: 'æä½', |
| | | align: 'center', |
| | | width: 280, |
| | | fixed: 'right', |
| | | render: (h, { row, column, index }) => { |
| | | // éå®ç¶æä¸æ¾ç¤ºæé® |
| | | // ç¶æ: 7=åºåºéå®, 9=ç§»åºéå®, 99=ç»çæ¤é, 199=å
¥åºæ¤é |
| | | const lockedStatuses = [7, 9, 99, 199]; |
| | | if (lockedStatuses.includes(row.status)) { |
| | | return <span style="color: #909399">ææ å¯æ§è¡æä½</span>; |
| | | } |
| | | |
| | | return ( |
| | | <div> |
| | | <el-button |
| | | type="primary" |
| | | size="small" |
| | | onClick={($e) => { this.handleBind(row); }} |
| | | >ç»å®</el-button> |
| | | <el-button |
| | | type="warning" |
| | | size="small" |
| | | style="margin-left: 6px" |
| | | onClick={($e) => { this.handleUnbind(row); }} |
| | | >è§£ç»</el-button> |
| | | <el-button |
| | | type="danger" |
| | | size="small" |
| | | style="margin-left: 6px" |
| | | onClick={($e) => { this.handleNgReport(row); }} |
| | | >NG䏿¥</el-button> |
| | | </div> |
| | | ); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // æççµè¯ç»å®æä½ |
| | | async handleBind(row) { |
| | | try { |
| | | await this.$confirm(`确认æ§è¡çµè¯ç»å®æä½ï¼\nçµè¯ç ï¼${row.serialNumber}`, "ç»å®ç¡®è®¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning" |
| | | }); |
| | | |
| | | const result = await this.http.post("/api/StockInfoDetail/bindContainer", { |
| | | palletCode: row.palletCode || "P001", |
| | | sfcList: [row.serialNumber], |
| | | location: row.location || "", |
| | | operationType: 1 |
| | | }, "æ£å¨è°ç¨MESæ¥å£..."); |
| | | |
| | | if (result.status) { |
| | | this.$Message.success(result.message || "çµè¯ç»å®æå"); |
| | | this.$refs.table.load(); |
| | | } else { |
| | | this.$error(result.message || "çµè¯ç»å®å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | this.$error(error.message || "ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // æççµè¯è§£ç»æä½ |
| | | async handleUnbind(row) { |
| | | try { |
| | | await this.$confirm(`确认æ§è¡çµè¯è§£ç»æä½ï¼\nçµè¯ç ï¼${row.serialNumber}`, "è§£ç»ç¡®è®¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning" |
| | | }); |
| | | |
| | | const result = await this.http.post("/api/StockInfoDetail/unbindContainer", { |
| | | palletCode: row.palletCode || "P001", |
| | | sfcList: [row.serialNumber] |
| | | }, "æ£å¨è°ç¨MESæ¥å£..."); |
| | | |
| | | if (result.status) { |
| | | this.$Message.success(result.message || "çµè¯è§£ç»æå"); |
| | | this.$refs.table.load(); |
| | | } else { |
| | | this.$error(result.message || "çµè¯è§£ç»å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | this.$error(error.message || "ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | // æçNGçµè¯ä¸æ¥æä½ |
| | | async handleNgReport(row) { |
| | | try { |
| | | await this.$confirm(`确认æ§è¡NGçµè¯ä¸æ¥æä½ï¼\nçµè¯ç ï¼${row.serialNumber}`, "NG䏿¥ç¡®è®¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning" |
| | | }); |
| | | |
| | | const result = await this.http.post("/api/StockInfoDetail/containerNgReport", { |
| | | palletCode: row.palletCode || "P001", |
| | | ngSfcList: [{ |
| | | sfc: row.serialNumber, |
| | | ngCode: "NG001", |
| | | ngEquipmentCode: "WCS_001", |
| | | ngResourceCode: "RESOURCE_001" |
| | | }] |
| | | }, "æ£å¨è°ç¨MESæ¥å£..."); |
| | | |
| | | if (result.status) { |
| | | this.$Message.success(result.message || "NG䏿¥æå"); |
| | | this.$refs.table.load(); |
| | | } else { |
| | | this.$error(result.message || "NG䏿¥å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | this.$error(error.message || "ç½ç»é误ï¼è¯·ç¨åéè¯"); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | onInited() { |
| | | // æ¡æ¶åå§åé
ç½®å |
| | | }, |
| | | searchBefore(param) { |
| | | return true; |
| | | }, |
| | | searchAfter(result) { |
| | | return true; |
| | | }, |
| | | addBefore(formData) { |
| | | return true; |
| | | }, |
| | | updateBefore(formData) { |
| | | return true; |
| | | }, |
| | | rowClick({ row, column, event }) { |
| | | this.$refs.table.$refs.table.toggleRowSelection(row); |
| | | }, |
| | | modelOpenAfter(row) { |
| | | // ç¹å»ç¼è¾ãæ°å»ºæé®å¼¹åºæ¡å |
| | | } |
| | | } |
| | | }; |
| | | |
| | | export default extension; |
copy from Code/WMS/WIDESEA_WMSClient/src/extension/stock/stockInfoDetail_Hty.js
copy to Code/WMS/WIDESEA_WMSClient/src/extension/stock/stockInfo_Hty.jsx
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <vol-box |
| | | v-model="showBox" |
| | | :lazy="true" |
| | | width="500px" |
| | | :padding="15" |
| | | title="æå¨å建任å¡" |
| | | > |
| | | <el-form :model="formData" ref="form" label-width="100px"> |
| | | <el-form-item label="ä»»å¡ç±»å" prop="taskType" required> |
| | | <el-select v-model="formData.taskType" placeholder="è¯·éæ©ä»»å¡ç±»å"> |
| | | <el-option label="å
¥åº" value="å
¥åº"></el-option> |
| | | <el-option label="åºåº" value="åºåº"></el-option> |
| | | <el-option label="ç§»åº" value="ç§»åº"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="èµ·ç¹å°å" prop="sourceAddress" required> |
| | | <el-input v-model="formData.sourceAddress" placeholder="请è¾å
¥èµ·ç¹å°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ç»ç¹å°å" prop="targetAddress" required> |
| | | <el-input v-model="formData.targetAddress" placeholder="请è¾å
¥ç»ç¹å°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æ¡ç " prop="barcode" required> |
| | | <el-input v-model="formData.barcode" placeholder="请è¾å
¥æ¡ç "></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ä»åºID" prop="warehouseId" required> |
| | | <el-input v-model="formData.warehouseId" placeholder="请è¾å
¥ä»åºID"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼å
级"> |
| | | <el-input v-model="formData.grade" readonly></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" size="small" @click="submit">ç¡®å®</el-button> |
| | | <el-button type="danger" size="small" @click="showBox = false">å
³é</el-button> |
| | | </template> |
| | | </vol-box> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import VolBox from "@/components/basic/VolBox.vue"; |
| | | export default { |
| | | components: { VolBox }, |
| | | data() { |
| | | return { |
| | | showBox: false, |
| | | formData: { |
| | | taskType: "", |
| | | sourceAddress: "", |
| | | targetAddress: "", |
| | | barcode: "", |
| | | warehouseId: "", |
| | | grade: 1, |
| | | }, |
| | | }; |
| | | }, |
| | | methods: { |
| | | open() { |
| | | this.showBox = true; |
| | | this.resetForm(); |
| | | }, |
| | | resetForm() { |
| | | this.formData = { |
| | | taskType: "", |
| | | sourceAddress: "", |
| | | targetAddress: "", |
| | | barcode: "", |
| | | warehouseId: "", |
| | | grade: 1, |
| | | }; |
| | | }, |
| | | submit() { |
| | | if (!this.formData.taskType) return this.$message.error("è¯·éæ©ä»»å¡ç±»å"); |
| | | if (!this.formData.sourceAddress) return this.$message.error("请è¾å
¥èµ·ç¹å°å"); |
| | | if (!this.formData.targetAddress) return this.$message.error("请è¾å
¥ç»ç¹å°å"); |
| | | if (!this.formData.barcode) return this.$message.error("请è¾å
¥æ¡ç "); |
| | | if (!this.formData.warehouseId) return this.$message.error("请è¾å
¥ä»åºID"); |
| | | |
| | | this.http |
| | | .post("/api/Task/CreateManualTask", this.formData, "æ°æ®å¤çä¸...") |
| | | .then((res) => { |
| | | if (!res.status) return this.$message.error(res.message); |
| | | this.$message.success("ä»»å¡å建æå"); |
| | | this.showBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.refresh(); |
| | | }); |
| | | }); |
| | | }, |
| | | }, |
| | | }; |
| | | </script> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div> |
| | | <!-- æå¨å建任å¡å¼¹çª --> |
| | | <vol-box v-model="showManualCreate" :lazy="true" width="500px" :padding="15" title="æå¨å建任å¡"> |
| | | <el-form :model="manualFormData" ref="form" label-width="100px"> |
| | | <el-form-item label="ä»»å¡ç±»å" prop="taskType" required> |
| | | <el-select v-model="manualFormData.taskType" placeholder="è¯·éæ©ä»»å¡ç±»å"> |
| | | <el-option label="å
¥åº" value="å
¥åº"></el-option> |
| | | <el-option label="åºåº" value="åºåº"></el-option> |
| | | <el-option label="ç§»åº" value="ç§»åº"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="èµ·ç¹å°å" prop="sourceAddress" required> |
| | | <el-input v-model="manualFormData.sourceAddress" placeholder="请è¾å
¥èµ·ç¹å°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ç»ç¹å°å" prop="targetAddress" required> |
| | | <el-input v-model="manualFormData.targetAddress" placeholder="请è¾å
¥ç»ç¹å°å"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="æ¡ç " prop="barcode" required> |
| | | <el-input v-model="manualFormData.barcode" placeholder="请è¾å
¥æ¡ç "></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ä»åºID" prop="warehouseId" required> |
| | | <el-input v-model="manualFormData.warehouseId" placeholder="请è¾å
¥ä»åºID"></el-input> |
| | | </el-form-item> |
| | | <el-form-item label="ä¼å
级"> |
| | | <el-input v-model="manualFormData.grade" readonly></el-input> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" size="small" @click="submitManualCreate">ç¡®å®</el-button> |
| | | <el-button type="danger" size="small" @click="showManualCreate = false">å
³é</el-button> |
| | | </template> |
| | | </vol-box> |
| | | |
| | | <!-- æå¨ä¸åä»»å¡å¼¹çª --> |
| | | <vol-box v-model="showDispatch" :lazy="true" width="900px" :padding="15" title="æå¨ä¸åä»»å¡å° WCS"> |
| | | <div v-if="dispatchRows.length > 0" class="dispatch-info"> |
| | | å·²é任塿°: <span class="count">{{ dispatchRows.length }}</span> 个 |
| | | </div> |
| | | |
| | | <el-table :data="dispatchTableData" border style="width: 100%; margin-top: 10px" max-height="400"> |
| | | <el-table-column prop="taskNum" label="ä»»å¡å·" width="120"></el-table-column> |
| | | <el-table-column prop="palletCode" label="æçå·" width="140"> |
| | | <template v-slot="{ row }"> |
| | | <el-input v-if="row && row.editable" v-model="row.palletCode" size="small" placeholder="请è¾å
¥"></el-input> |
| | | <span v-else>{{ row ? row.palletCode : '' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="sourceAddress" label="èµ·ç¹å°å" width="160"> |
| | | <template v-slot="{ row }"> |
| | | <el-input v-if="row && row.editable" v-model="row.sourceAddress" size="small" placeholder="请è¾å
¥"></el-input> |
| | | <span v-else>{{ row ? row.sourceAddress : '' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="targetAddress" label="ç»ç¹å°å" width="160"> |
| | | <template v-slot="{ row }"> |
| | | <el-input v-if="row && row.editable" v-model="row.targetAddress" size="small" placeholder="请è¾å
¥"></el-input> |
| | | <span v-else>{{ row ? row.targetAddress : '' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="grade" label="ä¼å
级" width="100"> |
| | | <template v-slot="{ row }"> |
| | | <el-input-number v-if="row && row.editable" v-model="row.grade" :min="1" :max="99" size="small" style="width: 80px"></el-input-number> |
| | | <span v-else>{{ row ? row.grade : '' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="statusName" label="ç¶æ" width="120"> |
| | | <template v-slot="{ row }"> |
| | | <span :class="{ 'status-error': row && !row.editable }">{{ row ? row.statusName : '' }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <div v-if="dispatchFailResults && dispatchFailResults.length > 0" class="fail-results"> |
| | | <div class="fail-title">ä¸å失败任å¡ï¼</div> |
| | | <el-table :data="dispatchFailResults" border style="width: 100%; margin-top: 10px" max-height="200"> |
| | | <el-table-column prop="taskNum" label="ä»»å¡å·" width="120"></el-table-column> |
| | | <el-table-column prop="errorMessage" label="失败åå "></el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <el-button type="primary" size="small" @click="submitDispatch" :loading="dispatchLoading">确认ä¸å</el-button> |
| | | <el-button type="danger" size="small" @click="showDispatch = false">åæ¶</el-button> |
| | | </template> |
| | | </vol-box> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import VolBox from "@/components/basic/VolBox.vue"; |
| | | |
| | | export default { |
| | | components: { VolBox }, |
| | | emits: ["parentCall"], |
| | | data() { |
| | | return { |
| | | // æå¨åå»ºä»»å¡ |
| | | showManualCreate: false, |
| | | manualFormData: { |
| | | taskType: "", |
| | | sourceAddress: "", |
| | | targetAddress: "", |
| | | barcode: "", |
| | | warehouseId: "", |
| | | grade: 1, |
| | | }, |
| | | // æå¨ä¸åä»»å¡ |
| | | showDispatch: false, |
| | | dispatchLoading: false, |
| | | dispatchRows: [], |
| | | dispatchTableData: [], |
| | | dispatchFailResults: [], |
| | | dispatchOriginalData: [], |
| | | }; |
| | | }, |
| | | methods: { |
| | | // æå¨åå»ºä»»å¡ - æå¼ |
| | | open() { |
| | | this.showManualCreate = true; |
| | | this.resetManualForm(); |
| | | }, |
| | | resetManualForm() { |
| | | this.manualFormData = { |
| | | taskType: "", |
| | | sourceAddress: "", |
| | | targetAddress: "", |
| | | barcode: "", |
| | | warehouseId: "", |
| | | grade: 1, |
| | | }; |
| | | }, |
| | | submitManualCreate() { |
| | | if (!this.manualFormData.taskType) return this.$message.error("è¯·éæ©ä»»å¡ç±»å"); |
| | | if (!this.manualFormData.sourceAddress) return this.$message.error("请è¾å
¥èµ·ç¹å°å"); |
| | | if (!this.manualFormData.targetAddress) return this.$message.error("请è¾å
¥ç»ç¹å°å"); |
| | | if (!this.manualFormData.barcode) return this.$message.error("请è¾å
¥æ¡ç "); |
| | | if (!this.manualFormData.warehouseId) return this.$message.error("请è¾å
¥ä»åºID"); |
| | | |
| | | this.http |
| | | .post("/api/Task/CreateManualTask", this.manualFormData, "æ°æ®å¤çä¸...") |
| | | .then((res) => { |
| | | if (!res.status) return this.$message.error(res.message); |
| | | this.$message.success("ä»»å¡å建æå"); |
| | | this.showManualCreate = false; |
| | | this.$emit("parentCall", ($vue) => { $vue.refresh(); }); |
| | | }); |
| | | }, |
| | | // æå¨ä¸åä»»å¡ - æå¼ |
| | | openDispatch(rows) { |
| | | console.log('openDispatch called with rows:', rows); |
| | | console.log('rows type:', typeof rows, Array.isArray(rows)); |
| | | // ç¡®ä¿æ¯æ°ç» |
| | | if (!rows) { |
| | | this.dispatchRows = []; |
| | | } else if (Array.isArray(rows)) { |
| | | this.dispatchRows = rows; |
| | | } else { |
| | | // 妿æ¯å个对象ï¼å
è£
ææ°ç» |
| | | this.dispatchRows = [rows]; |
| | | } |
| | | console.log('dispatchRows length:', this.dispatchRows.length); |
| | | this.dispatchFailResults = []; |
| | | // å
åå§åæ°æ®ï¼åæ¾ç¤ºå¼¹çª |
| | | this.initDispatchTableData(); |
| | | this.showDispatch = true; |
| | | }, |
| | | initDispatchTableData() { |
| | | console.log('initDispatchTableData dispatchRows:', this.dispatchRows); |
| | | console.log('dispatchRows isArray:', Array.isArray(this.dispatchRows), 'length:', this.dispatchRows?.length); |
| | | |
| | | // ç¡®ä¿ dispatchRows æ¯æ°ç» |
| | | if (!this.dispatchRows || !Array.isArray(this.dispatchRows)) { |
| | | console.warn('dispatchRows 䏿¯æææ°ç»ï¼é置为空æ°ç»'); |
| | | this.dispatchTableData = []; |
| | | return; |
| | | } |
| | | |
| | | const statusNames = { |
| | | 'inbound_200': 'å
¥åºæ°å', |
| | | 'outbound_100': 'åºåºæ°å', |
| | | 'relocation_300': 'ç§»åºæ°å', |
| | | 'outbound_110': 'å åæºåºåºæ§è¡ä¸', |
| | | 'outbound_115': 'å åæºåºåºå®æ', |
| | | 'inbound_220': 'è¾é线å
¥åºæ§è¡ä¸', |
| | | 'inbound_230': 'å åæºå
¥åºæ§è¡ä¸', |
| | | 'inbound_290': 'å
¥åºä»»å¡å®æ', |
| | | 'outbound_120': 'è¾é线åºåºæ§è¡ä¸', |
| | | 'outbound_125': 'è¾é线åºåºå®æ', |
| | | 'outbound_200': 'åºåºä»»å¡å®æ', |
| | | 'relocation_310': 'å åæºç§»åºæ§è¡ä¸' |
| | | }; |
| | | |
| | | const result = []; |
| | | const original = []; |
| | | let filteredCount = 0; // è®°å½è¢«è¿æ»¤ç任塿°é |
| | | for (const row of this.dispatchRows) { |
| | | console.log('Processing row:', row); |
| | | // Handle possible field name differences (camelCase vs PascalCase) |
| | | const taskId = row.taskId ?? row.Id ?? row.id ?? 0; |
| | | const taskType = row.taskType ?? row.TaskType ?? row.task_type ?? 0; |
| | | const taskStatus = row.taskStatus ?? row.TaskStatus ?? row.task_status ?? 0; |
| | | console.log('taskId:', taskId, 'taskType:', taskType, 'taskStatus:', taskStatus); |
| | | const statusKey = this.getStatusKey(taskType, taskStatus); |
| | | console.log('statusKey:', statusKey); |
| | | const statusName = statusNames[statusKey] || `ç¶æ${taskStatus}`; |
| | | const editable = this.isEditable(taskType, taskStatus); |
| | | console.log('editable:', editable, 'æ ¹æ® taskType:', taskType, 'taskStatus:', taskStatus); |
| | | |
| | | // éæ°å»ºç¶æçä»»å¡ä¸æ¾ç¤ºå¨å¼¹çªä¸ |
| | | if (!editable) { |
| | | console.log(`ä»»å¡${taskId}ç¶æ[${statusName}]䏿¯æ°å»ºï¼å·²è¿æ»¤`); |
| | | filteredCount++; |
| | | continue; |
| | | } |
| | | |
| | | const item = { |
| | | taskId: taskId, |
| | | taskNum: row.taskNum ?? row.TaskNum ?? 0, |
| | | sourceAddress: row.sourceAddress || row.SourceAddress || '', |
| | | targetAddress: row.targetAddress || row.TargetAddress || '', |
| | | grade: row.grade ?? row.Grade ?? 1, |
| | | statusName: statusName, |
| | | palletCode: row.palletCode || row.PalletCode || '', |
| | | editable: editable, |
| | | taskType: taskType, |
| | | taskStatus: taskStatus |
| | | }; |
| | | result.push(item); |
| | | // ä¿ååå§æ°æ®ç坿¬ |
| | | original.push({ ...item }); |
| | | } |
| | | this.dispatchTableData = result; |
| | | this.dispatchOriginalData = original; |
| | | console.log('dispatchTableData result:', this.dispatchTableData); |
| | | console.log('dispatchOriginalData:', this.dispatchOriginalData); |
| | | |
| | | // 妿æè¢«è¿æ»¤çä»»å¡ï¼æ¾ç¤ºæç¤º |
| | | if (filteredCount > 0) { |
| | | this.$message.warning(`éä¸ç${this.dispatchRows.length}个任å¡ä¸æ${filteredCount}ä¸ªéæ°å»ºç¶æä»»å¡å·²è¿æ»¤`); |
| | | } |
| | | }, |
| | | getStatusKey(taskType, taskStatus) { |
| | | if (taskType === 200) return `inbound_${taskStatus}`; |
| | | if (taskType === 100) return `outbound_${taskStatus}`; |
| | | if (taskType === 300) return `relocation_${taskStatus}`; |
| | | return `other_${taskStatus}`; |
| | | }, |
| | | isEditable(taskType, taskStatus) { |
| | | if (taskType === 200 && taskStatus === 200) return true; |
| | | if (taskType === 100 && taskStatus === 100) return true; |
| | | if (taskType === 300 && taskStatus === 300) return true; |
| | | return false; |
| | | }, |
| | | submitDispatch() { |
| | | if (this.dispatchTableData.length === 0) return this.$message.error("请å
鿩任å¡"); |
| | | |
| | | const dispatchData = this.dispatchTableData.map(row => ({ |
| | | taskId: row.taskId, |
| | | palletCode: row.palletCode, |
| | | sourceAddress: row.sourceAddress, |
| | | targetAddress: row.targetAddress, |
| | | grade: row.grade |
| | | })); |
| | | console.log('Dispatching data:', dispatchData); |
| | | |
| | | this.dispatchLoading = true; |
| | | this.http |
| | | .post("/api/Task/DispatchTasksToWCS", dispatchData, "æ°æ®å¤çä¸...") |
| | | .then((res) => { |
| | | this.dispatchLoading = false; |
| | | if (!res.status) { |
| | | this.$message.error(res.message); |
| | | if (res.data && res.data.failResults) { |
| | | this.dispatchFailResults = res.data.failResults; |
| | | } |
| | | return; |
| | | } |
| | | |
| | | if (res.data && res.data.failCount === 0) { |
| | | this.$message.success(res.message); |
| | | this.showDispatch = false; |
| | | this.$emit("parentCall", ($vue) => { $vue.refresh(); }); |
| | | return; |
| | | } |
| | | |
| | | if (res.data && res.data.failResults) { |
| | | this.dispatchFailResults = res.data.failResults; |
| | | } |
| | | |
| | | if (res.data && res.data.failCount > 0 && res.data.successCount > 0) { |
| | | this.$message.warning(res.message); |
| | | } else { |
| | | this.$message.error(res.message); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | this.dispatchLoading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .dispatch-info { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | .dispatch-info .count { |
| | | color: #409eff; |
| | | font-weight: bold; |
| | | } |
| | | .status-error { |
| | | color: #f56c6c; |
| | | } |
| | | .fail-results { |
| | | margin-top: 15px; |
| | | padding: 10px; |
| | | background: #fef0f0; |
| | | border-radius: 4px; |
| | | } |
| | | .fail-title { |
| | | font-size: 14px; |
| | | color: #f56c6c; |
| | | margin-bottom: 5px; |
| | | } |
| | | </style> |
| ÎļþÃû´Ó Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js ÐÞ¸Ä |
| | |
| | | |
| | | //æ¤jsæä»¶æ¯ç¨æ¥èªå®ä¹æ©å±ä¸å¡ä»£ç ï¼å¯ä»¥æ©å±ä¸äºèªå®ä¹é¡µé¢æè
éæ°é
ç½®çæç代ç |
| | | import gridBodyExtension from './extend/gridBodyExtension.vue' |
| | | |
| | | let extension = { |
| | | components: { |
| | | //æ¥è¯¢ç颿©å±ç»ä»¶ |
| | | gridHeader: '', |
| | | gridBody: '', |
| | | gridBody: gridBodyExtension, |
| | | gridFooter: '', |
| | | //æ°å»ºãç¼è¾å¼¹åºæ¡æ©å±ç»ä»¶ |
| | | modelHeader: '', |
| | | modelBody: '', |
| | | modelFooter: '' |
| | | modelFooter: '', |
| | | }, |
| | | tableAction: '', //æå®æå¼ 表çæé(è¿éå¡«å表å,é»è®¤ä¸ç¨å¡«å) |
| | | buttons: { view: [], box: [], detail: [] }, //æ©å±çæé® |
| | | methods: { |
| | | //ä¸é¢è¿äºæ¹æ³å¯ä»¥ä¿çä¹å¯ä»¥å é¤ |
| | | onInit() { |
| | | onInit() { |
| | | //æ·»å "æå¨å建任å¡"æé® |
| | | this.buttons.push({ |
| | | name: 'æå¨å建任å¡', |
| | | icon: 'el-icon-plus', |
| | | type: 'primary', |
| | | value: 'ManualCreateTask', |
| | | onClick: () => { |
| | | this.$refs.gridBody.open(); |
| | | } |
| | | }); |
| | | //æ·»å "æå¨ä¸å"æé® |
| | | this.buttons.push({ |
| | | name: 'æå¨ä¸å', |
| | | icon: 'el-icon-s-promotion', |
| | | type: 'primary', |
| | | value: 'DispatchTasksToWCS', |
| | | onClick: () => { |
| | | let rows = this.$refs.table.getSelected(); |
| | | if (rows.length == 0) return this.$error("请å
鿩任å¡"); |
| | | this.$refs.gridBody.openDispatch(rows); |
| | | } |
| | | }); |
| | | |
| | | let TaskHandCancelBtn = this.buttons.find(x => x.value == 'TaskHandCancel'); |
| | | if (TaskHandCancelBtn) { |
| | | TaskHandCancelBtn.onClick = function () { |
| | |
| | | } |
| | | }; |
| | | export default extension; |
| | | |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/customerInfo.js"; |
| | | import extend from "@/extension/basic/customerInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/locationInfo.js"; |
| | | import extend from "@/extension/basic/locationInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/materielCodeInfo.js"; |
| | | import extend from "@/extension/basic/materielCodeInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/materielInfo.js"; |
| | | import extend from "@/extension/basic/materielInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/palletCodeInfo.js"; |
| | | import extend from "@/extension/basic/palletCodeInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/supplierInfo.js"; |
| | | import extend from "@/extension/basic/supplierInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/userInfo.js"; |
| | | import extend from "@/extension/basic/userInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/basic/warehouse.js"; |
| | | import extend from "@/extension/basic/warehouse.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/check/checkOrder.js"; |
| | | import extend from "@/extension/check/checkOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/check/checkOrderResult.js"; |
| | | import extend from "@/extension/check/checkOrderResult.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/inboundOrder.js"; |
| | | import extend from "@/extension/inbound/inboundOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/inboundOrderDetail.js"; |
| | | import extend from "@/extension/inbound/inboundOrderDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/inboundOrderDetail_Hty.js"; |
| | | import extend from "@/extension/inbound/inboundOrderDetail_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/inboundOrder_Hty.js"; |
| | | import extend from "@/extension/inbound/inboundOrder_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/purchaseOrder.js"; |
| | | import extend from "@/extension/inbound/purchaseOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/purchaseOrderDetail.js"; |
| | | import extend from "@/extension/inbound/purchaseOrderDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/receiveOrder.js"; |
| | | import extend from "@/extension/inbound/receiveOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/inbound/receiveOrderDetail.js"; |
| | | import extend from "@/extension/inbound/receiveOrderDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/mesOutboundOrder.js"; |
| | | import extend from "@/extension/outbound/mesOutboundOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/outStockLockInfo.js"; |
| | | import extend from "@/extension/outbound/outStockLockInfo.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/outboundOrder.js"; |
| | | import extend from "@/extension/outbound/outboundOrder.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/outboundOrderDetail.js"; |
| | | import extend from "@/extension/outbound/outboundOrderDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/outboundOrderDetail_Hty.js"; |
| | | import extend from "@/extension/outbound/outboundOrderDetail_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/outbound/outboundOrder_Hty.js"; |
| | | import extend from "@/extension/outbound/outboundOrder_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/record/locationStatusChangeRecord.js"; |
| | | import extend from "@/extension/record/locationStatusChangeRecord.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/record/stockQuantityChangeRecord.js"; |
| | | import extend from "@/extension/record/stockQuantityChangeRecord.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stock.js"; |
| | | import extend from "@/extension/stock/stock.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfo.js"; |
| | | import extend from "@/extension/stock/stockInfo.jsx"; |
| | | import { |
| | | defineComponent, |
| | | getCurrentInstance, |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfoDetail.js"; |
| | | import extend from "@/extension/stock/stockInfoDetail.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfoDetail_Hty.js"; |
| | | import extend from "@/extension/stock/stockInfoDetail_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stockInfo_Hty.js"; |
| | | import extend from "@/extension/stock/stockInfo_Hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/stock/stockView.js"; |
| | | import extend from "@/extension/stock/stockView.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Dictionary.js"; |
| | | import extend from "@/extension/system/Sys_Dictionary.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import extend from "@/extension/system/Sys_DictionaryList.js"; |
| | | import extend from "@/extension/system/Sys_DictionaryList.jsx"; |
| | | var vueParam = { |
| | | data() { |
| | | return { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Log.js"; |
| | | import extend from "@/extension/system/Sys_Log.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Role.js"; |
| | | import extend from "@/extension/system/Sys_Role.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Role1.js"; |
| | | import extend from "@/extension/system/Sys_Role1.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_Tenant.js"; |
| | | import extend from "@/extension/system/Sys_Tenant.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | |
| | | export default defineComponent({ |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/Sys_User.js"; |
| | | import extend from "@/extension/system/Sys_User.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/system/system/Sys_Department.js"; |
| | | import extend from "@/extension/system/system/Sys_Department.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/taskinfo/task.js"; |
| | | import extend from "@/extension/taskinfo/task.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| | |
| | | </view-grid> |
| | | </template> |
| | | <script> |
| | | import extend from "@/extension/taskinfo/task_hty.js"; |
| | | import extend from "@/extension/taskinfo/task_hty.jsx"; |
| | | import { ref, defineComponent } from "vue"; |
| | | export default defineComponent({ |
| | | setup() { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import { defineConfig } from 'vite' |
| | | import vue from '@vitejs/plugin-vue' |
| | | import vueJsx from '@vitejs/plugin-vue-jsx' |
| | | import { resolve, dirname } from 'path' |
| | | import { fileURLToPath } from 'url' |
| | | |
| | | // https://vitejs.dev/config/ |
| | | export default defineConfig({ |
| | | plugins: [vue(), vueJsx()], |
| | | resolve: { |
| | | alias: { |
| | | '@': resolve(dirname(fileURLToPath(import.meta.url)), 'src') |
| | | } |
| | | }, |
| | | server: { |
| | | host: '0.0.0.0', |
| | | port: 8080, |
| | | open: false |
| | | }, |
| | | build: { |
| | | sourcemap: false |
| | | } |
| | | }) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | -- ============================================= |
| | | -- WMS MESæ¥å£è°ç¨æ¥å¿è¡¨ |
| | | -- åå»ºæ¥æ: 2026-04-12 |
| | | -- æè¿°: è®°å½ææMESæ¥å£çè°ç¨æ¥å¿ï¼å
æ¬è¯·æ±ãååºãèæ¶ãæå/å¤±è´¥ç¶æçä¿¡æ¯ |
| | | -- ============================================= |
| | | |
| | | IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'Dt_MesApiLog') |
| | | BEGIN |
| | | CREATE TABLE Dt_MesApiLog ( |
| | | Id BIGINT PRIMARY KEY IDENTITY(1,1), |
| | | ApiType NVARCHAR(50) NOT NULL, -- æ¥å£ç±»å |
| | | RequestJson NVARCHAR(MAX) NULL, -- 请æ±JSON |
| | | ResponseJson NVARCHAR(MAX) NULL, -- ååºJSON |
| | | IsSuccess BIT NOT NULL DEFAULT 0, -- æ¯å¦æå |
| | | ErrorMessage NVARCHAR(500) NULL, -- éè¯¯ä¿¡æ¯ |
| | | ElapsedMs INT NOT NULL DEFAULT 0, -- èæ¶(毫ç§) |
| | | CreateDate DATETIME NOT NULL, -- å建æ¶é´ |
| | | Creator NVARCHAR(50) NULL, -- å建人 |
| | | ModifyDate DATETIME NULL, -- ä¿®æ¹æ¶é´ |
| | | Modifier NVARCHAR(50) NULL -- ä¿®æ¹äºº |
| | | ); |
| | | |
| | | -- åå»ºç´¢å¼ |
| | | CREATE INDEX IX_MesApiLog_ApiType ON Dt_MesApiLog(ApiType); |
| | | CREATE INDEX IX_MesApiLog_CreateDate ON Dt_MesApiLog(CreateDate); |
| | | CREATE INDEX IX_MesApiLog_IsSuccess ON Dt_MesApiLog(IsSuccess); |
| | | |
| | | PRINT 'MESæ¥å£æ¥å¿è¡¨ Dt_MesApiLog å建æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MESæ¥å£æ¥å¿è¡¨ Dt_MesApiLog å·²åå¨'; |
| | | END |
| | | GO |
| | | |
| | | -- ============================================= |
| | | -- æå
¥MESç³»ç»é
ç½® |
| | | -- ============================================= |
| | | |
| | | -- æ£æ¥å¹¶æå
¥MES设å¤ç¼ç é
ç½® |
| | | IF NOT EXISTS (SELECT * FROM Dt_SystemConfig WHERE ConfigKey = 'MES_EquipmentCode') |
| | | BEGIN |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_EquipmentCode', 'WCS_001', 'MES设å¤ç¼ç ', GETDATE(), 'System'); |
| | | PRINT 'MES设å¤ç¼ç é
ç½®æå
¥æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MES设å¤ç¼ç é
置已åå¨'; |
| | | END |
| | | GO |
| | | |
| | | -- æ£æ¥å¹¶æå
¥MESèµæºç¼ç é
ç½® |
| | | IF NOT EXISTS (SELECT * FROM Dt_SystemConfig WHERE ConfigKey = 'MES_ResourceCode') |
| | | BEGIN |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_ResourceCode', 'RESOURCE_001', 'MESèµæºç¼ç ', GETDATE(), 'System'); |
| | | PRINT 'MESèµæºç¼ç é
ç½®æå
¥æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MESèµæºç¼ç é
置已åå¨'; |
| | | END |
| | | GO |
| | | |
| | | -- æ£æ¥å¹¶æå
¥MESæ¥å£å°åé
ç½® |
| | | IF NOT EXISTS (SELECT * FROM Dt_SystemConfig WHERE ConfigKey = 'MES_ApiBaseUrl') |
| | | BEGIN |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_ApiBaseUrl', 'http://mes-server/api', 'MESæ¥å£å°å', GETDATE(), 'System'); |
| | | PRINT 'MESæ¥å£å°åé
ç½®æå
¥æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MESæ¥å£å°åé
置已åå¨'; |
| | | END |
| | | GO |
| | | |
| | | -- æ£æ¥å¹¶æå
¥MESæ¥å£è¶
æ¶æ¶é´é
ç½® |
| | | IF NOT EXISTS (SELECT * FROM Dt_SystemConfig WHERE ConfigKey = 'MES_TimeoutSeconds') |
| | | BEGIN |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_TimeoutSeconds', '30', 'MESæ¥å£è¶
æ¶æ¶é´(ç§)', GETDATE(), 'System'); |
| | | PRINT 'MESæ¥å£è¶
æ¶æ¶é´é
ç½®æå
¥æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MESæ¥å£è¶
æ¶æ¶é´é
置已åå¨'; |
| | | END |
| | | GO |
| | | |
| | | PRINT 'MESæ¥å£æ¥å¿è¡¨åç³»ç»é
ç½®èæ¬æ§è¡å®æ'; |
| | |
| | | |
| | | void BeginTran(); |
| | | void BeginTran(MethodInfo method); |
| | | WebResponseContent BeginTran(Func<WebResponseContent> func); |
| | | Task<WebResponseContent> BeginTranAsync(Func<Task<WebResponseContent>> funcAsync); |
| | | void CommitTran(); |
| | | void CommitTran(MethodInfo method); |
| | | void RollbackTran(); |
| | |
| | | } |
| | | } |
| | | |
| | | private readonly SemaphoreSlim _asyncLock = new SemaphoreSlim(1, 1); |
| | | |
| | | public async Task<WebResponseContent> BeginTranAsync(Func<Task<WebResponseContent>> funcAsync) |
| | | { |
| | | await _asyncLock.WaitAsync(); |
| | | try |
| | | { |
| | | BeginTran(); // åè®¾è¿æ¯åæ¥æ¹æ³ï¼å¯å¨äºå¡ |
| | | WebResponseContent content = await funcAsync(); |
| | | if (content.Status) |
| | | CommitTran(); // 忥æäº¤ |
| | | else |
| | | RollbackTran(); // 忥忻 |
| | | return content; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | RollbackTran(); |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | finally |
| | | { |
| | | _asyncLock.Release(); |
| | | } |
| | | } |
| | | |
| | | public void CommitTran() |
| | | { |
| | | lock (this) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// æççµè¯ç»å®è¯·æ±DTO |
| | | /// </summary> |
| | | public class BindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä½ç½®ä¿¡æ¯ |
| | | /// </summary> |
| | | public string Location { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æä½ç±»åï¼0-é»è®¤ 1-è¿ç« 2-åºç« 3-è¿åºç« |
| | | /// </summary> |
| | | public int OperationType { get; set; } = 1; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// æçNGçµè¯ä¸æ¥è¯·æ±DTO |
| | | /// </summary> |
| | | public class ContainerNgReportRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGçµè¯å表 |
| | | /// </summary> |
| | | public List<NgSfcItemDto> NgSfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGçµè¯é¡¹DTO |
| | | /// </summary> |
| | | public class NgSfcItemDto |
| | | { |
| | | /// <summary> |
| | | /// äº§åæ¡ç |
| | | /// </summary> |
| | | public string Sfc { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NG代ç |
| | | /// </summary> |
| | | public string NgCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGè®¾å¤ |
| | | /// </summary> |
| | | public string NgEquipmentCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGèµæº |
| | | /// </summary> |
| | | public string NgResourceCode { get; set; } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// æçè¿ç«è¯·æ±DTO |
| | | /// </summary> |
| | | public class InboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿DTO |
| | | /// </summary> |
| | | public class MesApiLogDto |
| | | { |
| | | /// <summary> |
| | | /// æ¥å£ç±»å |
| | | /// </summary> |
| | | public string ApiType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请æ±JSON |
| | | /// </summary> |
| | | public string RequestJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ååºJSON |
| | | /// </summary> |
| | | public string ResponseJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | public bool IsSuccess { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | public string ErrorMessage { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èæ¶ï¼æ¯«ç§ï¼ |
| | | /// </summary> |
| | | public int ElapsedMs { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建人 |
| | | /// </summary> |
| | | public string Creator { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// æçåºç«è¯·æ±DTO |
| | | /// </summary> |
| | | public class OutboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 产ååæ°å表ï¼å¯éï¼ |
| | | /// </summary> |
| | | public List<ParamItemDto> ParamList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 忰项DTO |
| | | /// </summary> |
| | | public class ParamItemDto |
| | | { |
| | | /// <summary> |
| | | /// åæ°ç¼ç |
| | | /// </summary> |
| | | public string ParamCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åæ°å¼ |
| | | /// </summary> |
| | | public string ParamValue { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ééæ¶é´ |
| | | /// </summary> |
| | | public string CollectionTime { get; set; } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.MES |
| | | { |
| | | /// <summary> |
| | | /// æççµè¯è§£ç»è¯·æ±DTO |
| | | /// </summary> |
| | | public class UnbindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Text.Json.Serialization; |
| | | using WIDESEA_Common.TaskEnum; |
| | | |
| | | namespace WIDESEA_DTO.Task |
| | | { |
| | | /// <summary> |
| | | /// æå¨å建任å¡Dto |
| | | /// </summary> |
| | | public class CreateManualTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ç±»åï¼å
¥åº/åºåº/ç§»åº |
| | | /// </summary> |
| | | [JsonPropertyName("taskType")] |
| | | public string TaskType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("sourceAddress")] |
| | | public string SourceAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("targetAddress")] |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¡ç |
| | | /// </summary> |
| | | [JsonPropertyName("barcode")] |
| | | public string Barcode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»åºID |
| | | /// </summary> |
| | | [JsonPropertyName("warehouseId")] |
| | | public int WarehouseId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级ï¼é»è®¤1 |
| | | /// </summary> |
| | | [JsonPropertyName("grade")] |
| | | public int Grade { get; set; } = 1; |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Text.Json.Serialization; |
| | | |
| | | namespace WIDESEA_DTO.Task |
| | | { |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡Dto |
| | | /// </summary> |
| | | public class DispatchTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ID |
| | | /// </summary> |
| | | [JsonPropertyName("taskId")] |
| | | public long TaskId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | [JsonPropertyName("palletCode")] |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("sourceAddress")] |
| | | public string SourceAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("targetAddress")] |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级 |
| | | /// </summary> |
| | | [JsonPropertyName("grade")] |
| | | public int Grade { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ä¸åç»æDto |
| | | /// </summary> |
| | | public class DispatchTaskResultDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ID |
| | | /// </summary> |
| | | [JsonPropertyName("taskId")] |
| | | public long TaskId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | [JsonPropertyName("taskNum")] |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | [JsonPropertyName("success")] |
| | | public bool Success { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | [JsonPropertyName("errorMessage")] |
| | | public string ErrorMessage { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éä¸åç»æDto |
| | | /// </summary> |
| | | public class DispatchResultDto |
| | | { |
| | | /// <summary> |
| | | /// æåæ°é |
| | | /// </summary> |
| | | [JsonPropertyName("successCount")] |
| | | public int SuccessCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 失败æ°é |
| | | /// </summary> |
| | | [JsonPropertyName("failCount")] |
| | | public int FailCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 失败任å¡å表 |
| | | /// </summary> |
| | | [JsonPropertyName("failResults")] |
| | | public List<DispatchTaskResultDto> FailResults { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | namespace WIDESEA_DTO.Task |
| | | { |
| | | /// <summary> |
| | | /// WCSæ¥æ¶WMSä»»å¡çç»æDto |
| | | /// </summary> |
| | | public class ReceiveTaskResultDto |
| | | { |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | public bool Success { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¶æ¯ |
| | | /// </summary> |
| | | public string Message { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ°å»ºç任塿°é |
| | | /// </summary> |
| | | public int CreatedCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éå¤/å·²åå¨çä»»å¡å表 |
| | | /// </summary> |
| | | public List<DuplicateTaskDto> DuplicateTasks { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// éå¤ä»»å¡ä¿¡æ¯Dto |
| | | /// </summary> |
| | | public class DuplicateTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æçå· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ç±»å |
| | | /// </summary> |
| | | public int TaskType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å½åç¶æ |
| | | /// </summary> |
| | | public int TaskStatus { get; set; } |
| | | } |
| | | } |
| | |
| | | /// </summary> |
| | | [Required(ErrorMessage = "æ°ç¶æä¸è½ä¸ºç©º")] |
| | | public int NewStatus { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NextAddress - ä¸ä¸å°åï¼å¿
填项ï¼ç¨äºæå®ä»»å¡çä¸ä¸ä½ç½® |
| | | /// </summary> |
| | | public string? NextAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// currentAddress - å½åå°åï¼å¿
填项ï¼ç¨äºæå®ä»»å¡çå½åä½ç½® |
| | | /// </summary> |
| | | public string? CurrentAddress { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.Collections.Generic; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.MES; |
| | | |
| | | namespace WIDESEA_IMesService |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡æ¥å£ |
| | | /// </summary> |
| | | public interface IMesLogService : IDependency |
| | | { |
| | | /// <summary> |
| | | /// è®°å½MESæ¥å£è°ç¨æ¥å¿ |
| | | /// </summary> |
| | | /// <param name="log">æ¥å¿DTO</param> |
| | | /// <returns>æ¯å¦è®°å½æå</returns> |
| | | Task<bool> LogAsync(MesApiLogDto log); |
| | | |
| | | /// <summary> |
| | | /// è·åæè¿çMESæ¥å£è°ç¨è®°å½ |
| | | /// </summary> |
| | | /// <param name="apiType">æ¥å£ç±»å</param> |
| | | /// <param name="count">è®°å½æ°é</param> |
| | | /// <returns>æ¥å¿å表</returns> |
| | | Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50); |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <Project Sdk="Microsoft.NET.Sdk"> |
| | | |
| | | <PropertyGroup> |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <ProjectReference Include="..\WIDESEA_DTO\WIDESEA_DTO.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_Core\WIDESEA_Core.csproj" /> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
| | |
| | | /// <param name="taskId"></param> |
| | | /// <param name="newStatus"></param> |
| | | /// <returns></returns> |
| | | Task<WebResponseContent> UpdateTaskByStatusAsync(int taskId, int newStatus); |
| | | Task<WebResponseContent> UpdateTaskByStatusAsync(UpdateTaskDto taskDto); |
| | | |
| | | /// <summary> |
| | | /// å åæºåæ¾è´§å®æåç©æµéç¥åæå容æå®æä¿¡å· |
| | |
| | | /// <returns></returns> |
| | | Task<WebResponseContent> CreateRobotChangePalletTaskAsync(StockDTO stock); |
| | | |
| | | /// <summary> |
| | | /// æå¨åå»ºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="dto">æå¨å建任å¡åæ°</param> |
| | | /// <returns></returns> |
| | | Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto); |
| | | |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡å°WCS |
| | | /// </summary> |
| | | /// <param name="dtos">ä¸åä»»å¡åæ°å表</param> |
| | | /// <returns>æ¹éä¸åç»æ</returns> |
| | | Task<WebResponseContent> DispatchTasksToWCSAsync(List<DispatchTaskDto> dtos); |
| | | |
| | | |
| | | #region æå·åºä»»å¡æ¨¡å |
| | | /// <summary> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Threading.Tasks; |
| | | using SqlSugar; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.MES; |
| | | using WIDESEA_IMesService; |
| | | using WIDESEA_Model.Models.Mes; |
| | | |
| | | namespace WIDESEA_MesService |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡å®ç° |
| | | /// </summary> |
| | | public class MesLogService : IMesLogService |
| | | { |
| | | private readonly ISqlSugarClient _db; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | /// <param name="db">æ°æ®åºå®¢æ·ç«¯</param> |
| | | public MesLogService(ISqlSugarClient db) |
| | | { |
| | | _db = db; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è®°å½MESæ¥å£è°ç¨æ¥å¿ |
| | | /// </summary> |
| | | /// <param name="log">æ¥å¿DTO</param> |
| | | /// <returns>æ¯å¦è®°å½æå</returns> |
| | | public async Task<bool> LogAsync(MesApiLogDto log) |
| | | { |
| | | try |
| | | { |
| | | var entity = new Dt_MesApiLog |
| | | { |
| | | ApiType = log.ApiType, |
| | | RequestJson = log.RequestJson, |
| | | ResponseJson = log.ResponseJson, |
| | | IsSuccess = log.IsSuccess, |
| | | ErrorMessage = log.ErrorMessage, |
| | | ElapsedMs = log.ElapsedMs, |
| | | CreateDate = DateTime.Now, |
| | | Creator = log.Creator |
| | | }; |
| | | |
| | | var result = await _db.Insertable(entity).ExecuteCommandAsync(); |
| | | return result > 0; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è®°å½æ¥å¿å¤±è´¥ä¸å½±å主æµç¨ |
| | | Console.WriteLine($"è®°å½MESæ¥å¿å¤±è´¥: {ex.Message}"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæè¿çMESæ¥å£è°ç¨è®°å½ |
| | | /// </summary> |
| | | /// <param name="apiType">æ¥å£ç±»å</param> |
| | | /// <param name="count">è®°å½æ°é</param> |
| | | /// <returns>æ¥å¿å表</returns> |
| | | public async Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50) |
| | | { |
| | | try |
| | | { |
| | | var entities = await _db.Queryable<Dt_MesApiLog>() |
| | | .Where(x => x.ApiType == apiType) |
| | | .OrderByDescending(x => x.CreateDate) |
| | | .Take(count) |
| | | .ToListAsync(); |
| | | |
| | | return entities.Select(e => new MesApiLogDto |
| | | { |
| | | ApiType = e.ApiType, |
| | | RequestJson = e.RequestJson, |
| | | ResponseJson = e.ResponseJson, |
| | | IsSuccess = e.IsSuccess, |
| | | ErrorMessage = e.ErrorMessage, |
| | | ElapsedMs = e.ElapsedMs, |
| | | Creator = e.Creator |
| | | }).ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Console.WriteLine($"è·åMESæ¥å¿å¤±è´¥: {ex.Message}"); |
| | | return new List<MesApiLogDto>(); |
| | | } |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <Project Sdk="Microsoft.NET.Sdk"> |
| | | |
| | | <PropertyGroup> |
| | | <TargetFramework>net8.0</TargetFramework> |
| | | <ImplicitUsings>enable</ImplicitUsings> |
| | | <Nullable>enable</Nullable> |
| | | </PropertyGroup> |
| | | |
| | | <ItemGroup> |
| | | <ProjectReference Include="..\WIDESEA_IMesService\WIDESEA_IMesService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_Core\WIDESEA_Core.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_Model\WIDESEA_Model.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_DTO\WIDESEA_DTO.csproj" /> |
| | | </ItemGroup> |
| | | |
| | | </Project> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using SqlSugar; |
| | | using System; |
| | | |
| | | namespace WIDESEA_Model.Models.Mes |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£è°ç¨æ¥å¿å®ä½ |
| | | /// </summary> |
| | | [SugarTable("Dt_MesApiLog")] |
| | | public class Dt_MesApiLog |
| | | { |
| | | /// <summary> |
| | | /// 主é®ID |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¥å£ç±»åï¼InboundInContainer, OutboundInContainer, BindContainer, UnbindContainer, ContainerNgReport |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = false)] |
| | | public string ApiType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请æ±JSON |
| | | /// </summary> |
| | | [SugarColumn(ColumnDataType = "nvarchar(max)", IsNullable = true)] |
| | | public string RequestJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ååºJSON |
| | | /// </summary> |
| | | [SugarColumn(ColumnDataType = "nvarchar(max)", IsNullable = true)] |
| | | public string ResponseJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public bool IsSuccess { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | [SugarColumn(Length = 500, IsNullable = true)] |
| | | public string ErrorMessage { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èæ¶ï¼æ¯«ç§ï¼ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public int ElapsedMs { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建æ¶é´ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public DateTime CreateDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建人 |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = true)] |
| | | public string Creator { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¿®æ¹æ¶é´ |
| | | /// </summary> |
| | | public DateTime? ModifyDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¿®æ¹äºº |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = true)] |
| | | public string Modifier { get; set; } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using Microsoft.Extensions.Configuration; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.Helper; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region èªå¨åºåºä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// èªå¨å建åºåºä»»å¡ - æ¥è¯¢å°æåºåå¹¶åå»ºä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateAutoOutboundTasksAsync() |
| | | { |
| | | try |
| | | { |
| | | // 1. æ¥è¯¢å°æåºå |
| | | var expiredStocks = await _stockInfoService.Repository |
| | | .QueryDataNavAsync(s => s.OutboundDate <= DateTime.Now |
| | | && s.StockStatus == StockStatusEmun.å
¥åºå®æ.GetHashCode()); |
| | | |
| | | if (expiredStocks == null || !expiredStocks.Any()) |
| | | { |
| | | return WebResponseContent.Instance.OK("æ å°æåºåéè¦å¤ç"); |
| | | } |
| | | |
| | | // è¿æ»¤æä½ç½®ä¸ä½ç½®æåºåçè®°å½ |
| | | expiredStocks = expiredStocks |
| | | .Where(s => s.LocationDetails != null |
| | | && s.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode()) |
| | | .ToList(); |
| | | |
| | | if (!expiredStocks.Any()) |
| | | { |
| | | return WebResponseContent.Instance.OK("æ ç¬¦åæ¡ä»¶çå°æåºå"); |
| | | } |
| | | |
| | | // 2. æ£æ¥å·²åå¨çä»»å¡ |
| | | var palletCodes = expiredStocks.Select(s => s.PalletCode).ToList(); |
| | | var existingTasks = await Repository.QueryDataAsync(t => |
| | | palletCodes.Contains(t.PalletCode) |
| | | && (t.TaskStatus == TaskStatusEnum.New.GetHashCode() |
| | | || t.TaskStatus == TaskStatusEnum.SC_Executing.GetHashCode() |
| | | || t.TaskStatus == TaskInStatusEnum.InNew.GetHashCode())); |
| | | |
| | | var processedPallets = existingTasks.Select(t => t.PalletCode).ToHashSet(); |
| | | |
| | | // 3. çééè¦å¤ççåºå |
| | | var stocksToProcess = expiredStocks |
| | | .Where(s => !processedPallets.Contains(s.PalletCode)) |
| | | .ToList(); |
| | | |
| | | if (!stocksToProcess.Any()) |
| | | { |
| | | return WebResponseContent.Instance.OK("ææå°æåºåå·²åå¨ä»»å¡"); |
| | | } |
| | | |
| | | // 4. è·åé
ç½®çç®æ å°åæ å° |
| | | var targetAddressMap = _configuration.GetSection("AutoOutboundTask:TargetAddresses") |
| | | .Get<Dictionary<string, List<string>>>() |
| | | ?? new Dictionary<string, List<string>>(); |
| | | |
| | | // 5. æ¹éåå»ºä»»å¡ |
| | | var taskList = new List<Dt_Task>(); |
| | | foreach (var stock in stocksToProcess) |
| | | { |
| | | // æ ¹æ®å··éç¡®å®ç®æ å°åï¼ä¼å
æ ¹æ® Remark ç¡®å®ï¼Remark ä¸ºç©ºåæ ¹æ®å··éé
ç½®ï¼ |
| | | var targetAddress = DetermineTargetAddressByRemark( |
| | | stock.Remark ?? "", |
| | | stock.LocationDetails?.RoadwayNo ?? "", |
| | | targetAddressMap); |
| | | |
| | | var task = new Dt_Task |
| | | { |
| | | WarehouseId = stock.WarehouseId, |
| | | PalletCode = stock.PalletCode, |
| | | PalletType = stock.PalletType, |
| | | SourceAddress = stock.LocationCode, |
| | | CurrentAddress = stock.LocationCode, |
| | | NextAddress = targetAddress, |
| | | TargetAddress = targetAddress, |
| | | Roadway = stock.LocationDetails?.RoadwayNo ?? "", |
| | | TaskType = TaskTypeEnum.Outbound.GetHashCode(), |
| | | TaskStatus = TaskStatusEnum.New.GetHashCode(), |
| | | Grade = 1, |
| | | TaskNum = await BaseDal.GetTaskNo(), |
| | | Creater = "system_auto" |
| | | }; |
| | | taskList.Add(task); |
| | | } |
| | | |
| | | var transactionResult = await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | var addResult = await BaseDal.AddDataAsync(taskList) > 0; |
| | | if (!addResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æ¹éå建任å¡å¤±è´¥ï¼å
± {taskList.Count} 个任å¡"); |
| | | } |
| | | |
| | | // ä»»å¡å建æååï¼åæ¥éå®åºååè´§ä½ç¶æï¼é¿å
éå¤åé
|
| | | var stocksToUpdate = stocksToProcess |
| | | .Select(s => |
| | | { |
| | | s.StockStatus = StockStatusEmun.åºåºéå®.GetHashCode(); |
| | | return s; |
| | | }) |
| | | .ToList(); |
| | | |
| | | var updateStockResult = await _stockInfoService.Repository.UpdateDataAsync(stocksToUpdate); |
| | | if (!updateStockResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½åºåç¶ææ´æ°å¤±è´¥ï¼å
± {stocksToUpdate.Count} æ¡"); |
| | | } |
| | | |
| | | var locationsToUpdate = stocksToProcess |
| | | .Where(s => s.LocationDetails != null) |
| | | .GroupBy(s => s.LocationDetails.Id) |
| | | .Select(g => |
| | | { |
| | | var location = g.First().LocationDetails; |
| | | location.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode(); |
| | | return location; |
| | | }) |
| | | .ToList(); |
| | | |
| | | if (locationsToUpdate.Any()) |
| | | { |
| | | var updateLocationResult = await _locationInfoService.Repository.UpdateDataAsync(locationsToUpdate); |
| | | if (!updateLocationResult) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建æåï¼ä½è´§ä½ç¶ææ´æ°å¤±è´¥ï¼å
± {locationsToUpdate.Count} æ¡"); |
| | | } |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK(); |
| | | }); |
| | | if (!transactionResult.Status) |
| | | { |
| | | return transactionResult; |
| | | } |
| | | |
| | | // 6. éç¥ WCSï¼å¼æ¥ï¼ä¸å½±å主æµç¨ï¼ |
| | | _ = Task.Run(() => |
| | | { |
| | | try |
| | | { |
| | | var wmstaskDtos = _mapper.Map<List<WMSTaskDTO>>(taskList); |
| | | _httpClientHelper.Post<WebResponseContent>( |
| | | "http://localhost:9292/api/Task/ReceiveTask", |
| | | wmstaskDtos.ToJson()); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // WCS éç¥å¤±è´¥ä¸å½±åä»»å¡å建ï¼è®°å½æ¥å¿å³å¯ |
| | | Console.WriteLine($"WCS æ¹ééç¥å¤±è´¥ï¼ä»»å¡æ°é: {taskList.Count}, é误: {ex.Message}"); |
| | | } |
| | | }); |
| | | |
| | | return WebResponseContent.Instance.OK($"æåå建 {taskList.Count} 个åºåºä»»å¡", taskList.Count); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"èªå¨å建åºåºä»»å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion èªå¨åºåºä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEA_Common.Constants; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Common.WareHouseEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region å
¥åºä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// å建任å¡ï¼ç»çå
¥åºä»»å¡ã空æçååºä»»å¡ï¼ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateTaskInboundAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); |
| | | if (content.Status) |
| | | { |
| | | return content; |
| | | } |
| | | |
| | | if (string.IsNullOrWhiteSpace(taskDto.PalletCode) || |
| | | string.IsNullOrWhiteSpace(taskDto.Roadway)) |
| | | { |
| | | return WebResponseContent.Instance.Error("æ æçä»»å¡è¯¦æ
"); |
| | | } |
| | | |
| | | if (taskDto.TaskType != TaskTypeEnum.Inbound && taskDto.TaskType != TaskTypeEnum.InEmpty) |
| | | { |
| | | return WebResponseContent.Instance.Error("æ æçä»»å¡è¯¦æ
"); |
| | | } |
| | | |
| | | // ä½¿ç¨ switch è¡¨è¾¾å¼æ å°ä»»å¡ç±»å |
| | | int taskInboundType = taskDto.TaskType switch |
| | | { |
| | | TaskTypeEnum.Inbound => TaskInboundTypeEnum.Inbound.GetHashCode(), |
| | | TaskTypeEnum.InEmpty => TaskInboundTypeEnum.InEmpty.GetHashCode(), |
| | | _ => 0 // ç论ä¸ä¸ä¼èµ°å°è¿éï¼å 为已ç»éªè¯è¿äº |
| | | }; |
| | | |
| | | var task = new Dt_Task |
| | | { |
| | | TaskNum = await BaseDal.GetTaskNo(), |
| | | PalletCode = taskDto.PalletCode, |
| | | PalletType = taskDto.PalletType, |
| | | Roadway = taskDto.Roadway, |
| | | TaskType = taskInboundType, |
| | | TaskStatus = TaskInStatusEnum.InNew.GetHashCode(), |
| | | SourceAddress = taskDto.SourceAddress, |
| | | TargetAddress = taskDto.TargetAddress, |
| | | CurrentAddress = taskDto.SourceAddress, |
| | | NextAddress = taskDto.TargetAddress, |
| | | WarehouseId = taskDto.WarehouseId, |
| | | Grade = 1, |
| | | Creater = "system" |
| | | }; |
| | | |
| | | var result = await Repository.AddDataAsync(task) > 0; |
| | | if (!result) return WebResponseContent.Instance.Error("ä»»å¡å建失败"); |
| | | |
| | | var wmstaskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | return WebResponseContent.Instance.OK("ä»»å¡å建æå", wmstaskDto); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åå¯å
¥åºè´§ä½ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> GetTasksLocationAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfo(task.Roadway); |
| | | if (locationInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | locationInfo.LocationStatus = LocationStatusEnum.FreeLock.GetHashCode(); |
| | | task.CurrentAddress = task.SourceAddress; |
| | | task.NextAddress = locationInfo.LocationCode; |
| | | task.TargetAddress = locationInfo.LocationCode; |
| | | task.TaskStatus = TaskInStatusEnum.Line_InFinish.GetHashCode(); |
| | | |
| | | var updateTaskResult = await BaseDal.UpdateDataAsync(task); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | if (!updateTaskResult || !updateLocationResult) |
| | | { |
| | | return WebResponseContent.Instance.Error("任塿´æ°å¤±è´¥"); |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK("任塿´æ°æå", locationInfo.LocationCode); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"è·åä»»å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å
¥åºä»»å¡å®æï¼æ·»å åºåï¼ä¿®æ¹è´§ä½ç¶æï¼å é¤ä»»å¡æ°æ®ï¼æ·»å åå²ä»»å¡æ°æ® |
| | | /// </summary> |
| | | public async Task<WebResponseContent> InboundFinishTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | // 夿æ¯ä¸æ¯æå·åºä»»å¡ |
| | | if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) |
| | | { |
| | | return await CompleteAgvInboundTaskAsync(taskDto); |
| | | } |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | WebResponseContent content = new WebResponseContent(); |
| | | stockInfo.LocationCode = location.LocationCode; |
| | | stockInfo.LocationId = location.Id; |
| | | |
| | | SetOutboundDateByRoadway(task, stockInfo); |
| | | |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | // è°ç¨MESæçè¿ç« |
| | | //var inboundRequest = new InboundInContainerRequest |
| | | //{ |
| | | // EquipmentCode = "STK-GROUP-001", |
| | | // ResourceCode = "STK-GROUP-001", |
| | | // LocalTime = DateTime.Now, |
| | | // ContainerCode = taskDto.PalletCode |
| | | //}; |
| | | //var inboundResult = _mesService.InboundInContainer(inboundRequest); |
| | | //if (inboundResult == null || inboundResult.Data == null || !inboundResult.Data.IsSuccess) |
| | | //{ |
| | | // return content.Error($"ä»»å¡å®æå¤±è´¥ï¼MESè¿ç«å¤±è´¥: {inboundResult?.Data?.Msg ?? inboundResult?.ErrorMessage ?? "æªç¥é误"}"); |
| | | //} |
| | | return await CompleteTaskAsync(task, "å
¥åºå®æ"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"宿任å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®å··éç±»å设置åºåçåºåºæ¶é´å夿³¨ |
| | | /// </summary> |
| | | /// <param name="task">ä»»å¡ä¿¡æ¯</param> |
| | | /// <param name="stockInfo">åºåä¿¡æ¯</param> |
| | | private void SetOutboundDateByRoadway(Dt_Task task, Dt_StockInfo stockInfo) |
| | | { |
| | | var now = DateTime.Now; |
| | | if (task.Roadway.Contains("GW")) |
| | | { |
| | | stockInfo.OutboundDate = string.IsNullOrEmpty(stockInfo.Remark) |
| | | ? now.AddHours(OutboundTimeConstants.OUTBOUND_HOURS_GW1_FIRST) |
| | | : stockInfo.Remark == StockRemarkConstants.GW1 |
| | | ? now.AddHours(OutboundTimeConstants.OUTBOUND_HOURS_GW1_SECOND) |
| | | : now.AddHours(OutboundTimeConstants.OUTBOUND_HOURS_GW1_FIRST); |
| | | |
| | | stockInfo.Remark = string.IsNullOrEmpty(stockInfo.Remark) |
| | | ? StockRemarkConstants.GW1 |
| | | : stockInfo.Remark == StockRemarkConstants.GW1 |
| | | ? StockRemarkConstants.GW2 |
| | | : stockInfo.Remark; |
| | | } |
| | | else if (task.Roadway.Contains("CW")) |
| | | { |
| | | stockInfo.OutboundDate = now.AddHours(OutboundTimeConstants.OUTBOUND_HOURS_CW1); |
| | | if (stockInfo.Remark == StockRemarkConstants.GW2) |
| | | stockInfo.Remark = StockRemarkConstants.CW1; |
| | | } |
| | | else |
| | | { |
| | | stockInfo.OutboundDate = now; |
| | | } |
| | | } |
| | | |
| | | #endregion å
¥åºä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using System.ComponentModel; |
| | | using System.Reflection; |
| | | using Newtonsoft.Json; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.Helper; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region æå¨ä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// æå¨åå»ºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="dto">æå¨å建任å¡åæ°</param> |
| | | /// <returns></returns> |
| | | public async Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto) |
| | | { |
| | | try |
| | | { |
| | | int taskType; |
| | | int taskStatus; |
| | | switch (dto.TaskType) |
| | | { |
| | | case "å
¥åº": |
| | | taskType = TaskInboundTypeEnum.Inbound.GetHashCode(); |
| | | taskStatus = TaskInStatusEnum.InNew.GetHashCode(); |
| | | break; |
| | | |
| | | case "åºåº": |
| | | taskType = TaskOutboundTypeEnum.Outbound.GetHashCode(); |
| | | taskStatus = TaskOutStatusEnum.OutNew.GetHashCode(); |
| | | break; |
| | | |
| | | case "ç§»åº": |
| | | taskType = TaskRelocationTypeEnum.Relocation.GetHashCode(); |
| | | taskStatus = TaskRelocationStatusEnum.RelocationNew.GetHashCode(); |
| | | break; |
| | | |
| | | default: |
| | | return WebResponseContent.Instance.Error($"䏿¯æçä»»å¡ç±»å: {dto.TaskType}"); |
| | | } |
| | | |
| | | int taskNum = await BaseDal.GetTaskNo(); |
| | | |
| | | var task = new Dt_Task |
| | | { |
| | | TaskNum = taskNum, |
| | | PalletCode = dto.Barcode, |
| | | SourceAddress = dto.SourceAddress, |
| | | TargetAddress = dto.TargetAddress, |
| | | TaskType = taskType, |
| | | TaskStatus = taskStatus, |
| | | Grade = dto.Grade, |
| | | Roadway = dto.TargetAddress, |
| | | WarehouseId = dto.WarehouseId, |
| | | CurrentAddress = dto.SourceAddress, |
| | | NextAddress = dto.TargetAddress, |
| | | Creater = "manual", |
| | | CreateDate = DateTime.Now, |
| | | ModifyDate = DateTime.Now |
| | | }; |
| | | |
| | | var wmsTaskDtos = new List<WMSTaskDTO>() |
| | | { |
| | | new() |
| | | { |
| | | TaskNum = task.TaskNum, |
| | | PalletCode = task.PalletCode, |
| | | SourceAddress = task.SourceAddress, |
| | | TargetAddress = task.TargetAddress, |
| | | TaskType = task.TaskType, |
| | | Roadway = task.Roadway, |
| | | TaskStatus = task.TaskStatus, |
| | | WarehouseId = task.WarehouseId |
| | | } |
| | | }; |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | // ä¿åå°æ°æ®åºå¹¶åæ¥åéç»WCS |
| | | var result = await BaseDal.AddDataAsync(task) > 0; |
| | | if (!result) |
| | | return WebResponseContent.Instance.Error("å建任å¡å¤±è´¥"); |
| | | |
| | | var wcsResult = _httpClientHelper.Post<WebResponseContent>( |
| | | "http://localhost:9292/api/Task/ReceiveManualTask", |
| | | wmsTaskDtos.ToJson()); |
| | | |
| | | if (!wcsResult.IsSuccess || !wcsResult.Data.Status) |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å·²å建ä½åéç»WCS失败: {wcsResult.Data?.Message}"); |
| | | |
| | | return WebResponseContent.Instance.OK($"æå¨åå»ºä»»å¡æåï¼ä»»å¡å·: {taskNum}"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æå¨å建任å¡å¼å¸¸: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡å°WCSï¼æ¹éå¤çï¼ |
| | | /// </summary> |
| | | /// <param name="dtos">ä¸åä»»å¡åæ°å表</param> |
| | | /// <returns>æ¹éä¸åç»æ</returns> |
| | | public async Task<WebResponseContent> DispatchTasksToWCSAsync(List<DispatchTaskDto> dtos) |
| | | { |
| | | try |
| | | { |
| | | if (dtos == null || !dtos.Any()) |
| | | return WebResponseContent.Instance.Error("è¯·éæ©è¦ä¸åçä»»å¡"); |
| | | |
| | | var resultDto = new DispatchResultDto |
| | | { |
| | | SuccessCount = 0, |
| | | FailCount = 0, |
| | | FailResults = new List<DispatchTaskResultDto>() |
| | | }; |
| | | |
| | | // ç¬¬ä¸æ¥ï¼æ¥è¯¢å¹¶æ ¡éªææä»»å¡ç¶æï¼æ¶éææä»»å¡ |
| | | var validTasks = new List<(DispatchTaskDto Dto, Dt_Task Task)>(); |
| | | |
| | | foreach (var dto in dtos) |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(t => t.TaskId == dto.TaskId); |
| | | if (task == null) |
| | | { |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = dto.TaskId, |
| | | TaskNum = 0, |
| | | Success = false, |
| | | ErrorMessage = "ä»»å¡ä¸åå¨" |
| | | }); |
| | | resultDto.FailCount++; |
| | | continue; |
| | | } |
| | | |
| | | // æ ¡éªä»»å¡ç¶æï¼ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åå¯ä¸å |
| | | bool canDispatch = false; |
| | | if (task.TaskType == TaskInboundTypeEnum.Inbound.GetHashCode() |
| | | && task.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()) |
| | | canDispatch = true; |
| | | else if (task.TaskType == TaskOutboundTypeEnum.Outbound.GetHashCode() |
| | | && task.TaskStatus == TaskOutStatusEnum.OutNew.GetHashCode()) |
| | | canDispatch = true; |
| | | else if (task.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode() |
| | | && task.TaskStatus == TaskRelocationStatusEnum.RelocationNew.GetHashCode()) |
| | | canDispatch = true; |
| | | |
| | | if (!canDispatch) |
| | | { |
| | | var statusName = GetTaskStatusName(task.TaskType, task.TaskStatus); |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = dto.TaskId, |
| | | TaskNum = task.TaskNum, |
| | | Success = false, |
| | | ErrorMessage = $"ä»»å¡ç¶æ[{statusName}]ä¸å
许ä¸å" |
| | | }); |
| | | resultDto.FailCount++; |
| | | continue; |
| | | } |
| | | |
| | | validTasks.Add((dto, task)); |
| | | } |
| | | |
| | | // 妿å
¨é¨æ ¡éªå¤±è´¥ï¼ç´æ¥è¿å |
| | | if (validTasks.Count == 0) |
| | | return WebResponseContent.Instance.Error($"ä¸å失败ï¼å
±{resultDto.FailCount}个任å¡"); |
| | | |
| | | // ç¬¬äºæ¥ï¼æé ææWMSTaskDTOï¼ä¸æ¬¡æ§è°ç¨WCS |
| | | var wmsTaskDtos = validTasks.Select(vt => new WMSTaskDTO |
| | | { |
| | | Id = vt.Task.TaskId, |
| | | TaskNum = vt.Task.TaskNum, |
| | | PalletCode = vt.Dto.PalletCode, |
| | | SourceAddress = vt.Dto.SourceAddress, |
| | | TargetAddress = vt.Dto.TargetAddress, |
| | | CurrentAddress = vt.Dto.SourceAddress, |
| | | NextAddress = vt.Dto.TargetAddress, |
| | | TaskType = vt.Task.TaskType, |
| | | TaskStatus = vt.Task.TaskStatus, |
| | | Roadway = vt.Task.Roadway, |
| | | Grade = vt.Dto.Grade, |
| | | WarehouseId = vt.Task.WarehouseId, |
| | | PalletType = vt.Task.PalletType |
| | | }).ToList(); |
| | | |
| | | // 䏿¬¡æ§è°ç¨WCSæ¹éæ¥å£ |
| | | var wcsResult = _httpClientHelper.Post<WebResponseContent>( |
| | | "http://localhost:9292/api/Task/ReceiveManualTask", |
| | | wmsTaskDtos.ToJson()); |
| | | |
| | | if (wcsResult == null || !wcsResult.IsSuccess) |
| | | { |
| | | // WCSè°ç¨å¤±è´¥ï¼ææä»»å¡é½ç®å¤±è´¥ |
| | | // å°è¯ä»WCSååºä¸è§£æé误详æ
|
| | | string errorDetail = ""; |
| | | if (wcsResult?.Data != null) |
| | | { |
| | | // å°è¯å°Data转æ¢ä¸ºéè¯¯ä¿¡æ¯ |
| | | try |
| | | { |
| | | var errorData = wcsResult.Data.ToString(); |
| | | errorDetail = $"WCSé误: {errorData}"; |
| | | } |
| | | catch |
| | | { |
| | | errorDetail = wcsResult?.ErrorMessage ?? "WCSååºå¼å¸¸"; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | errorDetail = wcsResult?.ErrorMessage ?? "WCSååºå¼å¸¸"; |
| | | } |
| | | |
| | | foreach (var vt in validTasks) |
| | | { |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = vt.Dto.TaskId, |
| | | TaskNum = vt.Task.TaskNum, |
| | | Success = false, |
| | | ErrorMessage = $"{errorDetail} (ä»»å¡å·:{vt.Task.TaskNum}, æç:{vt.Dto.PalletCode})" |
| | | }); |
| | | resultDto.FailCount++; |
| | | } |
| | | resultDto.SuccessCount = 0; |
| | | return WebResponseContent.Instance.Error($"WCSæ¹éä¸å失败ï¼å
±{resultDto.FailCount}个任å¡"); |
| | | } |
| | | |
| | | // WCSè°ç¨æåï¼è§£æè¿åçç»æåæ°æ® |
| | | ReceiveTaskResultDto wcsResultData = null; |
| | | try |
| | | { |
| | | if (wcsResult.Data?.Data != null) |
| | | { |
| | | var jsonStr = wcsResult.Data.Data.ToString(); |
| | | if (!string.IsNullOrEmpty(jsonStr) && jsonStr.Contains("duplicateTasks")) |
| | | { |
| | | wcsResultData = JsonConvert.DeserializeObject<ReceiveTaskResultDto>(jsonStr); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è§£æWCSè¿åæ°æ®å¤±è´¥ï¼è®°å½æ¥å¿ä½ç»§ç»å¤ç |
| | | Console.WriteLine($"è§£æWCSè¿åæ°æ®å¼å¸¸: {ex.Message}"); |
| | | } |
| | | |
| | | // 妿æéå¤ä»»å¡ï¼è®°å½å°å¤±è´¥ç»æä¸ |
| | | if (wcsResultData?.DuplicateTasks != null && wcsResultData.DuplicateTasks.Count > 0) |
| | | { |
| | | foreach (var dup in wcsResultData.DuplicateTasks) |
| | | { |
| | | var statusName = GetTaskStatusName(dup.TaskType, dup.TaskStatus); |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = 0, // éå¤ä»»å¡å¯è½æ²¡æWMSçTaskId |
| | | TaskNum = dup.TaskNum, |
| | | Success = false, |
| | | ErrorMessage = $"WCSä¸å·²åå¨è¯¥ä»»å¡(æç:{dup.PalletCode}, ç¶æ:{statusName})" |
| | | }); |
| | | resultDto.FailCount++; |
| | | } |
| | | } |
| | | |
| | | // ç¬¬ä¸æ¥ï¼WCSè°ç¨æååï¼æ¹éæ´æ°DB |
| | | foreach (var vt in validTasks) |
| | | { |
| | | vt.Task.PalletCode = vt.Dto.PalletCode; |
| | | vt.Task.SourceAddress = vt.Dto.SourceAddress; |
| | | vt.Task.TargetAddress = vt.Dto.TargetAddress; |
| | | vt.Task.CurrentAddress = vt.Dto.SourceAddress; |
| | | vt.Task.NextAddress = vt.Dto.TargetAddress; |
| | | vt.Task.Grade = vt.Dto.Grade; |
| | | vt.Task.Dispatchertime = DateTime.Now; |
| | | } |
| | | |
| | | // æ¹éæ´æ°DB |
| | | var tasksToUpdate = validTasks.Select(vt => vt.Task).ToList(); |
| | | await BaseDal.UpdateDataAsync(tasksToUpdate); |
| | | |
| | | resultDto.SuccessCount = validTasks.Count - (wcsResultData?.DuplicateTasks?.Count ?? 0); |
| | | |
| | | if (resultDto.FailCount == 0) |
| | | return WebResponseContent.Instance.OK($"æåä¸å{resultDto.SuccessCount}个任å¡", resultDto); |
| | | |
| | | var errorResponse = WebResponseContent.Instance.Error($"é¨åä¸åæå{resultDto.SuccessCount}个ï¼å¤±è´¥{resultDto.FailCount}个"); |
| | | errorResponse.Data = resultDto; |
| | | return errorResponse; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä¸åä»»å¡å¼å¸¸: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä»»å¡ç¶æåç§° |
| | | /// </summary> |
| | | /// <param name="taskType">ä»»å¡ç±»å</param> |
| | | /// <param name="taskStatus">ä»»å¡ç¶æ</param> |
| | | /// <returns>ç¶æç䏿æè¿°</returns> |
| | | private string GetTaskStatusName(int taskType, int taskStatus) |
| | | { |
| | | FieldInfo? fieldInfo = taskType switch |
| | | { |
| | | _ when taskType == TaskInboundTypeEnum.Inbound.GetHashCode() => typeof(TaskInStatusEnum).GetField(((TaskInStatusEnum)taskStatus).ToString()), |
| | | _ when taskType == TaskOutboundTypeEnum.Outbound.GetHashCode() => typeof(TaskOutStatusEnum).GetField(((TaskOutStatusEnum)taskStatus).ToString()), |
| | | _ when taskType == TaskRelocationTypeEnum.Relocation.GetHashCode() => typeof(TaskRelocationStatusEnum).GetField(((TaskRelocationStatusEnum)taskStatus).ToString()), |
| | | _ => null |
| | | }; |
| | | |
| | | var descAttr = fieldInfo?.GetCustomAttributes(typeof(DescriptionAttribute), false) |
| | | .FirstOrDefault() as DescriptionAttribute; |
| | | return descAttr?.Description ?? taskStatus.ToString(); |
| | | } |
| | | |
| | | #endregion æå¨ä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEA_Common.Constants; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Common.WareHouseEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region åºåºä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®æå®çä»»å¡è¯¦æ
弿¥å建æ°çåºåºä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateTaskOutboundAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var stockResult = await _stockInfoService.GetStockInfoAsync(taskDto.WarehouseId); |
| | | if (stockResult == null || !stockResult.Any()) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°åºåä¿¡æ¯"); |
| | | |
| | | var taskList = stockResult.Select(item => new Dt_Task |
| | | { |
| | | WarehouseId = item.WarehouseId, |
| | | PalletCode = item.PalletCode, |
| | | PalletType = item.PalletType, |
| | | SourceAddress = item.LocationCode, |
| | | TargetAddress = taskDto.TargetAddress, |
| | | Roadway = item.LocationDetails.RoadwayNo, |
| | | TaskType = TaskTypeEnum.Outbound.GetHashCode(), |
| | | TaskStatus = TaskStatusEnum.New.GetHashCode(), |
| | | Grade = 1, |
| | | TaskNum = 0, |
| | | CurrentAddress = item.LocationCode, |
| | | NextAddress = taskDto.TargetAddress, |
| | | Creater = "system", |
| | | }).ToList(); |
| | | |
| | | var result = await BaseDal.AddDataAsync(taskList) > 0; |
| | | var wmstaskDto = result ? _mapper.Map<WMSTaskDTO>(taskList) : null; |
| | | return WebResponseContent.Instance.OK(result ? "ä»»å¡å建æå" : "ä»»å¡å建失败", wmstaskDto ?? new object()); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å建失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åºåºä»»å¡å®æ ï¼ä¿®æ¹åºåï¼ä¿®æ¹è´§ä½ç¶æï¼å é¤ä»»å¡æ°æ®ï¼æ·»å åå²ä»»å¡æ°æ® |
| | | /// </summary> |
| | | public async Task<WebResponseContent> OutboundFinishTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | // 夿æ¯ä¸æ¯æå·åºä»»å¡ |
| | | if (taskDto.WarehouseId == (int)WarehouseEnum.FJ1 || taskDto.WarehouseId == (int)WarehouseEnum.ZJ1) |
| | | { |
| | | OutTaskCompleteDto outTaskCompleteDto = new OutTaskCompleteDto() |
| | | { |
| | | TaskId = task.OrderNo ?? string.Empty, |
| | | DevId = task.TargetAddress ?? string.Empty, |
| | | ReqTime = DateTime.Now.ToString() |
| | | }; |
| | | return await OutTaskComplete(outTaskCompleteDto); |
| | | } |
| | | |
| | | WebResponseContent content = new WebResponseContent(); |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | stockInfo.LocationId = 0; |
| | | stockInfo.LocationCode = string.Empty; |
| | | stockInfo.OutboundDate = DateTime.Now; |
| | | |
| | | location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | |
| | | // 髿¸©2å·åºåºå°CWSC1æ¶ï¼èªå¨å建å
¥åºä»»å¡å°å¸¸æ¸©1å·å··é |
| | | WMSTaskDTO? inboundTaskDto = null; |
| | | if (task.TargetAddress == TaskAddressConstants.GW2_ADDRESS) |
| | | { |
| | | var inboundTask = new Dt_Task |
| | | { |
| | | TaskNum = await BaseDal.GetTaskNo(), |
| | | PalletCode = task.PalletCode, |
| | | PalletType = task.PalletType, |
| | | Roadway = "CW1", |
| | | TaskType = TaskInboundTypeEnum.Inbound.GetHashCode(), |
| | | TaskStatus = TaskInStatusEnum.InNew.GetHashCode(), |
| | | SourceAddress = task.TargetAddress, |
| | | TargetAddress = task.TargetAddress, |
| | | CurrentAddress = task.TargetAddress, |
| | | NextAddress = task.TargetAddress, |
| | | WarehouseId = (int)WarehouseEnum.CW1, |
| | | Grade = 1, |
| | | Creater = "system_auto" |
| | | }; |
| | | await Repository.AddDataAsync(inboundTask); |
| | | inboundTaskDto = _mapper.Map<WMSTaskDTO>(inboundTask); |
| | | } |
| | | |
| | | var completeResult = await CompleteTaskAsync(task, "åºåºå®æ"); |
| | | if (!completeResult.Status) |
| | | return completeResult; |
| | | |
| | | // è¿åå
¥åºä»»å¡ä¿¡æ¯ï¼å¦ææï¼ |
| | | if (inboundTaskDto != null) |
| | | { |
| | | return content.OK("åºåºå®æï¼å·²å建å
¥åºä»»å¡", inboundTaskDto); |
| | | } |
| | | return content.OK("åºåºå®æ"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"宿任å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion åºåºä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Task; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region ç§»åºä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// ç§»åºä»»å¡å®æï¼ä¿®æ¹åºåä½ç½®ä¸ç¶æï¼ä¿®æ¹æº/ç®æ è´§ä½ç¶æï¼å é¤ä»»å¡æ°æ® |
| | | /// </summary> |
| | | public async Task<WebResponseContent> RelocationFinishTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => |
| | | s.PalletCode == taskDto.PalletCode && |
| | | s.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode()); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçç§»åºä»»å¡"); |
| | | |
| | | var sourceLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); |
| | | if (sourceLocation == null) return WebResponseContent.Instance.Error("æªæ¾å°ç§»åºæºè´§ä½"); |
| | | |
| | | var targetLocation = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); |
| | | if (targetLocation == null) return WebResponseContent.Instance.Error("æªæ¾å°ç§»åºç®æ è´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | stockInfo.LocationCode = targetLocation.LocationCode; |
| | | stockInfo.LocationId = targetLocation.Id; |
| | | stockInfo.StockStatus = StockStatusEmun.å
¥åºå®æ.GetHashCode(); |
| | | |
| | | sourceLocation.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | targetLocation.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateSourceResult = await _locationInfoService.UpdateLocationInfoAsync(sourceLocation); |
| | | var updateTargetResult = await _locationInfoService.UpdateLocationInfoAsync(targetLocation); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | |
| | | if (!updateSourceResult || !updateTargetResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ç§»åºä»»å¡å®æå¤±è´¥"); |
| | | |
| | | return await CompleteTaskAsync(task, "ç§»åºå®æ"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"宿任å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion ç§»åºä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Stock; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region æºæ¢°æä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// åå»ºæºæ¢°æç»çä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateRobotGroupPalletTaskAsync(StockDTO stock) |
| | | { |
| | | return await CreateRobotPalletTaskAsync( |
| | | stock, |
| | | "ç»ç", |
| | | RobotTaskTypeEnum.GroupPallet, |
| | | s => string.IsNullOrWhiteSpace(s.TargetPalletNo) ? s.SourcePalletNo : s.TargetPalletNo, |
| | | requireStockWithoutLocation: false); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå»ºæºæ¢°ææ¢çä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateRobotChangePalletTaskAsync(StockDTO stock) |
| | | { |
| | | return await CreateRobotPalletTaskAsync( |
| | | stock, |
| | | "æ¢ç", |
| | | RobotTaskTypeEnum.ChangePallet, |
| | | s => s.SourcePalletNo, |
| | | requireStockWithoutLocation: true, |
| | | stockPalletCodeSelector: s => s.SourcePalletNo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå»ºæºæ¢°ææçä»»å¡ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> CreateRobotSplitPalletTaskAsync(StockDTO stock) |
| | | { |
| | | return await CreateRobotPalletTaskAsync( |
| | | stock, |
| | | "æç", |
| | | RobotTaskTypeEnum.SplitPallet, |
| | | s => s.SourcePalletNo, |
| | | requireStockWithoutLocation: true, |
| | | stockPalletCodeSelector: s => s.SourcePalletNo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå»ºæºæ¢°æä»»å¡çéç¨æ¹æ³ |
| | | /// </summary> |
| | | /// <param name="stock">åºåä¿¡æ¯</param> |
| | | /// <param name="taskName">ä»»å¡åç§°ï¼ç»ç/æ¢ç/æçï¼</param> |
| | | /// <param name="taskType">æºæ¢°æä»»å¡ç±»å</param> |
| | | /// <param name="palletCodeSelector">æçå·éæ©å¨</param> |
| | | /// <param name="requireStockWithoutLocation">æ¯å¦è¦æ±åºåæªç»å®è´§ä½</param> |
| | | /// <param name="stockPalletCodeSelector">åºåæ¥è¯¢ç¨çæçå·éæ©å¨</param> |
| | | /// <returns>åå»ºç»æ</returns> |
| | | private async Task<WebResponseContent> CreateRobotPalletTaskAsync( |
| | | StockDTO stock, |
| | | string taskName, |
| | | RobotTaskTypeEnum taskType, |
| | | Func<StockDTO, string?> palletCodeSelector, |
| | | bool requireStockWithoutLocation, |
| | | Func<StockDTO, string?>? stockPalletCodeSelector = null) |
| | | { |
| | | try |
| | | { |
| | | if (stock == null) |
| | | return WebResponseContent.Instance.Error("ä»»å¡åæ°ä¸è½ä¸ºç©º"); |
| | | |
| | | var palletCode = palletCodeSelector(stock)?.Trim(); |
| | | if (string.IsNullOrWhiteSpace(palletCode)) |
| | | return WebResponseContent.Instance.Error("æçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | var sourceLineNo = stock.SourceLineNo?.Trim(); |
| | | var targetLineNo = stock.TargetLineNo?.Trim(); |
| | | if (string.IsNullOrWhiteSpace(sourceLineNo) || string.IsNullOrWhiteSpace(targetLineNo)) |
| | | return WebResponseContent.Instance.Error("æ¥æºçº¿ä½ç¼å·åç®æ 线ä½ç¼å·ä¸è½ä¸ºç©º"); |
| | | |
| | | var existingTask = await BaseDal.QueryFirstAsync(t => |
| | | t.PalletCode == palletCode && |
| | | (t.TaskStatus == TaskRobotStatusEnum.RobotNew.GetHashCode() |
| | | || t.TaskStatus == TaskRobotStatusEnum.RobotExecuting.GetHashCode() |
| | | || t.TaskStatus == TaskRobotStatusEnum.RobotPickFinish.GetHashCode() |
| | | || t.TaskStatus == TaskRobotStatusEnum.RobotPutFinish.GetHashCode() |
| | | || t.TaskStatus == TaskRobotStatusEnum.RobotPending.GetHashCode())); |
| | | if (existingTask != null) |
| | | return WebResponseContent.Instance.Error($"æç[{palletCode}]å·²å卿ªå®æä»»å¡"); |
| | | |
| | | Dt_StockInfo? stockInfo = null; |
| | | if (requireStockWithoutLocation) |
| | | { |
| | | var stockPalletCode = (stockPalletCodeSelector ?? palletCodeSelector).Invoke(stock)?.Trim(); |
| | | if (string.IsNullOrWhiteSpace(stockPalletCode)) |
| | | return WebResponseContent.Instance.Error("æºæçå·ä¸è½ä¸ºç©º"); |
| | | |
| | | stockInfo = await _stockInfoService.GetStockInfoAsync(stockPalletCode); |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error($"æç[{stockPalletCode}]åºåä¸åå¨"); |
| | | |
| | | if (stockInfo.LocationId > 0 || !string.IsNullOrWhiteSpace(stockInfo.LocationCode)) |
| | | return WebResponseContent.Instance.Error($"æç[{stockPalletCode}]åºåå·²ç»å®è´§ä½ï¼ä¸è½åå»ºæºæ¢°æ{taskName}ä»»å¡"); |
| | | } |
| | | var section = App.Configuration.GetSection("RobotTaskAddressRules").GetSection(targetLineNo).GetChildren().Select(c => c.Value).ToArray(); |
| | | if (section.Length < 2) |
| | | return WebResponseContent.Instance.Error($"æªæ¾å°çº¿ä½[{targetLineNo}]çå°åé
ç½®"); |
| | | |
| | | var task = new Dt_Task |
| | | { |
| | | TaskNum = await BaseDal.GetTaskNo(), |
| | | PalletCode = palletCode, |
| | | PalletType = stockInfo?.PalletType ?? 0, |
| | | Roadway = stock.Roadway ?? string.Empty, |
| | | TaskType = taskType.GetHashCode(), |
| | | TaskStatus = TaskRobotStatusEnum.RobotNew.GetHashCode(), |
| | | SourceAddress = section[0]!, |
| | | TargetAddress = section[1]!, |
| | | CurrentAddress = targetLineNo, |
| | | NextAddress = targetLineNo, |
| | | WarehouseId = stockInfo?.WarehouseId ?? 1, |
| | | Grade = 1, |
| | | Remark = $"æºæ¢°æ{taskName}", |
| | | Creater = "system" |
| | | }; |
| | | |
| | | var result = await Repository.AddDataAsync(task) > 0; |
| | | if (!result) |
| | | return WebResponseContent.Instance.Error($"æºæ¢°æ{taskName}ä»»å¡å建失败"); |
| | | |
| | | var wmstaskDto = _mapper.Map<WMSTaskDTO>(task) ?? new WMSTaskDTO(); |
| | | return WebResponseContent.Instance.OK($"æºæ¢°æ{taskName}ä»»å¡å建æå", wmstaskDto); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æºæ¢°æ{taskName}ä»»å¡å建失败: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion æºæ¢°æä»»å¡ |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Task; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region ä»»å¡ç¶æç®¡ç |
| | | |
| | | /// <summary> |
| | | /// ä¿®æ¹ä»»å¡ç¶æï¼æ ¹æ®ä»»å¡IDä¿®æ¹ä¸ºæå®ç¶æï¼ |
| | | /// </summary> |
| | | /// <param name="taskDto">ä»»å¡ç¶ææ´æ°åæ°</param> |
| | | /// <returns>ä¿®æ¹ç»æ</returns> |
| | | public async Task<WebResponseContent> UpdateTaskByStatusAsync(UpdateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var taskInfo = await BaseDal.QueryFirstAsync(s => s.TaskNum == taskDto.Id); |
| | | if (taskInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | taskInfo.TaskStatus = taskDto.NewStatus; |
| | | taskInfo.NextAddress = taskDto.NextAddress; |
| | | taskInfo.CurrentAddress = taskDto.CurrentAddress; |
| | | await BaseDal.UpdateDataAsync(taskInfo); |
| | | |
| | | return WebResponseContent.Instance.OK("ä¿®æ¹æå", taskInfo); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä¿®æ¹å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion ä»»å¡ç¶æç®¡ç |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | using Mapster; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Model.Models; |
| | | |
| | | namespace WIDESEA_TaskInfoService |
| | | { |
| | | public partial class TaskService |
| | | { |
| | | #region 空æçä»»å¡ |
| | | |
| | | /// <summary> |
| | | /// å建空æçå
¥åºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="taskDto"></param> |
| | | /// <returns></returns> |
| | | public async Task<WebResponseContent> CreateTaskInboundTrayAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | WebResponseContent content = await GetTaskByPalletCodeAsync(taskDto.PalletCode); |
| | | if (content.Status) |
| | | { |
| | | return content; |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK("æ¥è¯¢æå"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æ¥è¯¢ä»»å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 空æçå
¥åºå®æ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> InboundFinishTaskTrayAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.TargetAddress); |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | stockInfo.LocationCode = location.LocationCode; |
| | | stockInfo.LocationId = location.Id; |
| | | stockInfo.StockStatus = StockStatusEmun.空æçåºå.GetHashCode(); |
| | | |
| | | location.LocationStatus = LocationStatusEnum.InStock.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | |
| | | var saveTaskHistoryResult = await SaveTaskHistoryAsync(task, "空æçå
¥åºå®æ"); |
| | | if (!saveTaskHistoryResult.Status) |
| | | return saveTaskHistoryResult; |
| | | |
| | | var saveStockHistoryResult = await SaveStockHistoryAsync(stockInfo, "空æçå
¥åºå®æ"); |
| | | if (!saveStockHistoryResult.Status) |
| | | return saveStockHistoryResult; |
| | | |
| | | var deleteResult = await BaseDal.DeleteDataAsync(task); |
| | | if (!deleteResult) return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | |
| | | return WebResponseContent.Instance.OK("ä»»å¡å®æ"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"宿任å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// å建空æçåºåºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="taskDto"></param> |
| | | /// <returns></returns> |
| | | public async Task<WebResponseContent> GetOutBoundTrayTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var dt_Task = await BaseDal.QueryFirstAsync(x => x.TargetAddress == taskDto.TargetAddress); |
| | | if (dt_Task != null) |
| | | { |
| | | var taskDTO = dt_Task.Adapt<WMSTaskDTO>(); |
| | | return WebResponseContent.Instance.OK("ä»»å¡å建æå", taskDTO); |
| | | } |
| | | |
| | | var stockInfo = await _stockInfoService.Repository.QueryDataNavFirstAsync(x => x.LocationDetails.WarehouseId == taskDto.WarehouseId && x.LocationDetails.LocationStatus == LocationStatusEnum.InStock.GetHashCode() && x.StockStatus == StockStatusEmun.空æçåºå.GetHashCode()); |
| | | if (stockInfo == null) |
| | | return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçåºåä¿¡æ¯"); |
| | | |
| | | var task = new Dt_Task() |
| | | { |
| | | WarehouseId = stockInfo.LocationDetails.WarehouseId, |
| | | PalletCode = stockInfo.PalletCode, |
| | | PalletType = stockInfo.PalletType, |
| | | SourceAddress = stockInfo.LocationCode, |
| | | CurrentAddress = stockInfo.LocationCode, |
| | | NextAddress = taskDto.TargetAddress, |
| | | TargetAddress = taskDto.TargetAddress, |
| | | Roadway = stockInfo.LocationDetails.RoadwayNo, |
| | | TaskType = TaskOutboundTypeEnum.OutEmpty.GetHashCode(), |
| | | TaskStatus = TaskStatusEnum.New.GetHashCode(), |
| | | Grade = 1, |
| | | TaskNum = await BaseDal.GetTaskNo(), |
| | | Creater = "system", |
| | | }; |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationId); |
| | | locationInfo.LocationStatus = LocationStatusEnum.InStockLock.GetHashCode(); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | if (!updateLocationResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å建失败"); |
| | | |
| | | var taskDtos = task.Adapt<WMSTaskDTO>(); |
| | | |
| | | var addResult = await BaseDal.AddDataAsync(task) > 0; |
| | | if (!addResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å建失败"); |
| | | return WebResponseContent.Instance.OK("ä»»å¡å建æå", taskDtos); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æ¥è¯¢ä»»å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 空æçåºåºå®æ |
| | | /// </summary> |
| | | public async Task<WebResponseContent> OutboundFinishTaskTrayAsync(CreateTaskDto taskDto) |
| | | { |
| | | try |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(s => s.PalletCode == taskDto.PalletCode); |
| | | if (task == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçä»»å¡"); |
| | | |
| | | var location = await _locationInfoService.GetLocationInfo(task.Roadway, task.SourceAddress); |
| | | if (location == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºçè´§ä½"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(taskDto.PalletCode); |
| | | if (stockInfo == null) return WebResponseContent.Instance.Error("æªæ¾å°å¯¹åºåºåä¿¡æ¯"); |
| | | |
| | | return await _unitOfWorkManage.BeginTranAsync(async () => |
| | | { |
| | | stockInfo.LocationId = 0; |
| | | stockInfo.LocationCode = string.Empty; |
| | | stockInfo.StockStatus = StockStatusEmun.åºåºå®æ.GetHashCode(); |
| | | |
| | | location.LocationStatus = LocationStatusEnum.Free.GetHashCode(); |
| | | |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(location); |
| | | var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); |
| | | if (!updateLocationResult || !updateStockResult) |
| | | return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | |
| | | var saveTaskHistoryResult = await SaveTaskHistoryAsync(task, "空æçåºåºå®æ"); |
| | | if (!saveTaskHistoryResult.Status) |
| | | return saveTaskHistoryResult; |
| | | |
| | | var saveStockHistoryResult = await SaveStockHistoryAsync(stockInfo, "空æçåºåºå®æ"); |
| | | if (!saveStockHistoryResult.Status) |
| | | return saveStockHistoryResult; |
| | | |
| | | var deleteResult = await BaseDal.DeleteDataAsync(task); |
| | | if (!deleteResult) return WebResponseContent.Instance.Error("ä»»å¡å®æå¤±è´¥"); |
| | | |
| | | return WebResponseContent.Instance.OK("ä»»å¡å®æ"); |
| | | }); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"宿任å¡å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | #endregion 空æçä»»å¡ |
| | | } |
| | | } |
| | |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseController; |
| | | using WIDESEA_DTO.Stock; |
| | | using WIDESEA_DTO.MES; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_IBasicService; |
| | | using WIDESEA_IMesService; |
| | | using WIDESEA_ISystemService; |
| | | using WIDESEA_Model.Models; |
| | | using WIDESEA_Common.StockEnum; |
| | | using System.Diagnostics; |
| | | |
| | | namespace WIDESEA_WMSServer.Controllers.Stock |
| | | { |
| | |
| | | [ApiController] |
| | | public class StockInfoController : ApiBaseController<IStockInfoService, Dt_StockInfo> |
| | | { |
| | | public StockInfoController(IStockInfoService service) : base(service) |
| | | private readonly IMesLogService _mesLogService; |
| | | private readonly IMesService _mesService; |
| | | private readonly ISys_DictionaryService _sysDictionaryService; |
| | | |
| | | public StockInfoController( |
| | | IStockInfoService service, |
| | | IMesLogService mesLogService, |
| | | IMesService mesService, |
| | | ISys_DictionaryService sysDictionaryService) : base(service) |
| | | { |
| | | _mesLogService = mesLogService; |
| | | _mesService = mesService; |
| | | _sysDictionaryService = sysDictionaryService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | var result = await Service.Get3DLayoutAsync(warehouseId); |
| | | return WebResponseContent.Instance.OK(data: result); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æçè¿ç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">è¿ç«è¯·æ±åæ°</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("inboundInContainer")] |
| | | public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. æ¥è¯¢åºåä¿¡æ¯ - 使ç¨åæ¡è®°å½æ¥è¯¢æ¹æ³æé«æç |
| | | var stockInfo = await Service.Repository.QueryDataNavFirstAsync(x => x.Id == dto.StockId); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | return response.Error("åºåä¿¡æ¯ä¸åå¨"); |
| | | } |
| | | |
| | | // 3. éªè¯åºåç¶æï¼ä»
"å
¥åºå®æ"ç¶æå
许è¿ç«ï¼ |
| | | if (stockInfo.StockStatus != StockStatusEmun.å
¥åºå®æ.GetHashCode()) |
| | | { |
| | | return response.Error($"å½ååºåç¶æä¸å
许è¿ç«æä½ï¼å½åç¶æï¼{stockInfo.StockStatus}"); |
| | | } |
| | | |
| | | // 4. è·åç³»ç»é
ç½® - ç´æ¥ä»æ°æ®åºæ¥è¯¢ |
| | | var configs = _sysDictionaryService.GetVueDictionary(new[] { "MES_EquipmentCode", "MES_ResourceCode" }); |
| | | |
| | | string equipmentCode = GetConfigValue(configs, "MES_EquipmentCode", "WCS_001"); |
| | | string resourceCode = GetConfigValue(configs, "MES_ResourceCode", "RESOURCE_001"); |
| | | |
| | | // 5. æé MESè¯·æ± |
| | | var mesRequest = new InboundInContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 6. è°ç¨MESæ¥å£ï¼åæ¥æ¹æ³ï¼ |
| | | var mesResult = _mesService.InboundInContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 7. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "InboundInContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.IsSuccess, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | // 8. è¿åç»æ |
| | | if (mesResult.IsSuccess) |
| | | { |
| | | return response.OK("æçè¿ç«æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "InboundInContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | return response.Error($"æçè¿ç«å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æçåºç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">åºç«è¯·æ±åæ°</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("outboundInContainer")] |
| | | public async Task<WebResponseContent> OutboundInContainer([FromBody] OutboundInContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. æ¥è¯¢åºåä¿¡æ¯ - 使ç¨åæ¡è®°å½æ¥è¯¢æ¹æ³æé«æç |
| | | var stockInfo = await Service.Repository.QueryDataNavFirstAsync(x => x.Id == dto.StockId); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | return response.Error("åºåä¿¡æ¯ä¸åå¨"); |
| | | } |
| | | |
| | | // 3. éªè¯åºåç¶æï¼"åºåºéå®"æ"åºåºå®æ"ç¶æå
许åºç«ï¼ |
| | | var allowedStatuses = new[] |
| | | { |
| | | StockStatusEmun.åºåºéå®.GetHashCode(), |
| | | StockStatusEmun.åºåºå®æ.GetHashCode() |
| | | }; |
| | | |
| | | if (!allowedStatuses.Contains(stockInfo.StockStatus)) |
| | | { |
| | | return response.Error($"å½ååºåç¶æä¸å
许åºç«æä½ï¼å½åç¶æï¼{stockInfo.StockStatus}"); |
| | | } |
| | | |
| | | // 4. è·åç³»ç»é
ç½® |
| | | var configs = _sysDictionaryService.GetVueDictionary(new[] { "MES_EquipmentCode", "MES_ResourceCode" }); |
| | | |
| | | string equipmentCode = GetConfigValue(configs, "MES_EquipmentCode", "WCS_001"); |
| | | string resourceCode = GetConfigValue(configs, "MES_ResourceCode", "RESOURCE_001"); |
| | | |
| | | // 5. æé MESè¯·æ± |
| | | var mesRequest = new OutboundInContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | ParamList = dto.ParamList?.Select(p => new ParamItem |
| | | { |
| | | ParamCode = p.ParamCode, |
| | | ParamValue = p.ParamValue, |
| | | CollectionTime = DateTime.TryParse(p.CollectionTime, out var ct) ? ct : DateTime.Now |
| | | }).ToList() |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 6. è°ç¨MESæ¥å£ï¼åæ¥æ¹æ³ï¼ |
| | | var mesResult = _mesService.OutboundInContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 7. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "OutboundInContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.IsSuccess, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | // 8. è¿åç»æ |
| | | if (mesResult.IsSuccess) |
| | | { |
| | | return response.OK("æçåºç«æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "OutboundInContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | return response.Error($"æçåºç«å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»é
ç½®åå
¸ä¸è·åé
ç½®å¼ |
| | | /// </summary> |
| | | /// <param name="configs">é
ç½®åå
¸å表</param> |
| | | /// <param name="key">é
ç½®é®</param> |
| | | /// <param name="defaultValue">é»è®¤å¼</param> |
| | | /// <returns>é
ç½®å¼</returns> |
| | | private string GetConfigValue(System.Collections.Generic.List<WIDESEA_DTO.System.VueDictionaryDTO> configs, string key, string defaultValue = "") |
| | | { |
| | | if (configs != null) |
| | | { |
| | | var config = configs.FirstOrDefault(c => c.DicNo == key); |
| | | if (config != null && config.Data != null) |
| | | { |
| | | // Dataæ¯dynamicç±»åï¼å°è¯è·å第ä¸ä¸ªå
ç´ çvalue屿§ |
| | | try |
| | | { |
| | | // 使ç¨dynamicæ¥è®¿é®å¿åç±»åç屿§ |
| | | dynamic data = config.Data; |
| | | if (data != null) |
| | | { |
| | | // dataå¯è½æ¯IEnumerableæè
å个对象 |
| | | var enumerable = data as System.Collections.IEnumerable; |
| | | if (enumerable != null) |
| | | { |
| | | foreach (var item in enumerable) |
| | | { |
| | | // è·å第ä¸ä¸ªå
ç´ |
| | | dynamic firstItem = item; |
| | | var value = firstItem.value; |
| | | return value?.ToString() ?? defaultValue; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch |
| | | { |
| | | // å¦ææ æ³è·åï¼è¿åé»è®¤å¼ |
| | | return defaultValue; |
| | | } |
| | | } |
| | | } |
| | | return defaultValue; |
| | | } |
| | | } |
| | | } |
| | |
| | | using Microsoft.AspNetCore.Http; |
| | | using Microsoft.AspNetCore.Mvc; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseController; |
| | | using WIDESEA_DTO.MES; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_IBasicService; |
| | | using WIDESEA_IMesService; |
| | | using WIDESEA_ISystemService; |
| | | using WIDESEA_Model.Models; |
| | | using System.Diagnostics; |
| | | |
| | | namespace WIDESEA_WMSServer.Controllers.Stock |
| | | { |
| | |
| | | [ApiController] |
| | | public class StockInfoDetailController : ApiBaseController<IStockInfoDetailService, Dt_StockInfoDetail> |
| | | { |
| | | public StockInfoDetailController(IStockInfoDetailService service) : base(service) |
| | | private readonly IMesLogService _mesLogService; |
| | | private readonly IMesService _mesService; |
| | | private readonly ISys_DictionaryService _sysDictionaryService; |
| | | |
| | | public StockInfoDetailController( |
| | | IStockInfoDetailService service, |
| | | IMesLogService mesLogService, |
| | | IMesService mesService, |
| | | ISys_DictionaryService sysDictionaryService) : base(service) |
| | | { |
| | | _mesLogService = mesLogService; |
| | | _mesService = mesService; |
| | | _sysDictionaryService = sysDictionaryService; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æççµè¯ç»å® - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">ç»å®è¯·æ±åæ°</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("bindContainer")] |
| | | public async Task<WebResponseContent> BindContainer([FromBody] BindContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.SfcList == null || !dto.SfcList.Any()) |
| | | { |
| | | return response.Error("çµè¯ç å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. éªè¯çµè¯ç¶æï¼é'å·²éå®'ç¶æå
许ç»å®ï¼ |
| | | var stockDetails = await Service.Repository.QueryDataAsync(x => dto.SfcList.Contains(x.SerialNumber)); |
| | | if (stockDetails != null && stockDetails.Any(d => d.Status == 99)) |
| | | { |
| | | return response.Error("å½ååºåæç»å
å«å·²éå®ç¶æï¼ä¸å
许æ§è¡ç»å®æä½"); |
| | | } |
| | | |
| | | // 3. è·åç³»ç»é
ç½® |
| | | var configs = _sysDictionaryService.GetVueDictionary(new[] { "MES_EquipmentCode", "MES_ResourceCode" }); |
| | | |
| | | string equipmentCode = GetConfigValue(configs, "MES_EquipmentCode", "WCS_001"); |
| | | string resourceCode = GetConfigValue(configs, "MES_ResourceCode", "RESOURCE_001"); |
| | | |
| | | // 3. æé MESè¯·æ± - å°çµè¯å表转æ¢ä¸ºContainerSfcItemæ ¼å¼ |
| | | var mesRequest = new BindContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | ContainerSfcList = dto.SfcList.Select(sfc => new ContainerSfcItem |
| | | { |
| | | Sfc = sfc, |
| | | Location = dto.Location ?? "" |
| | | }).ToList(), |
| | | OperationType = dto.OperationType |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ï¼åæ¥æ¹æ³ï¼ |
| | | var mesResult = _mesService.BindContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "BindContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.IsSuccess, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.IsSuccess) |
| | | { |
| | | return response.OK("æççµè¯ç»å®æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "BindContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | return response.Error($"æççµè¯ç»å®å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æççµè¯è§£ç» - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">è§£ç»è¯·æ±åæ°</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("unbindContainer")] |
| | | public async Task<WebResponseContent> UnbindContainer([FromBody] UnbindContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.SfcList == null || !dto.SfcList.Any()) |
| | | { |
| | | return response.Error("çµè¯ç å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. éªè¯çµè¯ç¶æï¼é'å·²éå®'ç¶æå
许解ç»ï¼ |
| | | var stockDetails = await Service.Repository.QueryDataAsync(x => dto.SfcList.Contains(x.SerialNumber)); |
| | | if (stockDetails != null && stockDetails.Any(d => d.Status == 99)) |
| | | { |
| | | return response.Error("å½ååºåæç»å
å«å·²éå®ç¶æï¼ä¸å
许æ§è¡è§£ç»æä½"); |
| | | } |
| | | |
| | | // 3. è·åç³»ç»é
ç½® |
| | | var configs = _sysDictionaryService.GetVueDictionary(new[] { "MES_EquipmentCode", "MES_ResourceCode" }); |
| | | |
| | | string equipmentCode = GetConfigValue(configs, "MES_EquipmentCode", "WCS_001"); |
| | | string resourceCode = GetConfigValue(configs, "MES_ResourceCode", "RESOURCE_001"); |
| | | |
| | | // 3. æé MESè¯·æ± |
| | | var mesRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = dto.PalletCode, |
| | | SfcList = dto.SfcList |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ï¼åæ¥æ¹æ³ï¼ |
| | | var mesResult = _mesService.UnBindContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "UnbindContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.IsSuccess, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.IsSuccess) |
| | | { |
| | | return response.OK("æççµè¯è§£ç»æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "UnbindContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | return response.Error($"æççµè¯è§£ç»å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æçNGçµè¯ä¸æ¥ - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">NG䏿¥è¯·æ±åæ°</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("containerNgReport")] |
| | | public async Task<WebResponseContent> ContainerNgReport([FromBody] ContainerNgReportRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.NgSfcList == null || !dto.NgSfcList.Any()) |
| | | { |
| | | return response.Error("NGçµè¯å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. éªè¯çµè¯ç¶æï¼é'å·²éå®'ç¶æå
许NG䏿¥ï¼ |
| | | var sfcList = dto.NgSfcList.Select(x => x.Sfc).ToList(); |
| | | var stockDetails = await Service.Repository.QueryDataAsync(x => sfcList.Contains(x.SerialNumber)); |
| | | if (stockDetails != null && stockDetails.Any(d => d.Status == 99)) |
| | | { |
| | | return response.Error("å½ååºåæç»å
å«å·²éå®ç¶æï¼ä¸å
许æ§è¡NG䏿¥æä½"); |
| | | } |
| | | |
| | | // 3. è·åç³»ç»é
ç½® |
| | | var configs = _sysDictionaryService.GetVueDictionary(new[] { "MES_EquipmentCode", "MES_ResourceCode" }); |
| | | |
| | | string equipmentCode = GetConfigValue(configs, "MES_EquipmentCode", "WCS_001"); |
| | | string resourceCode = GetConfigValue(configs, "MES_ResourceCode", "RESOURCE_001"); |
| | | |
| | | // 3. æé MESè¯·æ± - å°DTOæ ¼å¼è½¬æ¢ä¸ºMESè¯·æ±æ ¼å¼ |
| | | var mesRequest = new ContainerNgReportRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | NgSfcList = dto.NgSfcList.Select(ng => new NgSfcItem |
| | | { |
| | | Sfc = ng.Sfc, |
| | | NgCode = ng.NgCode, |
| | | NgEquipmentCode = ng.NgEquipmentCode, |
| | | NgResourceCode = ng.NgResourceCode |
| | | }).ToList() |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ï¼åæ¥æ¹æ³ï¼ |
| | | var mesResult = _mesService.ContainerNgReport(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "ContainerNgReport", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.IsSuccess, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.IsSuccess) |
| | | { |
| | | return response.OK("NGçµè¯ä¸æ¥æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "ContainerNgReport", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = App.User.UserName |
| | | }); |
| | | |
| | | return response.Error($"NGçµè¯ä¸æ¥å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»é
ç½®åå
¸ä¸è·åé
ç½®å¼ |
| | | /// </summary> |
| | | /// <param name="configs">é
ç½®åå
¸å表</param> |
| | | /// <param name="key">é
ç½®é®</param> |
| | | /// <param name="defaultValue">é»è®¤å¼</param> |
| | | /// <returns>é
ç½®å¼</returns> |
| | | private string GetConfigValue(System.Collections.Generic.List<WIDESEA_DTO.System.VueDictionaryDTO> configs, string key, string defaultValue = "") |
| | | { |
| | | if (configs != null) |
| | | { |
| | | var config = configs.FirstOrDefault(c => c.DicNo == key); |
| | | if (config != null && config.Data != null) |
| | | { |
| | | // Dataæ¯dynamicç±»åï¼å°è¯è·å第ä¸ä¸ªå
ç´ çvalue屿§ |
| | | try |
| | | { |
| | | // 使ç¨dynamicæ¥è®¿é®å¿åç±»åç屿§ |
| | | dynamic data = config.Data; |
| | | if (data != null) |
| | | { |
| | | // dataå¯è½æ¯IEnumerableæè
å个对象 |
| | | var enumerable = data as System.Collections.IEnumerable; |
| | | if (enumerable != null) |
| | | { |
| | | foreach (var item in enumerable) |
| | | { |
| | | // è·å第ä¸ä¸ªå
ç´ |
| | | dynamic firstItem = item; |
| | | var value = firstItem.value; |
| | | return value?.ToString() ?? defaultValue; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch |
| | | { |
| | | // å¦ææ æ³è·åï¼è¿åé»è®¤å¼ |
| | | return defaultValue; |
| | | } |
| | | } |
| | | } |
| | | return defaultValue; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå¨åå»ºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="dto">æå¨å建任å¡åæ°</param> |
| | | /// <returns></returns> |
| | | [HttpGet, HttpPost, Route("CreateManualTask"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> CreateManualTaskAsync([FromBody] CreateManualTaskDto dto) |
| | | { |
| | | return await Service.CreateManualTaskAsync(dto); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡å°WCS |
| | | /// </summary> |
| | | /// <param name="dtos">ä¸åä»»å¡åæ°å表</param> |
| | | /// <returns>æ¹éä¸åç»æ</returns> |
| | | [HttpGet, HttpPost, Route("DispatchTasksToWCS"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> DispatchTasksToWCSAsync([FromBody] List<DispatchTaskDto> dtos) |
| | | { |
| | | return await Service.DispatchTasksToWCSAsync(dtos); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åå¯å
¥åºè´§ä½ |
| | | /// </summary> |
| | | /// <param name="taskDto"></param> |
| | |
| | | [HttpGet, HttpPost, Route("UpdateTaskByStatus"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> UpdateTaskByStatusAsync([FromBody] UpdateTaskDto taskDto) |
| | | { |
| | | return await Service.UpdateTaskByStatusAsync(taskDto.Id, taskDto.NewStatus); |
| | | return await Service.UpdateTaskByStatusAsync(taskDto); |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | <ProjectReference Include="..\WIDESEA_BasicService\WIDESEA_BasicService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_CheckService\WIDESEA_CheckService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_InboundService\WIDESEA_InboundService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_MesService\WIDESEA_MesService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_OutboundService\WIDESEA_OutboundService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_RecordService\WIDESEA_RecordService.csproj" /> |
| | | <ProjectReference Include="..\WIDESEA_StockService\WIDESEA_StockService.csproj" /> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æå¨å建任å¡åè½å®æ½è®¡å |
| | | |
| | | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| | | |
| | | **Goal:** å¨WMSçé¢ä¸æ·»å æå¨å建任å¡åè½ï¼æ¯æå
¥åº/åºåº/ç§»åºä¸ç§ç±»åï¼ä»»å¡åéè³WCSåï¼WCSå¤æèµ·ç¹ä¸ºçº¿ä½ç¹ä½(11068/11010/11001)æ¶åå
¥è¾é线任å¡ã |
| | | |
| | | **Architecture:** WMSå端Vueé¡µé¢ â WMSå端API â WCS ReceiveTask â WCS FlowService夿并åå
¥è¾é线PLC |
| | | |
| | | **Tech Stack:** .NET 6 (WMS/WCS Backend), Vue3 (WMS Frontend), MapsterMapper, SqlSugar |
| | | |
| | | --- |
| | | |
| | | ## æä»¶ç»æ |
| | | |
| | | | æä»¶ | èè´£ | |
| | | |------|------| |
| | | | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` | æ·»å æå¨åå»ºä»»å¡æé®åå¤çé»è¾ | |
| | | | `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs` | **æ°å»º** - æå¨å建任å¡è¯·æ±DTO | |
| | | | `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` | æ·»å CreateManualTask æ¥å£ | |
| | | | `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs` | æ·»å CreateManualTaskAsync æ¹æ³ | |
| | | | `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs` | ReceiveWMSTask å·²æååé»è¾ï¼ç¡®è®¤å
¥å£æ£ç¡® | |
| | | | `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs` | æ·»å 线ä½ç¹ä½å¤æåè¾é线任å¡åå
¥é»è¾ | |
| | | |
| | | --- |
| | | |
| | | ## WMS å端 |
| | | |
| | | ### Task 1: æ·»å æå¨åå»ºä»»å¡æé® |
| | | |
| | | **æä»¶:** |
| | | - Modify: `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js:16` |
| | | |
| | | - [ ] **Step 1: å¨ buttons.box æ·»å æå¨å建æé®** |
| | | |
| | | å¨ `task.js` ç `buttons: { view: [], box: [], detail: [] }` 䏿·»å ï¼ |
| | | |
| | | ```javascript |
| | | buttons: { |
| | | view: [], |
| | | box: [ |
| | | { |
| | | value: 'CreateManualTask', |
| | | label: 'æå¨å建任å¡', |
| | | onClick: function () { |
| | | // å¼¹åºæå¨å建任å¡å¯¹è¯æ¡ |
| | | this.$refs.grid.openModel('Add'); |
| | | } |
| | | } |
| | | ], |
| | | detail: [] |
| | | }, |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å¨ modelFooter æ·»å èªå®ä¹å¼¹çª** |
| | | |
| | | å¨ `components.modelFooter` æ·»å Vue 模æ¿ï¼å¦ææ¡æ¶æ¯æèªå®ä¹å¼¹çªå
容ï¼ï¼æä½¿ç¨æ¡æ¶å
ç½®ç `openModel` é
å `addBefore` å¤çã |
| | | |
| | | > **注æ:** å
·ä½çå¼¹çªå®ç°åå³äºå½ååç«¯æ¡æ¶çæ©å±æºå¶ãè¥å½å页é¢ä¸æ¯æèªå®ä¹å段ï¼åéè¦å¨ `task.vue` 䏿·»å æ°ç页é¢ç»ä»¶ï¼æéè¿ `modelBody` æ©å±èªå®ä¹è¡¨åã |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js |
| | | git commit -m "feat(WMS): æ·»å æå¨åå»ºä»»å¡æé®" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## WMS å端 |
| | | |
| | | ### Task 2: å建 DTO |
| | | |
| | | **æä»¶:** |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs` |
| | | |
| | | - [ ] **Step 1: ç¼å CreateManualTaskDto** |
| | | |
| | | ```csharp |
| | | using System.ComponentModel.DataAnnotations; |
| | | using System.Text.Json.Serialization; |
| | | using WIDESEA_Common.TaskEnum; |
| | | |
| | | namespace WIDESEA_DTO.Task |
| | | { |
| | | /// <summary> |
| | | /// æå¨å建任å¡è¯·æ±DTO |
| | | /// </summary> |
| | | public class CreateManualTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ç±»åï¼1=å
¥åº, 2=åºåº, 3=ç§»åº |
| | | /// </summary> |
| | | [JsonPropertyName("taskType")] |
| | | [Required(ErrorMessage = "ä»»å¡ç±»åä¸è½ä¸ºç©º")] |
| | | public TaskTypeEnum TaskType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("sourceAddress")] |
| | | [Required(ErrorMessage = "èµ·ç¹å°åä¸è½ä¸ºç©º")] |
| | | public string SourceAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("targetAddress")] |
| | | [Required(ErrorMessage = "ç»ç¹å°åä¸è½ä¸ºç©º")] |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¡ç |
| | | /// </summary> |
| | | [JsonPropertyName("barcode")] |
| | | [Required(ErrorMessage = "æ¡ç ä¸è½ä¸ºç©º")] |
| | | public string Barcode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»åºID |
| | | /// </summary> |
| | | [JsonPropertyName("warehouseId")] |
| | | [Required(ErrorMessage = "ä»åºIDä¸è½ä¸ºç©º")] |
| | | public int WarehouseId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级ï¼é»è®¤1 |
| | | /// </summary> |
| | | [JsonPropertyName("grade")] |
| | | public int Grade { get; set; } = 1; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs |
| | | git commit -m "feat(WMS): æ°å¢CreateManualTaskDto" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### Task 3: æ·»å Controller æ¥å£ |
| | | |
| | | **æä»¶:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` |
| | | |
| | | - [ ] **Step 1: æ·»å CreateManualTask æ¥å£** |
| | | |
| | | å¨ `TaskController` ç±»ä¸æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æå¨åå»ºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="dto">æå¨å建任å¡åæ°</param> |
| | | /// <returns></returns> |
| | | [HttpGet, HttpPost, Route("CreateManualTask"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> CreateManualTaskAsync([FromBody] CreateManualTaskDto dto) |
| | | { |
| | | return await Service.CreateManualTaskAsync(dto); |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs |
| | | git commit -m "feat(WMS): æ·»å æå¨åå»ºä»»å¡æ¥å£ CreateManualTask" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### Task 4: æ·»å TaskService æ¹æ³ |
| | | |
| | | **æä»¶:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs` |
| | | |
| | | é¦å
æ¥çç°æ `TaskService.cs` ç»æï¼ç¡®è®¤æ¹æ³ç¾åæ ¼å¼ã |
| | | |
| | | - [ ] **Step 1: æ·»å CreateManualTaskAsync æ¹æ³** |
| | | |
| | | å¨ `TaskService` ç±»ä¸æ·»å ï¼åè `CreateAutoOutboundTasksAsync` çæ¨¡å¼ï¼ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æå¨åå»ºä»»å¡ |
| | | /// </summary> |
| | | /// <param name="dto">æå¨å建任å¡åæ°</param> |
| | | /// <returns></returns> |
| | | public async Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto) |
| | | { |
| | | try |
| | | { |
| | | // 1. çæä»»å¡å· |
| | | int taskNum = await BaseDal.GetTaskNo(); |
| | | |
| | | // 2. æ ¹æ®ä»»å¡ç±»åç¡®å®ç¶æå¼ |
| | | int taskStatus = dto.TaskType switch |
| | | { |
| | | TaskTypeEnum.Inbound => TaskInStatusEnum.InNew.GetHashCode(), // 200 |
| | | TaskTypeEnum.Outbound => TaskOutStatusEnum.OutNew.GetHashCode(), // 100 |
| | | TaskTypeEnum.Relocation => TaskRelocationStatusEnum.New.GetHashCode(), // 300 |
| | | _ => TaskStatusEnum.New.GetHashCode() |
| | | }; |
| | | |
| | | // 3. æå»ºä»»å¡å®ä½ |
| | | var task = new Dt_Task |
| | | { |
| | | TaskNum = taskNum, |
| | | PalletCode = dto.Barcode, |
| | | SourceAddress = dto.SourceAddress, |
| | | TargetAddress = dto.TargetAddress, |
| | | TaskType = dto.TaskType.GetHashCode(), |
| | | TaskStatus = taskStatus, |
| | | Grade = dto.Grade, |
| | | WarehouseId = dto.WarehouseId, |
| | | Creater = "manual", |
| | | CreateDate = DateTime.Now, |
| | | ModifyDate = DateTime.Now |
| | | }; |
| | | |
| | | // 4. ä¿åå°æ°æ®åº |
| | | var result = await BaseDal.Add(task); |
| | | if (!result) |
| | | return WebResponseContent.Instance.Error("å建任å¡å¤±è´¥"); |
| | | |
| | | // 5. åéä»»å¡å°WCS |
| | | var wmsTaskDto = new WMSTaskDTO |
| | | { |
| | | TaskNum = task.TaskNum, |
| | | PalletCode = task.PalletCode, |
| | | SourceAddress = task.SourceAddress, |
| | | TargetAddress = task.TargetAddress, |
| | | TaskType = task.TaskType, |
| | | TaskStatus = task.TaskStatus, |
| | | WarehouseId = task.WarehouseId ?? 0 |
| | | }; |
| | | |
| | | var wcsResult = await _httpClientHelper.PostAsync<WebResponseContent>( |
| | | "http://localhost:9292/api/Task/ReceiveTask", |
| | | wmsTaskDto.ToJson()); |
| | | |
| | | if (!wcsResult.IsSuccess || !wcsResult.Data.Status) |
| | | return WebResponseContent.Instance.Error($"ä»»å¡å·²å建ä½åéç»WCS失败: {wcsResult.Data?.Message}"); |
| | | |
| | | return WebResponseContent.Instance.OK($"æå¨åå»ºä»»å¡æåï¼ä»»å¡å·: {taskNum}"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"æå¨å建任å¡å¼å¸¸: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | > **注æ:** éè¦ç¡®è®¤ `TaskRelocationStatusEnum` æ¯å¦åå¨ï¼å¦ä¸åå¨åä½¿ç¨ `TaskStatusEnum.New`ã |
| | | |
| | | - [ ] **Step 2: æ·»å å¿
è¦ç using** |
| | | |
| | | ```csharp |
| | | using WIDESEA_DTO.Task; |
| | | using WIDESEA_Common.TaskEnum; |
| | | using WIDESEAWCS_DTO; |
| | | ``` |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs |
| | | git commit -m "feat(WMS): æ·»å æå¨åå»ºä»»å¡ CreateManualTaskAsync æ¹æ³" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## WCS å端 |
| | | |
| | | ### Task 5: 确认 ReceiveWMSTask å
¥å£ |
| | | |
| | | **æä»¶:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs` |
| | | |
| | | - [ ] **Step 1: 确认 ReceiveWMSTask æ¹æ³åå¨** |
| | | |
| | | 确认 `ReceiveWMSTask` æ¥æ¶ `WMSTaskDTO` å表åè·¯ç±å°å¯¹åº FlowServiceã |
| | | |
| | | ```csharp |
| | | public WebResponseContent ReceiveWMSTask([NotNull] List<WMSTaskDTO> taskDTOs) |
| | | { |
| | | // éåä»»å¡ï¼æ ¹æ® TaskType ååå°ä¸å FlowService |
| | | foreach (var item in taskDTOs) |
| | | { |
| | | // æ ¹æ® item.TaskType å¤æè·¯ç±å° Inbound/Outbound/Relocation |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æäº¤** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs |
| | | git commit -m "feat(WCS): 确认 ReceiveWMSTask å
¥å£æ£ç¡®" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ### Task 6: å¨ InboundTaskFlowService æ·»å 线ä½ç¹ä½å¤ç |
| | | |
| | | **æä»¶:** |
| | | - Modify: `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs` |
| | | |
| | | é¦å
æ¥çç°æç `InitializeOnReceive` æ¹æ³å®æ´å®ç°ã |
| | | |
| | | - [ ] **Step 1: æ·»å 线ä½ç¹ä½å¸¸é** |
| | | |
| | | å¨ç±»ä¸æ·»å ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// 线ä½å
¥åºç¹ä½ |
| | | /// </summary> |
| | | private static readonly string[] LINE_IN_POINTS = { "11068", "11010", "11001" }; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: ä¿®æ¹ InitializeOnReceive æ¹æ³** |
| | | |
| | | å¨ `InitializeOnReceive` æ¹æ³ä¸ï¼å¤æå¦æ `SourceAddress` æ¯çº¿ä½ç¹ä½ï¼ååå
¥è¾é线任å¡ï¼ |
| | | |
| | | ```csharp |
| | | public void InitializeOnReceive([NotNull] Dt_Task task, [NotNull] WMSTaskDTO source) |
| | | { |
| | | // å
æ§è¡åæçè·¯ç±é»è¾ |
| | | Dt_Router routers = _routerService.QueryNextRoute(source.SourceAddress); |
| | | if (routers.IsNullOrEmpty()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | task.TaskStatus = (int)TaskInStatusEnum.InNew; |
| | | task.CurrentAddress = source.SourceAddress; |
| | | task.NextAddress = routers.ChildPosi; |
| | | |
| | | // å¦æèµ·ç¹æ¯çº¿ä½ç¹ä½(11068/11010/11001)ï¼ç´æ¥åå
¥è¾éçº¿ä»»å¡ |
| | | if (LINE_IN_POINTS.Contains(source.SourceAddress)) |
| | | { |
| | | WriteConveyorLineTask(task, source.SourceAddress); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// åå
¥è¾é线任å¡å°PLC |
| | | /// </summary> |
| | | private void WriteConveyorLineTask(Dt_Task task, string sourceAddress) |
| | | { |
| | | // 1. éè¿ Storage.Devices æ¥æ¾å¯¹åºçè¾éçº¿è®¾å¤ |
| | | IDevice? device = Storage.Devices |
| | | .FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress)); |
| | | |
| | | if (device == null) |
| | | { |
| | | // è®°å½æ¥å¿ï¼æªæ¾å°å¯¹åºçè¾éçº¿è®¾å¤ |
| | | QuartzLogger.Error($"æå¨å建任å¡ï¼æªæ¾å°æºå°åã{sourceAddress}ã对åºçè¾é线设å¤", "InboundTaskFlowService"); |
| | | return; |
| | | } |
| | | |
| | | // 2. 转æ¢ä¸º CommonConveyorLine ç±»å |
| | | if (device is not CommonConveyorLine conveyorLine) |
| | | { |
| | | QuartzLogger.Error($"设å¤ã{device.DeviceCode}ã䏿¯è¾é线类å", "InboundTaskFlowService"); |
| | | return; |
| | | } |
| | | |
| | | // 3. è·åå设å¤ç¼ç |
| | | string? childDeviceCode = device.DeviceProDTOs |
| | | .FirstOrDefault(d => d.DeviceChildCode == sourceAddress)?.DeviceChildCode; |
| | | |
| | | if (string.IsNullOrEmpty(childDeviceCode)) |
| | | { |
| | | QuartzLogger.Error($"æºå°åã{sourceAddress}ãæªæ¾å°å¯¹åºçå设å¤ç¼ç ", "InboundTaskFlowService"); |
| | | return; |
| | | } |
| | | |
| | | // 4. æé ConveyorLineTaskCommandNew |
| | | ConveyorLineTaskCommandNew command = new ConveyorLineTaskCommandNew |
| | | { |
| | | TaskNo = (short)task.TaskNum, |
| | | Source = short.Parse(sourceAddress), |
| | | Target = short.Parse(task.TargetAddress ?? "0"), |
| | | Barcode = task.PalletCode ?? string.Empty, |
| | | WCS_STB = 1, // WCSå·²åéæ å¿ |
| | | WCS_ACK = 0, |
| | | PLC_STB = 0, |
| | | PLC_ACK = 0 |
| | | }; |
| | | |
| | | // 5. åå
¥PLC |
| | | bool success = conveyorLine.SendCommand(command, childDeviceCode); |
| | | if (success) |
| | | { |
| | | QuartzLogger.Info($"æå¨å建å
¥åºä»»å¡å·²åå
¥è¾é线ï¼ä»»å¡å·ã{task.TaskNum}ãï¼æºå°åã{sourceAddress}ã", conveyorLine.DeviceCode); |
| | | } |
| | | else |
| | | { |
| | | QuartzLogger.Error($"æå¨å建å
¥åºä»»å¡åå
¥è¾é线失败ï¼ä»»å¡å·ã{task.TaskNum}ãï¼æºå°åã{sourceAddress}ã", conveyorLine.DeviceCode); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: æ·»å å¿
è¦ç using** |
| | | |
| | | ```csharp |
| | | using WIDESEAWCS_QuartzJob; |
| | | using WIDESEAWCS_QuartzJob.ConveyorLine; |
| | | using WIDESEAWCS_Tasks; |
| | | using WIDESEAWCS_Core.LogHelper; |
| | | ``` |
| | | |
| | | - [ ] **Step 4: æäº¤** |
| | | |
| | | ```bash |
| | | git add WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs |
| | | git commit -m "feat(WCS): å
¥åºä»»å¡çº¿ä½ç¹ä½æ¶åå
¥è¾é线任å¡" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## éªè¯æ¸
å |
| | | |
| | | - [ ] WMS å端ï¼ç¹å»"æå¨å建任å¡"æé®å¼¹åºå¯¹è¯æ¡ |
| | | - [ ] WMS å端ï¼å¡«å表ååæäº¤ï¼è¿åæå |
| | | - [ ] WMS å端ï¼å建任å¡åå
¥æ°æ®åº |
| | | - [ ] WMS å端ï¼ä»»å¡æååéç» WCS |
| | | - [ ] WCS å端ï¼ReceiveTask æ¶å°ä»»å¡ |
| | | - [ ] WCS å端ï¼èµ·ç¹ä¸ºçº¿ä½ç¹ä½æ¶ï¼ä»»å¡åå
¥ PLC æå |
| | | - [ ] WCS å端ï¼èµ·ç¹ä¸ºæ®éç¹ä½æ¶ï¼èµ°åæè·¯ç±é»è¾ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æå¨ä¸åä»»å¡å° WCS åè½å®æ½è®¡å |
| | | |
| | | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| | | |
| | | **Goal:** å¨ WMS å端任å¡ç®¡ç页颿·»å å·¥å
·æ æé®ï¼æ¯æéä¸ä¸ä¸ªæå¤ä¸ªä»»å¡åï¼ç¼è¾å°åï¼èµ·ç¹/ç»ç¹ï¼åä¼å
级åæå¨ä¸åå° WCSã |
| | | |
| | | **Architecture:** |
| | | - åç«¯ï¼æ°å¢ `dispatchTasksToWCS.vue` å¼¹çªç»ä»¶ï¼å¤ç¨ `task.js` æ©å±æºå¶æ·»å å·¥å
·æ æé® |
| | | - åç«¯ï¼æ°å¢ `DispatchTasksToWCSAsync` æ¹æ³ï¼å¤ç¨ `ReceiveManualTask` æ¥å£ä¸åå° WCS |
| | | |
| | | **Tech Stack:** Vue 3 + Element Plusï¼å端ï¼ï¼ASP.NET Core + SqlSugarï¼åç«¯ï¼ |
| | | |
| | | --- |
| | | |
| | | ## æä»¶ç»æ |
| | | |
| | | | æ¹å¨ç±»å | æä»¶è·¯å¾ | |
| | | |----------|----------| |
| | | | æ°å¢ | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/dispatchTasksToWCS.vue` | |
| | | | ä¿®æ¹ | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` | |
| | | | æ°å¢ | `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/DispatchTaskDto.cs` | |
| | | | ä¿®æ¹ | `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs` | |
| | | | ä¿®æ¹ | `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` | |
| | | |
| | | --- |
| | | |
| | | ## Task 1: å端 - æ°å¢ DispatchTaskDto |
| | | |
| | | **æä»¶:** |
| | | - å建: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/DispatchTaskDto.cs` |
| | | |
| | | - [ ] **å建 DispatchTaskDto.cs** |
| | | |
| | | ```csharp |
| | | using System.Text.Json.Serialization; |
| | | |
| | | namespace WIDESEA_DTO.Task |
| | | { |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡Dto |
| | | /// </summary> |
| | | public class DispatchTaskDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ID |
| | | /// </summary> |
| | | [JsonPropertyName("taskId")] |
| | | public long TaskId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èµ·ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("sourceAddress")] |
| | | public string SourceAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ç»ç¹å°å |
| | | /// </summary> |
| | | [JsonPropertyName("targetAddress")] |
| | | public string TargetAddress { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¼å
级 |
| | | /// </summary> |
| | | [JsonPropertyName("grade")] |
| | | public int Grade { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡ä¸åç»æDto |
| | | /// </summary> |
| | | public class DispatchTaskResultDto |
| | | { |
| | | /// <summary> |
| | | /// ä»»å¡ID |
| | | /// </summary> |
| | | [JsonPropertyName("taskId")] |
| | | public long TaskId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä»»å¡å· |
| | | /// </summary> |
| | | [JsonPropertyName("taskNum")] |
| | | public int TaskNum { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | [JsonPropertyName("success")] |
| | | public bool Success { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | [JsonPropertyName("errorMessage")] |
| | | public string ErrorMessage { get; set; } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¹éä¸åç»æDto |
| | | /// </summary> |
| | | public class DispatchResultDto |
| | | { |
| | | /// <summary> |
| | | /// æåæ°é |
| | | /// </summary> |
| | | [JsonPropertyName("successCount")] |
| | | public int SuccessCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 失败æ°é |
| | | /// </summary> |
| | | [JsonPropertyName("failCount")] |
| | | public int FailCount { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 失败任å¡å表 |
| | | /// </summary> |
| | | [JsonPropertyName("failResults")] |
| | | public List<DispatchTaskResultDto> FailResults { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/DispatchTaskDto.cs |
| | | git commit -m "feat(WMS): æ°å¢æå¨ä¸åä»»å¡Dto |
| | | - DispatchTaskDto: ä¸å请æ±åæ° |
| | | - DispatchTaskResultDto: å个任å¡ä¸åç»æ |
| | | - DispatchResultDto: æ¹éä¸åç»æ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 2: å端 - TaskService æ°å¢ DispatchTasksToWCSAsync |
| | | |
| | | **æä»¶:** |
| | | - ä¿®æ¹: `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs` |
| | | |
| | | **åç½®äºè§£:** |
| | | - ä»»å¡ç¶ææä¸¾ï¼`TaskInStatusEnum.InNew`ï¼å
¥åºæ°åï¼ã`TaskOutStatusEnum.OutNew`ï¼åºåºæ°åï¼ã`TaskRelocationStatusEnum.RelocationNew`ï¼ç§»åºæ°åï¼ |
| | | - å·²æ WCS è°ç¨æ¹å¼ï¼`_httpClientHelper.Post<WebResponseContent>("http://localhost:9292/api/Task/ReceiveManualTask", json)` |
| | | - å·²æäºå¡å¤çï¼`await _unitOfWorkManage.BeginTranAsync(async () => { ... })` |
| | | - å·²æ `WMSTaskDTO` ç¨äºç» WCS åéä»»å¡ |
| | | |
| | | **å¨ `TaskService_WCS.cs` æ«å°¾ `#endregion WCSé»è¾å¤ç` ä¹åæ·»å ï¼** |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡å°WCS |
| | | /// </summary> |
| | | /// <param name="dtos">ä¸åä»»å¡åæ°å表</param> |
| | | /// <returns>æ¹éä¸åç»æ</returns> |
| | | public async Task<WebResponseContent> DispatchTasksToWCSAsync(List<DispatchTaskDto> dtos) |
| | | { |
| | | try |
| | | { |
| | | if (dtos == null || !dtos.Any()) |
| | | return WebResponseContent.Instance.Error("è¯·éæ©è¦ä¸åçä»»å¡"); |
| | | |
| | | var resultDto = new DispatchResultDto |
| | | { |
| | | SuccessCount = 0, |
| | | FailCount = 0, |
| | | FailResults = new List<DispatchTaskResultDto>() |
| | | }; |
| | | |
| | | foreach (var dto in dtos) |
| | | { |
| | | var task = await BaseDal.QueryFirstAsync(t => t.TaskId == dto.TaskId); |
| | | if (task == null) |
| | | { |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = dto.TaskId, |
| | | TaskNum = 0, |
| | | Success = false, |
| | | ErrorMessage = "ä»»å¡ä¸åå¨" |
| | | }); |
| | | resultDto.FailCount++; |
| | | continue; |
| | | } |
| | | |
| | | // æ ¡éªä»»å¡ç¶æï¼ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åå¯ä¸å |
| | | bool canDispatch = false; |
| | | if (task.TaskType == TaskInboundTypeEnum.Inbound.GetHashCode() |
| | | && task.TaskStatus == TaskInStatusEnum.InNew.GetHashCode()) |
| | | canDispatch = true; |
| | | else if (task.TaskType == TaskOutboundTypeEnum.Outbound.GetHashCode() |
| | | && task.TaskStatus == TaskOutStatusEnum.OutNew.GetHashCode()) |
| | | canDispatch = true; |
| | | else if (task.TaskType == TaskRelocationTypeEnum.Relocation.GetHashCode() |
| | | && task.TaskStatus == TaskRelocationStatusEnum.RelocationNew.GetHashCode()) |
| | | canDispatch = true; |
| | | |
| | | if (!canDispatch) |
| | | { |
| | | var statusName = GetTaskStatusName(task.TaskType, task.TaskStatus); |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = dto.TaskId, |
| | | TaskNum = task.TaskNum, |
| | | Success = false, |
| | | ErrorMessage = $"ä»»å¡ç¶æ[{statusName}]ä¸å
许ä¸å" |
| | | }); |
| | | resultDto.FailCount++; |
| | | continue; |
| | | } |
| | | |
| | | // æ´æ°ä»»å¡çå°ååä¼å
级 |
| | | task.SourceAddress = dto.SourceAddress; |
| | | task.TargetAddress = dto.TargetAddress; |
| | | task.CurrentAddress = dto.SourceAddress; |
| | | task.NextAddress = dto.TargetAddress; |
| | | task.Grade = dto.Grade; |
| | | task.Dispatchertime = DateTime.Now; |
| | | |
| | | await BaseDal.UpdateDataAsync(task); |
| | | |
| | | // æé WMSTaskDTOåéç»WCS |
| | | var wmsTaskDto = new WMSTaskDTO |
| | | { |
| | | Id = task.TaskId, |
| | | TaskNum = task.TaskNum, |
| | | PalletCode = task.PalletCode, |
| | | SourceAddress = task.SourceAddress, |
| | | TargetAddress = task.TargetAddress, |
| | | CurrentAddress = task.CurrentAddress, |
| | | NextAddress = task.NextAddress, |
| | | TaskType = task.TaskType, |
| | | TaskStatus = task.TaskStatus, |
| | | Roadway = task.Roadway, |
| | | Grade = task.Grade, |
| | | WarehouseId = task.WarehouseId, |
| | | PalletType = task.PalletType |
| | | }; |
| | | |
| | | var wcsResult = _httpClientHelper.Post<WebResponseContent>( |
| | | "http://localhost:9292/api/Task/ReceiveManualTask", |
| | | new List<WMSTaskDTO> { wmsTaskDto }.ToJson()); |
| | | |
| | | if (wcsResult != null && wcsResult.IsSuccess) |
| | | { |
| | | resultDto.SuccessCount++; |
| | | } |
| | | else |
| | | { |
| | | resultDto.FailResults.Add(new DispatchTaskResultDto |
| | | { |
| | | TaskId = dto.TaskId, |
| | | TaskNum = task.TaskNum, |
| | | Success = false, |
| | | ErrorMessage = wcsResult?.Message ?? "WCSååºå¼å¸¸" |
| | | }); |
| | | resultDto.FailCount++; |
| | | } |
| | | } |
| | | |
| | | if (resultDto.FailCount == 0) |
| | | return WebResponseContent.Instance.OK($"æåä¸å{resultDto.SuccessCount}个任å¡", resultDto); |
| | | |
| | | if (resultDto.SuccessCount == 0) |
| | | return WebResponseContent.Instance.Error($"ä¸å失败ï¼å
±{resultDto.FailCount}个任å¡", resultDto); |
| | | |
| | | return WebResponseContent.Instance.Error($"é¨åä¸åæå{resultDto.SuccessCount}个ï¼å¤±è´¥{resultDto.FailCount}个", resultDto); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error($"ä¸åä»»å¡å¼å¸¸: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åä»»å¡ç¶æåç§° |
| | | /// </summary> |
| | | private string GetTaskStatusName(int taskType, int taskStatus) |
| | | { |
| | | if (taskType == TaskInboundTypeEnum.Inbound.GetHashCode()) |
| | | return ((TaskInStatusEnum)taskStatus).ToString(); |
| | | if (taskType == TaskOutboundTypeEnum.Outbound.GetHashCode()) |
| | | return ((TaskOutStatusEnum)taskStatus).ToString(); |
| | | if (taskType == TaskRelocationTypeEnum.Relocation.GetHashCode()) |
| | | return ((TaskRelocationStatusEnum)taskStatus).ToString(); |
| | | return taskStatus.ToString(); |
| | | } |
| | | ``` |
| | | |
| | | **注æï¼** éè¦å¨æä»¶é¡¶é¨ç¡®è®¤å·²æä»¥ä¸ usingï¼ |
| | | ```csharp |
| | | using WIDESEA_DTO.Task; |
| | | |
| | | > **ç¶æåæ¥è¯´æ**ï¼WMS ä¸åæååï¼WMS 端任å¡ç¶æä¿æ"New"ä¸åï¼ä¸åæ¢å°æ§è¡ä¸ç¶æãè¿æ¯ç°æ `CreateManualTaskAsync` ç设计模å¼ï¼å 为 WCS ä¾§æç¬ç«çä»»å¡çå½å¨æï¼ï¼ä¸è·è¿æ¤ PR æ¹åãå¦é WMS 端ä¹åæ¥ç¶æï¼éå¦è¡è¯ä¼° WCSâWMS çç¶æåè°æºå¶ã |
| | | using WIDESEA_Model.Models; |
| | | ``` |
| | | |
| | | - [ ] **Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs |
| | | git commit -m "feat(WMS): TaskServiceæ°å¢DispatchTasksToWCSAsyncæ¹æ³ |
| | | - æ ¡éªä»»å¡ç¶æï¼ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åå¯ä¸å |
| | | - æ´æ°ä»»å¡å°ååä¼å
级åè°ç¨WCS ReceiveManualTaskæ¥å£ |
| | | - è¿åæ¹éä¸åç»æï¼æå/失败å表ååå ï¼ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 3: å端 - TaskController æ°å¢ä¸åæ¥å£ |
| | | |
| | | **æä»¶:** |
| | | - ä¿®æ¹: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` |
| | | |
| | | **å¨ Controller 䏿·»å 以䏿¹æ³ï¼æ¾å¨å
¶ä»æ¹æ³éè¿ï¼å»ºè®®å¨ CreateManualTaskAsync ä¹åï¼ï¼** |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æå¨ä¸åä»»å¡å°WCS |
| | | /// </summary> |
| | | /// <param name="dtos">ä¸åä»»å¡åæ°å表</param> |
| | | /// <returns>æ¹éä¸åç»æ</returns> |
| | | [HttpGet, HttpPost, Route("DispatchTasksToWCS"), AllowAnonymous] |
| | | public async Task<WebResponseContent?> DispatchTasksToWCSAsync([FromBody] List<DispatchTaskDto> dtos) |
| | | { |
| | | return await Service.DispatchTasksToWCSAsync(dtos); |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs |
| | | git commit -m "feat(WMS): TaskControlleræ°å¢DispatchTasksToWCSæ¥å£ |
| | | POST /api/TaskInfo/DispatchTasksToWCS |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 4: å端 - æ°å¢ dispatchTasksToWCS.vue å¼¹çªç»ä»¶ |
| | | |
| | | **æä»¶:** |
| | | - å建: `WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/dispatchTasksToWCS.vue` |
| | | |
| | | **åèç°æ addManualTask.vue çæ¨¡å¼ï¼ä½¿ç¨ el-table å®ç°æ¹éç¼è¾ï¼** |
| | | |
| | | ```vue |
| | | <template> |
| | | <div> |
| | | <vol-box v-model="showBox" :lazy="true" width="900px" :padding="15" title="æå¨ä¸åä»»å¡å° WCS"> |
| | | <div v-if="selectedRows.length > 0" class="dispatch-info"> |
| | | å·²é任塿°: <span class="count">{{ selectedRows.length }}</span> 个 |
| | | </div> |
| | | |
| | | <el-table :data="tableData" border style="width: 100%; margin-top: 10px" max-height="400"> |
| | | <el-table-column prop="taskNum" label="ä»»å¡å·" width="120"></el-table-column> |
| | | <el-table-column prop="sourceAddress" label="èµ·ç¹å°å" width="160"> |
| | | <template slot-scope="scope"> |
| | | <el-input |
| | | v-if="scope.row.editable" |
| | | v-model="scope.row.sourceAddress" |
| | | size="small" |
| | | placeholder="请è¾å
¥" |
| | | ></el-input> |
| | | <span v-else>{{ scope.row.sourceAddress }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="targetAddress" label="ç»ç¹å°å" width="160"> |
| | | <template slot-scope="scope"> |
| | | <el-input |
| | | v-if="scope.row.editable" |
| | | v-model="scope.row.targetAddress" |
| | | size="small" |
| | | placeholder="请è¾å
¥" |
| | | ></el-input> |
| | | <span v-else>{{ scope.row.targetAddress }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="grade" label="ä¼å
级" width="100"> |
| | | <template slot-scope="scope"> |
| | | <el-input-number |
| | | v-if="scope.row.editable" |
| | | v-model="scope.row.grade" |
| | | :min="1" |
| | | :max="99" |
| | | size="small" |
| | | style="width: 80px" |
| | | ></el-input-number> |
| | | <span v-else>{{ scope.row.grade }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="statusName" label="ç¶æ" width="120"> |
| | | <template slot-scope="scope"> |
| | | <span :class="{ 'status-error': !scope.row.editable }">{{ scope.row.statusName }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="palletCode" label="æçå·"></el-table-column> |
| | | </el-table> |
| | | |
| | | <!-- å¤±è´¥ç»æ --> |
| | | <div v-if="failResults.length > 0" class="fail-results"> |
| | | <div class="fail-title">ä¸å失败任å¡ï¼</div> |
| | | <el-table :data="failResults" border style="width: 100%; margin-top: 10px" max-height="200"> |
| | | <el-table-column prop="taskNum" label="ä»»å¡å·" width="120"></el-table-column> |
| | | <el-table-column prop="errorMessage" label="失败åå "></el-table-column> |
| | | </el-table> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <el-button type="primary" size="small" @click="submit" :loading="loading">确认ä¸å</el-button> |
| | | <el-button type="danger" size="small" @click="showBox = false">å
³é</el-button> |
| | | </template> |
| | | </vol-box> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import VolBox from "@/components/basic/VolBox.vue"; |
| | | |
| | | export default { |
| | | components: { VolBox }, |
| | | data() { |
| | | return { |
| | | showBox: false, |
| | | loading: false, |
| | | selectedRows: [], |
| | | tableData: [], |
| | | failResults: [], |
| | | // å¯ä¸åç¶æçä»»å¡ç±»ååç¶æå¼ï¼éä¸å端 TaskTypeEnum æä¸¾ä¸è´ï¼ |
| | | // Inbound=200, Outbound=100, Relocation=300 |
| | | // ç¶æ: InNew=200, OutNew=100, RelocationNew=300 |
| | | dispatchableStatuses: { |
| | | inbound: { taskType: 200, status: 200 }, // å
¥åºæ°å |
| | | outbound: { taskType: 100, status: 100 }, // åºåºæ°å |
| | | relocation: { taskType: 300, status: 300 } // ç§»åºæ°å |
| | | } |
| | | }; |
| | | }, |
| | | methods: { |
| | | open(rows) { |
| | | this.showBox = true; |
| | | this.selectedRows = rows || []; |
| | | this.failResults = []; |
| | | this.initTableData(); |
| | | }, |
| | | initTableData() { |
| | | // ä»»å¡ç¶æåç§°æ å°ï¼éä¸å端æä¸¾ä¸è´ï¼ |
| | | // taskType: Inbound=200, Outbound=100, Relocation=300 |
| | | // status: InNew=200, OutNew=100, RelocationNew=300, SC_OutExecuting=110, etc. |
| | | const statusNames = { |
| | | 'inbound_200': 'å
¥åºæ°å', |
| | | 'outbound_100': 'åºåºæ°å', |
| | | 'relocation_300': 'ç§»åºæ°å', |
| | | 'outbound_110': 'å åæºåºåºæ§è¡ä¸', |
| | | 'outbound_115': 'å åæºåºåºå®æ', |
| | | 'inbound_220': 'è¾é线å
¥åºæ§è¡ä¸', |
| | | 'inbound_230': 'å åæºå
¥åºæ§è¡ä¸', |
| | | 'inbound_290': 'å
¥åºä»»å¡å®æ', |
| | | 'outbound_120': 'è¾é线åºåºæ§è¡ä¸', |
| | | 'outbound_125': 'è¾é线åºåºå®æ', |
| | | 'outbound_200': 'åºåºä»»å¡å®æ', |
| | | 'relocation_310': 'å åæºç§»åºæ§è¡ä¸' |
| | | }; |
| | | |
| | | this.tableData = this.selectedRows.map(row => { |
| | | const taskType = row.taskType || 0; |
| | | const taskStatus = row.taskStatus || 0; |
| | | const statusKey = this.getStatusKey(taskType, taskStatus); |
| | | const statusName = statusNames[statusKey] || `ç¶æ${taskStatus}`; |
| | | |
| | | // 夿æ¯å¦å¯ç¼è¾ï¼ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åå¯ç¼è¾ |
| | | const editable = this.isEditable(taskType, taskStatus); |
| | | |
| | | return { |
| | | taskId: row.taskId, |
| | | taskNum: row.taskNum, |
| | | sourceAddress: row.sourceAddress || '', |
| | | targetAddress: row.targetAddress || '', |
| | | grade: row.grade || 1, |
| | | statusName: statusName, |
| | | palletCode: row.palletCode || '', |
| | | editable: editable, |
| | | taskType: taskType, |
| | | taskStatus: taskStatus |
| | | }; |
| | | }); |
| | | }, |
| | | getStatusKey(taskType, taskStatus) { |
| | | if (taskType === 200) return `inbound_${taskStatus}`; |
| | | if (taskType === 100) return `outbound_${taskStatus}`; |
| | | if (taskType === 300) return `relocation_${taskStatus}`; |
| | | return `other_${taskStatus}`; |
| | | }, |
| | | isEditable(taskType, taskStatus) { |
| | | if (taskType === 200 && taskStatus === 200) return true; // å
¥åºæ°å |
| | | if (taskType === 100 && taskStatus === 100) return true; // åºåºæ°å |
| | | if (taskType === 300 && taskStatus === 300) return true; // ç§»åºæ°å |
| | | return false; |
| | | }, |
| | | submit() { |
| | | if (this.tableData.length === 0) return this.$message.error("请å
鿩任å¡"); |
| | | |
| | | const dispatchData = this.tableData.map(row => ({ |
| | | taskId: row.taskId, |
| | | sourceAddress: row.sourceAddress, |
| | | targetAddress: row.targetAddress, |
| | | grade: row.grade |
| | | })); |
| | | |
| | | this.loading = true; |
| | | this.http |
| | | .post("/api/TaskInfo/DispatchTasksToWCS", dispatchData, "æ°æ®å¤çä¸...") |
| | | .then((res) => { |
| | | this.loading = false; |
| | | if (!res.status) { |
| | | this.$message.error(res.message); |
| | | // æ¾ç¤ºå¤±è´¥å表 |
| | | if (res.data && res.data.failResults) { |
| | | this.failResults = res.data.failResults; |
| | | } |
| | | return; |
| | | } |
| | | |
| | | // å
¨é¨æå |
| | | if (res.data && res.data.failCount === 0) { |
| | | this.$message.success(res.message); |
| | | this.showBox = false; |
| | | this.$emit("parentCall", ($vue) => { |
| | | $vue.refresh(); |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // é¨åæåæå
¨é¨å¤±è´¥ |
| | | if (res.data && res.data.failResults) { |
| | | this.failResults = res.data.failResults; |
| | | } |
| | | |
| | | if (res.data && res.data.failCount > 0 && res.data.successCount > 0) { |
| | | this.$message.warning(res.message); |
| | | } else { |
| | | this.$message.error(res.message); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | this.loading = false; |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .dispatch-info { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-bottom: 10px; |
| | | } |
| | | .dispatch-info .count { |
| | | color: #409eff; |
| | | font-weight: bold; |
| | | } |
| | | .status-error { |
| | | color: #f56c6c; |
| | | } |
| | | .fail-results { |
| | | margin-top: 15px; |
| | | padding: 10px; |
| | | background: #fef0f0; |
| | | border-radius: 4px; |
| | | } |
| | | .fail-title { |
| | | font-size: 14px; |
| | | color: #f56c6c; |
| | | margin-bottom: 5px; |
| | | } |
| | | </style> |
| | | ``` |
| | | |
| | | - [ ] **Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/dispatchTasksToWCS.vue |
| | | git commit -m "feat(WMS): æ°å¢dispatchTasksToWCS.vueæ¹éä¸åå¼¹çªç»ä»¶ |
| | | - å·¥å
·æ æé®è§¦åå¼¹çª |
| | | - è¡¨æ ¼å±ç¤ºéä¸ä»»å¡ï¼å¯ç¼è¾å°ååä¼å
级 |
| | | - éå¯ä¸åç¶æä»»å¡è¡æ 红ä¸ä¸å¯ç¼è¾ |
| | | - æ¾ç¤ºä¸å失败任å¡å表 |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 5: å端 - task.js æ·»å å·¥å
·æ æé® |
| | | |
| | | **æä»¶:** |
| | | - ä¿®æ¹: `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` |
| | | |
| | | **éè¦ä¿®æ¹ä¸¤å¤ï¼** |
| | | |
| | | 1. å¨ `components` é¨åå¼å
¥å¼¹çªç»ä»¶ï¼ |
| | | ```javascript |
| | | import addManualTask from './extend/addManualTask.vue' |
| | | import dispatchTasksToWCS from './extend/dispatchTasksToWCS.vue' // æ°å¢ |
| | | ``` |
| | | |
| | | 2. å¨ `components` å¯¹è±¡ä¸æ³¨åï¼ |
| | | ```javascript |
| | | components: { |
| | | gridBody: addManualTask, |
| | | dispatchBody: dispatchTasksToWCS, // æ°å¢ |
| | | }, |
| | | ``` |
| | | |
| | | 3. å¨ `onInit()` æ¹æ³ä¸æ·»å æå¨ä¸åæé®ï¼å¨æå¨åå»ºä»»å¡æé®ä¹åï¼ï¼ |
| | | |
| | | ```javascript |
| | | // æ·»å "æå¨ä¸å"æé® |
| | | this.buttons.push({ |
| | | name: 'æå¨ä¸å', |
| | | icon: 'el-icon-s-promotion', |
| | | type: 'primary', |
| | | value: 'DispatchTasksToWCS', |
| | | onClick: () => { |
| | | let rows = this.$refs.table.getSelected(); |
| | | if (rows.length == 0) return this.$error("请å
鿩任å¡"); |
| | | this.$refs.dispatchBody.open(rows); |
| | | } |
| | | }); |
| | | ``` |
| | | |
| | | **宿´ä¿®æ¹åç task.js å
³é®é¨åï¼** |
| | | |
| | | ```javascript |
| | | import addManualTask from './extend/addManualTask.vue' |
| | | import dispatchTasksToWCS from './extend/dispatchTasksToWCS.vue' |
| | | |
| | | let extension = { |
| | | components: { |
| | | gridBody: addManualTask, |
| | | dispatchBody: dispatchTasksToWCS, |
| | | }, |
| | | buttons: { view: [], box: [], detail: [] }, |
| | | methods: { |
| | | onInit() { |
| | | //æ·»å "æå¨å建任å¡"æé® |
| | | this.buttons.push({ |
| | | name: 'æå¨å建任å¡', |
| | | icon: 'el-icon-plus', |
| | | type: 'primary', |
| | | value: 'ManualCreateTask', |
| | | onClick: () => { |
| | | this.$refs.gridBody.open(); |
| | | } |
| | | }); |
| | | |
| | | // æ·»å "æå¨ä¸å"æé® |
| | | this.buttons.push({ |
| | | name: 'æå¨ä¸å', |
| | | icon: 'el-icon-s-promotion', |
| | | type: 'primary', |
| | | value: 'DispatchTasksToWCS', |
| | | onClick: () => { |
| | | let rows = this.$refs.table.getSelected(); |
| | | if (rows.length == 0) return this.$error("请å
鿩任å¡"); |
| | | this.$refs.dispatchBody.open(rows); |
| | | } |
| | | }); |
| | | // ... å
¶ä½ç°ææé®é»è¾ä¿æä¸å |
| | | }, |
| | | // ... å
¶ä½æ¹æ³ä¿æä¸å |
| | | } |
| | | }; |
| | | export default extension; |
| | | ``` |
| | | |
| | | - [ ] **Commit** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js |
| | | git commit -m "feat(WMS): task.jsæ·»å å·¥å
·æ 'æå¨ä¸å'æé® |
| | | - å¼å
¥dispatchTasksToWCS.vueç»ä»¶ |
| | | - ç¹å»æé®è·åéä¸ä»»å¡å¹¶æå¼ä¸åå¼¹çª |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 6: éªè¯æå»º |
| | | |
| | | - [ ] **WMS å端æå»º** |
| | | |
| | | ```bash |
| | | cd D:/Git/ShanMeiXinNengYuan/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer |
| | | dotnet build |
| | | ``` |
| | | |
| | | - [ ] **WMS å端æå»º** |
| | | |
| | | ```bash |
| | | cd D:/Git/ShanMeiXinNengYuan/Code/WMS/WIDESEA_WMSClient |
| | | npm run serve |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## éªæ¶æ å |
| | | |
| | | - [ ] å·¥å
·æ æ·»å "æå¨ä¸å"æé®ï¼æªéä¸ä»»å¡æ¶ç¹å»æç¤º"请å
鿩任å¡" |
| | | - [ ] å¼¹çªæ£ç¡®æ¾ç¤ºææéä¸ä»»å¡ |
| | | - [ ] ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åç¶æçä»»å¡å¯ç¼è¾å°ååä¼å
级 |
| | | - [ ] å
¶ä»ç¶æä»»å¡è¡æ 红ï¼å°å/ä¼å
级ä¸å¯ç¼è¾ |
| | | - [ ] 确认ä¸ååè°ç¨å端æ¥å£ |
| | | - [ ] æåæ¶å¼¹çªå
³éå¹¶å·æ°å表ï¼å¤±è´¥æ¶æ¾ç¤ºå¤±è´¥ä»»å¡ååå |
| | | - [ ] æ¹éä¸åæ¶æ£ç¡®ç»è®¡æå/失败æ°é |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # WMSåºå页é¢MESæ¥å£éæå®ç°è®¡å |
| | | |
| | | > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. |
| | | |
| | | **Goal:** 为WMSåºåä¿¡æ¯é¡µé¢ååºåæç»é¡µé¢æ·»å æä½åï¼è°ç¨MESç³»ç»çè¿ç«/åºç«/ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | |
| | | **Architecture:** å端å¨åºåè¡¨æ ¼ä¸æ·»å æä½åï¼ç¹å»åå¼¹åºç¡®è®¤å¯¹è¯æ¡ï¼ç¡®è®¤åè°ç¨å端APIï¼åç«¯æ¥æ¶è¯·æ±ï¼è°ç¨MESæå¡ï¼è®°å½å®æ´æ¥å¿ï¼è¿åç»æ |
| | | |
| | | **Tech Stack:** Vue 3, Element Plus, .NET 8, SqlSugar ORM, SQL Server, HttpClient |
| | | |
| | | --- |
| | | |
| | | ## æä»¶ç»æ |
| | | |
| | | ### å端æä»¶ |
| | | |
| | | ``` |
| | | WMS/WIDESEA_WMSClient/src/ |
| | | âââ views/stock/ |
| | | â âââ stockInfo.vue # ä¿®æ¹ï¼æ·»å æä½å |
| | | â âââ stockInfoDetail.vue # ä¿®æ¹ï¼æ·»å æä½å |
| | | âââ components/ |
| | | â âââ MesConfirmDialog.vue # æ°å¢ï¼MESç¡®è®¤å¯¹è¯æ¡ |
| | | âââ api/ |
| | | âââ mes.js # æ°å¢ï¼MES APIè°ç¨ |
| | | ``` |
| | | |
| | | ### å端æä»¶ |
| | | |
| | | ``` |
| | | WMS/WIDESEA_WMSServer/ |
| | | âââ Controllers/ |
| | | â âââ Stock/ |
| | | â âââ StockInfoController.cs # ä¿®æ¹ï¼æ·»å è¿ç«/åºç«æ¥å£ |
| | | â âââ StockInfoDetailController.cs # ä¿®æ¹ï¼æ·»å ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | âââ Services/ |
| | | â âââ Mes/ |
| | | â âââ IMesLogService.cs # æ°å¢ï¼æ¥å¿æå¡æ¥å£ |
| | | â âââ MesLogService.cs # æ°å¢ï¼æ¥å¿æå¡å®ç° |
| | | âââ DTO/ |
| | | â âââ Mes/ |
| | | â â âââ MesApiLogDto.cs # æ°å¢ï¼æ¥å¿DTO |
| | | â â âââ InboundInContainerRequestDto.cs # æ°å¢ï¼è¿ç«è¯·æ±DTO |
| | | â â âââ OutboundInContainerRequestDto.cs # æ°å¢ï¼åºç«è¯·æ±DTO |
| | | â â âââ BindContainerRequestDto.cs # æ°å¢ï¼ç»å®è¯·æ±DTO |
| | | â â âââ UnbindContainerRequestDto.cs # æ°å¢ï¼è§£ç»è¯·æ±DTO |
| | | â â âââ ContainerNgReportRequestDto.cs # æ°å¢ï¼NG䏿¥è¯·æ±DTO |
| | | â âââ Models/ |
| | | â âââ Mes/ |
| | | â âââ Dt_MesApiLog.cs # æ°å¢ï¼æ¥å¿å®ä½ |
| | | âââ Database/ |
| | | âââ Scripts/ |
| | | âââ 20260412_MesApiLog.sql # æ°å¢ï¼æ¥å¿è¡¨åå»ºèæ¬ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 1: åå»ºæ°æ®åºè¡¨ |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/Database/Scripts/20260412_MesApiLog.sql` |
| | | |
| | | - [ ] **Step 1: å建MESæ¥å£æ¥å¿è¡¨SQLèæ¬** |
| | | |
| | | ```sql |
| | | -- ============================================= |
| | | -- WMS MESæ¥å£è°ç¨æ¥å¿è¡¨ |
| | | -- ============================================= |
| | | |
| | | IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'Dt_MesApiLog') |
| | | BEGIN |
| | | CREATE TABLE Dt_MesApiLog ( |
| | | Id BIGINT PRIMARY KEY IDENTITY(1,1), |
| | | ApiType NVARCHAR(50) NOT NULL, -- æ¥å£ç±»å |
| | | RequestJson NVARCHAR(MAX) NULL, -- 请æ±JSON |
| | | ResponseJson NVARCHAR(MAX) NULL, -- ååºJSON |
| | | IsSuccess BIT NOT NULL DEFAULT 0, -- æ¯å¦æå |
| | | ErrorMessage NVARCHAR(500) NULL, -- éè¯¯ä¿¡æ¯ |
| | | ElapsedMs INT NOT NULL DEFAULT 0, -- èæ¶(毫ç§) |
| | | CreateDate DATETIME NOT NULL, -- å建æ¶é´ |
| | | Creator NVARCHAR(50) NULL, -- å建人 |
| | | ModifyDate DATETIME NULL, -- ä¿®æ¹æ¶é´ |
| | | Modifier NVARCHAR(50) NULL -- ä¿®æ¹äºº |
| | | ); |
| | | |
| | | -- åå»ºç´¢å¼ |
| | | CREATE INDEX IX_MesApiLog_ApiType ON Dt_MesApiLog(ApiType); |
| | | CREATE INDEX IX_MesApiLog_CreateDate ON Dt_MesApiLog(CreateDate); |
| | | CREATE INDEX IX_MesApiLog_IsSuccess ON Dt_MesApiLog(IsSuccess); |
| | | |
| | | PRINT 'MESæ¥å£æ¥å¿è¡¨ Dt_MesApiLog å建æå'; |
| | | END |
| | | ELSE |
| | | BEGIN |
| | | PRINT 'MESæ¥å£æ¥å¿è¡¨ Dt_MesApiLog å·²åå¨'; |
| | | END |
| | | |
| | | -- æå
¥MESç³»ç»é
ç½® |
| | | IF NOT EXISTS (SELECT * FROM Dt_SystemConfig WHERE ConfigKey = 'MES_EquipmentCode') |
| | | BEGIN |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_EquipmentCode', 'WCS_001', 'MES设å¤ç¼ç ', GETDATE(), 'System'); |
| | | |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_ResourceCode', 'RESOURCE_001', 'MESèµæºç¼ç ', GETDATE(), 'System'); |
| | | |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_ApiBaseUrl', 'http://mes-server/api', 'MESæ¥å£å°å', GETDATE(), 'System'); |
| | | |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate, Modifier) |
| | | VALUES ('MES_TimeoutSeconds', '30', 'MESæ¥å£è¶
æ¶æ¶é´(ç§)', GETDATE(), 'System'); |
| | | |
| | | PRINT 'MESç³»ç»é
ç½®æå
¥æå'; |
| | | END |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ§è¡SQLèæ¬å建表** |
| | | |
| | | Run: å¨SQL Server Management Studio䏿§è¡è¯¥èæ¬ |
| | | Expected: 表å建æåï¼é
ç½®æå
¥æå |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/Database/Scripts/20260412_MesApiLog.sql |
| | | git commit -m "feat(MES): æ·»å MESæ¥å£æ¥å¿è¡¨åç³»ç»é
ç½® |
| | | |
| | | - å建 Dt_MesApiLog è¡¨è®°å½æ¥å£è°ç¨æ¥å¿ |
| | | - æ·»å MESç¸å
³ç³»ç»é
置项ï¼è®¾å¤ç¼ç ãèµæºç¼ç ãæ¥å£å°åçï¼ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 2: å建å端å®ä½åDTO |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Mes/Dt_MesApiLog.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/MesApiLogDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/InboundInContainerRequestDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/OutboundInContainerRequestDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/BindContainerRequestDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/UnbindContainerRequestDto.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/ContainerNgReportRequestDto.cs` |
| | | |
| | | - [ ] **Step 1: å建MESæ¥å¿å®ä½** |
| | | |
| | | ```csharp |
| | | using SqlSugar; |
| | | using System; |
| | | |
| | | namespace WIDESEA_Model.Models.Mes |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£è°ç¨æ¥å¿å®ä½ |
| | | /// </summary> |
| | | [SugarTable("Dt_MesApiLog")] |
| | | public class Dt_MesApiLog |
| | | { |
| | | /// <summary> |
| | | /// 主é®ID |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] |
| | | public long Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¥å£ç±»åï¼InboundInContainer, OutboundInContainer, BindContainer, UnbindContainer, ContainerNgReport |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = false)] |
| | | public string ApiType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请æ±JSON |
| | | /// </summary> |
| | | [SugarColumn(ColumnDataType = "nvarchar(max)", IsNullable = true)] |
| | | public string RequestJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ååºJSON |
| | | /// </summary> |
| | | [SugarColumn(ColumnDataType = "nvarchar(max)", IsNullable = true)] |
| | | public string ResponseJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public bool IsSuccess { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | [SugarColumn(Length = 500, IsNullable = true)] |
| | | public string ErrorMessage { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èæ¶ï¼æ¯«ç§ï¼ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public int ElapsedMs { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建æ¶é´ |
| | | /// </summary> |
| | | [SugarColumn(IsNullable = false)] |
| | | public DateTime CreateDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建人 |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = true)] |
| | | public string Creator { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¿®æ¹æ¶é´ |
| | | /// </summary> |
| | | public DateTime? ModifyDate { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä¿®æ¹äºº |
| | | /// </summary> |
| | | [SugarColumn(Length = 50, IsNullable = true)] |
| | | public string Modifier { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å建MESæ¥å¿DTO** |
| | | |
| | | ```csharp |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿DTO |
| | | /// </summary> |
| | | public class MesApiLogDto |
| | | { |
| | | /// <summary> |
| | | /// æ¥å£ç±»å |
| | | /// </summary> |
| | | public string ApiType { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请æ±JSON |
| | | /// </summary> |
| | | public string RequestJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ååºJSON |
| | | /// </summary> |
| | | public string ResponseJson { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æ¯å¦æå |
| | | /// </summary> |
| | | public bool IsSuccess { get; set; } |
| | | |
| | | /// <summary> |
| | | /// éè¯¯ä¿¡æ¯ |
| | | /// </summary> |
| | | public string ErrorMessage { get; set; } |
| | | |
| | | /// <summary> |
| | | /// èæ¶ï¼æ¯«ç§ï¼ |
| | | /// </summary> |
| | | public int ElapsedMs { get; set; } |
| | | |
| | | /// <summary> |
| | | /// å建人 |
| | | /// </summary> |
| | | public string Creator { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: å建è¿ç«è¯·æ±DTO** |
| | | |
| | | ```csharp |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// æçè¿ç«è¯·æ±DTO |
| | | /// </summary> |
| | | public class InboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 4: å建åºç«è¯·æ±DTO** |
| | | |
| | | ```csharp |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// æçåºç«è¯·æ±DTO |
| | | /// </summary> |
| | | public class OutboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 产ååæ°å表ï¼å¯éï¼ |
| | | /// </summary> |
| | | public List<ParamItemDto> ParamList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 忰项DTO |
| | | /// </summary> |
| | | public class ParamItemDto |
| | | { |
| | | /// <summary> |
| | | /// åæ°ç¼ç |
| | | /// </summary> |
| | | public string ParamCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åæ°å¼ |
| | | /// </summary> |
| | | public string ParamValue { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ééæ¶é´ |
| | | /// </summary> |
| | | public string CollectionTime { get; set; } |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 5: å建ç»å®è¯·æ±DTO** |
| | | |
| | | ```csharp |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// æççµè¯ç»å®è¯·æ±DTO |
| | | /// </summary> |
| | | public class BindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä½ç½®ä¿¡æ¯ |
| | | /// </summary> |
| | | public string Location { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æä½ç±»åï¼0-é»è®¤ 1-è¿ç« 2-åºç« 3-è¿åºç« |
| | | /// </summary> |
| | | public int OperationType { get; set; } = 1; |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 6: å建解ç»è¯·æ±DTO** |
| | | |
| | | ```csharp |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// æççµè¯è§£ç»è¯·æ±DTO |
| | | /// </summary> |
| | | public class UnbindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 7: å建NG䏿¥è¯·æ±DTO** |
| | | |
| | | ```csharp |
| | | using System.Collections.Generic; |
| | | |
| | | namespace WIDESEA_DTO.Mes |
| | | { |
| | | /// <summary> |
| | | /// æçNGçµè¯ä¸æ¥è¯·æ±DTO |
| | | /// </summary> |
| | | public class ContainerNgReportRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGçµè¯å表 |
| | | /// </summary> |
| | | public List<NgSfcItemDto> NgSfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGçµè¯é¡¹DTO |
| | | /// </summary> |
| | | public class NgSfcItemDto |
| | | { |
| | | /// <summary> |
| | | /// äº§åæ¡ç |
| | | /// </summary> |
| | | public string Sfc { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NG代ç |
| | | /// </summary> |
| | | public string NgCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGè®¾å¤ |
| | | /// </summary> |
| | | public string NgEquipmentCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGèµæº |
| | | /// </summary> |
| | | public string NgResourceCode { get; set; } |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 8: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_Model/Models/Mes/Dt_MesApiLog.cs |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_DTO/Mes/*.cs |
| | | git commit -m "feat(MES): æ·»å MESæ¥å£ç¸å
³å®ä½åDTO |
| | | |
| | | - æ·»å Dt_MesApiLog æ¥å¿å®ä½ |
| | | - æ·»å MesApiLogDto å忥å£è¯·æ±DTO |
| | | - æ¯æè¿ç«ãåºç«ãç»å®ãè§£ç»ãNG䏿¥æ¥å£ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 3: å建MESæ¥å¿æå¡ |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs` |
| | | - Create: `WMS/WIDESEA_WMSServer/WIDESEA_MesService/MesLogService.cs` |
| | | |
| | | - [ ] **Step 1: å建MESæ¥å¿æå¡æ¥å£** |
| | | |
| | | ```csharp |
| | | using System.Collections.Generic; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Mes; |
| | | |
| | | namespace WIDESEA_IMesService |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡æ¥å£ |
| | | /// </summary> |
| | | public interface IMesLogService : IDependency |
| | | { |
| | | /// <summary> |
| | | /// è®°å½MESæ¥å£è°ç¨æ¥å¿ |
| | | /// </summary> |
| | | /// <param name="log">æ¥å¿DTO</param> |
| | | /// <returns>æ¯å¦è®°å½æå</returns> |
| | | Task<bool> LogAsync(MesApiLogDto log); |
| | | |
| | | /// <summary> |
| | | /// è·åæè¿çMESæ¥å£è°ç¨è®°å½ |
| | | /// </summary> |
| | | /// <param name="apiType">æ¥å£ç±»å</param> |
| | | /// <param name="count">è®°å½æ°é</param> |
| | | /// <returns>æ¥å¿å表</returns> |
| | | Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å建MESæ¥å¿æå¡å®ç°** |
| | | |
| | | ```csharp |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_DTO.Mes; |
| | | using WIDESEA_IMesService; |
| | | using WIDESEA_Model.Models.Mes; |
| | | |
| | | namespace WIDESEA_MesService |
| | | { |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡å®ç° |
| | | /// </summary> |
| | | public class MesLogService : IMesLogService |
| | | { |
| | | private readonly ISqlSugarClient _db; |
| | | |
| | | /// <summary> |
| | | /// æé 彿° |
| | | /// </summary> |
| | | public MesLogService(ISqlSugarClient db) |
| | | { |
| | | _db = db; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è®°å½MESæ¥å£è°ç¨æ¥å¿ |
| | | /// </summary> |
| | | public async Task<bool> LogAsync(MesApiLogDto log) |
| | | { |
| | | try |
| | | { |
| | | var entity = new Dt_MesApiLog |
| | | { |
| | | ApiType = log.ApiType, |
| | | RequestJson = log.RequestJson, |
| | | ResponseJson = log.ResponseJson, |
| | | IsSuccess = log.IsSuccess, |
| | | ErrorMessage = log.ErrorMessage, |
| | | ElapsedMs = log.ElapsedMs, |
| | | CreateDate = DateTime.Now, |
| | | Creator = log.Creator |
| | | }; |
| | | |
| | | var result = await _db.Insertable(entity).ExecuteCommandAsync(); |
| | | return result > 0; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // è®°å½æ¥å¿å¤±è´¥ä¸å½±å主æµç¨ |
| | | Console.WriteLine($"è®°å½MESæ¥å¿å¤±è´¥: {ex.Message}"); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åæè¿çMESæ¥å£è°ç¨è®°å½ |
| | | /// </summary> |
| | | public async Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50) |
| | | { |
| | | try |
| | | { |
| | | var entities = await _db.Queryable<Dt_MesApiLog>() |
| | | .Where(x => x.ApiType == apiType) |
| | | .OrderByDescending(x => x.CreateDate) |
| | | .Take(count) |
| | | .ToListAsync(); |
| | | |
| | | return entities.Select(e => new MesApiLogDto |
| | | { |
| | | ApiType = e.ApiType, |
| | | RequestJson = e.RequestJson, |
| | | ResponseJson = e.ResponseJson, |
| | | IsSuccess = e.IsSuccess, |
| | | ErrorMessage = e.ErrorMessage, |
| | | ElapsedMs = e.ElapsedMs, |
| | | Creator = e.Creator |
| | | }).ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Console.WriteLine($"è·åMESæ¥å¿å¤±è´¥: {ex.Message}"); |
| | | return new List<MesApiLogDto>(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_IMesService/IMesLogService.cs |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_MesService/MesLogService.cs |
| | | git commit -m "feat(MES): æ·»å MESæ¥å¿æå¡ |
| | | |
| | | - å®ç° IMesLogService æ¥å£ |
| | | - æ¯æè®°å½åæ¥è¯¢MESæ¥å£è°ç¨æ¥å¿ |
| | | - å¼å¸¸å¤çä¸å½±å主æµç¨ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 4: æ©å±StockInfoControlleræ·»å è¿ç«/åºç«æ¥å£ |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoController.cs` |
| | | |
| | | - [ ] **Step 1: å¨StockInfoController䏿·»å MESæ¥å£æ¹æ³** |
| | | |
| | | å¨ç°æStockInfoControllerç±»ä¸æ·»å 以䏿¹æ³ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// MESæ¥å¿æå¡ |
| | | /// </summary> |
| | | private readonly IMesLogService _mesLogService; |
| | | |
| | | /// <summary> |
| | | /// MESæå¡ï¼å·²å¨é¡¹ç®ä¸å®ä¹ï¼ |
| | | /// </summary> |
| | | private readonly IMesService _mesService; |
| | | |
| | | /// <summary> |
| | | /// ç³»ç»é
ç½®æå¡ |
| | | /// </summary> |
| | | private readonly ISystemConfigService _configService; |
| | | |
| | | // 卿é 彿°ä¸æ³¨å
¥è¿äºæå¡ï¼å¦æå°æªæ³¨å
¥ï¼ |
| | | ``` |
| | | |
| | | æ·»å è¿ç«æ¥å£ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçè¿ç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">è¿ç«è¯·æ±DTO</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("inboundInContainer")] |
| | | [Permission("MES_INBOUND")] |
| | | public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = System.Diagnostics.Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. æ¥è¯¢åºåä¿¡æ¯ |
| | | var stockInfo = await _service.FindAsIQueryable(x => x.Id == dto.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | return response.Error("åºåä¿¡æ¯ä¸åå¨"); |
| | | } |
| | | |
| | | // 3. éªè¯åºåç¶æï¼ä»
"å¾
å
¥åº"ç¶æå
许è¿ç«ï¼ |
| | | if (stockInfo.Status != 0) // å设0=å¾
å
¥åº |
| | | { |
| | | return response.Error($"å½ååºåç¶æä¸å
许è¿ç«æä½"); |
| | | } |
| | | |
| | | // 4. è·åç³»ç»é
ç½® |
| | | var equipmentCode = await _configService.GetConfigValueAsync("MES_EquipmentCode"); |
| | | var resourceCode = await _configService.GetConfigValueAsync("MES_ResourceCode"); |
| | | |
| | | if (string.IsNullOrWhiteSpace(equipmentCode) || string.IsNullOrWhiteSpace(resourceCode)) |
| | | { |
| | | return response.Error("MESç³»ç»é
ç½®ä¸å®æ´ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 5. æé MESè¯·æ± |
| | | var mesRequest = new InboundInContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 6. è°ç¨MESæ¥å£ |
| | | var mesResult = await _mesService.InboundInContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 7. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "InboundInContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.Success, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | // 8. è¿åç»æ |
| | | if (mesResult.Success) |
| | | { |
| | | return response.OK("æçè¿ç«æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "InboundInContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | return response.Error($"æçè¿ç«å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | æ·»å åºç«æ¥å£ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçåºç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">åºç«è¯·æ±DTO</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("outboundInContainer")] |
| | | [Permission("MES_OUTBOUND")] |
| | | public async Task<WebResponseContent> OutboundInContainer([FromBody] OutboundInContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = System.Diagnostics.Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. æ¥è¯¢åºåä¿¡æ¯ |
| | | var stockInfo = await _service.FindAsIQueryable(x => x.Id == dto.StockId) |
| | | .FirstAsync(); |
| | | |
| | | if (stockInfo == null) |
| | | { |
| | | return response.Error("åºåä¿¡æ¯ä¸åå¨"); |
| | | } |
| | | |
| | | // 3. éªè¯åºåç¶æï¼"å¨åº"æ"åºåºä¸"ç¶æå
许åºç«ï¼ |
| | | if (stockInfo.Status != 1 && stockInfo.Status != 2) // å设1=å¨åº, 2=åºåºä¸ |
| | | { |
| | | return response.Error($"å½ååºåç¶æä¸å
许åºç«æä½"); |
| | | } |
| | | |
| | | // 4. è·åç³»ç»é
ç½® |
| | | var equipmentCode = await _configService.GetConfigValueAsync("MES_EquipmentCode"); |
| | | var resourceCode = await _configService.GetConfigValueAsync("MES_ResourceCode"); |
| | | |
| | | if (string.IsNullOrWhiteSpace(equipmentCode) || string.IsNullOrWhiteSpace(resourceCode)) |
| | | { |
| | | return response.Error("MESç³»ç»é
ç½®ä¸å®æ´ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 5. æé MESè¯·æ± |
| | | var mesRequest = new OutboundInContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | ParamList = dto.ParamList?.Select(p => new ParamItem |
| | | { |
| | | ParamCode = p.ParamCode, |
| | | ParamValue = p.ParamValue, |
| | | CollectionTime = DateTime.TryParse(p.CollectionTime, out var ct) ? ct : DateTime.Now |
| | | }).ToList() |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 6. è°ç¨MESæ¥å£ |
| | | var mesResult = await _mesService.OutboundInContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 7. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "OutboundInContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.Success, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | // 8. è¿åç»æ |
| | | if (mesResult.Success) |
| | | { |
| | | return response.OK("æçåºç«æå"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | // è®°å½é误æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "OutboundInContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | return response.Error($"æçåºç«å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ·»å å¿
è¦çusingè¯å¥** |
| | | |
| | | 卿件顶鍿·»å ï¼ |
| | | |
| | | ```csharp |
| | | using WIDESEA_DTO.MES; |
| | | using WIDESEA_DTO.Mes; |
| | | using WIDESEA_IMesService; |
| | | ``` |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoController.cs |
| | | git commit -m "feat(MES): åºåä¿¡æ¯é¡µé¢æ·»å è¿ç«/åºç«æ¥å£ |
| | | |
| | | - POST /api/StockInfo/inboundInContainer æçè¿ç« |
| | | - POST /api/StockInfo/outboundInContainer æçåºç« |
| | | - æ·»å åºåç¶ææ ¡éª |
| | | - è®°å½å®æ´è°ç¨æ¥å¿ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 5: æ©å±StockInfoDetailControlleræ·»å ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoDetailController.cs` |
| | | |
| | | - [ ] **Step 1: å¨StockInfoDetailController䏿·»å MESæ¥å£æ¹æ³** |
| | | |
| | | å¨ç°æStockInfoDetailControllerç±»ä¸æ·»å ä¾èµæ³¨å
¥åæ¥å£æ¹æ³ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// MESæ¥å¿æå¡ |
| | | /// </summary> |
| | | private readonly IMesLogService _mesLogService; |
| | | |
| | | /// <summary> |
| | | /// MESæå¡ |
| | | /// </summary> |
| | | private readonly IMesService _mesService; |
| | | |
| | | /// <summary> |
| | | /// ç³»ç»é
ç½®æå¡ |
| | | /// </summary> |
| | | private readonly ISystemConfigService _configService; |
| | | ``` |
| | | |
| | | æ·»å ç»å®æ¥å£ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æççµè¯ç»å® - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">ç»å®è¯·æ±DTO</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("bindContainer")] |
| | | [Permission("MES_BIND")] |
| | | public async Task<WebResponseContent> BindContainer([FromBody] BindContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = System.Diagnostics.Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.SfcList == null || !dto.SfcList.Any()) |
| | | { |
| | | return response.Error("çµè¯ç å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. è·åç³»ç»é
ç½® |
| | | var equipmentCode = await _configService.GetConfigValueAsync("MES_EquipmentCode"); |
| | | var resourceCode = await _configService.GetConfigValueAsync("MES_ResourceCode"); |
| | | |
| | | if (string.IsNullOrWhiteSpace(equipmentCode) || string.IsNullOrWhiteSpace(resourceCode)) |
| | | { |
| | | return response.Error("MESç³»ç»é
ç½®ä¸å®æ´ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 3. æé MESè¯·æ± |
| | | var mesRequest = new BindContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | ContainerSfcList = dto.SfcList.Select(sfc => new ContainerSfcItem |
| | | { |
| | | Sfc = sfc, |
| | | Location = dto.Location ?? "" |
| | | }).ToList(), |
| | | OperationType = dto.OperationType |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ |
| | | var mesResult = await _mesService.BindContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "BindContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.Success, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.Success) |
| | | { |
| | | return response.OK($"æåç»å® {dto.SfcList.Count} 个çµè¯"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "BindContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | return response.Error($"çµè¯ç»å®å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | æ·»å è§£ç»æ¥å£ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æççµè¯è§£ç» - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">è§£ç»è¯·æ±DTO</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("unbindContainer")] |
| | | [Permission("MES_UNBIND")] |
| | | public async Task<WebResponseContent> UnbindContainer([FromBody] UnbindContainerRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = System.Diagnostics.Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.SfcList == null || !dto.SfcList.Any()) |
| | | { |
| | | return response.Error("çµè¯ç å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. è·åç³»ç»é
ç½® |
| | | var equipmentCode = await _configService.GetConfigValueAsync("MES_EquipmentCode"); |
| | | var resourceCode = await _configService.GetConfigValueAsync("MES_ResourceCode"); |
| | | |
| | | if (string.IsNullOrWhiteSpace(equipmentCode) || string.IsNullOrWhiteSpace(resourceCode)) |
| | | { |
| | | return response.Error("MESç³»ç»é
ç½®ä¸å®æ´ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 3. æé MESè¯·æ± |
| | | var mesRequest = new UnBindContainerRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainCode = dto.PalletCode, |
| | | SfcList = dto.SfcList |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ |
| | | var mesResult = await _mesService.UnBindContainer(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "UnbindContainer", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.Success, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.Success) |
| | | { |
| | | return response.OK($"æåè§£ç» {dto.SfcList.Count} 个çµè¯"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "UnbindContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | return response.Error($"çµè¯è§£ç»å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | æ·»å NG䏿¥æ¥å£ï¼ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçNGçµè¯ä¸æ¥ - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | /// <param name="dto">NG䏿¥è¯·æ±DTO</param> |
| | | /// <returns>æä½ç»æ</returns> |
| | | [HttpPost("containerNgReport")] |
| | | [Permission("MES_NG_REPORT")] |
| | | public async Task<WebResponseContent> ContainerNgReport([FromBody] ContainerNgReportRequestDto dto) |
| | | { |
| | | var response = new WebResponseContent(); |
| | | var stopwatch = System.Diagnostics.Stopwatch.StartNew(); |
| | | |
| | | try |
| | | { |
| | | // 1. åæ°éªè¯ |
| | | if (string.IsNullOrWhiteSpace(dto.PalletCode)) |
| | | { |
| | | return response.Error("æçç¼å·ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | if (dto.NgSfcList == null || !dto.NgSfcList.Any()) |
| | | { |
| | | return response.Error("NGçµè¯å表ä¸è½ä¸ºç©º"); |
| | | } |
| | | |
| | | // 2. è·åç³»ç»é
ç½® |
| | | var equipmentCode = await _configService.GetConfigValueAsync("MES_EquipmentCode"); |
| | | var resourceCode = await _configService.GetConfigValueAsync("MES_ResourceCode"); |
| | | |
| | | if (string.IsNullOrWhiteSpace(equipmentCode) || string.IsNullOrWhiteSpace(resourceCode)) |
| | | { |
| | | return response.Error("MESç³»ç»é
ç½®ä¸å®æ´ï¼è¯·è系管çå"); |
| | | } |
| | | |
| | | // 3. æé MESè¯·æ± |
| | | var mesRequest = new ContainerNgReportRequest |
| | | { |
| | | EquipmentCode = equipmentCode, |
| | | ResourceCode = resourceCode, |
| | | LocalTime = DateTime.Now, |
| | | ContainerCode = dto.PalletCode, |
| | | NgSfcList = dto.NgSfcList.Select(ng => new NgSfcItem |
| | | { |
| | | Sfc = ng.Sfc, |
| | | NgCode = ng.NgCode, |
| | | NgEquipmentCode = ng.NgEquipmentCode, |
| | | NgResourceCode = ng.NgResourceCode |
| | | }).ToList() |
| | | }; |
| | | |
| | | string requestJson = System.Text.Json.JsonSerializer.Serialize(mesRequest); |
| | | |
| | | // 4. è°ç¨MESæ¥å£ |
| | | var mesResult = await _mesService.ContainerNgReport(mesRequest); |
| | | stopwatch.Stop(); |
| | | |
| | | // 5. è®°å½æ¥å¿ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "ContainerNgReport", |
| | | RequestJson = requestJson, |
| | | ResponseJson = System.Text.Json.JsonSerializer.Serialize(mesResult), |
| | | IsSuccess = mesResult.Success, |
| | | ErrorMessage = mesResult.ErrorMessage, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | // 6. è¿åç»æ |
| | | if (mesResult.Success) |
| | | { |
| | | return response.OK($"æå䏿¥ {dto.NgSfcList.Count} 个NGçµè¯"); |
| | | } |
| | | else |
| | | { |
| | | return response.Error($"MESæ¥å£è°ç¨å¤±è´¥: {mesResult.ErrorMessage}"); |
| | | } |
| | | } |
| | | catch (System.Exception ex) |
| | | { |
| | | stopwatch.Stop(); |
| | | |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "ContainerNgReport", |
| | | IsSuccess = false, |
| | | ErrorMessage = ex.Message, |
| | | ElapsedMs = (int)stopwatch.ElapsedMilliseconds, |
| | | Creator = UserContext.Current.UserName |
| | | }); |
| | | |
| | | return response.Error($"NG䏿¥å¤±è´¥: {ex.Message}"); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æ·»å å¿
è¦çusingè¯å¥** |
| | | |
| | | 卿件顶鍿·»å ï¼ |
| | | |
| | | ```csharp |
| | | using WIDESEA_DTO.MES; |
| | | using WIDESEA_DTO.Mes; |
| | | using WIDESEA_IMesService; |
| | | ``` |
| | | |
| | | - [ ] **Step 3: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Stock/StockInfoDetailController.cs |
| | | git commit -m "feat(MES): åºåæç»é¡µé¢æ·»å ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | |
| | | - POST /api/StockInfoDetail/bindContainer æççµè¯ç»å® |
| | | - POST /api/StockInfoDetail/unbindContainer æççµè¯è§£ç» |
| | | - POST /api/StockInfoDetail/containerNgReport NGçµè¯ä¸æ¥ |
| | | - è®°å½å®æ´è°ç¨æ¥å¿ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 6: å建å端MES APIè°ç¨æ¨¡å |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSClient/src/api/mes.js` |
| | | |
| | | - [ ] **Step 1: å建MES API模å** |
| | | |
| | | ```javascript |
| | | /** |
| | | * MESæ¥å£API模å |
| | | */ |
| | | import axios from 'axios'; |
| | | |
| | | const baseURL = '/api'; |
| | | |
| | | // åºåä¿¡æ¯ç¸å
³MESæ¥å£ |
| | | export const stockInfoMesApi = { |
| | | /** |
| | | * æçè¿ç« |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, stockId } |
| | | * @returns {Promise} |
| | | */ |
| | | inboundInContainer(data) { |
| | | return axios.post(`${baseURL}/StockInfo/inboundInContainer`, data); |
| | | }, |
| | | |
| | | /** |
| | | * æçåºç« |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, stockId, paramList } |
| | | * @returns {Promise} |
| | | */ |
| | | outboundInContainer(data) { |
| | | return axios.post(`${baseURL}/StockInfo/outboundInContainer`, data); |
| | | } |
| | | }; |
| | | |
| | | // åºåæç»ç¸å
³MESæ¥å£ |
| | | export const stockDetailMesApi = { |
| | | /** |
| | | * æççµè¯ç»å® |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, sfcList, location, operationType } |
| | | * @returns {Promise} |
| | | */ |
| | | bindContainer(data) { |
| | | return axios.post(`${baseURL}/StockInfoDetail/bindContainer`, data); |
| | | }, |
| | | |
| | | /** |
| | | * æççµè¯è§£ç» |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, sfcList } |
| | | * @returns {Promise} |
| | | */ |
| | | unbindContainer(data) { |
| | | return axios.post(`${baseURL}/StockInfoDetail/unbindContainer`, data); |
| | | }, |
| | | |
| | | /** |
| | | * æçNGçµè¯ä¸æ¥ |
| | | * @param {Object} data - è¯·æ±æ°æ® { palletCode, ngSfcList } |
| | | * @returns {Promise} |
| | | */ |
| | | containerNgReport(data) { |
| | | return axios.post(`${baseURL}/StockInfoDetail/containerNgReport`, data); |
| | | } |
| | | }; |
| | | |
| | | export default { |
| | | stockInfo: stockInfoMesApi, |
| | | stockDetail: stockDetailMesApi |
| | | }; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/api/mes.js |
| | | git commit -m "feat(MES): æ·»å å端MES APIè°ç¨æ¨¡å |
| | | |
| | | - å°è£
åºåä¿¡æ¯è¿ç«/åºç«æ¥å£ |
| | | - å°è£
åºåæç»ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 7: å建MESç¡®è®¤å¯¹è¯æ¡ç»ä»¶ |
| | | |
| | | **Files:** |
| | | - Create: `WMS/WIDESEA_WMSClient/src/components/MesConfirmDialog.vue` |
| | | |
| | | - [ ] **Step 1: åå»ºç¡®è®¤å¯¹è¯æ¡ç»ä»¶** |
| | | |
| | | ```vue |
| | | <template> |
| | | <el-dialog |
| | | v-model="visible" |
| | | :title="dialogTitle" |
| | | width="500px" |
| | | :close-on-click-modal="false" |
| | | @close="handleClose" |
| | | > |
| | | <div class="mes-confirm-content"> |
| | | <p class="operation-text">{{ operationText }}</p> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row" v-for="(item, index) in displayInfo" :key="index"> |
| | | <span class="info-label">{{ item.label }}:</span> |
| | | <span class="info-value">{{ item.value }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-if="errorMessage" class="error-message"> |
| | | <el-icon><Warning /></el-icon> |
| | | <span>{{ errorMessage }}</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="handleClose">åæ¶</el-button> |
| | | <el-button |
| | | type="primary" |
| | | :loading="loading" |
| | | @click="handleConfirm" |
| | | > |
| | | 确认æ§è¡ |
| | | </el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script> |
| | | import { ref, computed } from 'vue'; |
| | | import { Warning } from '@element-plus/icons-vue'; |
| | | import { ElMessage } from 'element-plus'; |
| | | |
| | | export default { |
| | | name: 'MesConfirmDialog', |
| | | |
| | | components: { |
| | | Warning |
| | | }, |
| | | |
| | | props: { |
| | | modelValue: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | operationType: { |
| | | type: String, |
| | | required: true |
| | | }, |
| | | palletCode: { |
| | | type: String, |
| | | required: true |
| | | }, |
| | | stockInfo: { |
| | | type: Object, |
| | | default: null |
| | | }, |
| | | detailInfo: { |
| | | type: Object, |
| | | default: null |
| | | } |
| | | }, |
| | | |
| | | emits: ['update:modelValue', 'confirm'], |
| | | |
| | | setup(props, { emit }) { |
| | | const visible = computed({ |
| | | get: () => props.modelValue, |
| | | set: (val) => emit('update:modelValue', val) |
| | | }); |
| | | |
| | | const loading = ref(false); |
| | | const errorMessage = ref(''); |
| | | |
| | | const operationConfig = { |
| | | inbound: { title: 'æçè¿ç«', text: 'æ¨å³å°æ§è¡æçè¿ç«æä½' }, |
| | | outbound: { title: 'æçåºç«', text: 'æ¨å³å°æ§è¡æçåºç«æä½' }, |
| | | bind: { title: 'çµè¯ç»å®', text: 'æ¨å³å°æ§è¡çµè¯ç»å®æä½' }, |
| | | unbind: { title: 'çµè¯è§£ç»', text: 'æ¨å³å°æ§è¡çµè¯è§£ç»æä½' }, |
| | | ngReport: { title: 'NG䏿¥', text: 'æ¨å³å°æ§è¡NGçµè¯ä¸æ¥æä½' } |
| | | }; |
| | | |
| | | const dialogTitle = computed(() => { |
| | | return operationConfig[props.operationType]?.title || '确认æä½'; |
| | | }); |
| | | |
| | | const operationText = computed(() => { |
| | | return operationConfig[props.operationType]?.text || ''; |
| | | }); |
| | | |
| | | const displayInfo = computed(() => { |
| | | const info = [ |
| | | { label: 'æçç ', value: props.palletCode } |
| | | ]; |
| | | |
| | | if (props.detailInfo) { |
| | | info.push({ label: 'çµè¯æ°é', value: props.detailInfo.sfcCount || '-' }); |
| | | } |
| | | |
| | | return info; |
| | | }); |
| | | |
| | | const handleClose = () => { |
| | | visible.value = false; |
| | | errorMessage.value = ''; |
| | | }; |
| | | |
| | | const handleConfirm = async () => { |
| | | loading.value = true; |
| | | errorMessage.value = ''; |
| | | |
| | | try { |
| | | emit('confirm', { |
| | | operationType: props.operationType, |
| | | palletCode: props.palletCode, |
| | | stockInfo: props.stockInfo, |
| | | detailInfo: props.detailInfo, |
| | | onSuccess: () => { |
| | | visible.value = false; |
| | | loading.value = false; |
| | | }, |
| | | onError: (error) => { |
| | | errorMessage.value = error; |
| | | loading.value = false; |
| | | } |
| | | }); |
| | | } catch (error) { |
| | | errorMessage.value = error.message || 'æä½å¤±è´¥'; |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | |
| | | return { |
| | | visible, |
| | | loading, |
| | | errorMessage, |
| | | dialogTitle, |
| | | operationText, |
| | | displayInfo, |
| | | handleClose, |
| | | handleConfirm |
| | | }; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .mes-confirm-content { |
| | | padding: 10px 0; |
| | | } |
| | | |
| | | .operation-text { |
| | | font-size: 14px; |
| | | color: #303133; |
| | | margin-bottom: 20px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .info-section { |
| | | background: #f8fafc; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 12px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .info-row:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .info-label { |
| | | color: #909399; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .error-message { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | padding: 12px; |
| | | background: #fef0f0; |
| | | border: 1px solid #fde2e2; |
| | | border-radius: 6px; |
| | | color: #f56c6c; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .error-message .el-icon { |
| | | font-size: 18px; |
| | | } |
| | | </style> |
| | | ``` |
| | | |
| | | - [ ] **Step 2: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/components/MesConfirmDialog.vue |
| | | git commit -m "feat(MES): æ·»å MESæä½ç¡®è®¤å¯¹è¯æ¡ç»ä»¶ |
| | | |
| | | - æ¯æå¤ç§æä½ç±»åï¼è¿ç«ãåºç«ãç»å®ãè§£ç»ãNG䏿¥ï¼ |
| | | - æ¾ç¤ºå
³é®ä¿¡æ¯ï¼æçç ãçµè¯æ°éçï¼ |
| | | - éè¯¯ç¶æå±ç¤º |
| | | - 确认/åæ¶æä½ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 8: ä¿®æ¹stockInfo.vueæ·»å æä½å |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSClient/src/views/stock/stockInfo.vue` |
| | | |
| | | - [ ] **Step 1: å¨script䏿·»å ç»ä»¶å¼å
¥åæ¹æ³** |
| | | |
| | | å¨ç°æçscript setup䏿·»å ï¼ |
| | | |
| | | ```javascript |
| | | import MesConfirmDialog from '@/components/MesConfirmDialog.vue'; |
| | | import { stockInfoMesApi } from '@/api/mes'; |
| | | import { ElMessage, ElMessageBox } from 'element-plus'; |
| | | import { ref } from 'vue'; |
| | | |
| | | // MESå¯¹è¯æ¡ç¶æ |
| | | const mesDialogVisible = ref(false); |
| | | const currentOperationType = ref(''); |
| | | const currentStockRow = ref(null); |
| | | const mesLoading = ref(false); |
| | | |
| | | // æå¼MESç¡®è®¤å¯¹è¯æ¡ |
| | | const openMesDialog = (operationType, row) => { |
| | | currentOperationType.value = operationType; |
| | | currentStockRow.value = row; |
| | | mesDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å¤çMES确认 |
| | | const handleMesConfirm = async ({ onSuccess, onError }) => { |
| | | const row = currentStockRow.value; |
| | | const operationType = currentOperationType.value; |
| | | |
| | | try { |
| | | let result; |
| | | |
| | | switch (operationType) { |
| | | case 'inbound': |
| | | result = await stockInfoMesApi.inboundInContainer({ |
| | | palletCode: row.palletCode, |
| | | stockId: row.id |
| | | }); |
| | | break; |
| | | case 'outbound': |
| | | result = await stockInfoMesApi.outboundInContainer({ |
| | | palletCode: row.palletCode, |
| | | stockId: row.id |
| | | }); |
| | | break; |
| | | } |
| | | |
| | | if (result.data.status) { |
| | | ElMessage.success(result.data.message || 'æä½æå'); |
| | | onSuccess(); |
| | | // å·æ°å表 |
| | | proxy.$refs.grid.load(); |
| | | } else { |
| | | onError(result.data.message || 'æä½å¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | onError(error.response?.data?.message || error.message || 'ç½ç»é误ï¼è¯·ç¨åéè¯'); |
| | | } |
| | | }; |
| | | |
| | | // æ£æ¥æé®æ¯å¦åºè¯¥æ¾ç¤º |
| | | const shouldShowButton = (buttonType, row) => { |
| | | const status = row.status; // 0=å¾
å
¥åº, 1=å¨åº, 2=åºåºä¸, 3=éå® |
| | | |
| | | switch (buttonType) { |
| | | case 'inbound': |
| | | return status === 0; // ä»
å¾
å
¥åºæ¾ç¤ºè¿ç« |
| | | case 'outbound': |
| | | return status === 1 || status === 2; // å¨åºæåºåºä¸æ¾ç¤ºåºç« |
| | | default: |
| | | return false; |
| | | } |
| | | }; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å¨columns䏿·»å æä½å** |
| | | |
| | | å¨ç°æçcolumns refå®ä¹ä¸æ·»å æä½åï¼å¨æåæ·»å ï¼ï¼ |
| | | |
| | | ```javascript |
| | | const columns = ref([ |
| | | // ... ç°æåå®ä¹ ... |
| | | { |
| | | field: "actions", |
| | | title: "æä½", |
| | | width: 200, |
| | | fixed: "right", |
| | | align: "center", |
| | | formatter: (row) => { |
| | | const buttons = []; |
| | | |
| | | if (shouldShowButton('inbound', row)) { |
| | | buttons.push( |
| | | `<el-button type="primary" size="small" onclick="window.handleInbound(${row.id})">è¿ç«</el-button>` |
| | | ); |
| | | } |
| | | |
| | | if (shouldShowButton('outbound', row)) { |
| | | buttons.push( |
| | | `<el-button type="success" size="small" onclick="window.handleOutbound(${row.id})">åºç«</el-button>` |
| | | ); |
| | | } |
| | | |
| | | return buttons.join(' '); |
| | | } |
| | | } |
| | | ]); |
| | | ``` |
| | | |
| | | - [ ] **Step 3: 卿¨¡æ¿ä¸æ·»å å¯¹è¯æ¡ç»ä»¶** |
| | | |
| | | å¨templateä¸çview-gridæ ç¾åæ·»å ï¼ |
| | | |
| | | ```vue |
| | | <template> |
| | | <view-grid ... > |
| | | </view-grid> |
| | | |
| | | <!-- MESç¡®è®¤å¯¹è¯æ¡ --> |
| | | <MesConfirmDialog |
| | | v-model="mesDialogVisible" |
| | | :operation-type="currentOperationType" |
| | | :pallet-code="currentStockRow?.palletCode" |
| | | :stock-info="currentStockRow" |
| | | @confirm="handleMesConfirm" |
| | | /> |
| | | </template> |
| | | ``` |
| | | |
| | | - [ ] **Step 4: æ·»å å
¨å±æ¹æ³ç¨äºHTMLå符串ä¸çonclick** |
| | | |
| | | å¨setupçæåæ·»å ï¼ |
| | | |
| | | ```javascript |
| | | // æè½½å°windowä¾HTMLå符串ä¸çonclickä½¿ç¨ |
| | | window.handleInbound = (id) => { |
| | | const row = proxy.$refs.grid.tableData.find(item => item.id === id); |
| | | if (row) openMesDialog('inbound', row); |
| | | }; |
| | | |
| | | window.handleOutbound = (id) => { |
| | | const row = proxy.$refs.grid.tableData.find(item => item.id === id); |
| | | if (row) openMesDialog('outbound', row); |
| | | }; |
| | | ``` |
| | | |
| | | - [ ] **Step 5: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/views/stock/stockInfo.vue |
| | | git commit -m "feat(MES): åºåä¿¡æ¯é¡µé¢æ·»å è¿ç«/åºç«æä½å |
| | | |
| | | - æ·»å æä½åï¼æ ¹æ®åºåç¶æå¨ææ¾ç¤ºæé® |
| | | - å¾
å
¥åºç¶ææ¾ç¤ºè¿ç«æé® |
| | | - å¨åº/åºåºä¸ç¶ææ¾ç¤ºåºç«æé® |
| | | - éæMESç¡®è®¤å¯¹è¯æ¡ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## Task 9: ä¿®æ¹stockInfoDetail.vueæ·»å æä½å |
| | | |
| | | **Files:** |
| | | - Modify: `WMS/WIDESEA_WMSClient/src/views/stock/stockInfoDetail.vue` |
| | | |
| | | - [ ] **Step 1: å¨script䏿·»å ç»ä»¶å¼å
¥åæ¹æ³** |
| | | |
| | | å¨ç°æçscript setup䏿·»å ï¼ |
| | | |
| | | ```javascript |
| | | import MesConfirmDialog from '@/components/MesConfirmDialog.vue'; |
| | | import { stockDetailMesApi } from '@/api/mes'; |
| | | import { ElMessage } from 'element-plus'; |
| | | import { ref } from 'vue'; |
| | | |
| | | // MESå¯¹è¯æ¡ç¶æ |
| | | const mesDialogVisible = ref(false); |
| | | const currentOperationType = ref(''); |
| | | const currentDetailRow = ref(null); |
| | | const mesLoading = ref(false); |
| | | |
| | | // æå¼MESç¡®è®¤å¯¹è¯æ¡ |
| | | const openMesDialog = (operationType, row) => { |
| | | currentOperationType.value = operationType; |
| | | currentDetailRow.value = row; |
| | | mesDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å¤çMES确认 |
| | | const handleMesConfirm = async ({ onSuccess, onError }) => { |
| | | const row = currentDetailRow.value; |
| | | const operationType = currentOperationType.value; |
| | | |
| | | try { |
| | | let result; |
| | | |
| | | switch (operationType) { |
| | | case 'bind': |
| | | result = await stockDetailMesApi.bindContainer({ |
| | | palletCode: row.palletCode || 'P001', // éè¦ä»åºåä¿¡æ¯è·å |
| | | sfcList: [row.serialNumber], |
| | | location: row.location || '', |
| | | operationType: 1 |
| | | }); |
| | | break; |
| | | case 'unbind': |
| | | result = await stockDetailMesApi.unbindContainer({ |
| | | palletCode: row.palletCode || 'P001', |
| | | sfcList: [row.serialNumber] |
| | | }); |
| | | break; |
| | | case 'ngReport': |
| | | result = await stockDetailMesApi.containerNgReport({ |
| | | palletCode: row.palletCode || 'P001', |
| | | ngSfcList: [{ |
| | | sfc: row.serialNumber, |
| | | ngCode: 'NG001', |
| | | ngEquipmentCode: 'WCS_001', |
| | | ngResourceCode: 'RESOURCE_001' |
| | | }] |
| | | }); |
| | | break; |
| | | } |
| | | |
| | | if (result.data.status) { |
| | | ElMessage.success(result.data.message || 'æä½æå'); |
| | | onSuccess(); |
| | | proxy.$refs.grid.load(); |
| | | } else { |
| | | onError(result.data.message || 'æä½å¤±è´¥'); |
| | | } |
| | | } catch (error) { |
| | | onError(error.response?.data?.message || error.message || 'ç½ç»é误ï¼è¯·ç¨åéè¯'); |
| | | } |
| | | }; |
| | | |
| | | // æ£æ¥æé®æ¯å¦åºè¯¥æ¾ç¤º |
| | | const shouldShowButton = (row) => { |
| | | const status = row.status; // 1=æ£å¸¸, 2=å¼å¸¸, 99=å·²éå® |
| | | return status !== 99; // é"å·²éå®"ç¶ææ¾ç¤ºæææé® |
| | | }; |
| | | ``` |
| | | |
| | | - [ ] **Step 2: å¨columns䏿·»å æä½å** |
| | | |
| | | å¨ç°æçcolumns refå®ä¹ä¸æ·»å æä½åï¼å¨æåæ·»å ï¼ï¼ |
| | | |
| | | ```javascript |
| | | const columns = ref([ |
| | | // ... ç°æåå®ä¹ ... |
| | | { |
| | | field: "actions", |
| | | title: "æä½", |
| | | width: 280, |
| | | fixed: "right", |
| | | align: "center", |
| | | formatter: (row) => { |
| | | if (!shouldShowButton(row)) { |
| | | return '<span class="text-muted">ææ å¯æ§è¡æä½</span>'; |
| | | } |
| | | |
| | | return ` |
| | | <el-button type="primary" size="small" onclick="window.handleBind(${row.id})">ç»å®</el-button> |
| | | <el-button type="warning" size="small" onclick="window.handleUnbind(${row.id})">è§£ç»</el-button> |
| | | <el-button type="danger" size="small" onclick="window.handleNgReport(${row.id})">NG䏿¥</el-button> |
| | | `; |
| | | } |
| | | } |
| | | ]); |
| | | ``` |
| | | |
| | | - [ ] **Step 3: 卿¨¡æ¿ä¸æ·»å å¯¹è¯æ¡ç»ä»¶** |
| | | |
| | | å¨templateä¸çview-gridæ ç¾åæ·»å ï¼ |
| | | |
| | | ```vue |
| | | <template> |
| | | <view-grid ... > |
| | | </view-grid> |
| | | |
| | | <!-- MESç¡®è®¤å¯¹è¯æ¡ --> |
| | | <MesConfirmDialog |
| | | v-model="mesDialogVisible" |
| | | :operation-type="currentOperationType" |
| | | :pallet-code="currentDetailRow?.palletCode" |
| | | :detail-info="{ sfcCount: 1 }" |
| | | @confirm="handleMesConfirm" |
| | | /> |
| | | </template> |
| | | ``` |
| | | |
| | | - [ ] **Step 4: æ·»å å
¨å±æ¹æ³** |
| | | |
| | | å¨setupçæåæ·»å ï¼ |
| | | |
| | | ```javascript |
| | | window.handleBind = (id) => { |
| | | const row = proxy.$refs.grid.tableData.find(item => item.id === id); |
| | | if (row) openMesDialog('bind', row); |
| | | }; |
| | | |
| | | window.handleUnbind = (id) => { |
| | | const row = proxy.$refs.grid.tableData.find(item => item.id === id); |
| | | if (row) openMesDialog('unbind', row); |
| | | }; |
| | | |
| | | window.handleNgReport = (id) => { |
| | | const row = proxy.$refs.grid.tableData.find(item => item.id === id); |
| | | if (row) openMesDialog('ngReport', row); |
| | | }; |
| | | ``` |
| | | |
| | | - [ ] **Step 5: æäº¤** |
| | | |
| | | ```bash |
| | | git add WMS/WIDESEA_WMSClient/src/views/stock/stockInfoDetail.vue |
| | | git commit -m "feat(MES): åºåæç»é¡µé¢æ·»å ç»å®/è§£ç»/NG䏿¥æä½å |
| | | |
| | | - æ·»å æä½åï¼æ ¹æ®çµè¯ç¶æå¨ææ¾ç¤ºæé® |
| | | - ééå®ç¶ææ¾ç¤ºç»å®ãè§£ç»ãNG䏿¥æé® |
| | | - éæMESç¡®è®¤å¯¹è¯æ¡ |
| | | |
| | | Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>" |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## æµè¯æ£æ¥æ¸
å |
| | | |
| | | 宿以䏿æä»»å¡åï¼è¿è¡ä»¥ä¸æµè¯ï¼ |
| | | |
| | | ### å端æµè¯ |
| | | |
| | | - [ ] éªè¯æ°æ®åºè¡¨ Dt_MesApiLog å·²å建 |
| | | - [ ] éªè¯ç³»ç»é
置已æå
¥ |
| | | - [ ] æµè¯è¿ç«æ¥å£ï¼PostmanæSwaggerï¼ |
| | | - [ ] æµè¯åºç«æ¥å£ |
| | | - [ ] æµè¯ç»å®æ¥å£ |
| | | - [ ] æµè¯è§£ç»æ¥å£ |
| | | - [ ] æµè¯NG䏿¥æ¥å£ |
| | | - [ ] éªè¯æ¥å¿è®°å½æ£ç¡® |
| | | |
| | | ### å端æµè¯ |
| | | |
| | | - [ ] åºåä¿¡æ¯é¡µé¢æä½åæ£å¸¸æ¾ç¤º |
| | | - [ ] æé®æ ¹æ®ç¶ææ£ç¡®æ¾ç¤º/éè |
| | | - [ ] ç¹å»æé®å¼¹åºç¡®è®¤å¯¹è¯æ¡ |
| | | - [ ] 确认åæåè°ç¨æ¥å£ |
| | | - [ ] æååå·æ°å表 |
| | | - [ ] å¤±è´¥åæ¾ç¤ºé误æç¤º |
| | | - [ ] åºåæç»é¡µé¢æä½åæ£å¸¸æ¾ç¤º |
| | | - [ ] æææé®åè½æ£å¸¸ |
| | | |
| | | ### éææµè¯ |
| | | |
| | | - [ ] 宿´æµç¨æµè¯ï¼ç¹å»âç¡®è®¤âæ§è¡âç»æï¼ |
| | | - [ ] ç½ç»å¼å¸¸å¤ç |
| | | - [ ] MESæå¡å¼å¸¸å¤ç |
| | | - [ ] æéæ§å¶æµè¯ |
| | | |
| | | --- |
| | | |
| | | ## 夿³¨ |
| | | |
| | | 1. **ç¶æå¼æ å°**ï¼ä»£ç ä¸ä½¿ç¨çç¶æå¼ï¼0=å¾
å
¥åº, 1=å¨åºçï¼éè¦æ ¹æ®å®é
æä¸¾å¼è°æ´ |
| | | 2. **æçç è·å**ï¼åºåæç»é¡µé¢ä¸éè¦éè¿stockIdå
³èè·åæçç |
| | | 3. **æéé
ç½®**ï¼éè¦å¨ç³»ç»ä¸æ·»å MESç¸å
³æé项 |
| | | 4. **MESæ¥å£å°å**ï¼å¨ç³»ç»é
ç½®ä¸è®¾ç½®æ£ç¡®çMESæ¥å£å°å |
| | | 5. **é误å¤ç**ï¼æ ¹æ®å®é
MESè¿åçé误ç è°æ´æç¤ºä¿¡æ¯ |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æå¨å建任å¡åè½è®¾è®¡ |
| | | |
| | | ## 1. éæ±æ¦è¿° |
| | | |
| | | å¨ WMS çé¢ä¸æ·»å æå¨å建任å¡åè½ãç¨æ·è¾å
¥èµ·ç¹ãç»ç¹ãæ¡ç ãä»åºIDï¼ç³»ç»èªå¨çæä»»å¡å·çåæ®µï¼åéç» WCSãWCS æ ¹æ®èµ·ç¹æ¯å¦ä¸ºçº¿ä½ç¹ä½(11068/11010/11001)夿æ¯å¦éè¦åå
¥è¾é线任å¡ã |
| | | |
| | | ## 2. æ´ä½æµç¨ |
| | | |
| | | ``` |
| | | ç¨æ·(WMSçé¢) |
| | | â è¾å
¥ï¼ä»»å¡ç±»å/èµ·ç¹/ç»ç¹/æ¡ç /ä»åºID |
| | | WMSå端 |
| | | â è°ç¨ BaseDal.GetTaskNo() çæ TaskNum |
| | | â æ ¹æ®ä»»å¡ç±»åè®¾ç½®ç¶æ |
| | | â è°ç¨ WCS ReceiveTask |
| | | WCSå端 |
| | | â å¤æèµ·ç¹æ¯å¦ä¸ºçº¿ä½ç¹ä½(11068/11010/11001) |
| | | â æ¯ â æ¥ Storage.Devices è·åè¾é线å®ä¾ |
| | | â åå
¥è¾é线任å¡(èµ·ç¹/ç»ç¹/ä»»å¡å·ç) |
| | | â è¿åæå |
| | | ``` |
| | | |
| | | ## 3. WMS å端æ¹å¨ |
| | | |
| | | ### 3.1 ä»»å¡é¡µé¢ (`task.vue`) |
| | | |
| | | å¨ç°æä»»å¡ç®¡ç页颿·»å **æå¨å建任å¡**æé®ï¼å¼¹åºå¯¹è¯æ¡ã |
| | | |
| | | ### 3.2 å¯¹è¯æ¡å段 |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | ä»»å¡ç±»å | ä¸ææ¡ | å
¥åº / åºåº / ç§»åº | |
| | | | èµ·ç¹å°å | è¾å
¥æ¡ | ç¨æ·è¾å
¥ï¼å¦ 11068 | |
| | | | ç»ç¹å°å | è¾å
¥æ¡ | ç¨æ·è¾å
¥ | |
| | | | æ¡ç | è¾å
¥æ¡ | ç¨æ·è¾å
¥ | |
| | | | ä»åºID | è¾å
¥æ¡ | ç¨æ·è¾å
¥ | |
| | | | ä¼å
级 | åªè¯» | é»è®¤å¼ 1 | |
| | | |
| | | ## 4. WMS å端æ¹å¨ |
| | | |
| | | ### 4.1 æ°å¢æ¥å£ |
| | | |
| | | **Controller:** `TaskController.cs` |
| | | ``` |
| | | POST /api/Task/CreateManualTask |
| | | ``` |
| | | |
| | | ### 4.2 Service æ¹æ³ |
| | | |
| | | **TaskService.cs** æ°å¢ `CreateManualTaskAsync` æ¹æ³ï¼ |
| | | |
| | | ```csharp |
| | | public async Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto) |
| | | { |
| | | // 1. è°ç¨ BaseDal.GetTaskNo() çæ TaskNum |
| | | // 2. æ ¹æ®ä»»å¡ç±»åè®¾ç½®ç¶æ |
| | | // - å
¥åº â InNew (200) |
| | | // - åºåº â OutNew (100) |
| | | // - ç§»åº â RelocationNew (300) |
| | | // 3. æå»º Dt_Task å®ä½ |
| | | // 4. è°ç¨ WCS ReceiveTask (POST /api/Task/ReceiveTask) |
| | | // 5. è¿åç»æ |
| | | } |
| | | ``` |
| | | |
| | | ### 4.3 DTO å®ä¹ |
| | | |
| | | ```csharp |
| | | public class CreateManualTaskDto |
| | | { |
| | | public int TaskType { get; set; } // 1=å
¥åº, 2=åºåº, 3=ç§»åº |
| | | public string SourceAddress { get; set; } |
| | | public string TargetAddress { get; set; } |
| | | public string Barcode { get; set; } |
| | | public int WarehouseId { get; set; } |
| | | public int Grade { get; set; } = 1; // é»è®¤ä¼å
级1 |
| | | } |
| | | ``` |
| | | |
| | | ## 5. WCS å端æ¹å¨ |
| | | |
| | | ### 5.1 å·²æé»è¾å¤ç¨ |
| | | |
| | | `ReceiveWMSTask` æ¹æ³å·²æ¯ææ¥æ¶ WMS ä»»å¡å¹¶ååå°å¯¹åº FlowServiceï¼ |
| | | - å
¥åºä»»å¡ â `InboundTaskFlowService.InitializeOnReceive()` |
| | | - åºåºä»»å¡ â `OutboundTaskFlowService.InitializeOnReceive()` |
| | | - ç§»åºä»»å¡ â `RelocationTaskFlowService.InitializeOnReceive()` |
| | | |
| | | ### 5.2 线ä½ç¹ä½å¤æ |
| | | |
| | | å¨ `InboundTaskFlowService.InitializeOnReceive()` ä¸ï¼å¤æ `SourceAddress` æ¯å¦ä¸ºçº¿ä½ç¹ä½(11068/11010/11001)ãè¿ä¸ä¸ªç¹ä½å为**å
¥åºçº¿ä½ç¹ä½**ã |
| | | |
| | | ### 5.3 è·åè¾é线å®ä¾ |
| | | |
| | | ```csharp |
| | | var conveyorLine = Storage.Devices |
| | | .FirstOrDefault(x => x.DeviceProDTOs.Any(d => d.DeviceChildCode == sourceAddress)); |
| | | ``` |
| | | |
| | | ### 5.4 æ°å¢ï¼åå
¥è¾éçº¿ä»»å¡ |
| | | |
| | | **æ¤é»è¾ä¸ºæ°å¢**ï¼ç®å FlowService ä¸ä¸åå¨åå
¥è¾é线çé»è¾ï¼éè¦å¨å¤æä¸ºçº¿ä½ç¹ä½åæ°å¢ï¼ |
| | | |
| | | 1. è·åè¾é线å®ä¾æååï¼è¯»åæºçº¿ä½å· |
| | | 2. æé `ConveyorLineTaskCommandNew` 对象 |
| | | 3. è°ç¨ `conveyorLine.WriteCustomer(sourceLineNo, command)` åå
¥ PLC |
| | | |
| | | åå
¥åæ®µï¼ |
| | | - `TaskNo` = WCS åé
çä»»å¡å· |
| | | - `Source` = èµ·ç¹å°å |
| | | - `Target` = ç»ç¹å°å |
| | | - `Barcode` = æ¡ç |
| | | - `WCS_STB` = 1 (æ è®°WCSå·²åé) |
| | | |
| | | ### 5.5 éå¤ä»»å¡å¤ç |
| | | |
| | | `ReceiveWMSTask` ä¸å·²æéå¤ä»»å¡æ£æ¥é»è¾ï¼æ ¹æ® TaskNum æ PalletCodeï¼ï¼æå¨å建æ¶å¦ééå¤è¿åé误ã |
| | | |
| | | ## 6. ä»»å¡ç¶ææä¸¾ |
| | | |
| | | | ç±»å | æ°å»ºç¶æ | ç¶æå¼ | |
| | | |------|----------|--------| |
| | | | å
¥åº | InNew | 200 | |
| | | | åºåº | OutNew | 100 | |
| | | | ç§»åº | RelocationNew | 300 | |
| | | |
| | | ## 7. é误å¤ç |
| | | |
| | | - ä»»å¡å·è·å失败 â è¿åé误 |
| | | - WCS æ¥æ¾è¾é线å®ä¾å¤±è´¥ â è¿åéè¯¯ç» WMS |
| | | - åå
¥ PLC 失败 â è¿åé误ï¼WMS ä»»å¡ç¶æä¿ææ°å»º |
| | | - WCS è¿åéå¤ä»»å¡ â è¿åéè¯¯ç» WMS |
| | | |
| | | ## 8. æ¶åçæºæä»¶ |
| | | |
| | | ### WMS å端 |
| | | - `WMS/WIDESEA_WMSClient/src/views/taskinfo/task.vue` |
| | | - `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` |
| | | |
| | | ### WMS å端 |
| | | - `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService.cs` |
| | | - `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` |
| | | |
| | | ### WCS å端 |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs` |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/InboundTaskFlowService.cs` |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/OutboundTaskFlowService.cs` |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/Flows/RelocationTaskFlowService.cs` |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs` (åèåå
¥æ¨¡å¼) |
| | | - `WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLine/ConveyorLineTaskCommandNew.cs` (ä»»å¡å½ä»¤ç»æ) |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æå¨ä¸åä»»å¡å° WCS åè½è®¾è®¡ |
| | | |
| | | **æ¥æ**: 2026-04-12 |
| | | **ç¶æ**: å·²æ¹å |
| | | |
| | | --- |
| | | |
| | | ## 1. åè½æ¦è¿° |
| | | |
| | | å¨ WMS å端任å¡ç®¡ç页颿·»å å·¥å
·æ æé®ï¼æ¯æä»ä»»å¡å表ä¸éæ©ä¸ä¸ªæå¤ä¸ªä»»å¡ï¼æå¨ç¼è¾å°åï¼èµ·ç¹/ç»ç¹ï¼åä¼å
级åï¼ä¸åå° WCS ç³»ç»æ§è¡ã |
| | | |
| | | **使ç¨åºæ¯**ï¼å½ä»»å¡å è®¾å¤æ
éãç½ç»é®é¢çåå æªè½æ£å¸¸ä¸åæ¶ï¼æä½å坿å¨éæ°ä¸åã |
| | | |
| | | --- |
| | | |
| | | ## 2. å端æ¹å¨ |
| | | |
| | | ### 2.1 æ°å¢æä»¶ |
| | | |
| | | | æä»¶ | ç¨é | |
| | | |------|------| |
| | | | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/dispatchTasksToWCS.vue` | æ¹éä¸åç¼è¾å¼¹çªç»ä»¶ | |
| | | |
| | | ### 2.2 ä¿®æ¹æä»¶ |
| | | |
| | | | æä»¶ | æ¹å¨ | |
| | | |------|------| |
| | | | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` | æ·»å å·¥å
·æ "æå¨ä¸å"æé® | |
| | | |
| | | ### 2.3 å¼¹çªäº¤äº |
| | | |
| | | **è§¦åæ¹å¼**ï¼å·¥å
·æ ç¹å»"æå¨ä¸å"æé® |
| | | |
| | | **åç½®æ¡ä»¶**ï¼è³å°éä¸ä¸é¡¹ä»»å¡ |
| | | |
| | | **å¼¹çªå
容**ï¼ |
| | | - 顶鍿¾ç¤º"å·²é任塿°: N 个" |
| | | - è¡¨æ ¼å±ç¤ºææéä¸ä»»å¡ï¼åï¼ä»»å¡å·ãèµ·ç¹å°åãç»ç¹å°åãä¼å
级ãç¶æ |
| | | - å°ååæ®µï¼`el-input` æ `el-select`ï¼åå³äºæ¯å¦ææ åå°ååå
¸ï¼ |
| | | - ä¼å
级ï¼`el-input-number`ï¼èå´ 1-99 |
| | | - ç¶æåï¼ä»
å±ç¤ºï¼ä¸å¯ç¼è¾ |
| | | |
| | | **æé®**ï¼åæ¶ã确认ä¸å |
| | | |
| | | **ä¸åå**ï¼ |
| | | - æåï¼å¼¹çªå
³éï¼å·æ°ä»»å¡å表 |
| | | - 失败ï¼å¼¹çªå
æ¾ç¤ºå¤±è´¥ä»»å¡å表ï¼ä»»å¡å· + 失败åå ï¼ |
| | | |
| | | --- |
| | | |
| | | ## 3. å端æ¹å¨ |
| | | |
| | | ### 3.1 æ°å¢ DTO |
| | | |
| | | **æä»¶**: `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/DispatchTaskDto.cs` |
| | | |
| | | ```csharp |
| | | public class DispatchTaskDto |
| | | { |
| | | public long TaskId { get; set; } |
| | | public string SourceAddress { get; set; } |
| | | public string TargetAddress { get; set; } |
| | | public int Priority { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | ### 3.2 æ°å¢æ¥å£ |
| | | |
| | | **Controller**: `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` |
| | | |
| | | ``` |
| | | POST /api/TaskInfo/DispatchTasksToWCS |
| | | ``` |
| | | |
| | | **Service**: `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs` |
| | | |
| | | æ°å¢æ¹æ³ `DispatchTasksToWCSAsync(List<DispatchTaskDto> dtos)` |
| | | |
| | | ### 3.3 ä¸å¡é»è¾ |
| | | |
| | | ``` |
| | | 1. æ ¡éªéä¸ä»»å¡æ°é > 0 |
| | | 2. æ ¡éªä»»å¡ç¶æï¼ä»
å
许以ä¸ç¶æçä»»å¡ä¸åï¼ |
| | | - å
¥åºï¼InNewï¼å
¥åºæ°åï¼ |
| | | - åºåºï¼OutNewï¼åºåºæ°åï¼ |
| | | - ç§»åºï¼RelocationNewï¼ç§»åºæ°åï¼ |
| | | 3. æ´æ°ä»»å¡çå°åï¼SourceAddressãTargetAddressï¼åä¼å
级ï¼Gradeï¼ |
| | | 4. è°ç¨ WCS æ¥å£ï¼POST http://localhost:9292/api/Task/ReceiveManualTask |
| | | 5. æ±æ»æ¯æ¡ä»»å¡çä¸åç»æï¼æå/失败ååå ï¼ |
| | | 6. è¿åç»å端 |
| | | ``` |
| | | |
| | | ### 3.4 WCS æ¥å£å¤ç¨ |
| | | |
| | | **å·²ææ¥å£**: `POST /api/Task/ReceiveManualTask`ï¼commit b032763ï¼ |
| | | |
| | | WMS è°ç¨è¯¥æ¥å£ï¼å°ä»»å¡æ°æ®ä»¥ `WMSTaskDTO` æ ¼å¼åéã |
| | | |
| | | --- |
| | | |
| | | ## 4. é误å¤ç |
| | | |
| | | | åºæ¯ | å端å¤ç | å端å¤ç | |
| | | |------|----------|----------| |
| | | | æªéä¸ä»»å¡ | æé®ç½®ç°ï¼ç¹å»æç¤º"请å
鿩任å¡" | è¿åé误æç¤º | |
| | | | ä»»å¡ç¶æä¸å¯ä¸å | è¡å
ç¶æåæ çº¢ï¼å°å/ä¼å
级置ç°ä¸å¯ç¼è¾ | æ ¡éªå¹¶è¿åä¸å¯ä¸åä»»å¡å表 | |
| | | | WCS è°ç¨è¶
æ¶ | è¯¥ä»»å¡æ è®°"ä¸åè¶
æ¶" | æ è®°ä»»å¡ï¼ä¸åç»æè¿åå端 | |
| | | | WCS è¿å失败 | æ¾ç¤º WCS é误åå ï¼å¦"设å¤å¿"ï¼ | éä¼ WCS éè¯¯ä¿¡æ¯ | |
| | | | å
¨é¨æå | å¼¹çªå
³éï¼å·æ°å表 | è¿åæå | |
| | | |
| | | --- |
| | | |
| | | ## 5. æ¶åçä»£ç æä»¶ |
| | | |
| | | | å±çº§ | æä»¶è·¯å¾ | æ¹å¨ç±»å | |
| | | |------|----------|----------| |
| | | | å端 | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js` | ä¿®æ¹ | |
| | | | å端 | `WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/dispatchTasksToWCS.vue` | æ°å¢ | |
| | | | å端 | `WMS/WIDESEA_WMSClient/src/api/` | æ°å¢ API æ¹æ³ | |
| | | | å端 | `WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/DispatchTaskDto.cs` | æ°å¢ | |
| | | | å端 | `WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs` | ä¿®æ¹ | |
| | | | å端 | `WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs` | ä¿®æ¹ | |
| | | | å端 | `WMS/WIDESEA_WMSServer/WIDESEA_Core/Helper/HTTP/HttpClientHelper.cs` | å¤ç¨ | |
| | | |
| | | --- |
| | | |
| | | ## 6. UI 示æå¾ |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â æå¨ä¸åä»»å¡å° WCS [X] â |
| | | ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠|
| | | â å·²é任塿°: 5 个 â |
| | | â âââââââââââââââââââââââââââââââââââââââââââââââââââââââ â |
| | | â â ä»»å¡å· â èµ·ç¹å°å â ç»ç¹å°å â ä¼å
级 â ç¶æ â â |
| | | â ââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠â |
| | | â â T001 â [PLC-A01 ] â [Rack-05] â [ 5 ] â å
¥åºæ°åâ â |
| | | â â T002 â [PLC-A02 ] â [Rack-06] â [ 3 ] â å
¥åºæ°åâ â |
| | | â âââââââââââââââââââââââââââââââââââââââââââââââââââââââ â |
| | | ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ⤠|
| | | â [åæ¶] [确认ä¸å] â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## 7. éªæ¶æ å |
| | | |
| | | - [ ] å·¥å
·æ æ·»å "æå¨ä¸å"æé®ï¼æªéä¸ä»»å¡æ¶æé®å¯ç¨ä½ç¹å»æç¤ºéæ© |
| | | - [ ] å¼¹çªæ£ç¡®æ¾ç¤ºææéä¸ä»»å¡ |
| | | - [ ] ä»
å
¥åºæ°å/åºåºæ°å/ç§»åºæ°åç¶æçä»»å¡å¯ç¼è¾å°ååä¼å
级 |
| | | - [ ] 确认ä¸ååè°ç¨å端æ¥å£ |
| | | - [ ] æå/å¤±è´¥ç»ææ£ç¡®åé¦ç»ç¨æ· |
| | | - [ ] æååå·æ°ä»»å¡å表 |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # WMSåºå页é¢MESæ¥å£éæè®¾è®¡ææ¡£ |
| | | |
| | | **æ¥æ**: 2026-04-12 |
| | | **项ç®**: WIDESEA WMS |
| | | **ä½è
**: Claude Code |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãéæ±æ¦è¿° |
| | | |
| | | 为WMSåºåä¿¡æ¯é¡µé¢ååºåæç»é¡µé¢æ·»å æä½åï¼è°ç¨MESç³»ç»çåºç«/å
¥ç«/ç»å®/è§£ç»/NG䏿¥æ¥å£ï¼å®ç°WMSä¸MESçæ°æ®åæ¥ã |
| | | |
| | | ### åè½èå´ |
| | | |
| | | **åºåä¿¡æ¯é¡µé¢ï¼stockInfo.vueï¼- æç级å«ï¼** |
| | | - æçè¿ç«ï¼è°ç¨MES InboundInContaineræ¥å£ï¼ |
| | | - æçåºç«ï¼è°ç¨MES OutboundInContaineræ¥å£ï¼ |
| | | |
| | | **åºåæç»é¡µé¢ï¼stockInfoDetail.vueï¼- çµè¯çº§å«ï¼** |
| | | - æççµè¯ç»å®ï¼è°ç¨MES BindContaineræ¥å£ï¼ |
| | | - æççµè¯è§£ç»ï¼è°ç¨MES UnBindContaineræ¥å£ï¼ |
| | | - æçNGçµè¯ä¸æ¥ï¼è°ç¨MES ContainerNgReportæ¥å£ï¼ |
| | | |
| | | --- |
| | | |
| | | ## äºãæ¶æè®¾è®¡ |
| | | |
| | | ### 2.1 ç³»ç»æ¶æå¾ |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â å端 (Vue 3) â |
| | | â ââââââââââââââââââââ ââââââââââââââââââââ ââââââââââââââââââ â |
| | | â â stockInfo.vue â âstockInfoDetail â â MesDialog.vue â â |
| | | â â (åºåä¿¡æ¯) â â .vue(åºåæç») â â (ç¡®è®¤å¯¹è¯æ¡) â â |
| | | â â + æä½å â â + æä½å â â â â |
| | | â ââââââââââ¬ââââââââââ ââââââââââ¬ââââââââââ ââââââââââ¬ââââââââ â |
| | | â â â â â |
| | | â âââââââââââââââââââââââ´âââââââââââââââââââââââ â |
| | | â â â |
| | | ââââââââââââââââââââââââââââââââ¼ââââââââââââââââââââââââââââââââââââ |
| | | â HTTP API |
| | | ââââââââââââââââââââââââââââââââ¼ââââââââââââââââââââââââââââââââââââ |
| | | â â¼ å端 (.NET) â |
| | | â ââââââââââââââââââââ ââââââââââââââââââââ ââââââââââââââââââ â |
| | | â â StockController ââ â MesController â â MesLogService â â |
| | | â â â â â â â â |
| | | â ââââââââââââââââââââ ââââââââââ¬ââââââââââ ââââââââââââââââââ â |
| | | â â â |
| | | â â¼ â |
| | | â ââââââââââââââââââââ ââââââââââââââââââââ ââââââââââââââââââ â |
| | | â â IMesService ââ â MesService â âDt_MesApiLog â â |
| | | â â (æ¥å£å®ä¹) â â (HTTPè°ç¨) â â (æ¥å¿è¡¨) â â |
| | | â ââââââââââââââââââââ ââââââââââââââââââââ ââââââââââââââââââ â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â |
| | | â¼ |
| | | ââââââââââââââââ |
| | | â MESç³»ç» â |
| | | â (å¤é¨æ¥å£) â |
| | | ââââââââââââââââ |
| | | ``` |
| | | |
| | | ### 2.2 ææ¯æ |
| | | |
| | | - **å端**: Vue 3, Element Plus, Pinia |
| | | - **å端**: .NET 8, ASP.NET Core, SqlSugar ORM |
| | | - **æ°æ®åº**: SQL Server |
| | | - **HTTP客æ·ç«¯**: HttpClient (å端è°ç¨MES) |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãå端设计 |
| | | |
| | | ### 3.1 åºåä¿¡æ¯é¡µé¢ (stockInfo.vue) |
| | | |
| | | #### æä½å设计 |
| | | |
| | | **è¡¨æ ¼åé
ç½®ï¼** |
| | | ```javascript |
| | | { |
| | | field: "actions", |
| | | title: "æä½", |
| | | width: 200, |
| | | fixed: "right", |
| | | align: "center", |
| | | formatter: (row) => renderActions(row) |
| | | } |
| | | ``` |
| | | |
| | | **æé®å®ä¹ï¼** |
| | | - è¿ç«æé®ï¼è°ç¨æçè¿ç«æ¥å£ |
| | | - åºç«æé®ï¼è°ç¨æçåºç«æ¥å£ |
| | | |
| | | **æé®æ¾ç¤ºè§åï¼** |
| | | |
| | | | åºåç¶æ | è¿ç« | åºç« | |
| | | |---------|:----:|:----:| |
| | | | å¾
å
¥åº (0) | â | â | |
| | | | å¨åº (1) | â | â | |
| | | | åºåºä¸ (2) | â | â | |
| | | | éå® (3) | â | â | |
| | | |
| | | ### 3.2 åºåæç»é¡µé¢ (stockInfoDetail.vue) |
| | | |
| | | #### æä½å设计 |
| | | |
| | | **è¡¨æ ¼åé
ç½®ï¼** |
| | | ```javascript |
| | | { |
| | | field: "actions", |
| | | title: "æä½", |
| | | width: 280, |
| | | fixed: "right", |
| | | align: "center", |
| | | formatter: (row) => renderActions(row) |
| | | } |
| | | ``` |
| | | |
| | | **æé®å®ä¹ï¼** |
| | | - ç»å®æé®ï¼è°ç¨æççµè¯ç»å®æ¥å£ |
| | | - è§£ç»æé®ï¼è°ç¨æççµè¯è§£ç»æ¥å£ |
| | | - NG䏿¥æé®ï¼è°ç¨æçNGçµè¯ä¸æ¥æ¥å£ |
| | | |
| | | **æé®æ¾ç¤ºè§åï¼** |
| | | |
| | | | çµè¯ç¶æ | ç»å® | è§£ç» | NG䏿¥ | |
| | | |---------|:----:|:----:|:------:| |
| | | | æ£å¸¸ (1) | â | â | â | |
| | | | å¼å¸¸ (2) | â | â | â | |
| | | | å·²éå® (99) | â | â | â | |
| | | |
| | | ### 3.3 ç¡®è®¤å¯¹è¯æ¡ç»ä»¶ (MesConfirmDialog.vue) |
| | | |
| | | **ç»ä»¶èè´£ï¼** |
| | | - æ¾ç¤ºå³å°æ§è¡çæä½ä¿¡æ¯ |
| | | - å±ç¤ºå
³é®åæ°ï¼æçç ã设å¤ç¼ç çï¼ |
| | | - æä¾ç¡®è®¤/åæ¶æé® |
| | | - æ¾ç¤ºè°ç¨ç»æï¼æå/å¤±è´¥ï¼ |
| | | |
| | | **Propså®ä¹ï¼** |
| | | ```typescript |
| | | interface MesConfirmDialogProps { |
| | | visible: boolean; |
| | | operationType: 'inbound' | 'outbound' | 'bind' | 'unbind' | 'ngReport'; |
| | | palletCode: string; |
| | | stockInfo?: any; |
| | | detailInfo?: any; |
| | | } |
| | | ``` |
| | | |
| | | ### 3.4 äº¤äºæµç¨ |
| | | |
| | | ``` |
| | | ç¨æ·ç¹å»æä½æé® |
| | | â |
| | | â¼ |
| | | æ£æ¥ç»å½ç¶æ âââââââ æªç»å½ âââââ æç¤º"请å
ç»å½" |
| | | â |
| | | â¼ å·²ç»å½ |
| | | æ£æ¥æä½æé âââââââ æ æé âââââ æç¤º"æ æéæ§è¡æ¤æä½" |
| | | â |
| | | â¼ ææé |
| | | å¼¹åºç¡®è®¤å¯¹è¯æ¡ |
| | | â |
| | | â¼ |
| | | ç¨æ·ç¹å»"确认æ§è¡" |
| | | â |
| | | â¼ |
| | | æ¾ç¤ºloadingç¶æ |
| | | â |
| | | â¼ |
| | | è°ç¨å端API |
| | | â |
| | | âââ æå âââââ æ¾ç¤ºæåæç¤º âââââ å·æ°å表 |
| | | â |
| | | âââ 失败 âââââ æ¾ç¤ºé误æç¤º + "éè¯"æé® |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## åãå端设计 |
| | | |
| | | ### 4.1 APIæ¥å£è®¾è®¡ |
| | | |
| | | #### 4.1.1 åºåä¿¡æ¯ç¸å
³æ¥å£ |
| | | |
| | | **æçè¿ç«** |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçè¿ç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | [HttpPost("inboundInContainer")] |
| | | public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto) |
| | | ``` |
| | | |
| | | **请æ±DTOï¼** |
| | | ```csharp |
| | | public class InboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | **æçåºç«** |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçåºç« - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | [HttpPost("outboundInContainer")] |
| | | public async Task<WebResponseContent> OutboundInContainer([FromBody] OutboundInContainerRequestDto dto) |
| | | ``` |
| | | |
| | | **请æ±DTOï¼** |
| | | ```csharp |
| | | public class OutboundInContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// åºåID |
| | | /// </summary> |
| | | public long StockId { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 产ååæ°å表ï¼å¯éï¼ |
| | | /// </summary> |
| | | public List<ParamItemDto> ParamList { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | #### 4.1.2 åºåæç»ç¸å
³æ¥å£ |
| | | |
| | | **æççµè¯ç»å®** |
| | | ```csharp |
| | | /// <summary> |
| | | /// æççµè¯ç»å® - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | [HttpPost("bindContainer")] |
| | | public async Task<WebResponseContent> BindContainer([FromBody] BindContainerRequestDto dto) |
| | | ``` |
| | | |
| | | **请æ±DTOï¼** |
| | | ```csharp |
| | | public class BindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | |
| | | /// <summary> |
| | | /// ä½ç½®ä¿¡æ¯ |
| | | /// </summary> |
| | | public string Location { get; set; } |
| | | |
| | | /// <summary> |
| | | /// æä½ç±»åï¼0-é»è®¤ 1-è¿ç« 2-åºç« 3-è¿åºç« |
| | | /// </summary> |
| | | public int OperationType { get; set; } = 1; |
| | | } |
| | | ``` |
| | | |
| | | **æççµè¯è§£ç»** |
| | | ```csharp |
| | | /// <summary> |
| | | /// æççµè¯è§£ç» - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | [HttpPost("unbindContainer")] |
| | | public async Task<WebResponseContent> UnbindContainer([FromBody] UnbindContainerRequestDto dto) |
| | | ``` |
| | | |
| | | **请æ±DTOï¼** |
| | | ```csharp |
| | | public class UnbindContainerRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// çµè¯ç å表 |
| | | /// </summary> |
| | | public List<string> SfcList { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | **æçNGçµè¯ä¸æ¥** |
| | | ```csharp |
| | | /// <summary> |
| | | /// æçNGçµè¯ä¸æ¥ - è°ç¨MESæ¥å£ |
| | | /// </summary> |
| | | [HttpPost("containerNgReport")] |
| | | public async Task<WebResponseContent> ContainerNgReport([FromBody] ContainerNgReportRequestDto dto) |
| | | ``` |
| | | |
| | | **请æ±DTOï¼** |
| | | ```csharp |
| | | public class ContainerNgReportRequestDto |
| | | { |
| | | /// <summary> |
| | | /// æçç¼å· |
| | | /// </summary> |
| | | public string PalletCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGçµè¯å表 |
| | | /// </summary> |
| | | public List<NgSfcItemDto> NgSfcList { get; set; } |
| | | } |
| | | |
| | | public class NgSfcItemDto |
| | | { |
| | | /// <summary> |
| | | /// äº§åæ¡ç |
| | | /// </summary> |
| | | public string Sfc { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NG代ç |
| | | /// </summary> |
| | | public string NgCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGè®¾å¤ |
| | | /// </summary> |
| | | public string NgEquipmentCode { get; set; } |
| | | |
| | | /// <summary> |
| | | /// NGèµæº |
| | | /// </summary> |
| | | public string NgResourceCode { get; set; } |
| | | } |
| | | ``` |
| | | |
| | | ### 4.2 æ°æ®åºè®¾è®¡ |
| | | |
| | | #### 4.2.1 MESæ¥å£è°ç¨æ¥å¿è¡¨ |
| | | |
| | | ```sql |
| | | CREATE TABLE Dt_MesApiLog ( |
| | | Id BIGINT PRIMARY KEY IDENTITY(1,1), |
| | | ApiType NVARCHAR(50) NOT NULL, -- æ¥å£ç±»å |
| | | RequestJson NVARCHAR(MAX) NULL, -- 请æ±JSON |
| | | ResponseJson NVARCHAR(MAX) NULL, -- ååºJSON |
| | | IsSuccess BIT NOT NULL DEFAULT 0, -- æ¯å¦æå |
| | | ErrorMessage NVARCHAR(500) NULL, -- éè¯¯ä¿¡æ¯ |
| | | ElapsedMs INT NOT NULL DEFAULT 0, -- èæ¶(毫ç§) |
| | | CreateDate DATETIME NOT NULL, -- å建æ¶é´ |
| | | Creator NVARCHAR(50) NULL, -- å建人 |
| | | INDEX IX_MesApiLog_ApiType (ApiType), |
| | | INDEX IX_MesApiLog_CreateDate (CreateDate) |
| | | ); |
| | | ``` |
| | | |
| | | **åæ®µè¯´æï¼** |
| | | |
| | | | åæ®µ | ç±»å | 说æ | |
| | | |------|------|------| |
| | | | Id | bigint | ä¸»é® | |
| | | | ApiType | string(50) | æ¥å£ç±»åï¼InboundInContainer, OutboundInContainer, BindContainer, UnbindContainer, ContainerNgReport | |
| | | | RequestJson | string(MAX) | MESæ¥å£è¯·æ±JSON | |
| | | | ResponseJson | string(MAX) | MESæ¥å£ååºJSON | |
| | | | IsSuccess | bool | è°ç¨æ¯å¦æå | |
| | | | ErrorMessage | string(500) | 失败æ¶çéè¯¯ä¿¡æ¯ | |
| | | | ElapsedMs | int | æ¥å£è°ç¨èæ¶ï¼æ¯«ç§ï¼ | |
| | | | CreateDate | datetime | å建æ¶é´ | |
| | | | Creator | string(50) | å建人 | |
| | | |
| | | #### 4.2.2 ç³»ç»é
置表æ©å± |
| | | |
| | | ```sql |
| | | -- å¨ Dt_SystemConfig è¡¨ä¸æ°å¢MESé
置项 |
| | | INSERT INTO Dt_SystemConfig (ConfigKey, ConfigValue, Description, CreateDate) |
| | | VALUES |
| | | ('MES_EquipmentCode', 'WCS_001', 'MES设å¤ç¼ç ', GETDATE()), |
| | | ('MES_ResourceCode', 'RESOURCE_001', 'MESèµæºç¼ç ', GETDATE()), |
| | | ('MES_ApiBaseUrl', 'http://mes-server/api', 'MESæ¥å£å°å', GETDATE()), |
| | | ('MES_TimeoutSeconds', '30', 'MESæ¥å£è¶
æ¶æ¶é´(ç§)', GETDATE()); |
| | | ``` |
| | | |
| | | ### 4.3 æå¡å±è®¾è®¡ |
| | | |
| | | #### 4.3.1 MESæ¥å¿æå¡æ¥å£ |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡æ¥å£ |
| | | /// </summary> |
| | | public interface IMesLogService : IDependency |
| | | { |
| | | /// <summary> |
| | | /// è®°å½MESæ¥å£è°ç¨æ¥å¿ |
| | | /// </summary> |
| | | Task<bool> LogAsync(MesApiLogDto log); |
| | | |
| | | /// <summary> |
| | | /// è·åæè¿çMESæ¥å£è°ç¨è®°å½ |
| | | /// </summary> |
| | | Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50); |
| | | } |
| | | ``` |
| | | |
| | | #### 4.3.2 MESæ¥å¿æå¡å®ç° |
| | | |
| | | ```csharp |
| | | /// <summary> |
| | | /// MESæ¥å£æ¥å¿æå¡å®ç° |
| | | /// </summary> |
| | | public class MesLogService : IMesLogService |
| | | { |
| | | private readonly ISqlSugarClient _db; |
| | | |
| | | public async Task<bool> LogAsync(MesApiLogDto log) |
| | | { |
| | | var entity = new Dt_MesApiLog |
| | | { |
| | | ApiType = log.ApiType, |
| | | RequestJson = log.RequestJson, |
| | | ResponseJson = log.ResponseJson, |
| | | IsSuccess = log.IsSuccess, |
| | | ErrorMessage = log.ErrorMessage, |
| | | ElapsedMs = log.ElapsedMs, |
| | | CreateDate = DateTime.Now, |
| | | Creator = log.Creator |
| | | }; |
| | | |
| | | return await _db.Insertable(entity).ExecuteCommandAsync() > 0; |
| | | } |
| | | |
| | | public async Task<List<MesApiLogDto>> GetRecentLogsAsync(string apiType, int count = 50) |
| | | { |
| | | return await _db.Queryable<Dt_MesApiLog>() |
| | | .Where(x => x.ApiType == apiType) |
| | | .OrderByDescending(x => x.CreateDate) |
| | | .Take(count) |
| | | .ToListAsync(); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## äºãæ¥å£è°ç¨æµç¨ |
| | | |
| | | ### 5.1 æçè¿ç«æµç¨ |
| | | |
| | | ``` |
| | | ç¨æ·ç¹å»"è¿ç«"æé® |
| | | â |
| | | â¼ |
| | | å端弹åºç¡®è®¤å¯¹è¯æ¡ï¼æ¾ç¤ºæçç ã设å¤ç¼ç çï¼ |
| | | â |
| | | â¼ |
| | | ç¨æ·ç¡®è®¤ |
| | | â |
| | | â¼ |
| | | å端è°ç¨ POST /api/StockInfo/inboundInContainer |
| | | â |
| | | â¼ |
| | | å端 StockInfoController.InboundInContainer() |
| | | â |
| | | âââ 1. éªè¯åºåç¶æï¼ä»
"å¾
å
¥åº"ç¶æå
许è¿ç«ï¼ |
| | | â |
| | | âââ 2. è·åç³»ç»é
ç½®ï¼è®¾å¤ç¼ç ãèµæºç¼ç ï¼ |
| | | â |
| | | âââ 3. æé MES请æ±å¯¹è±¡ |
| | | â |
| | | âââ 4. è°ç¨ IMesService.InboundInContainer() |
| | | â â |
| | | â âââ è®°å½å¼å§æ¶é´ |
| | | â âââ åéHTTP请æ±å°MES |
| | | â âââ è®°å½ååºãèæ¶ |
| | | â âââ ä¿åæ¥å¿å° Dt_MesApiLog |
| | | â |
| | | âââ 5. è¿åç»æç»å端 |
| | | â |
| | | âââ å端æ¾ç¤ºæå/失败æç¤º |
| | | ``` |
| | | |
| | | ### 5.2 æççµè¯ç»å®æµç¨ |
| | | |
| | | ``` |
| | | ç¨æ·ç¹å»"ç»å®"æé® |
| | | â |
| | | â¼ |
| | | å端弹åºç¡®è®¤å¯¹è¯æ¡ï¼æ¾ç¤ºæçç ãçµè¯ç åè¡¨ï¼ |
| | | â |
| | | â¼ |
| | | ç¨æ·ç¡®è®¤ |
| | | â |
| | | â¼ |
| | | å端è°ç¨ POST /api/StockInfoDetail/bindContainer |
| | | â |
| | | â¼ |
| | | å端 StockInfoDetailController.BindContainer() |
| | | â |
| | | âââ 1. éªè¯çµè¯ç¶æï¼é"å·²éå®"ç¶æå
许ç»å®ï¼ |
| | | â |
| | | âââ 2. è·åç³»ç»é
ç½® |
| | | â |
| | | âââ 3. æé MES请æ±å¯¹è±¡ï¼å
å«çµè¯ç åè¡¨ï¼ |
| | | â |
| | | âââ 4. è°ç¨ IMesService.BindContainer() |
| | | â â |
| | | â âââ è®°å½å¼å§æ¶é´ |
| | | â âââ åéHTTP请æ±å°MES |
| | | â âââ è®°å½ååºãèæ¶ |
| | | â âââ ä¿åæ¥å¿å° Dt_MesApiLog |
| | | â |
| | | âââ 5. è¿åç»æç»å端 |
| | | â |
| | | âââ å端æ¾ç¤ºæå/失败æç¤º |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## å
ãé误å¤ç |
| | | |
| | | ### 6.1 é误类å |
| | | |
| | | | é误类å | 说æ | å¤çæ¹å¼ | |
| | | |---------|------|---------| |
| | | | ç½ç»è¶
æ¶ | MESæå¡å¨æ ååºæè¿æ¥è¶
æ¶ | æ¾ç¤ºé误æç¤ºï¼æä¾"éè¯"æé® | |
| | | | ä¸å¡æ ¡éªå¤±è´¥ | æçä¸åå¨ãçµè¯å·²ç»å®ç | æ¾ç¤ºMESè¿åçéè¯¯ä¿¡æ¯ | |
| | | | 认è¯å¤±è´¥ | MESæ¥å£è®¤è¯ä¿¡æ¯è¿æ | æ¾ç¤º"MES认è¯å¤±è´¥ï¼è¯·è系管çå" | |
| | | | åæ°é误 | 请æ±åæ°ä¸å®æ´ææ ¼å¼é误 | æ¾ç¤º"åæ°é误ï¼{å
·ä½é误}" | |
| | | | æªç¥é误 | MESç³»ç»è¿åå¼å¸¸ååº | æ¾ç¤º"MESç³»ç»å¼å¸¸ï¼è¯·ç¨åéè¯" | |
| | | |
| | | ### 6.2 å端é误æç¤º |
| | | |
| | | ```javascript |
| | | // æåæç¤º |
| | | ElMessage.success('æçè¿ç«æå'); |
| | | |
| | | // 失败æç¤º |
| | | ElMessage.error({ |
| | | message: 'MESæå¡å¨è¿æ¥è¶
æ¶ï¼è¯·æ£æ¥ç½ç»åéè¯', |
| | | showRetry: true, |
| | | onRetry: () => retryOperation() |
| | | }); |
| | | ``` |
| | | |
| | | ### 6.3 å端é误æ¥å¿ |
| | | |
| | | ```csharp |
| | | try |
| | | { |
| | | // è°ç¨MESæ¥å£ |
| | | } |
| | | catch (HttpRequestException ex) |
| | | { |
| | | // ç½ç»å¼å¸¸ |
| | | await _mesLogService.LogAsync(new MesApiLogDto |
| | | { |
| | | ApiType = "InboundInContainer", |
| | | IsSuccess = false, |
| | | ErrorMessage = $"ç½ç»å¼å¸¸: {ex.Message}", |
| | | ElapsedMs = elapsedMs |
| | | }); |
| | | return ResponseContent.Error("MESæå¡å¨è¿æ¥å¤±è´¥ï¼è¯·æ£æ¥ç½ç»"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // å
¶ä»å¼å¸¸ |
| | | _logger.LogError(ex, "è°ç¨MESæ¥å£å¼å¸¸"); |
| | | return ResponseContent.Error($"MESæ¥å£è°ç¨å¤±è´¥: {ex.Message}"); |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ä¸ãæéæ§å¶ |
| | | |
| | | ### 7.1 åè½æéå®ä¹ |
| | | |
| | | 建议å¨ç³»ç»ä¸æ°å¢ä»¥ä¸åè½æéï¼ |
| | | |
| | | | æé代ç | æéåç§° | 说æ | |
| | | |---------|---------|------| |
| | | | MES_INBOUND | MESè¿ç«æä½ | å
许æ§è¡æçè¿ç«æä½ | |
| | | | MES_OUTBOUND | MESåºç«æä½ | å
许æ§è¡æçåºç«æä½ | |
| | | | MES_BIND | MESç»å®æä½ | å
许æ§è¡çµè¯ç»å®æä½ | |
| | | | MES_UNBIND | MESè§£ç»æä½ | å
许æ§è¡çµè¯è§£ç»æä½ | |
| | | | MES_NG_REPORT | MES NG䏿¥ | å
许æ§è¡NG䏿¥æä½ | |
| | | |
| | | ### 7.2 æééªè¯ |
| | | |
| | | ```csharp |
| | | [HttpPost("inboundInContainer")] |
| | | [Permission("MES_INBOUND")] |
| | | public async Task<WebResponseContent> InboundInContainer([FromBody] InboundInContainerRequestDto dto) |
| | | { |
| | | // æ¥å£å®ç° |
| | | } |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## å
«ãæä»¶åæ´æ¸
å |
| | | |
| | | ### 8.1 å端æä»¶ |
| | | |
| | | ``` |
| | | WMS/WIDESEA_WMSClient/src/ |
| | | âââ views/stock/ |
| | | â âââ stockInfo.vue # ä¿®æ¹ï¼æ·»å æä½å |
| | | â âââ stockInfoDetail.vue # ä¿®æ¹ï¼æ·»å æä½å |
| | | âââ components/ |
| | | â âââ MesConfirmDialog.vue # æ°å¢ï¼MESç¡®è®¤å¯¹è¯æ¡ |
| | | âââ api/ |
| | | âââ mes.js # æ°å¢ï¼MES APIè°ç¨ |
| | | ``` |
| | | |
| | | ### 8.2 å端æä»¶ |
| | | |
| | | ``` |
| | | WMS/WIDESEA_WMSServer/ |
| | | âââ Controllers/ |
| | | â âââ Stock/ |
| | | â âââ StockInfoController.cs # ä¿®æ¹ï¼æ·»å è¿ç«/åºç«æ¥å£ |
| | | â âââ StockInfoDetailController.cs # ä¿®æ¹ï¼æ·»å ç»å®/è§£ç»/NG䏿¥æ¥å£ |
| | | âââ Services/ |
| | | â âââ Mes/ |
| | | â âââ IMesLogService.cs # æ°å¢ï¼æ¥å¿æå¡æ¥å£ |
| | | â âââ MesLogService.cs # æ°å¢ï¼æ¥å¿æå¡å®ç° |
| | | âââ DTO/ |
| | | âââ Mes/ |
| | | â âââ MesApiLogDto.cs # æ°å¢ï¼æ¥å¿DTO |
| | | â âââ InboundInContainerRequestDto.cs # æ°å¢ï¼è¿ç«è¯·æ±DTO |
| | | â âââ OutboundInContainerRequestDto.cs # æ°å¢ï¼åºç«è¯·æ±DTO |
| | | â âââ BindContainerRequestDto.cs # æ°å¢ï¼ç»å®è¯·æ±DTO |
| | | â âââ UnbindContainerRequestDto.cs # æ°å¢ï¼è§£ç»è¯·æ±DTO |
| | | â âââ ContainerNgReportRequestDto.cs # æ°å¢ï¼NG䏿¥è¯·æ±DTO |
| | | âââ Models/ |
| | | âââ Mes/ |
| | | âââ Dt_MesApiLog.cs # æ°å¢ï¼æ¥å¿å®ä½ |
| | | ``` |
| | | |
| | | ### 8.3 æ°æ®åºæä»¶ |
| | | |
| | | ``` |
| | | Database/ |
| | | âââ Scripts/ |
| | | âââ 20260412_MesApiLog.sql # æ°å¢ï¼æ¥å¿è¡¨åå»ºèæ¬ |
| | | ``` |
| | | |
| | | --- |
| | | |
| | | ## ä¹ãæµè¯è¦ç¹ |
| | | |
| | | ### 9.1 åè½æµè¯ |
| | | |
| | | | æµè¯åºæ¯ | é¢æç»æ | |
| | | |---------|---------| |
| | | | å¾
å
¥åºç¶ææçç¹å»è¿ç« | å¼¹åºç¡®è®¤å¯¹è¯æ¡ï¼ç¡®è®¤åæåè°ç¨ | |
| | | | å¨åºç¶ææçç¹å»è¿ç« | è¿ç«æé®ä¸æ¾ç¤º | |
| | | | ç½ç»ä¸ææ¶ç¹å»æä½ | æ¾ç¤ºç½ç»é误æç¤ºï¼æä¾éè¯æé® | |
| | | | MESè¿åä¸å¡é误 | æ¾ç¤ºMESè¿åçå
·ä½éè¯¯ä¿¡æ¯ | |
| | | | ç¹å»æä½åå·æ°é¡µé¢ | æä½è®°å½å·²ä¿åå°æ¥å¿è¡¨ | |
| | | |
| | | ### 9.2 æ§è½æµè¯ |
| | | |
| | | | ææ | ç®æ å¼ | |
| | | |------|--------| |
| | | | MESæ¥å£ååºæ¶é´ | < 2ç§ | |
| | | | å端æé®ç¹å»ååº | < 100ms | |
| | | | æ¥å¿åå
¥èæ¶ | < 50ms | |
| | | |
| | | --- |
| | | |
| | | ## åãåç»ä¼å建议 |
| | | |
| | | 1. **æ¹éæä½**ï¼æ¯æéä¸å¤ä¸ªæç/çµè¯æ¹éè°ç¨MESæ¥å£ |
| | | 2. **èªå¨éè¯**ï¼å¯¹äºç½ç»è¶
æ¶çä¸´æ¶æ
éï¼èªå¨éè¯3次 |
| | | 3. **æ¥å£çæ§**ï¼å¢å MESæ¥å£è°ç¨ç宿¶çæ§ååè¦ |
| | | 4. **åæ°é
ç½®å**ï¼å°è¶
æ¶æ¶é´ãéè¯æ¬¡æ°çåæ°åæå¯é
置项 |
| | | 5. **æä½å®¡è®¡**ï¼å¢å æä½å®¡è®¡æ¥å¿ï¼è®°å½è°å¨ä»ä¹æ¶é´æ§è¡äºä»ä¹æä½ |
| | | |
| | | --- |
| | | |
| | | **ææ¡£çæ¬**: 1.0 |
| | | **æåæ´æ°**: 2026-04-12 |
| | |
| | | "id": "1001", |
| | | "name": "A\u533A_\u4E00\u6CE8\u8F93\u9001\u7EBF", |
| | | "plcType": "S71500", |
| | | "port": 105, |
| | | "port": 103, |
| | | "activationKey": "", |
| | | "autoStart": false, |
| | | "protocolTemplateId": "protocol-1001", |
| | |
| | | "id": "1002", |
| | | "name": "A\u533A_\u6362\u76D8\u8F93\u9001\u7EBF", |
| | | "plcType": "S71500", |
| | | "port": 108, |
| | | "port": 104, |
| | | "activationKey": "", |
| | | "autoStart": false, |
| | | "protocolTemplateId": "protocol-1002", |
| | |
| | | "dbNumber": 50, |
| | | "offset": 18, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | }, |
| | |
| | | "dbNumber": 50, |
| | | "offset": 578, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | }, |
| | |
| | | "dbNumber": 50, |
| | | "offset": 1378, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | }, |
| | |
| | | "dbNumber": 50, |
| | | "offset": 1618, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "length": 22, |
| | | "dataType": 0, |
| | | "length": 20, |
| | | "direction": 2 |
| | | } |
| | | ] |
| | |
| | | "dbNumber": 50, |
| | | "offset": 18, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "length": 22, |
| | | "dataType": 0, |
| | | "length": 20, |
| | | "direction": 2 |
| | | }, |
| | | { |
| | | "fieldKey": "11010_TaskNo", |
| | | "dbNumber": 50, |
| | | "offset": 400, |
| | | "offset": 360, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_Source", |
| | | "dbNumber": 50, |
| | | "offset": 402, |
| | | "offset": 362, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_Target", |
| | | "dbNumber": 50, |
| | | "offset": 404, |
| | | "offset": 364, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_BoxType", |
| | | "dbNumber": 50, |
| | | "offset": 406, |
| | | "offset": 366, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_CV_State", |
| | | "dbNumber": 50, |
| | | "offset": 407, |
| | | "offset": 367, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_CV_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 408, |
| | | "offset": 368, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_WCS_STB", |
| | | "dbNumber": 50, |
| | | "offset": 409, |
| | | "offset": 369, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_WCS_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 410, |
| | | "offset": 370, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_PLC_STB", |
| | | "dbNumber": 50, |
| | | "offset": 411, |
| | | "offset": 371, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_PLC_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 412, |
| | | "offset": 372, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_PLC_REQ", |
| | | "dbNumber": 50, |
| | | "offset": 413, |
| | | "offset": 373, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_WCS_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 414, |
| | | "offset": 374, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_WCS_Special", |
| | | "dbNumber": 50, |
| | | "offset": 415, |
| | | "offset": 375, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_Equ_Auto", |
| | | "dbNumber": 50, |
| | | "offset": 416, |
| | | "offset": 376, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_Last_pallet", |
| | | "dbNumber": 50, |
| | | "offset": 417, |
| | | "offset": 377, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11010_Barcode", |
| | | "dbNumber": 50, |
| | | "offset": 418, |
| | | "offset": 378, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "length": 22, |
| | | "dataType": 0, |
| | | "length": 20, |
| | | "direction": 2 |
| | | }, |
| | | { |
| | | "fieldKey": "11020_TaskNo", |
| | | "dbNumber": 50, |
| | | "offset": 800, |
| | | "offset": 760, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_Source", |
| | | "dbNumber": 50, |
| | | "offset": 802, |
| | | "offset": 762, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_Target", |
| | | "dbNumber": 50, |
| | | "offset": 804, |
| | | "offset": 764, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_BoxType", |
| | | "dbNumber": 50, |
| | | "offset": 806, |
| | | "offset": 766, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_CV_State", |
| | | "dbNumber": 50, |
| | | "offset": 807, |
| | | "offset": 767, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_CV_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 808, |
| | | "offset": 768, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_WCS_STB", |
| | | "dbNumber": 50, |
| | | "offset": 809, |
| | | "offset": 769, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_WCS_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 810, |
| | | "offset": 770, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_PLC_STB", |
| | | "dbNumber": 50, |
| | | "offset": 811, |
| | | "offset": 771, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_PLC_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 812, |
| | | "offset": 772, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_PLC_REQ", |
| | | "dbNumber": 50, |
| | | "offset": 813, |
| | | "offset": 773, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_WCS_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 814, |
| | | "offset": 774, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_WCS_Special", |
| | | "dbNumber": 50, |
| | | "offset": 815, |
| | | "offset": 775, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_Equ_Auto", |
| | | "dbNumber": 50, |
| | | "offset": 816, |
| | | "offset": 776, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_Last_pallet", |
| | | "dbNumber": 50, |
| | | "offset": 817, |
| | | "offset": 777, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11020_Barcode", |
| | | "dbNumber": 50, |
| | | "offset": 818, |
| | | "offset": 778, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | }, |
| | | { |
| | | "fieldKey": "11026_TaskNo", |
| | | "dbNumber": 50, |
| | | "offset": 1040, |
| | | "offset": 1000, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_Source", |
| | | "dbNumber": 50, |
| | | "offset": 1042, |
| | | "offset": 1002, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_Target", |
| | | "dbNumber": 50, |
| | | "offset": 1044, |
| | | "offset": 1004, |
| | | "bit": 1, |
| | | "dataType": 1, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_BoxType", |
| | | "dbNumber": 50, |
| | | "offset": 1046, |
| | | "offset": 1006, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_CV_State", |
| | | "dbNumber": 50, |
| | | "offset": 1047, |
| | | "offset": 1007, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_CV_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 1048, |
| | | "offset": 1008, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_WCS_STB", |
| | | "dbNumber": 50, |
| | | "offset": 1049, |
| | | "offset": 1009, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_WCS_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 1050, |
| | | "offset": 1010, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_PLC_STB", |
| | | "dbNumber": 50, |
| | | "offset": 1051, |
| | | "offset": 1011, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_PLC_ACK", |
| | | "dbNumber": 50, |
| | | "offset": 1052, |
| | | "offset": 1012, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_PLC_REQ", |
| | | "dbNumber": 50, |
| | | "offset": 1053, |
| | | "offset": 1013, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_WCS_ERRCode", |
| | | "dbNumber": 50, |
| | | "offset": 1054, |
| | | "offset": 1014, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_WCS_Special", |
| | | "dbNumber": 50, |
| | | "offset": 1055, |
| | | "offset": 1015, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_Equ_Auto", |
| | | "dbNumber": 50, |
| | | "offset": 1056, |
| | | "offset": 1016, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_Last_pallet", |
| | | "dbNumber": 50, |
| | | "offset": 1057, |
| | | "offset": 1017, |
| | | "bit": 1, |
| | | "dataType": 0, |
| | | "length": 1, |
| | |
| | | { |
| | | "fieldKey": "11026_Barcode", |
| | | "dbNumber": 50, |
| | | "offset": 1058, |
| | | "offset": 1018, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | } |
| | |
| | | "dbNumber": 50, |
| | | "offset": 18, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 20, |
| | | "direction": 2 |
| | | }, |
| | |
| | | "dbNumber": 50, |
| | | "offset": 338, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 20, |
| | | "direction": 2 |
| | | }, |
| | |
| | | "dbNumber": 50, |
| | | "offset": 618, |
| | | "bit": 1, |
| | | "dataType": 3, |
| | | "dataType": 0, |
| | | "length": 22, |
| | | "direction": 2 |
| | | } |