| | |
| | | <td><span style="color: #999;">选填</span></td> |
| | | <td>请求时间戳,格式: <code>yyyy-MM-dd HH:mm:ss</code>。由上层系统设定。</td> |
| | | </tr> |
| | | <!-- <tr>--> |
| | | <!-- <td><code>clientCode</code></td>--> |
| | | <!-- <td><span style="color: #999;">选填</span></td>--> |
| | | <!-- <td>客户端编号,如 PDA、HCWMS 等。如果填写,需先在 RCS-2000 系统配置,上层系统调用时进行填写,当多系统调用时,调度系统可以进行调用方区分。</td>--> |
| | | <!-- </tr>--> |
| | | <!-- <tr> |
| | | <td><code>clientCode</code></td> |
| | | <td><span style="color: #999;">选填</span></td> |
| | | <td>客户端编号,如 PDA、HCWMS 等。如果填写,需先在 RCS-2000 系统配置,上层系统调用时进行填写,当多系统调用时,调度系统可以进行调用方区分。</td> |
| | | </tr>--> |
| | | <tr> |
| | | <td><code>tokenCode</code></td> |
| | | <td><span style="color: #999;">选填</span></td> |
| | |
| | | |
| | | </section> |
| | | |
| | | <!-- 生成任务单 --> |
| | | <section id="api-task-create" class="api-section"> |
| | | <h2>生成任务单* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>创建搬运任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/bus/submit</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>批次编号(上层系统生成,唯一标识)</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>tasks</code></td> |
| | | <td>array</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务数组,包含具体的任务详情</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>任务数组元素参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>taskNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务编号(上层系统生成,唯一标识)</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>oriSta</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>起点站点编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>destSta</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>终点站点编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>oriLoc</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>起点库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>destLoc</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>终点库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>priority</code></td> |
| | | <td>int</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>优先级:1-300,默认为1</td> |
| | | </tr> |
| | | |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | |
| | | "batchNo": "122334", |
| | | "tasks": [ |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriLoc": "A100100101", |
| | | "destSta": "STA001", |
| | | "priority": 1 |
| | | }, |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriSta": "STA002", |
| | | "destLoc": "B02-03-05", |
| | | "priority": 2 |
| | | } |
| | | ] |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "任务创建成功", |
| | | "data": { |
| | | "taskNo": "TASK20231220001", |
| | | "taskId": "T1234567890", |
| | | "status": "ASSIGN" |
| | | }, |
| | | "timestamp": 1671526800000 |
| | | }</code></pre> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-create', 'form')" id="task-create-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-create', 'json')" id="task-create-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-create-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>taskNo <span class="required">*</span></label> |
| | | <input type="text" id="task-create-taskNo" placeholder="TASK20231220001" |
| | | value="TASK20231220001"> |
| | | <div class="error-msg" id="task-create-taskNo-error">请输入任务编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>batchNo <span class="required">*</span></label> |
| | | <input type="text" id="task-create-batchNo" placeholder="122334" |
| | | value="122334"> |
| | | <div class="error-msg" id="task-create-batchNo-error">请输入批次编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>taskType <span class="required">*</span></label> |
| | | <select id="task-create-taskType"> |
| | | <option value="1" selected>1 - 出库(oriLoc和destSta必填)</option> |
| | | <option value="2">2 - 入库(oriSta和destLoc必填)</option> |
| | | <option value="3">3 - 库位间移库(oriLoc和destLoc必填)</option> |
| | | <option value="4">4 - 站点间搬运(oriSta和destSta必填)</option> |
| | | </select> |
| | | <div class="error-msg" id="task-create-taskType-error">请选择任务类型</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>oriSta</label> |
| | | <input type="text" id="task-create-oriSta" placeholder="STA001" value=""> |
| | | <div class="hint">起点站点编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>destSta</label> |
| | | <input type="text" id="task-create-destSta" placeholder="STA002" value="STA001"> |
| | | <div class="hint">终点站点编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>oriLoc</label> |
| | | <input type="text" id="task-create-oriLoc" placeholder="A100100101" value="A100100101"> |
| | | <div class="hint">起点库位编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>destLoc</label> |
| | | <input type="text" id="task-create-destLoc" placeholder="B02-03-05" value=""> |
| | | <div class="hint">终点库位编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>priority</label> |
| | | <input type="text" id="task-create-priority" placeholder="1" value="1"> |
| | | <div class="hint">优先级:1-300,默认为1</div> |
| | | </div> |
| | | |
| | | </div> |
| | | <div class="json-input-container" id="task-create-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-create-json">{ |
| | | "taskNo": "TASK20231220001", |
| | | "batchNo": "122334", |
| | | "tasks": [ |
| | | { |
| | | "oriLoc": "A100100101", |
| | | "destSta": "STA001", |
| | | "priority": 1 |
| | | |
| | | } |
| | | ] |
| | | }</textarea> |
| | | <div class="error-msg" id="task-create-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskCreate()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskCreateForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-create-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 取消任务 --> |
| | | <section id="api-task-cancel" class="api-section"> |
| | | <h2>取消任务单* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>取消已创建的任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/task/cancel</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>tasks</code></td> |
| | | <td>array</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>要取消的任务编号数组</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: RED;">是</span></td> |
| | | <td>任务批次编号</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | “batchNo”: “12345”, |
| | | “tasks”: [“123”, “456”] |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | code: 200, |
| | | msg: ‘…’, |
| | | data: [ |
| | | { |
| | | “taskNo”: “123”, |
| | | “success”: true, |
| | | “msg”: null |
| | | }, |
| | | { |
| | | “taskNo”: “456”, |
| | | “success”: false, |
| | | “msg”: “456 is not exist” |
| | | } |
| | | ] |
| | | }</code></pre> |
| | | |
| | | <div class="note"> |
| | | <div class="note-title">注意事项</div> |
| | | <p>• 已经在执行中的任务无法取消,会返回相应错误码</p> |
| | | <p>• 取消任务后,AGV会停止执行并返回待命状态</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-cancel', 'form')" id="task-cancel-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-cancel', 'json')" id="task-cancel-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-cancel-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>tasks <span class="required">*</span></label> |
| | | <input type="text" id="task-cancel-tasks" placeholder="TASK20231220001,TASK20231220002" |
| | | value="TASK20231220001,TASK20231220002"> |
| | | <div class="error-msg" id="task-cancel-tasks-error">请输入要取消的任务编号</div> |
| | | <div class="hint">多个任务编号请用逗号分隔</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>batchNo</label> |
| | | <input type="text" id="task-cancel-batchNo" placeholder="12345" |
| | | value="12345"> |
| | | <div class="hint">任务批次编号(选填)</div> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="task-cancel-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-cancel-json">{ |
| | | "batchNo": "12345", |
| | | "tasks": ["TASK20231220001", "TASK20231220002"] |
| | | }</textarea> |
| | | <div class="error-msg" id="task-cancel-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskCancel()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskCancelForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-cancel-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 任务执行通知 --> |
| | | <section id="api-task-notice" class="api-section"> |
| | | <h2>任务执行通知* <span class="tag">回调接口</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>RCS回调上层系统接口</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/task/report</div> |
| | | |
| | | <div class="note" style="background: linear-gradient(135deg, #e3f2fd, #bbdefb); border-left-color: #2196f3;"> |
| | | <div class="note-title" style="color: #1565c0;">📢 接口说明</div> |
| | | <p style="color: #1976d2;">此接口由<strong>上层系统提供</strong>,RCS系统在任务状态发生变化时主动回调。上层系统需要实现此接口并配置回调地址到RCS系统中。 |
| | | </p> |
| | | </div> |
| | | |
| | | <h4>请求参数(RCS推送)</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务批次</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>taskNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>timestamp</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>时间戳</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>推送示例(RCS → 上层系统)</h4> |
| | | <pre><code>{ |
| | | "taskNo": "TASK20231220001", |
| | | "batchNo": "2345", |
| | | "timestamp": "2023-12-20 14:30:25" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例(上层系统需返回)</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "接收成功" |
| | | }</code></pre> |
| | | |
| | | |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试(模拟RCS推送)</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="form-group"> |
| | | <label>回调地址 <span class="required">*</span></label> |
| | | <input type="text" id="task-notice-callback-url" placeholder="http://localhost:8080/api/callback" value="http://localhost:8080/api/callback"> |
| | | <span class="error-message" id="task-notice-callback-url-error">请输入回调地址</span> |
| | | </div> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskNotice()">发送请求</button> |
| | | <button class="reset-btn" onclick="resetTaskNoticeForm()">重置</button> |
| | | </div> |
| | | <div id="mock-task-notice-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 申请入库任务 --> |
| | | <section id="api-task-priority" class="api-section"> |
| | | <h2>申请入库任务* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>申请入库任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/location/allocate</div> |
| | | <div class="note" style="background: linear-gradient(135deg, #e3f2fd, #bbdefb); border-left-color: #2196f3;"> |
| | | <div class="note-title" style="color: #1565c0;">📢 接口说明</div> |
| | | <p style="color: #1976d2;">此接口由<strong>上层系统提供</strong>,RCS系统在任务状态发生变化时主动回调。上层系统需要实现此接口并配置回调地址到RCS系统中。 |
| | | </p> |
| | | </div> |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>barcode</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>料箱码</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>staNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>入库站点</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | "barcode": "8000001", |
| | | "staNo": "1005" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "success", |
| | | "data": { |
| | | "locNo": "A100100101" |
| | | } |
| | | }</code></pre> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-priority', 'form')" id="task-priority-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-priority', 'json')" id="task-priority-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-priority-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>taskNo <span class="required">*</span></label> |
| | | <input type="text" id="task-priority-taskNo" placeholder="TASK20231220001" |
| | | value="TASK20231220001"> |
| | | <div class="error-msg" id="task-priority-taskNo-error">请输入任务编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>priority <span class="required">*</span></label> |
| | | <input type="text" id="task-priority-priority" placeholder="1-300" value="3"> |
| | | <div class="hint">优先级范围:1-300</div> |
| | | <div class="error-msg" id="task-priority-priority-error">请输入优先级(1-300)</div> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="task-priority-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-priority-json">{ |
| | | "taskNo": "TASK20231220001", |
| | | "priority": "3" |
| | | }</textarea> |
| | | <div class="error-msg" id="task-priority-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskPriority()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskPriorityForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-priority-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 库位状态修改 --> |
| | | <!-- <section id="api-loc-status" class="api-section"> |
| | | <h2>库位状态修改</h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>修改库位状态</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/loc/status/update</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>locCode</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>status</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>库位状态:0-禁用、1-启用、2-在库、3-空库位</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | "locCode": "A100100101", |
| | | "status": "0" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "库位状态修改成功" |
| | | }</code></pre> |
| | | |
| | | <div class="note"> |
| | | <div class="note-title">使用场景</div> |
| | | <p>• 临时封闭某个库位(维护、检修等)</p> |
| | | <p>• 库位异常时禁用</p> |
| | | <p>• 维护完成后重新启用库位</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button id="loc-status-form-btn" class="mode-btn active" |
| | | onclick="switchInputMode('loc-status', 'form')">表单输入 |
| | | </button> |
| | | <button id="loc-status-json-btn" class="mode-btn" onclick="switchInputMode('loc-status', 'json')"> |
| | | JSON输入 |
| | | </button> |
| | | </div> |
| | | <div class="form-input-container" id="loc-status-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>库位编码 <span class="required">*</span></label> |
| | | <input type="text" id="loc-status-locCode" placeholder="A100100101" value="A100100101"> |
| | | <span class="error-message" id="loc-status-locCode-error">请输入库位编码</span> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>状态 <span class="required">*</span></label> |
| | | <select id="loc-status-status"> |
| | | <option value="">请选择状态</option> |
| | | <option value="0">0 - 禁用</option> |
| | | <option value="1" selected>1 - 启用</option> |
| | | <option value="2">2 - 在库</option> |
| | | <option value="3">3 - 空库位</option> |
| | | </select> |
| | | <span class="error-message" id="loc-status-status-error">请选择状态</span> |
| | | </div> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockLocStatus()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetLocStatusForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="loc-status-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="loc-status-json" rows="8">{ |
| | | "locCode": "A100100101", |
| | | "status": "1" |
| | | }</textarea> |
| | | <span class="error-message" id="loc-status-json-error">请输入有效的JSON参数</span> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockLocStatus()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetLocStatusForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-loc-status-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> --> |
| | | |
| | | |
| | | <!-- 动态加载的接口内容 --> |
| | | <div id="api-container"> |
| | | <!-- 接口内容将通过JavaScript动态加载 --> |
| | | </div> |
| | | |
| | | <!-- 错误码说明 --> |
| | | <section id="error-codes" class="api-section"> |
| | |
| | | </div> |
| | | |
| | | <script> |
| | | // 验证任务创建参数 |
| | | function validateTaskCreate() { |
| | | let isValid = true; |
| | | // 动态加载API配置并渲染接口内容 |
| | | function loadApiConfigs() { |
| | | try { |
| | | // 直接定义API配置数据,避免CORS错误 |
| | | const apiConfigs = [ |
| | | { |
| | | "apiId": "api-task-create", |
| | | "name": "生成任务单", |
| | | "description": "创建搬运任务", |
| | | "isCommon": true, |
| | | "method": "POST", |
| | | "url": "/api/open/bus/submit", |
| | | "menu": { |
| | | "category": "任务管理", |
| | | "order": 1 |
| | | }, |
| | | "request": { |
| | | "parameters": [ |
| | | { |
| | | "name": "batchNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "批次编号(上层系统生成,唯一标识)", |
| | | "default": "122334" |
| | | }, |
| | | { |
| | | "name": "tasks", |
| | | "type": "array", |
| | | "required": true, |
| | | "description": "任务数组,包含具体的任务详情", |
| | | "items": [ |
| | | { |
| | | "name": "taskNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "任务编号(上层系统生成,唯一标识)", |
| | | "default": "TASK20231220001" |
| | | }, |
| | | { |
| | | "name": "oriSta", |
| | | "type": "string", |
| | | "required": false, |
| | | "description": "起点站点编号" |
| | | }, |
| | | { |
| | | "name": "destSta", |
| | | "type": "string", |
| | | "required": false, |
| | | "description": "终点站点编号" |
| | | }, |
| | | { |
| | | "name": "oriLoc", |
| | | "type": "string", |
| | | "required": false, |
| | | "description": "起点库位编号" |
| | | }, |
| | | { |
| | | "name": "destLoc", |
| | | "type": "string", |
| | | "required": false, |
| | | "description": "终点库位编号" |
| | | }, |
| | | { |
| | | "name": "priority", |
| | | "type": "int", |
| | | "required": false, |
| | | "description": "优先级:1-300,默认为1", |
| | | "default": 1 |
| | | } |
| | | ] |
| | | } |
| | | ], |
| | | "example": { |
| | | "batchNo": "122334", |
| | | "tasks": [ |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriLoc": "A100100101", |
| | | "destSta": "STA001", |
| | | "priority": 1 |
| | | }, |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriSta": "STA002", |
| | | "destLoc": "B02-03-05", |
| | | "priority": 2 |
| | | } |
| | | ] |
| | | } |
| | | }, |
| | | "response": { |
| | | "parameters": [ |
| | | { |
| | | "name": "code", |
| | | "type": "integer", |
| | | "description": "返回编号,200表示成功,1~N表示失败" |
| | | }, |
| | | { |
| | | "name": "message", |
| | | "type": "string", |
| | | "description": "返回消息,请求成功表示成功,内容为详细的错误描述" |
| | | }, |
| | | { |
| | | "name": "data", |
| | | "type": "object", |
| | | "description": "返回的数据结构" |
| | | }, |
| | | { |
| | | "name": "timestamp", |
| | | "type": "integer", |
| | | "description": "时间戳" |
| | | } |
| | | ], |
| | | "example": { |
| | | "code": 200, |
| | | "message": "任务创建成功", |
| | | "data": { |
| | | "taskNo": "TASK20231220001", |
| | | "taskId": "T1234567890", |
| | | "status": "ASSIGN" |
| | | }, |
| | | "timestamp": 1671526800000 |
| | | } |
| | | } |
| | | }, |
| | | { |
| | | "apiId": "api-task-cancel", |
| | | "name": "取消任务", |
| | | "description": "取消搬运任务", |
| | | "isCommon": false, |
| | | "method": "POST", |
| | | "url": "/api/open/bus/cancel", |
| | | "menu": { |
| | | "category": "任务管理", |
| | | "order": 2 |
| | | }, |
| | | "request": { |
| | | "parameters": [ |
| | | { |
| | | "name": "taskNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "任务编号", |
| | | "default": "TASK20231220001" |
| | | } |
| | | ], |
| | | "example": { |
| | | "taskNo": "TASK20231220001" |
| | | } |
| | | }, |
| | | "response": { |
| | | "parameters": [ |
| | | { |
| | | "name": "code", |
| | | "type": "integer", |
| | | "description": "返回编号,200表示成功,1~N表示失败" |
| | | }, |
| | | { |
| | | "name": "message", |
| | | "type": "string", |
| | | "description": "返回消息,请求成功表示成功,内容为详细的错误描述" |
| | | }, |
| | | { |
| | | "name": "timestamp", |
| | | "type": "integer", |
| | | "description": "时间戳" |
| | | } |
| | | ], |
| | | "example": { |
| | | "code": 200, |
| | | "message": "任务取消成功", |
| | | "timestamp": 1671526800000 |
| | | } |
| | | } |
| | | }, |
| | | { |
| | | "apiId": "api-task-allocate", |
| | | "name": "申请入库接口", |
| | | "description": "申请任务入库", |
| | | "isCommon": true, |
| | | "method": "POST", |
| | | "url": "/api/open/task/allocate", |
| | | "menu": { |
| | | "category": "任务管理", |
| | | "order": 3 |
| | | }, |
| | | "request": { |
| | | "parameters": [ |
| | | { |
| | | "name": "staNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "站点编号", |
| | | "default": "1001" |
| | | }, |
| | | { |
| | | "name": "barcode", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "托盘码", |
| | | "default": "80000001" |
| | | } |
| | | ], |
| | | "example": { |
| | | "staNo": "1001", |
| | | "barcode": "80000001" |
| | | } |
| | | }, |
| | | "response": { |
| | | "parameters": [ |
| | | { |
| | | "name": "code", |
| | | "type": "integer", |
| | | "description": "返回编号,200表示成功,1~N表示失败" |
| | | }, |
| | | { |
| | | "name": "message", |
| | | "type": "string", |
| | | "description": "返回消息,请求成功表示成功,内容为详细的错误描述" |
| | | }, |
| | | { |
| | | "name": "data", |
| | | "type": "object", |
| | | "description": "返回的数据结构" |
| | | }, |
| | | { |
| | | "name": "timestamp", |
| | | "type": "integer", |
| | | "description": "时间戳" |
| | | } |
| | | ], |
| | | "example": { |
| | | "code": 200, |
| | | "message": "申请入库成功", |
| | | "data": { |
| | | "taskNo": "TASK20231220001", |
| | | "locNo": "A100100101", |
| | | "batchNo": "TASK20231220001" |
| | | }, |
| | | "timestamp": 1671526800000 |
| | | } |
| | | } |
| | | }, |
| | | { |
| | | "apiId": "api-task-notice", |
| | | "name": "任务状态通知", |
| | | "description": "通知任务状态变更", |
| | | "isCommon": false, |
| | | "method": "POST", |
| | | "url": "/api/open/bus/notice", |
| | | "menu": { |
| | | "category": "任务管理", |
| | | "order": 4 |
| | | }, |
| | | "request": { |
| | | "parameters": [ |
| | | { |
| | | "name": "taskNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "任务编号", |
| | | "default": "TASK20231220001" |
| | | }, |
| | | { |
| | | "name": "status", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "任务状态", |
| | | "default": "COMPLETE" |
| | | } |
| | | ], |
| | | "example": { |
| | | "taskNo": "TASK20231220001", |
| | | "status": "COMPLETE" |
| | | } |
| | | }, |
| | | "response": { |
| | | "parameters": [ |
| | | { |
| | | "name": "code", |
| | | "type": "integer", |
| | | "description": "返回编号,200表示成功,1~N表示失败" |
| | | }, |
| | | { |
| | | "name": "message", |
| | | "type": "string", |
| | | "description": "返回消息,请求成功表示成功,内容为详细的错误描述" |
| | | }, |
| | | { |
| | | "name": "timestamp", |
| | | "type": "integer", |
| | | "description": "时间戳" |
| | | } |
| | | ], |
| | | "example": { |
| | | "code": 200, |
| | | "message": "状态通知成功", |
| | | "timestamp": 1671526800000 |
| | | } |
| | | } |
| | | }, |
| | | { |
| | | "apiId": "api-task-priority", |
| | | "name": "任务优先级调整", |
| | | "description": "调整任务优先级", |
| | | "isCommon": false, |
| | | "method": "POST", |
| | | "url": "/api/open/bus/priority", |
| | | "menu": { |
| | | "category": "任务管理", |
| | | "order": 5 |
| | | }, |
| | | "request": { |
| | | "parameters": [ |
| | | { |
| | | "name": "taskNo", |
| | | "type": "string", |
| | | "required": true, |
| | | "description": "任务编号", |
| | | "default": "TASK20231220001" |
| | | }, |
| | | { |
| | | "name": "priority", |
| | | "type": "int", |
| | | "required": true, |
| | | "description": "优先级:1-300", |
| | | "default": 10 |
| | | } |
| | | ], |
| | | "example": { |
| | | "taskNo": "TASK20231220001", |
| | | "priority": 10 |
| | | } |
| | | }, |
| | | "response": { |
| | | "parameters": [ |
| | | { |
| | | "name": "code", |
| | | "type": "integer", |
| | | "description": "返回编号,200表示成功,1~N表示失败" |
| | | }, |
| | | { |
| | | "name": "message", |
| | | "type": "string", |
| | | "description": "返回消息,请求成功表示成功,内容为详细的错误描述" |
| | | }, |
| | | { |
| | | "name": "timestamp", |
| | | "type": "integer", |
| | | "description": "时间戳" |
| | | } |
| | | ], |
| | | "example": { |
| | | "code": 200, |
| | | "message": "优先级调整成功", |
| | | "timestamp": 1671526800000 |
| | | } |
| | | } |
| | | } |
| | | ]; |
| | | |
| | | const taskNo = document.getElementById('task-create-taskNo'); |
| | | const taskType = document.getElementById('task-create-taskType'); |
| | | const oriSta = document.getElementById('task-create-oriSta'); |
| | | const destSta = document.getElementById('task-create-destSta'); |
| | | const oriLoc = document.getElementById('task-create-oriLoc'); |
| | | const destLoc = document.getElementById('task-create-destLoc'); |
| | | // 渲染接口内容 |
| | | const apiContainer = document.getElementById('api-container'); |
| | | apiContainer.innerHTML = ''; |
| | | |
| | | const taskNoError = document.getElementById('task-create-taskNo-error'); |
| | | const taskTypeError = document.getElementById('task-create-taskType-error'); |
| | | apiConfigs.forEach(config => { |
| | | apiContainer.appendChild(renderApiSection(config)); |
| | | }); |
| | | |
| | | taskNo.classList.remove('error'); |
| | | taskType.classList.remove('error'); |
| | | oriSta.classList.remove('error'); |
| | | destSta.classList.remove('error'); |
| | | oriLoc.classList.remove('error'); |
| | | destLoc.classList.remove('error'); |
| | | |
| | | taskNoError.classList.remove('show'); |
| | | taskTypeError.classList.remove('show'); |
| | | |
| | | if (!taskNo.value.trim()) { |
| | | taskNo.classList.add('error'); |
| | | taskNoError.classList.add('show'); |
| | | isValid = false; |
| | | } catch (error) { |
| | | console.error('Failed to load API configs:', error); |
| | | } |
| | | |
| | | if (!taskType.value) { |
| | | taskType.classList.add('error'); |
| | | taskTypeError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | const taskTypeValue = parseInt(taskType.value); |
| | | if (taskTypeValue === 1 || taskTypeValue === 3) { |
| | | if (!oriLoc.value.trim()) { |
| | | oriLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 2 || taskTypeValue === 4) { |
| | | if (!oriSta.value.trim()) { |
| | | oriSta.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 1 || taskTypeValue === 4) { |
| | | if (!destSta.value.trim()) { |
| | | destSta.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 2 || taskTypeValue === 3) { |
| | | if (!destLoc.value.trim()) { |
| | | destLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | |
| | | if (oriLoc.value.trim() && destLoc.value.trim() && oriLoc.value.trim() === destLoc.value.trim()) { |
| | | oriLoc.classList.add('error'); |
| | | destLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务创建表单 |
| | | function resetTaskCreateForm() { |
| | | document.getElementById('task-create-taskNo').value = 'TASK20231220001'; |
| | | document.getElementById('task-create-batchNo').value = '122334'; |
| | | document.getElementById('task-create-taskType').value = '1'; |
| | | document.getElementById('task-create-oriSta').value = ''; |
| | | document.getElementById('task-create-destSta').value = 'STA001'; |
| | | document.getElementById('task-create-oriLoc').value = 'A100100101'; |
| | | document.getElementById('task-create-destLoc').value = ''; |
| | | document.getElementById('task-create-priority').value = '1'; |
| | | // 渲染单个API章节 |
| | | function renderApiSection(config) { |
| | | const section = document.createElement('section'); |
| | | section.id = config.apiId; |
| | | section.className = 'api-section'; |
| | | |
| | | syncFormToJson('task-create'); |
| | | // 标题 |
| | | const h2 = document.createElement('h2'); |
| | | h2.textContent = config.name + (config.isCommon ? '*' : ''); |
| | | if (config.isCommon) { |
| | | const tag = document.createElement('span'); |
| | | tag.className = 'tag'; |
| | | tag.textContent = '常用'; |
| | | h2.appendChild(tag); |
| | | } |
| | | section.appendChild(h2); |
| | | |
| | | const inputs = document.querySelectorAll('#task-create-taskNo, #task-create-batchNo, #task-create-taskType, #task-create-oriSta, #task-create-destSta, #task-create-oriLoc, #task-create-destLoc'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | // API信息 |
| | | const apiInfo = document.createElement('div'); |
| | | apiInfo.className = 'api-info'; |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-create-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-create-taskNo-error') error.textContent = '请输入任务编号'; |
| | | if (error.id === 'task-create-taskType-error') error.textContent = '请选择任务类型'; |
| | | // API方法和描述 |
| | | const h3 = document.createElement('h3'); |
| | | const methodSpan = document.createElement('span'); |
| | | methodSpan.className = `api-method method-${config.method.toLowerCase()}`; |
| | | methodSpan.textContent = config.method; |
| | | h3.appendChild(methodSpan); |
| | | const descSpan = document.createElement('span'); |
| | | descSpan.textContent = ' ' + config.description; |
| | | h3.appendChild(descSpan); |
| | | apiInfo.appendChild(h3); |
| | | |
| | | // API URL |
| | | const apiUrl = document.createElement('div'); |
| | | apiUrl.className = 'api-url'; |
| | | apiUrl.textContent = config.url; |
| | | apiInfo.appendChild(apiUrl); |
| | | |
| | | // 请求参数 |
| | | if (config.request && config.request.parameters) { |
| | | const h4 = document.createElement('h4'); |
| | | h4.textContent = '请求参数'; |
| | | apiInfo.appendChild(h4); |
| | | |
| | | const table = document.createElement('table'); |
| | | const thead = document.createElement('thead'); |
| | | const headerRow = document.createElement('tr'); |
| | | headerRow.innerHTML = ` |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | `; |
| | | thead.appendChild(headerRow); |
| | | table.appendChild(thead); |
| | | |
| | | const tbody = document.createElement('tbody'); |
| | | config.request.parameters.forEach(param => { |
| | | const row = document.createElement('tr'); |
| | | row.innerHTML = ` |
| | | <td><code>${param.name}</code></td> |
| | | <td>${param.type}</td> |
| | | <td><span style="color: ${param.required ? '#f93e3e; font-weight: bold;' : '#999;'};">${param.required ? '是' : '否'}</span></td> |
| | | <td>${param.description}</td> |
| | | `; |
| | | tbody.appendChild(row); |
| | | |
| | | // 如果是数组类型,渲染数组元素参数 |
| | | if (param.type === 'array' && param.items) { |
| | | const h4Items = document.createElement('h4'); |
| | | h4Items.textContent = `${param.name}数组元素参数`; |
| | | apiInfo.appendChild(h4Items); |
| | | |
| | | const tableItems = document.createElement('table'); |
| | | const theadItems = document.createElement('thead'); |
| | | const headerRowItems = document.createElement('tr'); |
| | | headerRowItems.innerHTML = ` |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | `; |
| | | theadItems.appendChild(headerRowItems); |
| | | tableItems.appendChild(theadItems); |
| | | |
| | | const tbodyItems = document.createElement('tbody'); |
| | | param.items.forEach(itemParam => { |
| | | const rowItem = document.createElement('tr'); |
| | | rowItem.innerHTML = ` |
| | | <td><code>${itemParam.name}</code></td> |
| | | <td>${itemParam.type}</td> |
| | | <td><span style="color: ${itemParam.required ? '#f93e3e; font-weight: bold;' : '#999;'};">${itemParam.required ? '是' : '否'}</span></td> |
| | | <td>${itemParam.description}</td> |
| | | `; |
| | | tbodyItems.appendChild(rowItem); |
| | | }); |
| | | tableItems.appendChild(tbodyItems); |
| | | apiInfo.appendChild(tableItems); |
| | | } |
| | | }); |
| | | table.appendChild(tbody); |
| | | apiInfo.appendChild(table); |
| | | } |
| | | |
| | | // 请求示例 |
| | | if (config.request && config.request.example) { |
| | | const h4 = document.createElement('h4'); |
| | | h4.textContent = '请求示例'; |
| | | apiInfo.appendChild(h4); |
| | | |
| | | const pre = document.createElement('pre'); |
| | | const code = document.createElement('code'); |
| | | code.textContent = JSON.stringify(config.request.example, null, 2); |
| | | pre.appendChild(code); |
| | | apiInfo.appendChild(pre); |
| | | } |
| | | |
| | | // 返回示例 |
| | | if (config.response && config.response.example) { |
| | | const h4 = document.createElement('h4'); |
| | | h4.textContent = '返回示例'; |
| | | apiInfo.appendChild(h4); |
| | | |
| | | const pre = document.createElement('pre'); |
| | | const code = document.createElement('code'); |
| | | code.textContent = JSON.stringify(config.response.example, null, 2); |
| | | pre.appendChild(code); |
| | | apiInfo.appendChild(pre); |
| | | } |
| | | |
| | | section.appendChild(apiInfo); |
| | | |
| | | // Mock测试 |
| | | if (config.mock) { |
| | | const mockContainer = document.createElement('div'); |
| | | mockContainer.className = 'mock-container'; |
| | | |
| | | const h4 = document.createElement('h4'); |
| | | h4.textContent = 'Mock 测试'; |
| | | mockContainer.appendChild(h4); |
| | | |
| | | const toggleBtn = document.createElement('button'); |
| | | toggleBtn.className = 'mock-toggle-btn'; |
| | | toggleBtn.onclick = function() { toggleMockContent(this); }; |
| | | toggleBtn.textContent = '展开'; |
| | | mockContainer.appendChild(toggleBtn); |
| | | |
| | | const mockContent = document.createElement('div'); |
| | | mockContent.className = 'mock-content collapsed'; |
| | | |
| | | // 模式切换 |
| | | const modeSwitch = document.createElement('div'); |
| | | modeSwitch.className = 'mode-switch'; |
| | | |
| | | const formBtn = document.createElement('button'); |
| | | formBtn.className = 'active'; |
| | | formBtn.onclick = function() { switchInputMode(config.apiId.replace('api-', ''), 'form'); }; |
| | | formBtn.id = `${config.apiId.replace('api-', '')}-form-btn`; |
| | | formBtn.textContent = '表单输入'; |
| | | modeSwitch.appendChild(formBtn); |
| | | |
| | | const jsonBtn = document.createElement('button'); |
| | | jsonBtn.onclick = function() { switchInputMode(config.apiId.replace('api-', ''), 'json'); }; |
| | | jsonBtn.id = `${config.apiId.replace('api-', '')}-json-btn`; |
| | | jsonBtn.textContent = 'JSON输入'; |
| | | modeSwitch.appendChild(jsonBtn); |
| | | |
| | | mockContent.appendChild(modeSwitch); |
| | | |
| | | // Mock表单 |
| | | const mockForm = document.createElement('div'); |
| | | mockForm.className = 'mock-form'; |
| | | |
| | | // 表单输入容器 |
| | | const formContainer = document.createElement('div'); |
| | | formContainer.className = 'form-input-container'; |
| | | formContainer.id = `${config.apiId.replace('api-', '')}-form-container`; |
| | | |
| | | const h5 = document.createElement('h5'); |
| | | h5.textContent = '请求参数'; |
| | | formContainer.appendChild(h5); |
| | | |
| | | // 渲染表单字段 |
| | | if (config.mock.formFields) { |
| | | config.mock.formFields.forEach(field => { |
| | | const formGroup = document.createElement('div'); |
| | | formGroup.className = 'form-group'; |
| | | |
| | | const label = document.createElement('label'); |
| | | label.textContent = field.label + (field.required ? ' <span class="required">*</span>' : ''); |
| | | formGroup.appendChild(label); |
| | | |
| | | if (field.type === 'select') { |
| | | const select = document.createElement('select'); |
| | | select.id = `${config.apiId.replace('api-', '')}-${field.name}`; |
| | | if (field.options) { |
| | | field.options.forEach(option => { |
| | | const opt = document.createElement('option'); |
| | | opt.value = option.value; |
| | | opt.textContent = option.label; |
| | | if (option.value === field.default) { |
| | | opt.selected = true; |
| | | } |
| | | select.appendChild(opt); |
| | | }); |
| | | } |
| | | formGroup.appendChild(select); |
| | | } else { |
| | | const input = document.createElement('input'); |
| | | input.type = field.type; |
| | | input.id = `${config.apiId.replace('api-', '')}-${field.name}`; |
| | | input.placeholder = field.default || ''; |
| | | input.value = field.default || ''; |
| | | formGroup.appendChild(input); |
| | | } |
| | | |
| | | if (field.required) { |
| | | const errorMsg = document.createElement('div'); |
| | | errorMsg.className = 'error-msg'; |
| | | errorMsg.id = `${config.apiId.replace('api-', '')}-${field.name}-error`; |
| | | errorMsg.textContent = `请输入${field.label}`; |
| | | formGroup.appendChild(errorMsg); |
| | | } |
| | | |
| | | formContainer.appendChild(formGroup); |
| | | }); |
| | | } |
| | | |
| | | mockForm.appendChild(formContainer); |
| | | |
| | | // JSON输入容器 |
| | | const jsonContainer = document.createElement('div'); |
| | | jsonContainer.className = 'json-input-container'; |
| | | jsonContainer.id = `${config.apiId.replace('api-', '')}-json-container`; |
| | | |
| | | const h5Json = document.createElement('h5'); |
| | | h5Json.textContent = 'JSON输入'; |
| | | jsonContainer.appendChild(h5Json); |
| | | |
| | | const textarea = document.createElement('textarea'); |
| | | textarea.className = 'json-textarea'; |
| | | textarea.id = `${config.apiId.replace('api-', '')}-json`; |
| | | textarea.value = JSON.stringify(config.mock.jsonExample, null, 2); |
| | | jsonContainer.appendChild(textarea); |
| | | |
| | | const jsonError = document.createElement('div'); |
| | | jsonError.className = 'error-msg'; |
| | | jsonError.id = `${config.apiId.replace('api-', '')}-json-error`; |
| | | jsonError.textContent = '请输入有效的JSON格式'; |
| | | jsonContainer.appendChild(jsonError); |
| | | |
| | | mockForm.appendChild(jsonContainer); |
| | | |
| | | // 表单操作按钮 |
| | | const formActions = document.createElement('div'); |
| | | formActions.className = 'mock-form-actions'; |
| | | |
| | | const mockBtn = document.createElement('button'); |
| | | mockBtn.className = 'mock-btn'; |
| | | mockBtn.onclick = function() { mockApiRequest(config.apiId.replace('api-', ''), config); }; |
| | | mockBtn.textContent = '执行 Mock 请求'; |
| | | formActions.appendChild(mockBtn); |
| | | |
| | | const resetBtn = document.createElement('button'); |
| | | resetBtn.className = 'reset-btn'; |
| | | resetBtn.onclick = function() { resetApiForm(config.apiId.replace('api-', ''), config); }; |
| | | resetBtn.textContent = '重置'; |
| | | formActions.appendChild(resetBtn); |
| | | |
| | | mockForm.appendChild(formActions); |
| | | mockContent.appendChild(mockForm); |
| | | |
| | | // Mock结果 |
| | | const resultDiv = document.createElement('div'); |
| | | resultDiv.id = `mock-${config.apiId.replace('api-', '')}-result`; |
| | | resultDiv.className = 'mock-result'; |
| | | mockContent.appendChild(resultDiv); |
| | | |
| | | mockContainer.appendChild(mockContent); |
| | | section.appendChild(mockContainer); |
| | | } |
| | | |
| | | return section; |
| | | } |
| | | |
| | | // Mock API请求 |
| | | function mockApiRequest(apiId, config) { |
| | | let params; |
| | | const isJsonMode = document.getElementById(`${apiId}-json-container`).classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson(`${apiId}-json`); |
| | | if (!params) return; |
| | | } else { |
| | | const formParams = getParamsFromForm(apiId); |
| | | params = {}; |
| | | Object.keys(formParams).forEach(key => { |
| | | params[key] = formParams[key]; |
| | | }); |
| | | } |
| | | |
| | | const resultDiv = document.getElementById(`mock-${apiId}-result`); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | let response; |
| | | if (config.mock.responseTemplate) { |
| | | response = JSON.parse(JSON.stringify(config.mock.responseTemplate)); |
| | | // 替换模板变量 |
| | | if (response.data === '{{taskResults}}' && params.tasks && Array.isArray(params.tasks)) { |
| | | response.data = params.tasks.map(taskNo => ({ |
| | | taskNo: taskNo, |
| | | success: true, |
| | | msg: null |
| | | })); |
| | | } |
| | | if (response.data && response.data.taskNo === '{{taskNo}}') { |
| | | response.data.taskNo = params.taskNo; |
| | | } |
| | | if (response.data && response.data.taskId === '{{taskId}}') { |
| | | response.data.taskId = 'T' + Math.random().toString(36).substr(2, 10); |
| | | } |
| | | if (response.timestamp === '{{timestamp}}') { |
| | | response.timestamp = Date.now(); |
| | | } |
| | | } else { |
| | | response = { |
| | | code: 200, |
| | | message: '请求成功' |
| | | }; |
| | | } |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;">✓ 请求成功</p> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | `; |
| | | }, 1000); |
| | | } |
| | | |
| | | // 重置API表单 |
| | | function resetApiForm(apiId, config) { |
| | | // 重置表单字段 |
| | | const inputs = document.querySelectorAll(`#${apiId}-form-container input, #${apiId}-form-container select`); |
| | | inputs.forEach(input => { |
| | | const fieldName = input.id.replace(`${apiId}-`, ''); |
| | | const fieldConfig = config.mock.formFields.find(f => f.name === fieldName); |
| | | if (fieldConfig) { |
| | | input.value = fieldConfig.default || ''; |
| | | } |
| | | input.classList.remove('error'); |
| | | }); |
| | | |
| | | document.getElementById('mock-task-create-result').classList.remove('show'); |
| | | document.getElementById('mock-task-create-result').innerHTML = ''; |
| | | // 重置JSON输入 |
| | | const textarea = document.getElementById(`${apiId}-json`); |
| | | if (textarea) { |
| | | textarea.value = JSON.stringify(config.mock.jsonExample, null, 2); |
| | | } |
| | | |
| | | const jsonError = document.getElementById('task-create-json-error'); |
| | | if (jsonError) jsonError.classList.remove('show'); |
| | | |
| | | // 隐藏错误信息 |
| | | const errors = document.querySelectorAll(`[id^="${apiId}-"][id$="-error"]`); |
| | | errors.forEach(error => error.classList.remove('show')); |
| | | |
| | | const resultDiv = document.getElementById('mock-task-create-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | // 隐藏结果 |
| | | const resultDiv = document.getElementById(`mock-${apiId}-result`); |
| | | if (resultDiv) { |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | } |
| | | |
| | | // 页面加载完成后加载API配置 |
| | | window.addEventListener('DOMContentLoaded', loadApiConfigs); |
| | | |
| | | // 切换Mock内容展开/折叠 |
| | | function toggleMockContent(element) { |
| | | const mockContent = element.nextElementSibling; |
| | | if (mockContent) { |
| | | mockContent.classList.toggle('collapsed'); |
| | | mockContent.classList.toggle('expanded'); |
| | | element.textContent = mockContent.classList.contains('expanded') ? '收起' : '展开'; |
| | | } |
| | | } |
| | | |
| | | // 切换输入模式 |
| | |
| | | const jsonContainer = document.getElementById(`${formId}-json-container`); |
| | | |
| | | if (mode === 'form') { |
| | | syncJsonToForm(formId); |
| | | formBtn.classList.add('active'); |
| | | jsonBtn.classList.remove('active'); |
| | | formContainer.classList.remove('hidden'); |
| | | jsonContainer.classList.remove('active'); |
| | | } else { |
| | | syncFormToJson(formId); |
| | | formBtn.classList.remove('active'); |
| | | jsonBtn.classList.add('active'); |
| | | formContainer.classList.add('hidden'); |
| | | jsonContainer.classList.add('active'); |
| | | } |
| | | } |
| | | |
| | | function syncFormToJson(formId) { |
| | | let params; |
| | | if (formId === 'task-create') { |
| | | // 对于任务创建表单,使用新的数组格式 |
| | | const formParams = getParamsFromForm(formId); |
| | | params = { |
| | | taskNo: formParams.taskNo, |
| | | batchNo: formParams.batchNo || '122334', |
| | | tasks: [{ |
| | | taskType: formParams.taskType, |
| | | oriSta: formParams.oriSta, |
| | | destSta: formParams.destSta, |
| | | oriLoc: formParams.oriLoc, |
| | | destLoc: formParams.destLoc, |
| | | priority: formParams.priority ? parseInt(formParams.priority) : 1 |
| | | }] |
| | | }; |
| | | } else if (formId === 'task-cancel') { |
| | | // 对于任务取消表单,使用tasks数组格式 |
| | | const formParams = getParamsFromForm(formId); |
| | | params = { |
| | | batchNo: formParams.batchNo || '12345', |
| | | tasks: formParams.tasks.split(',').map(task => task.trim()) |
| | | }; |
| | | } else { |
| | | // 对于其他表单,使用原有的格式 |
| | | params = getParamsFromForm(formId); |
| | | } |
| | | const textarea = document.getElementById(`${formId}-json`); |
| | | if (textarea) { |
| | | textarea.value = JSON.stringify(params, null, 2); |
| | | } |
| | | } |
| | | |
| | | function syncJsonToForm(formId) { |
| | | const textarea = document.getElementById(`${formId}-json`); |
| | | if (!textarea) return; |
| | | |
| | | try { |
| | | const params = JSON.parse(textarea.value); |
| | | const inputs = document.querySelectorAll(`#${formId}-form-container input, #${formId}-form-container select`); |
| | | |
| | | if (formId === 'task-create' && params.tasks && Array.isArray(params.tasks) && params.tasks.length > 0) { |
| | | // 对于任务创建表单,从tasks数组中获取第一个任务的数据 |
| | | const task = params.tasks[0]; |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } else if (task[key] !== undefined) { |
| | | input.value = task[key]; |
| | | } |
| | | }); |
| | | } else if (formId === 'task-cancel' && params.tasks && Array.isArray(params.tasks)) { |
| | | // 对于任务取消表单,将tasks数组转换为逗号分隔的字符串 |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (key === 'tasks') { |
| | | input.value = params.tasks.join(', '); |
| | | } else if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } |
| | | }); |
| | | } else { |
| | | // 对于其他表单,使用原有的逻辑 |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } |
| | | }); |
| | | } |
| | | } catch (e) { |
| | | console.error('JSON解析失败,无法同步到表单', e); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 验证任务创建JSON参数 |
| | | function validateTaskCreateJson(params) { |
| | | const errorDiv = document.getElementById('task-create-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.taskNo || !params.taskNo.trim()) { |
| | | errorDiv.textContent = 'taskNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.batchNo || !params.batchNo.trim()) { |
| | | errorDiv.textContent = 'batchNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.tasks || !Array.isArray(params.tasks)) { |
| | | errorDiv.textContent = 'tasks必须是数组格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (params.tasks.length === 0) { |
| | | errorDiv.textContent = 'tasks数组不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | // 验证tasks数组中的每个任务 |
| | | for (let i = 0; i < params.tasks.length; i++) { |
| | | const task = params.tasks[i]; |
| | | if (!task || typeof task !== 'object') { |
| | | errorDiv.textContent = `tasks数组第${i+1}个元素必须是对象`; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | // 验证起点和终点 |
| | | if (task.oriLoc && task.destLoc && task.oriLoc.trim() === task.destLoc.trim()) { |
| | | errorDiv.textContent = `tasks数组第${i+1}个元素的起点库位和终点库位不能相同`; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 生成任务单 |
| | | function mockTaskCreate() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-create-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-create-json'); |
| | | if (!params) return; |
| | | if (!validateTaskCreateJson(params)) return; |
| | | } else { |
| | | // 从表单获取参数并转换为新的数组格式 |
| | | const formParams = getParamsFromForm('task-create'); |
| | | params = { |
| | | taskNo: formParams.taskNo, |
| | | batchNo: formParams.batchNo || '122334', |
| | | tasks: [{ |
| | | taskType: formParams.taskType, |
| | | oriSta: formParams.oriSta, |
| | | destSta: formParams.destSta, |
| | | oriLoc: formParams.oriLoc, |
| | | destLoc: formParams.destLoc, |
| | | priority: formParams.priority ? parseInt(formParams.priority) : 1 |
| | | }] |
| | | }; |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-create-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const response = { |
| | | code: 200, |
| | | message: "任务创建成功", |
| | | data: { |
| | | taskNo: params.taskNo, |
| | | batchNo: params.batchNo, |
| | | taskId: "T" + Math.random().toString(36).substr(2, 10), |
| | | status: "ASSIGN", |
| | | taskCount: params.tasks.length |
| | | }, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(params, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #fff; border-radius: 8px; border: 2px solid #49cc90;">🎯 成功创建 ${params.tasks.length} 个搬运任务,等待分配机器人执行</p> |
| | | `; |
| | | }, 800); |
| | | } |
| | | |
| | | // 验证任务取消参数 |
| | | function validateTaskCancel() { |
| | | let isValid = true; |
| | | |
| | | const tasks = document.getElementById('task-cancel-tasks'); |
| | | |
| | | const tasksError = document.getElementById('task-cancel-tasks-error'); |
| | | |
| | | tasks.classList.remove('error'); |
| | | |
| | | tasksError.classList.remove('show'); |
| | | |
| | | if (!tasks.value.trim()) { |
| | | tasks.classList.add('error'); |
| | | tasksError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务取消表单 |
| | | function resetTaskCancelForm() { |
| | | document.getElementById('task-cancel-tasks').value = 'TASK20231220001,TASK20231220002'; |
| | | document.getElementById('task-cancel-batchNo').value = '12345'; |
| | | |
| | | syncFormToJson('task-cancel'); |
| | | |
| | | const inputs = document.querySelectorAll('#task-cancel-tasks'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-cancel-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-cancel-tasks-error') error.textContent = '请输入要取消的任务编号'; |
| | | }); |
| | | |
| | | const resultDiv = document.getElementById('mock-task-cancel-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | |
| | | // 验证任务取消JSON参数 |
| | | function validateTaskCancelJson(params) { |
| | | const errorDiv = document.getElementById('task-cancel-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.tasks || !Array.isArray(params.tasks) || params.tasks.length === 0) { |
| | | errorDiv.textContent = 'tasks必须是非空数组'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 取消任务 |
| | | function mockTaskCancel() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-cancel-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-cancel-json'); |
| | | if (!params) return; |
| | | if (!validateTaskCancelJson(params)) return; |
| | | } else { |
| | | if (!validateTaskCancel()) return; |
| | | const formParams = getParamsFromForm('task-cancel'); |
| | | // 将逗号分隔的任务编号字符串转换为数组 |
| | | params = { |
| | | tasks: formParams.tasks.split(',').map(task => task.trim()), |
| | | batchNo: formParams.batchNo |
| | | }; |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-cancel-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | // 生成每个任务的取消结果 |
| | | const data = params.tasks.map(taskNo => { |
| | | // 模拟随机的取消结果 |
| | | const success = Math.random() > 0.2; // 80%的概率成功 |
| | | return { |
| | | taskNo: taskNo, |
| | | success: success, |
| | | msg: success ? null : `${taskNo} 不存在或无法取消` |
| | | }; |
| | | }); |
| | | |
| | | const response = { |
| | | code: 200, |
| | | msg: "任务取消成功", |
| | | data: data, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(params, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #4caf50;">✅ 任务取消请求已处理,共取消 ${params.tasks.length} 个任务</p> |
| | | `; |
| | | }, 1000); |
| | | } |
| | | |
| | | // Mock 任务执行通知 |
| | | function mockTaskNotice() { |
| | | const callbackUrl = document.getElementById('task-notice-callback-url'); |
| | | |
| | | if (!callbackUrl.value.trim()) { |
| | | callbackUrl.classList.add('error'); |
| | | document.getElementById('task-notice-callback-url-error').classList.add('show'); |
| | | return; |
| | | } else { |
| | | callbackUrl.classList.remove('error'); |
| | | document.getElementById('task-notice-callback-url-error').classList.remove('show'); |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-notice-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | const pushData = { |
| | | taskNo: "TASK20231220001", |
| | | robotCode: "AGV" + Math.floor(Math.random() * 10 + 1).toString().padStart(3, '0'), |
| | | finishTime: new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(/\//g, '-') |
| | | }; |
| | | |
| | | fetch(callbackUrl.value.trim(), { |
| | | method: 'POST', |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | }, |
| | | body: JSON.stringify(pushData) |
| | | }) |
| | | .then(response => { |
| | | if (!response.ok) { |
| | | throw new Error(`HTTP error! status: ${response.status}`); |
| | | } |
| | | return response.json(); |
| | | }) |
| | | .then(data => { |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(pushData, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(data, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;">🎯 任务执行通知已成功发送</p> |
| | | `; |
| | | }) |
| | | .catch(error => { |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #f44336; font-weight: bold;" class="error-icon">✖ 请求失败</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(pushData, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #f44336; padding: 10px; background: #ffebee; border-radius: 8px; border-left: 4px solid #f44336;"> |
| | | ❌ 错误信息:<strong>${error.message}</strong> |
| | | </p> |
| | | <p style="margin-top: 10px; color: #999; font-size: 12px;">提示:请确保回调地址可访问,且服务器已启动并支持CORS跨域请求</p> |
| | | `; |
| | | }); |
| | | } |
| | | |
| | | function resetTaskNoticeForm() { |
| | | document.getElementById('task-notice-callback-url').value = 'http://localhost:8080/api/callback'; |
| | | |
| | | document.getElementById('mock-task-notice-result').classList.remove('show'); |
| | | document.getElementById('mock-task-notice-result').innerHTML = ''; |
| | | |
| | | const inputs = document.querySelectorAll('#api-task-notice input'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | const errors = document.querySelectorAll('#api-task-notice .error-message'); |
| | | errors.forEach(error => error.classList.remove('show')); |
| | | } |
| | | |
| | | // 验证库位状态修改参数 |
| | | function validateLocStatus() { |
| | | let isValid = true; |
| | | const locCode = document.getElementById('loc-status-locCode'); |
| | | const status = document.getElementById('loc-status-status'); |
| | | |
| | | if (!locCode.value.trim()) { |
| | | locCode.classList.add('error'); |
| | | document.getElementById('loc-status-locCode-error').classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | locCode.classList.remove('error'); |
| | | document.getElementById('loc-status-locCode-error').classList.remove('show'); |
| | | } |
| | | |
| | | if (!status.value) { |
| | | status.classList.add('error'); |
| | | document.getElementById('loc-status-status-error').classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | status.classList.remove('error'); |
| | | document.getElementById('loc-status-status-error').classList.remove('show'); |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | function validateLocStatusJson(params) { |
| | | const errorDiv = document.getElementById('loc-status-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.locCode || !params.locCode.trim()) { |
| | | errorDiv.textContent = 'locCode不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.status || !params.status.toString().trim()) { |
| | | errorDiv.textContent = 'status不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } else { |
| | | const statusValue = params.status.toString().trim(); |
| | | if (!['0', '1', '2', '3'].includes(statusValue)) { |
| | | errorDiv.textContent = 'status必须是0-3之间的数字(0-禁用、1-启用、2-在库、3-空库位)'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // 重置库位状态修改表单 |
| | | function resetLocStatusForm() { |
| | | document.getElementById('loc-status-locCode').value = 'A100100101'; |
| | | document.getElementById('loc-status-status').value = '1'; |
| | | |
| | | syncFormToJson('loc-status'); |
| | | |
| | | document.getElementById('mock-loc-status-result').classList.remove('show'); |
| | | document.getElementById('mock-loc-status-result').innerHTML = ''; |
| | | |
| | | const inputs = document.querySelectorAll('#loc-status-form-container input, #loc-status-form-container select'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | const errors = document.querySelectorAll('#loc-status-form-container .error-message'); |
| | | errors.forEach(error => error.classList.remove('show')); |
| | | |
| | | const jsonError = document.getElementById('loc-status-json-error'); |
| | | if (jsonError) jsonError.classList.remove('show'); |
| | | } |
| | | |
| | | // 验证任务优先级参数 |
| | | function validateTaskPriority() { |
| | | let isValid = true; |
| | | |
| | | const taskNo = document.getElementById('task-priority-taskNo'); |
| | | const priority = document.getElementById('task-priority-priority'); |
| | | |
| | | const taskNoError = document.getElementById('task-priority-taskNo-error'); |
| | | const priorityError = document.getElementById('task-priority-priority-error'); |
| | | |
| | | taskNo.classList.remove('error'); |
| | | priority.classList.remove('error'); |
| | | |
| | | taskNoError.classList.remove('show'); |
| | | priorityError.classList.remove('show'); |
| | | |
| | | if (!taskNo.value.trim()) { |
| | | taskNo.classList.add('error'); |
| | | taskNoError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | if (!priority.value.trim()) { |
| | | priority.classList.add('error'); |
| | | priorityError.classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | const priorityNum = parseInt(priority.value.trim()); |
| | | if (isNaN(priorityNum) || priorityNum < 1 || priorityNum > 300) { |
| | | priority.classList.add('error'); |
| | | priorityError.textContent = '优先级必须是1-300的数字'; |
| | | priorityError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务优先级表单 |
| | | function resetTaskPriorityForm() { |
| | | document.getElementById('task-priority-taskNo').value = 'TASK20231220001'; |
| | | document.getElementById('task-priority-priority').value = '2'; |
| | | |
| | | syncFormToJson('task-priority'); |
| | | |
| | | const inputs = document.querySelectorAll('#task-priority-taskNo, #task-priority-priority'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-priority-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-priority-taskNo-error') error.textContent = '请输入任务编号'; |
| | | if (error.id === 'task-priority-priority-error') error.textContent = '请输入优先级(1-300)'; |
| | | }); |
| | | |
| | | const resultDiv = document.getElementById('mock-task-priority-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | |
| | | // 验证任务优先级JSON参数 |
| | | function validateTaskPriorityJson(params) { |
| | | const errorDiv = document.getElementById('task-priority-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.taskNo || !params.taskNo.trim()) { |
| | | errorDiv.textContent = 'taskNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.priority || !params.priority.toString().trim()) { |
| | | errorDiv.textContent = 'priority不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } else { |
| | | const priorityNum = parseInt(params.priority.toString().trim()); |
| | | if (isNaN(priorityNum) || priorityNum < 1 || priorityNum > 300) { |
| | | errorDiv.textContent = 'priority必须是1-300的数字'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 任务优先级设置 |
| | | function mockTaskPriority() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-priority-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-priority-json'); |
| | | if (!params) return; |
| | | if (!validateTaskPriorityJson(params)) return; |
| | | } else { |
| | | if (!validateTaskPriority()) return; |
| | | params = getParamsFromForm('task-priority'); |
| | | } |
| | | |
| | | const taskNo = params.taskNo; |
| | | const priority = params.priority; |
| | | |
| | | const resultDiv = document.getElementById('mock-task-priority-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const response = { |
| | | code: 200, |
| | | message: "请求成功", |
| | | data: { |
| | | taskNo: taskNo, |
| | | priority: priority |
| | | }, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | const priorityNum = parseInt(priority); |
| | | let priorityInfo; |
| | | if (priorityNum <= 100) { |
| | | priorityInfo = {text: '低', color: '#9e9e9e', icon: '⬇️'}; |
| | | } else if (priorityNum <= 200) { |
| | | priorityInfo = {text: '中', color: '#2196f3', icon: '➡️'}; |
| | | } else { |
| | | priorityInfo = {text: '高', color: '#f44336', icon: '⬆️'}; |
| | | } |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #f5f5f5; border-radius: 8px; border-left: 4px solid ${priorityInfo.color};"> |
| | | ${priorityInfo.icon} 任务优先级已设置为:<strong style="color: ${priorityInfo.color};">${priorityInfo.text}</strong> |
| | | </p> |
| | | `; |
| | | }, 600); |
| | | } |
| | | |
| | | // Mock 库位状态修改 |
| | | function mockLocStatus() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('loc-status-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('loc-status-json'); |
| | | if (!params) return; |
| | | if (!validateLocStatusJson(params)) return; |
| | | } else { |
| | | if (!validateLocStatus()) return; |
| | | params = getParamsFromForm('loc-status'); |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-loc-status-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const locCode = params.locCode; |
| | | const status = params.status; |
| | | |
| | | const response = { |
| | | code: 200, |
| | | message: "库位状态修改成功", |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | const statusMap = { |
| | | '0': {text: '禁用', color: '#f44336', icon: '🚫'}, |
| | | '1': {text: '启用', color: '#4caf50', icon: '✅'}, |
| | | '2': {text: '在库', color: '#ff9800', icon: '📦'}, |
| | | '3': {text: '空库位', color: '#2196f3', icon: '⬜'} |
| | | }; |
| | | |
| | | const statusInfo = statusMap[status]; |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #f5f5f5; border-radius: 8px; border-left: 4px solid ${statusInfo.color};"> |
| | | ${statusInfo.icon} 库位 <strong>${locCode}</strong> 状态:<strong style="color: ${statusInfo.color};">${statusInfo.text}</strong> |
| | | </p> |
| | | `; |
| | | }, 700); |
| | | } |
| | | |
| | | |
| | | |
| | | // 复制代码功能 |
| | | function copyCode(button) { |
| | | const codeBlock = button.nextElementSibling.querySelector('code'); |
| | | const text = codeBlock.textContent; |
| | | |
| | | navigator.clipboard.writeText(text).then(() => { |
| | | const originalText = button.innerHTML; |
| | | button.innerHTML = '✓ 已复制'; |
| | | button.style.background = 'rgba(73, 204, 144, 0.2)'; |
| | | button.style.borderColor = 'rgba(73, 204, 144, 0.4)'; |
| | | button.style.color = '#49cc90'; |
| | | |
| | | setTimeout(() => { |
| | | button.innerHTML = originalText; |
| | | button.style.background = 'rgba(255, 255, 255, 0.1)'; |
| | | button.style.borderColor = 'rgba(255, 255, 255, 0.2)'; |
| | | button.style.color = '#d4d4d4'; |
| | | }, 2000); |
| | | }).catch(err => { |
| | | console.error('复制失败:', err); |
| | | }); |
| | | } |
| | | |
| | | function toggleMockContent(button) { |
| | | const content = button.nextElementSibling; |
| | | if (content.classList.contains('expanded')) { |
| | | content.classList.remove('expanded'); |
| | | content.classList.add('collapsed'); |
| | | button.textContent = '展开'; |
| | | } else { |
| | | content.classList.remove('collapsed'); |
| | | content.classList.add('expanded'); |
| | | button.textContent = '折叠'; |
| | | } |
| | | } |
| | | |
| | | // 监听滚动消息 |
| | | window.addEventListener('message', function (event) { |
| | | // 监听来自父窗口的消息 |
| | | window.addEventListener('message', function(event) { |
| | | if (event.data.type === 'scrollToSection') { |
| | | const targetElement = document.getElementById(event.data.sectionId); |
| | | if (targetElement) { |
| | | targetElement.scrollIntoView({behavior: 'smooth', block: 'start'}); |
| | | const sectionId = event.data.sectionId; |
| | | const section = document.getElementById(sectionId); |
| | | if (section) { |
| | | section.scrollIntoView({ behavior: 'smooth' }); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | | </body> |
| | | </html> |
| | | </html> |