From 50dced4d37268cc1c79bac44a2ad99b038d31791 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 27 Oct 2026 20:41:18 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B2=E5=8F=A3=E4=B8=8B=E6=8B=89=E6=A1=86?= =?UTF-8?q?=E5=8E=BB=E6=8E=89=E7=94=B5=E8=84=91=E8=87=AA=E5=B8=A6=E7=9A=84?= =?UTF-8?q?=20COM1=EF=BC=8C=E5=8F=AA=E7=95=99=E5=AE=9E=E8=AE=AD=E5=8F=B0?= =?UTF-8?q?=E4=B8=8A=E7=9A=84=20COM2=E2=80=93COM5=EF=BC=9B=E5=B1=95?= =?UTF-8?q?=E5=BC=80=E6=97=B6=E6=AF=8F=E4=B8=AA=E4=B8=B2=E5=8F=A3=E5=90=8E?= =?UTF-8?q?=E9=9D=A2=E7=94=A8=E7=81=B0=E5=AD=97=E6=A0=87=E5=87=BA=E6=8E=A5?= =?UTF-8?q?=E7=9A=84=E8=AE=BE=E5=A4=87=EF=BC=88ADAM-4017+=E3=80=81ADAM-415?= =?UTF-8?q?0=E3=80=81ZigBee=20=E5=8D=8F=E8=B0=83=E5=99=A8=E3=80=81LED=20?= =?UTF-8?q?=E5=B1=8F=EF=BC=89=EF=BC=8C=E9=80=89=E4=B8=AD=E5=90=8E=E7=9A=84?= =?UTF-8?q?=E5=80=BC=E8=BF=98=E6=98=AF=20COM2=20=E8=BF=99=E6=A0=B7?= =?UTF-8?q?=E7=9A=84=E4=B8=B2=E5=8F=A3=E5=90=8D=EF=BC=8C=E5=92=8C=E7=9C=9F?= =?UTF-8?q?=E6=9C=BA=E4=B8=80=E8=87=B4=E3=80=82=E9=A1=B9=E7=9B=AE=205=20?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=203=20=E8=B7=B3=E8=BF=87=20COM1=20=E7=9A=84?= =?UTF-8?q?=E5=86=99=E6=B3=95=E7=85=A7=E4=B9=A6=E4=BF=9D=E7=95=99=EF=BC=8C?= =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E8=AF=B4=E6=98=8E=E8=A1=A5=E4=B8=80=E5=8F=A5?= =?UTF-8?q?=EF=BC=9B=E4=BD=BF=E7=94=A8=E8=AF=B4=E6=98=8E=E3=80=81=E8=AE=BE?= =?UTF-8?q?=E8=AE=A1=E6=96=B9=E6=A1=88=E5=90=8C=E6=AD=A5=EF=BC=9B=E6=8C=89?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E9=80=89=E4=B8=B2=E5=8F=A3=E7=9A=84=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E4=B8=8B=E6=A0=87=E8=B7=9F=E7=9D=80=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docs/设计方案.md | 2 +- runtime/Sim.WinForms/Ports/SerialPort.cs | 6 +++--- samples/p5-t3-推送灾情/task.md | 2 +- server/test/classroom.ts | 2 +- server/test/load.ts | 2 +- server/test/runner.test.ts | 10 +++++----- web/src/pages/HelpPage.vue | 2 +- web/src/winforms/ControlView.vue | 8 ++++++-- web/src/winforms/winforms.css | 7 +++++++ 9 files changed, 26 insertions(+), 15 deletions(-) diff --git a/docs/设计方案.md b/docs/设计方案.md index ff36640..3882108 100644 --- a/docs/设计方案.md +++ b/docs/设计方案.md @@ -55,7 +55,7 @@ **还原真实行为**:在后台线程里直接修改控件,会抛出和 VS 中按 F5 调试时一样的"线程间操作无效"异常;单选按钮、复选框、下拉框的事件顺序与真实 WinForms 一致。 -**教材要求的运行能力**:多窗体(`Show`、`Hide`、`Close`,项目 1 的登录程序就用到);控制台输出面板(`Console.WriteLine`);虚拟 COM 口(`SerialPort.GetPortNames()` 返回 COM1–COM5,保留"选串口、点打开"的操作步骤)。 +**教材要求的运行能力**:多窗体(`Show`、`Hide`、`Close`,项目 1 的登录程序就用到);控制台输出面板(`Console.WriteLine`);虚拟 COM 口(`SerialPort.GetPortNames()` 返回 COM2–COM5,对应实训台的四台设备,保留"选串口、点打开"的操作步骤)。 **导入与导出 VS 工程**:设计器能读懂 VS 生成的 `Designer.cs`,教材配套的 19 个参考工程可直接导入,作为初始模板和参考答案;学生作品也能导出为 VS 工程,在机房真机上运行。 diff --git a/runtime/Sim.WinForms/Ports/SerialPort.cs b/runtime/Sim.WinForms/Ports/SerialPort.cs index bd03cb0..b5d321a 100644 --- a/runtime/Sim.WinForms/Ports/SerialPort.cs +++ b/runtime/Sim.WinForms/Ports/SerialPort.cs @@ -8,8 +8,8 @@ namespace System.IO.Ports; /// public class SerialPort : Component { - /// COM1 是电脑自带串口,COM2–COM5 对应实训台上的 4017、4150、ZigBee 协调器和 LED 屏 - private static readonly string[] VirtualPorts = { "COM1", "COM2", "COM3", "COM4", "COM5" }; + /// COM2–COM5 对应实训台上的 4017、4150、ZigBee 协调器和 LED 屏,不提供电脑自带的 COM1 + private static readonly string[] VirtualPorts = { "COM2", "COM3", "COM4", "COM5" }; public SerialPort() { } @@ -19,7 +19,7 @@ public class SerialPort : Component public static string[] GetPortNames() => (string[])VirtualPorts.Clone(); - public string PortName { get; set; } = "COM1"; + public string PortName { get; set; } = "COM2"; public int BaudRate { get; set; } = 9600; public int DataBits { get; set; } = 8; public int ReadTimeout { get; set; } = -1; diff --git a/samples/p5-t3-推送灾情/task.md b/samples/p5-t3-推送灾情/task.md index 589b2c6..c8339f3 100644 --- a/samples/p5-t3-推送灾情/task.md +++ b/samples/p5-t3-推送灾情/task.md @@ -37,7 +37,7 @@ 1. 点 **+ 新建类**,建 `RecordClass`,写两个静态成员:`string[,] record = new string[50, 2]`(每条记录存时间和内容)、`int recoudeindex = 0`(下一条记录存在第几行)。 2. Form1 的代码开头加上 `using System.IO.Ports;`、`using DeviceCtrlLibrary;`、`using DeviceCtrlLibrary.Model;`;全局变量:`ADAM4150ResModel ResModel;`、`bool IsOpen = false;`、`string LED_MSG = "";`。 -3. **Form1_Load**:清空两个下拉框,用 for 循环加串口号;遇到 `COM1`(电脑自带的串口)就 `continue` 跳过。 +3. **Form1_Load**:清空两个下拉框,用 for 循环加串口号;遇到 `COM1`(电脑自带的串口)就 `continue` 跳过。平台上没有 COM1,这段照书保留,在机房真机上才用得到。 4. **btn_Open 的 Click**:打开时调用 `adam4150Helper.Open(com_environmentPort.Text)` 和 `ledHelper.OpenLedCom(com_ledPort.Text)`,按钮改成"关闭";关闭时关闭 ADAM-4150 串口,按钮改回"开启"。 5. **btn_get 的 Click**: - 用 `adam4150Helper.SetData()` 读出数据存进 `ResModel`,清空 `LED_MSG`,显示当前时间,火焰、烟雾两个框先写"正常"; diff --git a/server/test/classroom.ts b/server/test/classroom.ts index 548121f..2adbbfe 100644 --- a/server/test/classroom.ts +++ b/server/test/classroom.ts @@ -214,7 +214,7 @@ try { async (s) => { const window = s.window! window.action('com_lamp', { action: 'dropDown' }) - window.action('com_lamp', { action: 'select', index: 3 }) + window.action('com_lamp', { action: 'select', index: 2 }) window.action('btn_open', { action: 'click' }) await Bun.sleep(300) // 设备消息由服务器记进实训台状态,再以 board 消息推给浏览器 diff --git a/server/test/load.ts b/server/test/load.ts index bb71552..952f50c 100644 --- a/server/test/load.ts +++ b/server/test/load.ts @@ -80,7 +80,7 @@ const latencies = await Promise.all( const form = instance.form! const id = (name: string) => findId(form, name)! send(instance, { type: 'action', id: id('com_Port'), action: 'dropDown' }) - send(instance, { type: 'action', id: id('com_Port'), action: 'select', index: 4 }) + send(instance, { type: 'action', id: id('com_Port'), action: 'select', index: 3 }) send(instance, { type: 'action', id: id('btn_Open'), action: 'click' }) send(instance, { type: 'action', id: id('txt_SendText'), action: 'text', value: '压力测试' }) await Bun.sleep(200) diff --git a/server/test/runner.test.ts b/server/test/runner.test.ts index 6f02c04..d7d7fb5 100644 --- a/server/test/runner.test.ts +++ b/server/test/runner.test.ts @@ -196,7 +196,7 @@ test('项目2 任务2:温度读数来自实训台,滑块变化后再次获 const { runner, id } = await startSample('p2-t2-模拟量采集') const port = id('com_port') // 串口列表在 Load 里就已填好 - runner.send({ type: 'action', id: port, action: 'select', index: 1 }) + runner.send({ type: 'action', id: port, action: 'select', index: 0 }) runner.send({ type: 'action', id: id('btn_Open'), action: 'click' }) const textOf = (name: string) => runner @@ -224,7 +224,7 @@ test('项目3 任务1:单选按钮切换,事件顺序与 WinForms 一致, await runner.waitFor('patch', (m) => m.changes.some((c) => c.id === lamp && c.prop === 'IsOn' && c.value === true)) expect(runner.messages.some((m) => m.type === 'device')).toBe(false) - runner.send({ type: 'action', id: id('com_port'), action: 'select', index: 3 }) + runner.send({ type: 'action', id: id('com_port'), action: 'select', index: 2 }) runner.send({ type: 'action', id: id('btn_open'), action: 'click' }) // 选"关":先触发"开"的 CheckedChanged(又开一次),再触发"关"的 CheckedChanged,最终关灯 @@ -241,8 +241,8 @@ test('项目3 任务1:单选按钮切换,事件顺序与 WinForms 一致, test('项目3 任务2:勾选人体开关后,有人经过时 5 秒内路灯打开', async () => { const { runner, id } = await startSample('p3-t2-人体红外ZigBee联动') - runner.send({ type: 'action', id: id('com_lamp'), action: 'select', index: 3 }) - runner.send({ type: 'action', id: id('com_environment'), action: 'select', index: 2 }) + runner.send({ type: 'action', id: id('com_lamp'), action: 'select', index: 2 }) + runner.send({ type: 'action', id: id('com_environment'), action: 'select', index: 1 }) runner.send({ type: 'action', id: id('btn_open'), action: 'click' }) // 复选框的 Click 里读取 Checked:此时 Checked 必须已经是 true @@ -316,7 +316,7 @@ test('项目1 任务2:计算器(装箱拆箱)和多态', async () => { /** 选 COM3、点"开启",等定时器读到实训台上的传感器 */ async function openAdam4150(runner: Runner, id: (name: string) => string) { - runner.send({ type: 'action', id: id('com_port'), action: 'select', index: 2 }) + runner.send({ type: 'action', id: id('com_port'), action: 'select', index: 1 }) runner.send({ type: 'action', id: id('btn_open'), action: 'click' }) } diff --git a/web/src/pages/HelpPage.vue b/web/src/pages/HelpPage.vue index 5ccd62b..615f89d 100644 --- a/web/src/pages/HelpPage.vue +++ b/web/src/pages/HelpPage.vue @@ -105,7 +105,7 @@ onBeforeUnmount(() => window.removeEventListener('keydown', onKey))

5. 虚拟实训台