fix(课表小组件): 三项修复——header 显示「年级+班级」、body 去班级行、空态改内联 SVG、表格换私有类名去掉全局竖线
build / build (push) Successful in 3m52s

- header 与下拉项显示 gradeName + className(「高一 1班」)
- body 单元格只显示科目,不再重复班级
- 空态由「CSS 背景图 + 空 div」改为模板内联 SVG + 「暂无课表数据」
- 表格类名 my-table → tt:避开全局 componets/_my_table.scss 带进的 #c7c7c7 竖线与 th #fafafa 灰底
- 表头去灰底并加 1px 分隔线(#e9edf1),行间横线加深 #eef1f4,表头字色 #344449
This commit is contained in:
chenxing
2026-10-13 21:02:41 +08:00
parent 0baba07707
commit 479f7b22a7
+69 -35
View File
@@ -9,12 +9,12 @@
animated animated
/> />
<template v-else-if="classes.length > 0"> <template v-else>
<!-- 班级切换器:挂进卡片 header(index.vue 埋的 wg-hdr-<id> 锚点);多班(教师任教/班主任、校领导全校)才显示 --> <!-- 班级切换器:挂进卡片 header(index.vue 埋的 wg-hdr-<id> 锚点);多班(教师任教/班主任、校领导全校)才显示 -->
<Teleport v-if="classes.length > 1" :to="'#wg-hdr-' + widgetId"> <Teleport v-if="classes.length > 1" :to="'#wg-hdr-' + widgetId">
<div class="cls-dd" :class="{ open: ddOpen }"> <div class="cls-dd" :class="{ open: ddOpen }">
<button type="button" class="cls-trigger" @click.stop="ddOpen = !ddOpen"> <button type="button" class="cls-trigger" @click.stop="ddOpen = !ddOpen">
<span class="cls-name">{{ currentClass.className }}</span> <span class="cls-name">{{ classLabel(currentClass) }}</span>
<svg class="caret" viewBox="0 0 1024 1024" width="10" height="10" aria-hidden="true"> <svg class="caret" viewBox="0 0 1024 1024" width="10" height="10" aria-hidden="true">
<path fill="currentColor" d="M512 704 128 320l64-64 320 320 320-320 64 64z" /> <path fill="currentColor" d="M512 704 128 320l64-64 320 320 320-320 64 64z" />
</svg> </svg>
@@ -27,14 +27,14 @@
:class="{ on: index === clsIdx }" :class="{ on: index === clsIdx }"
@click="pickClass(index)" @click="pickClass(index)"
> >
{{ cls.className }} {{ classLabel(cls) }}
</div> </div>
</div> </div>
</div> </div>
</Teleport> </Teleport>
<div v-if="slots.length > 0" class="table-wrap"> <div v-if="slots.length > 0" class="table-wrap">
<table class="my-table"> <table class="tt">
<thead> <thead>
<tr> <tr>
<th>节</th> <th>节</th>
@@ -44,20 +44,33 @@
<tbody> <tbody>
<tr v-for="slot in slots" :key="slot.slotNo"> <tr v-for="slot in slots" :key="slot.slotNo">
<td class="sec">{{ cnNum(slot.slotNo) }}</td> <td class="sec">{{ cnNum(slot.slotNo) }}</td>
<td v-for="day in dayCols" :key="day.index"> <td v-for="day in dayCols" :key="day.index">{{ subjectOf(slot, day.index) }}</td>
<template v-if="subjectOf(slot, day.index)">
<div class="cla">{{ currentClass.className }}</div>
<div class="sub">{{ subjectOf(slot, day.index) }}</div>
</template>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<div v-else class="no-data-box"></div>
</template>
<div v-else class="no-data-box"></div> <!-- 空态:模板内联 SVG,不依赖外部图片 / CSS 背景 -->
<div v-else class="wg-empty">
<svg width="112" height="112" viewBox="0 0 210 242" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<rect opacity="0.01" x="0.5" y="0.5" width="209" height="209" stroke="#DCDEE0" stroke-dasharray="5" />
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M21 69.5625H47.25V171.938H24.9375H21H2.625V95.8125H21V69.5625Z" fill="#F2F3F5" />
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M105 36.5217C104.368 36.671 103.709 36.75 103.031 36.75C98.3196 36.75 94.5 32.9304 94.5 28.2188C94.5 23.721 97.9807 20.0361 102.395 19.7108C102.382 19.486 102.375 19.2594 102.375 19.0312C102.375 12.8698 107.37 7.875 113.531 7.875C118.555 7.875 122.803 11.1953 124.201 15.7611C124.362 15.7537 124.524 15.75 124.688 15.75C130.486 15.75 135.188 20.451 135.188 26.25C135.188 32.049 130.486 36.75 124.688 36.75C124.243 36.75 123.805 36.7224 123.375 36.6688V36.75H105V36.5217Z" fill="#F2F3F5" />
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M20.8304 43.8601C20.5247 43.9314 20.2058 43.969 19.878 43.969C17.5982 43.969 15.75 42.1461 15.75 39.8973C15.75 37.7506 17.4342 35.9919 19.5704 35.8367C19.5638 35.7293 19.5605 35.6211 19.5605 35.5121C19.5605 32.5714 21.9774 30.1875 24.9587 30.1875C27.3894 30.1875 29.4449 31.7722 30.1212 33.9512C30.1994 33.9477 30.2779 33.946 30.3569 33.946C33.1629 33.946 35.4376 36.1896 35.4376 38.9573C35.4376 41.725 33.1629 43.9687 30.3569 43.9687C30.1417 43.9687 29.9297 43.9555 29.7215 43.9299V43.9688H20.8304V43.8601Z" fill="#F2F3F5" />
<path opacity="0.8" fill-rule="evenodd" clip-rule="evenodd" d="M190.616 19.6875V38.0625H202.125V139.609H161.438V38.0625V19.6875H190.616Z" fill="#F2F3F5" />
<rect y="182.438" width="210" height="27.5625" fill="#F7F8FA" />
<rect opacity="0.6" x="107.625" y="82.6875" width="47.25" height="69.5625" rx="2" fill="#DCDCDC" />
<rect x="57.75" y="65.625" width="84" height="86.625" rx="2" fill="#F2F3F5" />
<rect x="65.625" y="73.5" width="68.25" height="72.1875" rx="1" fill="#fff" />
<rect x="77.4375" y="87.9375" width="44.625" height="7.875" rx="1" fill="#EAEDF1" />
<rect x="77.4375" y="106.312" width="44.625" height="7.875" fill="#EAEDF1" />
<rect x="77.4375" y="124.688" width="44.625" height="7.875" rx="1" fill="#EAEDF1" />
<rect x="47.25" y="145.688" width="115.5" height="36.75" rx="1" fill="#EAEDF1" />
<rect x="85.3125" y="160.125" width="39.375" height="7.875" rx="1" fill="#F7F8FA" />
</svg>
<span class="txt">暂无课表数据</span>
</div>
</template>
</div> </div>
</template> </template>
@@ -75,7 +88,7 @@ const WEEK_NAMES = ["周一", "周二", "周三", "周四", "周五", "周六",
const refRoot = ref<HTMLElement | null>(null); const refRoot = ref<HTMLElement | null>(null);
const loading = ref(true); const loading = ref(true);
/** oapi data[]:每项一个班级(classId/className/timetable.slots…) */ /** oapi data[]:每项一个班级(classId/className/gradeName/timetable.slots…) */
const classes = ref<any[]>([]); const classes = ref<any[]>([]);
const clsIdx = ref(0); const clsIdx = ref(0);
const ddOpen = ref(false); const ddOpen = ref(false);
@@ -83,14 +96,14 @@ let observer: ResizeObserver | null = null;
const currentClass = computed<any>(() => classes.value[clsIdx.value] || {}); const currentClass = computed<any>(() => classes.value[clsIdx.value] || {});
/** 节次行:按 slotNo 升序(R2:按接口实际返回渲染) */ /** 节次行:按 slotNo 升序(按接口实际返回渲染) */
const slots = computed<any[]>(() => { const slots = computed<any[]>(() => {
const list = currentClass.value && currentClass.value.timetable && currentClass.value.timetable.slots; const list = currentClass.value && currentClass.value.timetable && currentClass.value.timetable.slots;
if (!Array.isArray(list)) return []; if (!Array.isArray(list)) return [];
return [...list].sort((a, b) => ((a && a.slotNo) || 0) - ((b && b.slotNo) || 0)); return [...list].sort((a, b) => ((a && a.slotNo) || 0) - ((b && b.slotNo) || 0));
}); });
/** 星期列:恒 周一~周五;周六/周日有课才追加(R3) */ /** 星期列:恒 周一~周五;周六/周日有课才追加 */
const dayCols = computed(() => { const dayCols = computed(() => {
const cols = [0, 1, 2, 3, 4]; const cols = [0, 1, 2, 3, 4];
if (slots.value.some(slot => subjectOf(slot, 5))) cols.push(5); if (slots.value.some(slot => subjectOf(slot, 5))) cols.push(5);
@@ -98,6 +111,14 @@ const dayCols = computed(() => {
return cols.map(index => ({ index, name: WEEK_NAMES[index] })); return cols.map(index => ({ index, name: WEEK_NAMES[index] }));
}); });
/** 班级展示名 = 年级 + 班级(如「高一 1班」);无年级时退化为班级名 */
function classLabel(cls: any): string {
if (!cls) return "";
const grade = cls.gradeName ? String(cls.gradeName) : "";
const name = cls.className ? String(cls.className) : "";
return grade ? `${grade} ${name}` : name;
}
function subjectOf(slot: any, index: number): string { function subjectOf(slot: any, index: number): string {
const arr = slot && slot.subjects; const arr = slot && slot.subjects;
if (!Array.isArray(arr) || !arr[index]) return ""; if (!Array.isArray(arr) || !arr[index]) return "";
@@ -212,46 +233,59 @@ function reportHeight() {
} }
/* ---------- 课表 ---------- */ /* ---------- 课表 ---------- */
/* ⚠️ 表格类名必须用私有名(tt):用 my-table 会命中全局 componets/_my_table.scss,
带进 #c7c7c7 竖线与 th 灰底 ⇒「竖线明显 / 表头与卡头糊成一片 / 横线被压得看不见」 */
.table-wrap { .table-wrap {
padding: 0 15px; padding: 2px 15px 12px;
} }
.my-table { .tt {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
table-layout: fixed;
th { th {
height: 44px; height: 44px;
font-size: 13px; font-size: 13px;
font-weight: 700; font-weight: 700;
color: #6e7c87; color: #344449;
text-align: center; text-align: center;
border: 0;
border-bottom: 1px solid #e9edf1;
}
th:first-child,
td:first-child {
width: 46px;
} }
td { td {
height: 52px; height: 52px;
border-top: 1px solid #f2f4f6; border-bottom: 1px solid #eef1f4;
padding: 4px 2px; padding: 4px 2px;
text-align: center; text-align: center;
font-size: 13px; font-size: 13px;
vertical-align: middle; vertical-align: middle;
} }
tr:last-child td {
border-bottom: 0;
}
td.sec { td.sec {
color: #6e7c87; color: #6e7c87;
font-weight: 700; font-weight: 700;
} }
.cla {
color: #344449;
line-height: 1.35;
}
.sub {
color: #98a2b0;
line-height: 1.35;
font-size: 12px;
}
} }
/* 空态:沿用原版 no-data-box.svg(插画 + 转曲「暂无数据」文案)。
原版规则为 background-size:100px 100px(会压扁),此处取 100px auto 保比例。 */ /* ---------- 空态(模板内联 SVG,不依赖外部图片 / CSS 背景) ---------- */
.no-data-box { .wg-empty {
min-height: 130px; display: flex;
background: url("../../assets/image/no-data-box.svg") no-repeat 50% 50%; flex-direction: column;
background-size: 100px auto; align-items: center;
justify-content: center;
gap: 6px;
min-height: 132px;
padding: 16px 0 20px;
.txt {
font-size: 12px;
color: #98a2b0;
}
} }
</style> </style>