mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-01 16:49:22 +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:
parent
ab20d6cecb
commit
0f9ad4f81a
@ -43,6 +43,48 @@
|
||||
/>
|
||||
</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">
|
||||
<v-btn
|
||||
size="x-large"
|
||||
@ -57,12 +99,17 @@
|
||||
</div>
|
||||
|
||||
<div v-if="filteredStudents.length === 0" class="mt-4 text-error">
|
||||
<template v-if="pickerMode === 'name'">
|
||||
没有可抽取的学生,请调整过滤选项
|
||||
</template>
|
||||
<template v-else>
|
||||
请设置有效的学号范围
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-caption">
|
||||
当前可抽取学生: {{ filteredStudents.length }}人
|
||||
<v-tooltip location="bottom">
|
||||
<v-tooltip v-if="pickerMode === 'name'" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-icon
|
||||
v-bind="props"
|
||||
@ -81,10 +128,11 @@
|
||||
<div v-if="tempFilters.excludeExcluded">
|
||||
• 已排除不参与学生 ({{ excludedCount }}人)
|
||||
</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
|
||||
:color="tempFilters.excludeLate ? 'warning' : 'default'"
|
||||
:variant="tempFilters.excludeLate ? 'elevated' : 'text'"
|
||||
@ -107,9 +155,7 @@
|
||||
<v-chip
|
||||
:color="tempFilters.excludeExcluded ? 'grey' : 'default'"
|
||||
:variant="tempFilters.excludeExcluded ? 'elevated' : 'text'"
|
||||
@click="
|
||||
tempFilters.excludeExcluded = !tempFilters.excludeExcluded
|
||||
"
|
||||
@click="tempFilters.excludeExcluded = !tempFilters.excludeExcluded"
|
||||
prepend-icon="mdi-account-cancel"
|
||||
class="filter-chip"
|
||||
>
|
||||
@ -195,7 +241,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSetting } from "@/utils/settings";
|
||||
import { getSetting, setSetting } from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
name: "RandomPicker",
|
||||
@ -227,6 +273,9 @@ export default {
|
||||
excludeLate: getSetting("randomPicker.excludeLate"),
|
||||
excludeExcluded: getSetting("randomPicker.excludeExcluded"),
|
||||
},
|
||||
pickerMode: getSetting("randomPicker.mode"),
|
||||
minNumber: getSetting("randomPicker.minNumber"),
|
||||
maxNumber: getSetting("randomPicker.maxNumber"),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -241,12 +290,25 @@ export default {
|
||||
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() {
|
||||
if (this.pickerMode === "number") {
|
||||
return this.numberModeStudents;
|
||||
}
|
||||
|
||||
if (!this.studentList || !this.studentList.length) return [];
|
||||
|
||||
return this.studentList.filter((student) => {
|
||||
// 根据临时过滤选项过滤学生
|
||||
if (
|
||||
this.tempFilters.excludeAbsent &&
|
||||
this.attendance.absent.includes(student)
|
||||
@ -318,6 +380,35 @@ export default {
|
||||
},
|
||||
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: {
|
||||
open() {
|
||||
@ -616,4 +707,45 @@ export default {
|
||||
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>
|
||||
|
30
src/components/settings/cards/RandomPickerCard.vue
Normal file
30
src/components/settings/cards/RandomPickerCard.vue
Normal 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>
|
@ -143,7 +143,9 @@
|
||||
<v-tabs-window-item value="student">
|
||||
<student-list-card border :is-mobile="isMobile" />
|
||||
</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"
|
||||
><settings-card border title="开发者选项" icon="mdi-developer-board">
|
||||
<v-list>
|
||||
@ -222,7 +224,7 @@ import SettingsExplorer from "@/components/settings/SettingsExplorer.vue";
|
||||
import SettingsLinkGenerator from "@/components/SettingsLinkGenerator.vue";
|
||||
import dataProvider from "@/utils/dataProvider";
|
||||
import NamespaceSettingsCard from "@/components/settings/cards/NamespaceSettingsCard.vue";
|
||||
|
||||
import RandomPickerCard from "@/components/settings/cards/RandomPickerCard.vue";
|
||||
export default {
|
||||
name: "Settings",
|
||||
components: {
|
||||
@ -240,6 +242,7 @@ export default {
|
||||
SettingsExplorer,
|
||||
SettingsLinkGenerator,
|
||||
NamespaceSettingsCard,
|
||||
RandomPickerCard,
|
||||
},
|
||||
setup() {
|
||||
const { mobile } = useDisplay();
|
||||
@ -372,6 +375,11 @@ export default {
|
||||
icon: "mdi-account-group",
|
||||
value: "student",
|
||||
},
|
||||
{
|
||||
title: "随机点名",
|
||||
icon: "mdi-dice-multiple",
|
||||
value: "randomPicker",
|
||||
},
|
||||
{
|
||||
title: "开发者",
|
||||
icon: "mdi-developer-board",
|
||||
|
@ -360,7 +360,7 @@ const settingsDefinitions = {
|
||||
"randomPicker.defaultCount": {
|
||||
type: "number",
|
||||
default: 1,
|
||||
validate: (value) => value >= 1 && value <= 10,
|
||||
validate: (value) => value >= 1 && value,
|
||||
description: "默认抽取人数",
|
||||
icon: "mdi-counter",
|
||||
},
|
||||
@ -382,6 +382,27 @@ const settingsDefinitions = {
|
||||
description: "是否排除不参与学生",
|
||||
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",
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user