1
0
mirror of https://github.com/ZeroCatDev/Classworks.git synced 2025-07-02 00:59:23 +00:00

Add mode switching and number range settings to RandomPicker component. Introduce picker modes for name and number, allowing users to set a range for student IDs. Update settings management for new properties and enhance UI for better user experience.

This commit is contained in:
SunWuyuan 2025-05-24 21:21:20 +08:00
parent ab20d6cecb
commit 0f9ad4f81a
No known key found for this signature in database
GPG Key ID: A6A54CF66F56BB64
4 changed files with 205 additions and 14 deletions

View File

@ -43,6 +43,48 @@
/> />
</div> </div>
<!-- 添加模式切换 -->
<div class="mode-switch-container mt-6">
<v-btn-toggle
v-model="pickerMode"
color="primary"
rounded="pill"
mandatory
class="mode-toggle"
>
<v-btn value="name" prepend-icon="mdi-account">姓名模式</v-btn>
<v-btn value="number" prepend-icon="mdi-numeric">学号模式</v-btn>
</v-btn-toggle>
</div>
<!-- 学号范围设置 -->
<div v-if="pickerMode === 'number'" class="number-range-container mt-4">
<div class="text-subtitle-1 mb-2">学号范围设置</div>
<div class="d-flex justify-center align-center gap-4">
<v-text-field
v-model.number="minNumber"
label="最小值"
type="number"
min="1"
max="100"
hide-details
class="number-input"
density="compact"
/>
<span class="mx-2"></span>
<v-text-field
v-model.number="maxNumber"
label="最大值"
type="number"
min="1"
max="100"
hide-details
class="number-input"
density="compact"
/>
</div>
</div>
<div class="mt-4"> <div class="mt-4">
<v-btn <v-btn
size="x-large" size="x-large"
@ -57,12 +99,17 @@
</div> </div>
<div v-if="filteredStudents.length === 0" class="mt-4 text-error"> <div v-if="filteredStudents.length === 0" class="mt-4 text-error">
没有可抽取的学生请调整过滤选项 <template v-if="pickerMode === 'name'">
没有可抽取的学生请调整过滤选项
</template>
<template v-else>
请设置有效的学号范围
</template>
</div> </div>
<div class="mt-4 text-caption"> <div class="mt-4 text-caption">
当前可抽取学生: {{ filteredStudents.length }} 当前可抽取学生: {{ filteredStudents.length }}
<v-tooltip location="bottom"> <v-tooltip v-if="pickerMode === 'name'" location="bottom">
<template v-slot:activator="{ props }"> <template v-slot:activator="{ props }">
<v-icon <v-icon
v-bind="props" v-bind="props"
@ -81,10 +128,11 @@
<div v-if="tempFilters.excludeExcluded"> <div v-if="tempFilters.excludeExcluded">
已排除不参与学生 ({{ excludedCount }}) 已排除不参与学生 ({{ excludedCount }})
</div> </div>
</div> </v-tooltip </div>
><!-- 添加临时过滤选项 --> </v-tooltip>
<div class="d-flex flex-wrap justify-center gap-2 mt-4"> <!-- 添加临时过滤选项 -->
<div v-if="pickerMode === 'name'" class="d-flex flex-wrap justify-center gap-2 mt-4">
<v-chip <v-chip
:color="tempFilters.excludeLate ? 'warning' : 'default'" :color="tempFilters.excludeLate ? 'warning' : 'default'"
:variant="tempFilters.excludeLate ? 'elevated' : 'text'" :variant="tempFilters.excludeLate ? 'elevated' : 'text'"
@ -107,9 +155,7 @@
<v-chip <v-chip
:color="tempFilters.excludeExcluded ? 'grey' : 'default'" :color="tempFilters.excludeExcluded ? 'grey' : 'default'"
:variant="tempFilters.excludeExcluded ? 'elevated' : 'text'" :variant="tempFilters.excludeExcluded ? 'elevated' : 'text'"
@click=" @click="tempFilters.excludeExcluded = !tempFilters.excludeExcluded"
tempFilters.excludeExcluded = !tempFilters.excludeExcluded
"
prepend-icon="mdi-account-cancel" prepend-icon="mdi-account-cancel"
class="filter-chip" class="filter-chip"
> >
@ -195,7 +241,7 @@
</template> </template>
<script> <script>
import { getSetting } from "@/utils/settings"; import { getSetting, setSetting } from "@/utils/settings";
export default { export default {
name: "RandomPicker", name: "RandomPicker",
@ -227,6 +273,9 @@ export default {
excludeLate: getSetting("randomPicker.excludeLate"), excludeLate: getSetting("randomPicker.excludeLate"),
excludeExcluded: getSetting("randomPicker.excludeExcluded"), excludeExcluded: getSetting("randomPicker.excludeExcluded"),
}, },
pickerMode: getSetting("randomPicker.mode"),
minNumber: getSetting("randomPicker.minNumber"),
maxNumber: getSetting("randomPicker.maxNumber"),
}; };
}, },
computed: { computed: {
@ -241,12 +290,25 @@ export default {
return this.attendance.exclude ? this.attendance.exclude.length : 0; return this.attendance.exclude ? this.attendance.exclude.length : 0;
}, },
// 使 //
numberModeStudents() {
if (this.pickerMode !== "number") return [];
const students = [];
for (let i = this.minNumber; i <= this.maxNumber; i++) {
students.push(i.toString().padStart(2, "0") + "号");
}
return students;
},
// filteredStudents
filteredStudents() { filteredStudents() {
if (this.pickerMode === "number") {
return this.numberModeStudents;
}
if (!this.studentList || !this.studentList.length) return []; if (!this.studentList || !this.studentList.length) return [];
return this.studentList.filter((student) => { return this.studentList.filter((student) => {
//
if ( if (
this.tempFilters.excludeAbsent && this.tempFilters.excludeAbsent &&
this.attendance.absent.includes(student) this.attendance.absent.includes(student)
@ -318,6 +380,35 @@ export default {
}, },
deep: true, deep: true,
}, },
//
pickerMode: {
handler(newMode) {
setSetting("randomPicker.mode", newMode);
},
},
minNumber: {
handler(newValue) {
if (newValue > this.maxNumber) {
this.minNumber = this.maxNumber;
}
if (newValue < 1) {
this.minNumber = 1;
}
setSetting("randomPicker.minNumber", this.minNumber);
},
},
maxNumber: {
handler(newValue) {
if (newValue < this.minNumber) {
this.maxNumber = this.minNumber;
}
if (newValue > 100) {
this.maxNumber = 100;
}
setSetting("randomPicker.maxNumber", this.maxNumber);
},
},
}, },
methods: { methods: {
open() { open() {
@ -616,4 +707,45 @@ export default {
font-size: 1rem; font-size: 1rem;
} }
} }
//
.mode-switch-container {
.mode-toggle {
border: 1px solid rgba(var(--v-theme-primary), 0.2);
border-radius: 50px;
padding: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.v-btn {
min-width: 120px;
height: 40px;
font-weight: 500;
letter-spacing: 0.5px;
&.v-btn--active {
transform: scale(1.02);
font-weight: 600;
}
}
}
}
//
.number-range-container {
max-width: 300px;
margin: 0 auto;
padding: 16px;
background: rgba(var(--v-theme-surface-variant), 0.1);
border-radius: 12px;
border: 1px solid rgba(var(--v-theme-primary), 0.1);
.number-input {
width: 100px;
:deep(.v-field) {
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
}
}
</style> </style>

View File

@ -0,0 +1,30 @@
<template>
<settings-card title="编辑设置" icon="mdi-cog">
<v-list>
<setting-item setting-key="randomPicker.enabled" />
<v-divider class="my-2" />
<setting-item setting-key="randomPicker.mode" />
<v-divider class="my-2" />
<setting-item setting-key="randomPicker.minNumber" />
<v-divider class="my-2" />
<setting-item setting-key="randomPicker.maxNumber" />
<v-divider class="my-2" />
<setting-item setting-key="randomPicker.defaultCount" />
<v-divider class="my-2" />
<setting-item setting-key="randomPicker.animation" />
</v-list>
</settings-card>
</template>
<script>
import SettingsCard from '@/components/SettingsCard.vue';
import SettingItem from '../SettingItem.vue';
</script>

View File

@ -143,7 +143,9 @@
<v-tabs-window-item value="student"> <v-tabs-window-item value="student">
<student-list-card border :is-mobile="isMobile" /> <student-list-card border :is-mobile="isMobile" />
</v-tabs-window-item> </v-tabs-window-item>
<v-tabs-window-item value="randomPicker">
<random-picker-card border :is-mobile="isMobile" />
</v-tabs-window-item>
<v-tabs-window-item value="developer" <v-tabs-window-item value="developer"
><settings-card border title="开发者选项" icon="mdi-developer-board"> ><settings-card border title="开发者选项" icon="mdi-developer-board">
<v-list> <v-list>
@ -222,7 +224,7 @@ import SettingsExplorer from "@/components/settings/SettingsExplorer.vue";
import SettingsLinkGenerator from "@/components/SettingsLinkGenerator.vue"; import SettingsLinkGenerator from "@/components/SettingsLinkGenerator.vue";
import dataProvider from "@/utils/dataProvider"; import dataProvider from "@/utils/dataProvider";
import NamespaceSettingsCard from "@/components/settings/cards/NamespaceSettingsCard.vue"; import NamespaceSettingsCard from "@/components/settings/cards/NamespaceSettingsCard.vue";
import RandomPickerCard from "@/components/settings/cards/RandomPickerCard.vue";
export default { export default {
name: "Settings", name: "Settings",
components: { components: {
@ -240,6 +242,7 @@ export default {
SettingsExplorer, SettingsExplorer,
SettingsLinkGenerator, SettingsLinkGenerator,
NamespaceSettingsCard, NamespaceSettingsCard,
RandomPickerCard,
}, },
setup() { setup() {
const { mobile } = useDisplay(); const { mobile } = useDisplay();
@ -372,6 +375,11 @@ export default {
icon: "mdi-account-group", icon: "mdi-account-group",
value: "student", value: "student",
}, },
{
title: "随机点名",
icon: "mdi-dice-multiple",
value: "randomPicker",
},
{ {
title: "开发者", title: "开发者",
icon: "mdi-developer-board", icon: "mdi-developer-board",

View File

@ -360,7 +360,7 @@ const settingsDefinitions = {
"randomPicker.defaultCount": { "randomPicker.defaultCount": {
type: "number", type: "number",
default: 1, default: 1,
validate: (value) => value >= 1 && value <= 10, validate: (value) => value >= 1 && value,
description: "默认抽取人数", description: "默认抽取人数",
icon: "mdi-counter", icon: "mdi-counter",
}, },
@ -382,6 +382,27 @@ const settingsDefinitions = {
description: "是否排除不参与学生", description: "是否排除不参与学生",
icon: "mdi-account-cancel", icon: "mdi-account-cancel",
}, },
"randomPicker.mode": {
type: "string",
default: "name",
validate: (value) => ["name", "number"].includes(value),
description: "随机点名模式",
icon: "mdi-format-list-numbered",
},
"randomPicker.maxNumber": {
type: "number",
default: 60,
validate: (value) => value >= 1 && value,
description: "学号模式最大值",
icon: "mdi-numeric",
},
"randomPicker.minNumber": {
type: "number",
default: 1,
validate: (value) => value >= 1 && value,
description: "学号模式最小值",
icon: "mdi-numeric-negative-1",
},
}; };
/** /**