项目 4 任务 2 网络摄像机:PictureBox、Image / Bitmap、照片列表
CI/CD / test (push) Canceled after 0s
CI/CD / deploy (push) Canceled after 0s

- 摄像头:自绘东围墙场景(Camera/scene.svg),按云台位置切成 640×480 帧(build-frames.ts);
  Pan 每次转一格,红外对射被遮挡时画面出现翻墙的人;类名、委托、事件参数与教材 dll 一致,
  ImageRead 每 250 ms 在后台线程触发
- Image / Bitmap 保存真实图片数据:Save、FromFile、FromStream,文件夹不存在时报 GDI+ 一般性错误;
  图片每张只发给浏览器一次(按内容哈希缓存)
- 程序所在目录(AppDomain.CurrentDomain.BaseDirectory,编译检查单独放行)和当前目录指向可写的 bin/Debug,
  沙箱里在沙箱的临时目录
- PictureBox(SizeMode、BorderStyle);设计器工具箱加"图片框";运行区显示程序保存的图片,点开看大图;
  实训台摄像头图标显示开启状态
- 评分规则加图片框显示图片、摄像头开关与转向、保存图片三种检查;示例 p4-t2-网络摄像机
- 测试:摄像头端到端、图片读写与程序目录、AppDomain 编译检查、评分出错情况

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-22 20:58:09 +08:00
1 parent 4ed9450c02
commit 6b088240da
76 files changed
+1290 -14

No files matched your search

+19
View File
@@ -11,6 +11,9 @@ const START_TIMEOUT = 10_000
const RELAY_NAMES = ['报警灯', '照明灯', '路灯', '插座 1', '插座 2']
const ZIGBEE_NAMES = ['ZigBee 节点 0', '照明灯 1']
/** 摄像头云台开始时的位置(见 IPCameraHelper.cs) */
const CAMERA_START = { x: 3, y: 1 }
const CAMERA_WORDS = { on: '开启(传送画面)', off: '关闭', up: '向上转', down: '向下转', left: '向左转', right: '向右转' }
// ---------- 并发限制 ----------
let running = 0
@@ -160,6 +163,14 @@ function satisfied(driver: ProgramDriver, e: Exclude<Expectation, { kind: 'uncha
return driver.messageBoxes.some((box) => box.text.includes(e.text))
case 'console':
return driver.console.includes(e.text)
case 'image':
return Boolean(props(e.control)?.Image)
case 'camera': {
const { on, x, y } = driver.board.state.camera
return { on, off: !on, up: y < CAMERA_START.y, down: y > CAMERA_START.y, left: x < CAMERA_START.x, right: x > CAMERA_START.x }[e.state]
}
case 'savedImage':
return driver.savedImages.some((path) => path.includes(e.path))
}
}
@@ -195,5 +206,13 @@ function describeFailure(driver: ProgramDriver, e: Exclude<Expectation, { kind:
}
case 'console':
return `期望${prefix}控制台${desc ?? `输出"${e.text}"`},实际输出${quote(driver.console.trim())}`
case 'image':
return `期望${prefix} ${e.control} ${desc ?? '显示图片'},实际是空的`
case 'camera':
return `期望${prefix}网络摄像机${desc ?? CAMERA_WORDS[e.state]},实际${driver.board.state.camera.on ? '开着' : '没有开启'}${e.state === 'on' || e.state === 'off' ? '' : '、云台没有朝这个方向转'}`
case 'savedImage': {
const saved = driver.savedImages.map((p) => `"${p}"`).join('、')
return `期望${prefix}${desc ?? `保存图片到"${e.path}"`},${saved ? `实际保存的是 ${saved}` : '实际没有保存图片'}`
}
}
}