From b0327633d7d0c19693a4e577d1e17b3b22e8274e Mon Sep 17 00:00:00 2001
From: wanshenmean <cathay_xy@163.com>
Date: 星期日, 12 四月 2026 01:23:56 +0800
Subject: [PATCH] refactor(WCS&WMS): 新增手动下发输送线任务
---
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs | 35 ++
Code/docs/superpowers/specs/2026-04-11-manual-task-creation-design.md | 151 ++++++++
Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs | 83 ++++
Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs | 47 ++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs | 73 ++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs | 6
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs | 11
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue | 93 +++++
Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs | 7
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs | 17 +
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs | 9
Code/docs/superpowers/plans/2026-04-11-manual-task-creation-plan.md | 434 +++++++++++++++++++++++++
Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs | 14
Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js | 17
14 files changed, 989 insertions(+), 8 deletions(-)
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs
index 7df0366..7da55c0 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_ITaskInfoService/ITaskService.cs
@@ -61,6 +61,20 @@
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>
/// 鏍规嵁鎵樼洏鍙枫�佽捣濮嬪湴鍧�鍚慦MS璇锋眰浠诲姟
/// </summary>
/// <param name="palletCode">鎵樼洏鍙�</param>
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs
index 7515054..a027af3 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Server/Controllers/Task/TaskController.cs
@@ -25,6 +25,12 @@
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)
{
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
index 02204d3..ac3cb72 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_TaskInfoService/TaskService.cs
@@ -644,6 +644,41 @@
{
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
+ {
+ // 璋冪敤 ReceiveWMSTask 鍒涘缓 WCS 浠诲姟
+ content = ReceiveWMSTask(taskDTOs);
+ 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 &&
+ x.Creater == "WMS");
+ }
}
public enum ConveyorLineDBNameNew
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
index c016c47..0017804 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/CommonConveyorLineNewJob.cs
@@ -14,6 +14,7 @@
using WIDESEAWCS_Model.Models;
using WIDESEAWCS_QuartzJob;
using WIDESEAWCS_QuartzJob.Service;
+using ManualInboundTaskHandler = WIDESEAWCS_Tasks.ConveyorLineNewJob.ManualInbound.ManualInboundTaskHandler;
namespace WIDESEAWCS_Tasks
{
@@ -212,6 +213,22 @@
// 濡傛灉 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;
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
index 9f8828c..144ba00 100644
--- a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ConveyorLineDispatchHandler.cs
@@ -210,14 +210,13 @@
// 鏇存柊浠诲姟鐘舵�佸埌涓嬩竴闃舵锛堥�氬父鏄畬鎴愶級
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);
}
}
diff --git a/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs
new file mode 100644
index 0000000..2feaa88
--- /dev/null
+++ b/Code/WCS/WIDESEAWCS_Server/WIDESEAWCS_Tasks/ConveyorLineNewJob/ManualInbound/ManualInboundTaskHandler.cs
@@ -0,0 +1,73 @@
+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>
+ /// 璐熻矗澶勭悊鎵嬪姩鍒涘缓鐨勫叆搴撲换鍔★紝褰揚LC璇锋眰鍏ュ簱鏃讹紝鏍规嵁childDeviceCode鏌ユ壘浠诲姟骞跺啓鍏LC銆�
+ /// </remarks>
+ public class ManualInboundTaskHandler
+ {
+ /// <summary>
+ /// 浠诲姟鏈嶅姟
+ /// </summary>
+ private readonly ITaskService _taskService;
+
+ /// <summary>
+ /// 鏋勯�犲嚱鏁�
+ /// </summary>
+ /// <param name="taskService">浠诲姟鏈嶅姟</param>
+ public ManualInboundTaskHandler(ITaskService taskService)
+ {
+ _taskService = taskService;
+ }
+
+ /// <summary>
+ /// 鍐欏叆鎵嬪姩鍏ュ簱浠诲姟鍒癙LC
+ /// </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.TargetAddress ?? "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");
+ }
+ }
+ }
+}
diff --git a/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue b/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue
new file mode 100644
index 0000000..980044b
--- /dev/null
+++ b/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/extend/addManualTask.vue
@@ -0,0 +1,93 @@
+<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="璇疯緭鍏ヤ粨搴揑D"></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("璇疯緭鍏ヤ粨搴揑D");
+
+ 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>
diff --git a/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js b/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js
index 4e7fe7d..dde046b 100644
--- a/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js
+++ b/Code/WMS/WIDESEA_WMSClient/src/extension/taskinfo/task.js
@@ -1,11 +1,12 @@
//姝s鏂囦欢鏄敤鏉ヨ嚜瀹氫箟鎵╁睍涓氬姟浠g爜锛屽彲浠ユ墿灞曚竴浜涜嚜瀹氫箟椤甸潰鎴栬�呴噸鏂伴厤缃敓鎴愮殑浠g爜
+import addManualTask from './extend/addManualTask.vue'
let extension = {
components: {
//鏌ヨ鐣岄潰鎵╁睍缁勪欢
gridHeader: '',
- gridBody: '',
+ gridBody: addManualTask,
gridFooter: '',
//鏂板缓銆佺紪杈戝脊鍑烘鎵╁睍缁勪欢
modelHeader: '',
@@ -16,7 +17,18 @@
buttons: { view: [], box: [], detail: [] }, //鎵╁睍鐨勬寜閽�
methods: {
//涓嬮潰杩欎簺鏂规硶鍙互淇濈暀涔熷彲浠ュ垹闄�
- onInit() {
+ onInit() {
+ //娣诲姞"鎵嬪姩鍒涘缓浠诲姟"鎸夐挳
+ this.buttons.push({
+ name: '鎵嬪姩鍒涘缓浠诲姟',
+ icon: 'el-icon-plus',
+ type: 'primary',
+ value: 'ManualCreateTask',
+ onClick: () => {
+ this.$refs.gridBody.open();
+ }
+ });
+
let TaskHandCancelBtn = this.buttons.find(x => x.value == 'TaskHandCancel');
if (TaskHandCancelBtn) {
TaskHandCancelBtn.onClick = function () {
@@ -93,4 +105,3 @@
}
};
export default extension;
-
\ No newline at end of file
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs
new file mode 100644
index 0000000..b967a71
--- /dev/null
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_DTO/Task/CreateManualTaskDto.cs
@@ -0,0 +1,47 @@
+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;
+ }
+}
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
index 0287bb3..224ef16 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_ITaskInfoService/ITaskService.cs
@@ -160,6 +160,13 @@
/// <returns></returns>
Task<WebResponseContent> CreateRobotChangePalletTaskAsync(StockDTO stock);
+ /// <summary>
+ /// 鎵嬪姩鍒涘缓浠诲姟
+ /// </summary>
+ /// <param name="dto">鎵嬪姩鍒涘缓浠诲姟鍙傛暟</param>
+ /// <returns></returns>
+ Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto);
+
#region 鏋佸嵎搴撲换鍔℃ā鍧�
/// <summary>
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs
index 9aa52de..9c14375 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_TaskInfoService/TaskService_WCS.cs
@@ -876,6 +876,89 @@
}
}
+ /// <summary>
+ /// 鎵嬪姩鍒涘缓浠诲姟
+ /// </summary>
+ /// <param name="dto">鎵嬪姩鍒涘缓浠诲姟鍙傛暟</param>
+ /// <returns></returns>
+ public async Task<WebResponseContent> CreateManualTaskAsync(CreateManualTaskDto dto)
+ {
+ try
+ {
+ // 1. 鏍规嵁浠诲姟绫诲瀷瀛楃涓茬‘瀹� TaskType 鍜� TaskStatus
+ int taskType;
+ int taskStatus;
+ switch (dto.TaskType)
+ {
+ case "鍏ュ簱":
+ taskType = TaskTypeEnum.Inbound.GetHashCode();
+ taskStatus = TaskInStatusEnum.InNew.GetHashCode();
+ break;
+ case "鍑哄簱":
+ taskType = TaskTypeEnum.Outbound.GetHashCode();
+ taskStatus = TaskOutStatusEnum.OutNew.GetHashCode();
+ break;
+ case "绉诲簱":
+ taskType = TaskTypeEnum.Relocation.GetHashCode();
+ taskStatus = TaskRelocationStatusEnum.RelocationNew.GetHashCode();
+ break;
+ default:
+ return WebResponseContent.Instance.Error($"涓嶆敮鎸佺殑浠诲姟绫诲瀷: {dto.TaskType}");
+ }
+
+ // 2. 鐢熸垚浠诲姟鍙�
+ int taskNum = await BaseDal.GetTaskNo();
+
+ // 3. 鏋勫缓浠诲姟瀹炰綋
+ var task = new Dt_Task
+ {
+ TaskNum = taskNum,
+ PalletCode = dto.Barcode,
+ SourceAddress = dto.SourceAddress,
+ TargetAddress = dto.TargetAddress,
+ TaskType = taskType,
+ TaskStatus = taskStatus,
+ Grade = dto.Grade,
+ WarehouseId = dto.WarehouseId,
+ CurrentAddress = dto.SourceAddress,
+ NextAddress = dto.TargetAddress,
+ Creater = "manual",
+ CreateDate = DateTime.Now,
+ ModifyDate = DateTime.Now
+ };
+
+ // 4. 淇濆瓨鍒版暟鎹簱
+ var result = await BaseDal.AddDataAsync(task) > 0;
+ 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
+ };
+
+ var wcsResult = _httpClientHelper.Post<WebResponseContent>(
+ "http://localhost:9292/api/Task/ReceiveManualTask",
+ 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}");
+ }
+ }
+
#endregion WCS閫昏緫澶勭悊
}
}
\ No newline at end of file
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
index 764d061..c1494fa 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/TaskInfo/TaskController.cs
@@ -47,6 +47,17 @@
}
/// <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>
/// 鑾峰彇鍙叆搴撹揣浣�
/// </summary>
/// <param name="taskDto"></param>
diff --git a/Code/docs/superpowers/plans/2026-04-11-manual-task-creation-plan.md b/Code/docs/superpowers/plans/2026-04-11-manual-task-creation-plan.md
new file mode 100644
index 0000000..c1902be
--- /dev/null
+++ b/Code/docs/superpowers/plans/2026-04-11-manual-task-creation-plan.md
@@ -0,0 +1,434 @@
+# 鎵嬪姩鍒涘缓浠诲姟鍔熻兘瀹炴柦璁″垝
+
+> **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:** 鍦╓MS鐣岄潰涓婃坊鍔犳墜鍔ㄥ垱寤轰换鍔″姛鑳斤紝鏀寔鍏ュ簱/鍑哄簱/绉诲簱涓夌绫诲瀷锛屼换鍔″彂閫佽嚦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 宸叉湁鍒嗗彂閫昏緫锛岀‘璁ゅ叆鍙f纭� |
+| `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 鍏ュ彛姝g‘"
+```
+
+---
+
+### 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>
+/// 鍐欏叆杈撻�佺嚎浠诲姟鍒癙LC
+/// </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 鍚庣锛歊eceiveTask 鏀跺埌浠诲姟
+- [ ] WCS 鍚庣锛氳捣鐐逛负绾夸綋鐐逛綅鏃讹紝浠诲姟鍐欏叆 PLC 鎴愬姛
+- [ ] WCS 鍚庣锛氳捣鐐逛负鏅�氱偣浣嶆椂锛岃蛋鍘熸湁璺敱閫昏緫
diff --git a/Code/docs/superpowers/specs/2026-04-11-manual-task-creation-design.md b/Code/docs/superpowers/specs/2026-04-11-manual-task-creation-design.md
new file mode 100644
index 0000000..a2a07aa
--- /dev/null
+++ b/Code/docs/superpowers/specs/2026-04-11-manual-task-creation-design.md
@@ -0,0 +1,151 @@
+# 鎵嬪姩鍒涘缓浠诲姟鍔熻兘璁捐
+
+## 1. 闇�姹傛杩�
+
+鍦� WMS 鐣岄潰涓婃坊鍔犳墜鍔ㄥ垱寤轰换鍔″姛鑳姐�傜敤鎴疯緭鍏ヨ捣鐐广�佺粓鐐广�佹潯鐮併�佷粨搴揑D锛岀郴缁熻嚜鍔ㄧ敓鎴愪换鍔″彿绛夊瓧娈碉紝鍙戦�佺粰 WCS銆俉CS 鏍规嵁璧风偣鏄惁涓虹嚎浣撶偣浣�(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 澶辫触 鈫� 杩斿洖閿欒锛學MS 浠诲姟鐘舵�佷繚鎸佹柊寤�
+- 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` (浠诲姟鍛戒护缁撴瀯)
--
Gitblit v1.9.3