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>
|
||||||
|
|
||||||
|
<!-- 添加模式切换 -->
|
||||||
|
<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>
|
||||||
|
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">
|
<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",
|
||||||
|
@ -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",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user