fix(island,server): 连续圆角四角修正 + 叫人分紧急/普通两级
灵动岛圆角(用户反馈"左上角和右下角缺一块 / 圆角边缘割裂"): - squircle.ts 改为"每个角独立圆心 + 角度参数"的超椭圆采样(原本四角共用同一个偏移向量, 左上/右下被切掉一块);四角几何与 WinIsland 的连续超椭圆一致,r 与 h/2、w/2 自动收敛。 - verify:desktop 新增像素级断言「连续圆角四角一致」:从四角沿对角线找岛体边界, 四角步进必须两两一致(展开 15/15/15/15、紧急 14/14/14/14、胶囊 5/5/5/5), 并保留路径绕行 |winding|≈2π 断言(抓"角上往回折")。该断言即本次回归的守卫。 - 截图留档同时写入裁剪图与整窗图,便于人工复核角形。 叫人分紧急 / 普通两级(用户要求"叫人也分为紧急和普通"): - shared:CreateCallRequest 新增 urgent;紧急叫人 → URGENT(无视上课时段立即展开), 普通叫人(默认)→ HIGH(按普通通知排队)。 - desktop:isImmediate 只认 priority=URGENT,不再把 kind=call 一律视为立即消息; 普通叫人回到与普通通知相同的排队 / 隐藏 / 下课弹出路径。 - web:通知发布 → 叫人、学生管理 → 叫人 两个弹窗新增"级别"单选(默认普通)+ 联动提示文案。 验证:verify:e2e 135/135(新增普通 / 紧急叫人级别断言)、verify:web 20/20(新增级别单选断言)、 verify:desktop 59/59 + 离线复跑 53/53、typecheck / lint / format 全绿。
This commit is contained in:
1 parent
1b4dd14e4a
commit
0690546307
13 files changed
+553
-205
No files matched your search
@@ -65,12 +65,15 @@ const callStudentId = ref('');
|
||||
const callStudents = ref<StudentDto[]>([]);
|
||||
const callQuickPhrase = ref<string>(CALL_QUICK_PHRASES[0] ?? '');
|
||||
const callMessage = ref('');
|
||||
/** 紧急叫人:无视上课时段立即展开;默认普通(只进队列,课后弹出) */
|
||||
const callUrgent = ref(false);
|
||||
|
||||
async function openCall(): Promise<void> {
|
||||
callClassId.value = filter.classId || classes.value[0]?.id || '';
|
||||
callStudentId.value = '';
|
||||
callMessage.value = '';
|
||||
callQuickPhrase.value = CALL_QUICK_PHRASES[0] ?? '';
|
||||
callUrgent.value = false;
|
||||
callStudents.value = [];
|
||||
callVisible.value = true;
|
||||
if (callClassId.value) await loadCallStudents();
|
||||
@@ -103,10 +106,11 @@ async function submitCall(): Promise<void> {
|
||||
const created = await callApi.create({
|
||||
classId: callClassId.value,
|
||||
studentId: callStudentId.value,
|
||||
urgent: callUrgent.value,
|
||||
...(callMessage.value.trim() ? { message: callMessage.value.trim() } : {}),
|
||||
...(callQuickPhrase.value.trim() ? { quickPhrase: callQuickPhrase.value.trim() } : {}),
|
||||
});
|
||||
ElMessage.success(`已通知:${created.title}`);
|
||||
ElMessage.success(`已${callUrgent.value ? '紧急' : ''}通知:${created.title}`);
|
||||
callVisible.value = false;
|
||||
} finally {
|
||||
callSending.value = false;
|
||||
@@ -382,11 +386,21 @@ onUnmounted(() => {
|
||||
placeholder="可选;填写后优先于快捷短语"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="级别">
|
||||
<el-radio-group v-model="callUrgent">
|
||||
<el-radio-button :value="false">普通(不打断课堂)</el-radio-button>
|
||||
<el-radio-button :value="true">紧急(立即展开)</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-alert
|
||||
type="warning"
|
||||
:type="callUrgent ? 'error' : 'warning'"
|
||||
:closable="false"
|
||||
title="学生端桌面会立即浮出「请 XXX 同学找 XXX 老师」,上课时段也照常弹出"
|
||||
:title="
|
||||
callUrgent
|
||||
? '紧急叫人:学生端桌面无视上课时段立即展开,需学生点「收到」'
|
||||
: '普通叫人:学生端课间先显示胶囊、点击展开;上课时段只排队,下课后弹出'
|
||||
"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button @click="callVisible = false">取消</el-button>
|
||||
|
||||
@@ -123,12 +123,13 @@ onMounted(async () => {
|
||||
const callVisible = ref(false);
|
||||
const callSending = ref(false);
|
||||
const callTarget = ref<StudentDto | null>(null);
|
||||
const callForm = reactive({ quickPhrase: '', message: '' });
|
||||
const callForm = reactive({ quickPhrase: '', message: '', urgent: false });
|
||||
|
||||
function openCall(row: StudentDto): void {
|
||||
callTarget.value = row;
|
||||
callForm.quickPhrase = CALL_QUICK_PHRASES[0] ?? '';
|
||||
callForm.message = '';
|
||||
callForm.urgent = false;
|
||||
callVisible.value = true;
|
||||
}
|
||||
|
||||
@@ -153,10 +154,11 @@ async function submitCall(): Promise<void> {
|
||||
const created = await callApi.create({
|
||||
classId: target.classId,
|
||||
studentId: target.id,
|
||||
urgent: callForm.urgent,
|
||||
...(callForm.message.trim() ? { message: callForm.message.trim() } : {}),
|
||||
...(callForm.quickPhrase.trim() ? { quickPhrase: callForm.quickPhrase.trim() } : {}),
|
||||
});
|
||||
ElMessage.success(`已通知 ${target.name}:${created.title}`);
|
||||
ElMessage.success(`已${callForm.urgent ? '紧急' : ''}通知 ${target.name}:${created.title}`);
|
||||
callVisible.value = false;
|
||||
} finally {
|
||||
callSending.value = false;
|
||||
@@ -235,8 +237,11 @@ async function submitCall(): Promise<void> {
|
||||
class="call-alert"
|
||||
>
|
||||
<template #default>
|
||||
发送后学生端桌面会立即浮出「请 {{ callTarget.name }} 同学找 XXX 老师」,
|
||||
无需学生刷新;上课时段也会立刻显示。
|
||||
发送后学生端桌面会浮出「请 {{ callTarget.name }} 同学找 XXX 老师」;
|
||||
<b>紧急</b>
|
||||
叫人无视上课时段立即展开,
|
||||
<b>普通</b>
|
||||
叫人课间先显示胶囊、上课时段只排队。
|
||||
</template>
|
||||
</el-alert>
|
||||
|
||||
@@ -256,6 +261,14 @@ async function submitCall(): Promise<void> {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="call-section">
|
||||
<div class="call-label">级别(默认普通:不打断课堂)</div>
|
||||
<el-radio-group v-model="callForm.urgent">
|
||||
<el-radio-button :value="false">普通</el-radio-button>
|
||||
<el-radio-button :value="true">紧急</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
|
||||
<div class="call-section">
|
||||
<div class="call-label">自定义消息(可选,优先于快捷短语)</div>
|
||||
<el-input
|
||||
|
||||
Reference in new issue
Block a user