试用前走查的修改:报错看得见、学生找得到作业、运行区和设计器的若干体验问题
- 运行区:编译错误、运行异常、控制台输出和保存的图片移到窗体下面,不再被实训台挤成 0 高;缩放和放大按钮移到桌面上方,不压窗体的关闭按钮;放大后也能停止程序;点停止后清掉窗体 - 运行异常:常见 .NET 异常配中文说明,显示出错的文件、行号和方法,点击跳到代码 - 运行中的下拉列表挂到页面最外层,能伸出窗体和分组框(小窗体也能选到 COM4、COM5) - 学生登录后进"我的作业";任务面板从工具栏下面开始,不挡导航;记住上次做的实验,从数据库页面返回、恢复数据时默认用它 - 代码页和设计页左栏都占 3/5,文件标签放不下时换行;实验选择框加宽;关闭粘性滚动 - 设计器:双击生成的事件方法带缩进;双击工具箱放进选中控件所在的容器并错开位置;新控件比容器宽时按比例缩小;无边框窗体不画标题栏 - 中文界面:代码编辑器(查找替换等)、属性窗口的颜色选项 - SQL:DATEADD、DATEDIFF、DATEPART 的日期单位(day、hour)解析成 IdentifierLiteral 时报"不支持",补上 - 项目 8 的预置环境数据改成建库那天之前的 7 天;p6-t3 评分项改为"按日期查询环境数据" - 没有 AI 建议时不显示"全部采纳 AI 建议"和相关说明;导出 CSV 只给纯数字的文字加制表符 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
da623fa648
commit
f6024dc113
30 files changed
+537
-255
No files matched your search
@@ -1,7 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
// 按控件类型渲染一个 WinForms 控件及其子控件。
|
||||
// 用户操作只通过 act() 上报,由运行器按真实 WinForms 的顺序触发事件。
|
||||
import { computed, inject, provide, ref, type CSSProperties } from 'vue'
|
||||
import { computed, inject, onBeforeUnmount, provide, ref, watch, type CSSProperties } from 'vue'
|
||||
import type { ControlNode, UserAction } from '@iot/shared'
|
||||
import { AMBIENT_BACK_COLOR, AMBIENT_BACK_TYPES, boxCss, DEFAULT_BACK_COLOR, displayText } from './format'
|
||||
import { backgroundCss, imageSources, RUN_IMAGES, srcset, type ImageValue } from './images'
|
||||
@@ -49,10 +49,12 @@ const passwordChar = computed(() => {
|
||||
return ch && ch !== '\0' ? ch : ''
|
||||
})
|
||||
|
||||
// ComboBox
|
||||
// ComboBox:下拉列表挂到页面最外层(和真实 WinForms 一样可以伸出窗体),按控件在屏幕上的位置和缩放摆放
|
||||
const dropDownOpen = ref(false)
|
||||
const items = computed(() => (p.value.Items as string[] | undefined) ?? [])
|
||||
const editable = computed(() => p.value.DropDownStyle !== 'DropDownList')
|
||||
const combo = ref<HTMLElement>()
|
||||
const listStyle = ref<CSSProperties>({})
|
||||
|
||||
function openDropDown() {
|
||||
if (!enabled.value) return
|
||||
@@ -60,11 +62,37 @@ function openDropDown() {
|
||||
dropDownOpen.value = false
|
||||
return
|
||||
}
|
||||
const el = combo.value
|
||||
if (!el) return
|
||||
const rect = el.getBoundingClientRect()
|
||||
listStyle.value = {
|
||||
left: `${rect.left}px`,
|
||||
top: `${rect.bottom}px`,
|
||||
width: `${el.offsetWidth}px`,
|
||||
transform: `scale(${rect.width / el.offsetWidth || 1})`,
|
||||
font: getComputedStyle(el).font,
|
||||
}
|
||||
// 先触发 Click(教材在 Click 里填充串口列表),列表随后按最新的 Items 显示
|
||||
act({ action: 'dropDown' })
|
||||
dropDownOpen.value = true
|
||||
}
|
||||
|
||||
/** 点列表以外的地方、滚动页面时收起列表 */
|
||||
function closeOnOutside(event: Event) {
|
||||
const target = event.target as Node
|
||||
if (combo.value?.contains(target) || (target instanceof Element && target.closest('.wf-combobox-list'))) return
|
||||
dropDownOpen.value = false
|
||||
}
|
||||
watch(dropDownOpen, (open) => {
|
||||
const method = open ? 'addEventListener' : 'removeEventListener'
|
||||
window[method]('mousedown', closeOnOutside, true)
|
||||
window[method]('scroll', closeOnOutside, true)
|
||||
})
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener('mousedown', closeOnOutside, true)
|
||||
window.removeEventListener('scroll', closeOnOutside, true)
|
||||
})
|
||||
|
||||
function selectItem(index: number) {
|
||||
dropDownOpen.value = false
|
||||
act({ action: 'select', index })
|
||||
@@ -130,7 +158,7 @@ const itemHeight = computed(() => `${(p.value.ItemHeight as number | undefined)
|
||||
</div>
|
||||
|
||||
<!-- ComboBox -->
|
||||
<div v-else-if="node.type === 'ComboBox'" class="wf-control wf-combobox" :style="style">
|
||||
<div v-else-if="node.type === 'ComboBox'" ref="combo" class="wf-control wf-combobox" :style="style">
|
||||
<input
|
||||
:value="String(p.Text ?? '')"
|
||||
:readonly="!editable"
|
||||
@@ -139,10 +167,12 @@ const itemHeight = computed(() => `${(p.value.ItemHeight as number | undefined)
|
||||
@input="act({ action: 'text', value: ($event.target as HTMLInputElement).value })"
|
||||
/>
|
||||
<span class="wf-combobox-arrow" @mousedown.prevent="openDropDown">▾</span>
|
||||
<ul v-if="dropDownOpen" class="wf-combobox-list">
|
||||
<li v-for="(item, index) in items" :key="index" @mousedown.prevent="selectItem(index)">{{ item }}</li>
|
||||
<li v-if="items.length === 0" class="wf-combobox-empty"> </li>
|
||||
</ul>
|
||||
<Teleport to="body">
|
||||
<ul v-if="dropDownOpen" class="wf-combobox-list" :style="listStyle">
|
||||
<li v-for="(item, index) in items" :key="index" @mousedown.prevent="selectItem(index)">{{ item }}</li>
|
||||
<li v-if="items.length === 0" class="wf-combobox-empty"> </li>
|
||||
</ul>
|
||||
</Teleport>
|
||||
</div>
|
||||
|
||||
<!-- ListBox:点空白处只触发 Click,点某一项先选中再触发 Click -->
|
||||
|
||||
Reference in new issue
Block a user