mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-07-05 02:59:23 +00:00
1
This commit is contained in:
parent
a3decdb6d8
commit
e31578ee10
@ -4,7 +4,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite --host",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint . --fix"
|
"lint": "eslint . --fix"
|
||||||
|
@ -1,58 +1,253 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app-bar>
|
<v-app-bar elevation="1">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-btn icon="mdi-arrow-left" variant="text" @click="$router.push('/')" />
|
<v-btn
|
||||||
|
icon="mdi-arrow-left"
|
||||||
|
variant="text"
|
||||||
|
@click="$router.push('/')"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-app-bar-title>设置</v-app-bar-title>
|
<v-app-bar-title class="text-h6 font-weight-medium">设置</v-app-bar-title>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
|
|
||||||
<v-container>
|
<v-container class="py-4">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12" md="6">
|
||||||
<v-card>
|
<v-card elevation="2" class="rounded-lg">
|
||||||
<v-card-title>服务器设置</v-card-title>
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-server" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">服务器设置</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="serverDomain"
|
v-model="serverDomain"
|
||||||
label="服务器域名"
|
label="服务器域名"
|
||||||
placeholder="例如: http://example.com"
|
placeholder="例如: http://example.com"
|
||||||
|
prepend-inner-icon="mdi-web"
|
||||||
|
variant="outlined"
|
||||||
|
density="comfortable"
|
||||||
|
class="mb-4"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="classNumber"
|
v-model="classNumber"
|
||||||
label="班号"
|
label="班号"
|
||||||
placeholder="例如: 1 或 A"
|
placeholder="例如: 1 或 A"
|
||||||
|
prepend-inner-icon="mdi-account-group"
|
||||||
|
variant="outlined"
|
||||||
|
density="comfortable"
|
||||||
required
|
required
|
||||||
:rules="[v => !!v || '班号不能为空', v => /^[A-Za-z0-9]+$/.test(v) || '班号只能包含字母和数字']"
|
:rules="[v => !!v || '班号不能为空', v => /^[A-Za-z0-9]+$/.test(v) || '班号只能包含字母和数字']"
|
||||||
/>
|
/>
|
||||||
<v-btn color="primary" @click="saveServerSettings">保存</v-btn>
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="px-4 pb-4">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
block
|
||||||
|
@click="saveServerSettings"
|
||||||
|
>
|
||||||
|
保存设置
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title class="d-flex align-center">
|
<v-col cols="12" md="6">
|
||||||
学生列表设置
|
<v-card elevation="2" class="rounded-lg">
|
||||||
<v-spacer />
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-refresh" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">自动刷新设置(不建议启用)</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-switch
|
||||||
|
v-model="autoRefresh"
|
||||||
|
label="启用自动刷新"
|
||||||
|
color="primary"
|
||||||
|
hide-details
|
||||||
|
class="mb-4"
|
||||||
|
/>
|
||||||
|
<v-text-field
|
||||||
|
v-model="refreshInterval"
|
||||||
|
type="number"
|
||||||
|
label="刷新间隔"
|
||||||
|
suffix="秒"
|
||||||
|
:disabled="!autoRefresh"
|
||||||
|
variant="outlined"
|
||||||
|
density="comfortable"
|
||||||
|
:rules="[
|
||||||
|
v => v >= 10 || '刷新间隔不能小于10秒',
|
||||||
|
v => v <= 3600 || '刷新间隔不能大于3600秒'
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="px-4 pb-4">
|
||||||
<v-btn
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
block
|
||||||
|
@click="saveRefreshSettings"
|
||||||
|
>
|
||||||
|
保存设置
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-card elevation="2" class="rounded-lg">
|
||||||
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-format-size" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">字体设置</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-text-field
|
||||||
|
v-model="fontSize"
|
||||||
|
type="number"
|
||||||
|
label="字体大小"
|
||||||
|
suffix="px"
|
||||||
|
variant="outlined"
|
||||||
|
density="comfortable"
|
||||||
|
class="mb-4"
|
||||||
|
:rules="[
|
||||||
|
v => v >= 16 || '字体大小不能小于16px',
|
||||||
|
v => v <= 100 || '字体大小不能大于100px'
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="px-4 pb-4">
|
||||||
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="outlined"
|
||||||
|
prepend-icon="mdi-refresh"
|
||||||
|
class="flex-grow-1"
|
||||||
|
@click="resetFontSize"
|
||||||
|
>
|
||||||
|
重置
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
class="flex-grow-1"
|
||||||
|
@click="saveFontSize"
|
||||||
|
>
|
||||||
|
保存设置
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-card elevation="2" class="rounded-lg">
|
||||||
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-pencil-cog" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">编辑设置</v-card-title>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<v-switch
|
||||||
|
v-model="autoSave"
|
||||||
|
label="启用自动保存"
|
||||||
|
color="primary"
|
||||||
|
hide-details
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<v-tooltip location="right">
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-help-circle-outline"
|
||||||
|
size="small"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
编辑完成后自动上传到服务器
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
|
</v-switch>
|
||||||
|
|
||||||
|
<v-switch
|
||||||
|
v-model="refreshBeforeEdit"
|
||||||
|
label="编辑前自动刷新"
|
||||||
|
color="primary"
|
||||||
|
hide-details
|
||||||
|
>
|
||||||
|
<template v-slot:append>
|
||||||
|
<v-tooltip location="right">
|
||||||
|
<template v-slot:activator="{ props }">
|
||||||
|
<v-icon
|
||||||
|
v-bind="props"
|
||||||
|
icon="mdi-help-circle-outline"
|
||||||
|
size="small"
|
||||||
|
class="ml-2"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
打开编辑框前自动从服务器获取最新数据
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
|
</v-switch>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-actions class="px-4 pb-4">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-content-save"
|
||||||
|
block
|
||||||
|
@click="saveEditSettings"
|
||||||
|
>
|
||||||
|
保存设置
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-card elevation="2" class="rounded-lg">
|
||||||
|
<v-card-item>
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon icon="mdi-account-multiple" size="large" class="mr-2" />
|
||||||
|
</template>
|
||||||
|
<v-card-title class="text-h6">学生列表设置</v-card-title>
|
||||||
|
<template v-slot:append>
|
||||||
|
<v-btn
|
||||||
|
:color="showAdvancedEdit ? 'primary' : undefined"
|
||||||
variant="text"
|
variant="text"
|
||||||
prepend-icon="mdi-code-braces"
|
prepend-icon="mdi-code-braces"
|
||||||
@click="showAdvancedEdit = !showAdvancedEdit"
|
@click="showAdvancedEdit = !showAdvancedEdit"
|
||||||
>
|
>
|
||||||
{{ showAdvancedEdit ? '基础编辑' : '高级编辑' }}
|
{{ showAdvancedEdit ? '返回基础编辑' : '高级编辑' }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-title>
|
</template>
|
||||||
|
</v-card-item>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-expand-transition>
|
<v-expand-transition>
|
||||||
<div v-if="!showAdvancedEdit">
|
<div v-if="!showAdvancedEdit">
|
||||||
<v-row class="mb-4">
|
<v-row class="mb-6">
|
||||||
<v-col cols="12" sm="6" md="4">
|
<v-col cols="12" sm="6" md="4">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newStudent"
|
v-model="newStudent"
|
||||||
label="添加学生"
|
label="添加学生"
|
||||||
placeholder="输入学生姓名"
|
placeholder="输入学生姓名后回车添加"
|
||||||
|
prepend-inner-icon="mdi-account-plus"
|
||||||
|
variant="outlined"
|
||||||
hide-details
|
hide-details
|
||||||
@keyup.enter="addStudent"
|
@keyup.enter="addStudent"
|
||||||
>
|
>
|
||||||
@ -60,6 +255,7 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-plus"
|
icon="mdi-plus"
|
||||||
variant="text"
|
variant="text"
|
||||||
|
color="primary"
|
||||||
:disabled="!newStudent.trim()"
|
:disabled="!newStudent.trim()"
|
||||||
@click="addStudent"
|
@click="addStudent"
|
||||||
/>
|
/>
|
||||||
@ -77,134 +273,162 @@
|
|||||||
md="4"
|
md="4"
|
||||||
lg="3"
|
lg="3"
|
||||||
>
|
>
|
||||||
<v-card variant="outlined" class="student-card">
|
<v-hover v-slot="{ isHovering, props }">
|
||||||
<v-card-text class="d-flex align-center">
|
<v-card
|
||||||
<span class="mr-2">{{ index + 1 }}.</span>
|
v-bind="props"
|
||||||
<span class="text-body-1 flex-grow-1">{{ student }}</span>
|
:elevation="isMobile ? 1 : (isHovering ? 4 : 1)"
|
||||||
|
:class="[
|
||||||
|
'student-card',
|
||||||
|
{
|
||||||
|
'bg-primary-subtle': isHovering && !isMobile,
|
||||||
|
'mobile': isMobile
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
border
|
||||||
|
>
|
||||||
|
<v-card-text class="d-flex align-center pa-3">
|
||||||
|
<v-menu
|
||||||
|
location="bottom"
|
||||||
|
:open-on-hover="!isMobile"
|
||||||
|
:open-on-long-press="isMobile"
|
||||||
|
>
|
||||||
|
<template v-slot:activator="{ props: menuProps }">
|
||||||
|
<v-btn
|
||||||
|
variant="tonal"
|
||||||
|
size="small"
|
||||||
|
class="mr-3 font-weight-medium"
|
||||||
|
v-bind="menuProps"
|
||||||
|
>
|
||||||
|
{{ index + 1 }}
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list density="compact" nav>
|
||||||
|
<v-list-item
|
||||||
|
prepend-icon="mdi-arrow-up-bold"
|
||||||
|
:disabled="index === 0"
|
||||||
|
@click="moveToTop(index)"
|
||||||
|
>
|
||||||
|
置顶
|
||||||
|
</v-list-item>
|
||||||
|
<v-divider />
|
||||||
|
<v-list-item
|
||||||
|
prepend-icon="mdi-arrow-up"
|
||||||
|
:disabled="index === 0"
|
||||||
|
@click="moveStudent(index, 'up')"
|
||||||
|
>
|
||||||
|
上移
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item
|
||||||
|
prepend-icon="mdi-arrow-down"
|
||||||
|
:disabled="index === studentsList.length - 1"
|
||||||
|
@click="moveStudent(index, 'down')"
|
||||||
|
>
|
||||||
|
下移
|
||||||
|
</v-list-item>
|
||||||
|
<v-divider />
|
||||||
|
<v-list-item
|
||||||
|
prepend-icon="mdi-format-list-numbered"
|
||||||
|
@click="setStudentNumber(index)"
|
||||||
|
>
|
||||||
|
设置序号
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
|
||||||
|
<v-text-field
|
||||||
|
v-if="editingIndex === index"
|
||||||
|
v-model="editingName"
|
||||||
|
density="compact"
|
||||||
|
variant="underlined"
|
||||||
|
hide-details
|
||||||
|
class="flex-grow-1"
|
||||||
|
@keyup.enter="saveEdit"
|
||||||
|
@blur="saveEdit"
|
||||||
|
autofocus
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-body-1 flex-grow-1"
|
||||||
|
@click="isMobile ? startEdit(index, student) : null"
|
||||||
|
@dblclick="!isMobile ? startEdit(index, student) : null"
|
||||||
|
>
|
||||||
|
{{ student }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="d-flex gap-1 action-buttons"
|
||||||
|
:class="{'opacity-100': isHovering || isMobile}"
|
||||||
|
>
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-pencil"
|
||||||
|
variant="text"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
@click="startEdit(index, student)"
|
||||||
|
/>
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-delete"
|
icon="mdi-delete"
|
||||||
variant="text"
|
variant="text"
|
||||||
color="error"
|
color="error"
|
||||||
size="small"
|
size="small"
|
||||||
@click="removeStudent(index)"
|
@click="confirmDelete(index)"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
</v-hover>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-expand-transition>
|
<v-expand-transition>
|
||||||
<div v-if="showAdvancedEdit">
|
<div v-if="showAdvancedEdit" class="pt-2">
|
||||||
<v-textarea
|
<v-textarea
|
||||||
v-model="students"
|
v-model="students"
|
||||||
label="学生列表(每行一个名字)"
|
label="批量编辑学生列表"
|
||||||
|
placeholder="每行输入一个学生姓名"
|
||||||
hint="使用文本编辑模式批量编辑学生名单"
|
hint="使用文本编辑模式批量编辑学生名单"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
|
variant="outlined"
|
||||||
|
rows="10"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-row class="mt-4">
|
<v-row class="mt-6">
|
||||||
<v-col cols="12" class="d-flex gap-2">
|
<v-col cols="12" class="d-flex gap-2">
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
prepend-icon="mdi-content-save"
|
prepend-icon="mdi-content-save"
|
||||||
|
size="large"
|
||||||
@click="saveStudents"
|
@click="saveStudents"
|
||||||
>
|
>
|
||||||
保存
|
保存学生列表
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
prepend-icon="mdi-refresh"
|
prepend-icon="mdi-refresh"
|
||||||
|
size="large"
|
||||||
@click="reloadStudentList"
|
@click="reloadStudentList"
|
||||||
>
|
>
|
||||||
重置
|
重置列表
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card disabled>
|
<v-card elevation="2" class="rounded-lg">
|
||||||
<v-card-title>自动刷新设置</v-card-title>
|
<v-card-item>
|
||||||
<v-card-text>
|
<template v-slot:prepend>
|
||||||
<v-switch v-model="autoRefresh" label="启用自动刷新"/>
|
<v-icon icon="mdi-information" size="large" class="mr-2" />
|
||||||
<v-text-field
|
</template>
|
||||||
v-model="refreshInterval"
|
<v-card-title class="text-h6">关于</v-card-title>
|
||||||
type="number"
|
</v-card-item>
|
||||||
label="刷新间隔(秒)"
|
|
||||||
:disabled="!autoRefresh"
|
|
||||||
/>
|
|
||||||
<v-btn color="primary" @click="saveRefreshSettings">保存</v-btn>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>字体设置</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-row align="center">
|
|
||||||
<v-col>
|
|
||||||
<v-text-field
|
|
||||||
v-model="fontSize"
|
|
||||||
type="number"
|
|
||||||
label="字体大小"
|
|
||||||
suffix="px"
|
|
||||||
:rules="[
|
|
||||||
v => v >= 16 || '字体大小不能小于16px',
|
|
||||||
v => v <= 100 || '字体大小不能大于100px'
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="auto">
|
|
||||||
<v-btn color="primary" @click="saveFontSize">保存</v-btn>
|
|
||||||
</v-col>
|
|
||||||
<v-col cols="auto">
|
|
||||||
<v-btn color="error" @click="resetFontSize">重置</v-btn>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-card>
|
|
||||||
<v-card-title>编辑设置</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<v-switch
|
|
||||||
v-model="autoSave"
|
|
||||||
label="启用自动保存"
|
|
||||||
hint="编辑完成后自动上传到服务器"
|
|
||||||
persistent-hint
|
|
||||||
@change="saveEditSettings"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<v-switch
|
|
||||||
v-model="refreshBeforeEdit"
|
|
||||||
label="编辑前自动刷新"
|
|
||||||
hint="打开编辑框前自动从服务器获取最新数据"
|
|
||||||
persistent-hint
|
|
||||||
@change="saveEditSettings"
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-card>
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row justify="center" align="center">
|
<v-row justify="center" align="center">
|
||||||
<v-col cols="12" md="8" class="text-center">
|
<v-col cols="12" md="8" class="text-center">
|
||||||
@ -216,9 +440,13 @@
|
|||||||
</v-avatar>
|
</v-avatar>
|
||||||
<h2 class="text-h5 mb-2">HomeworkPage</h2>
|
<h2 class="text-h5 mb-2">HomeworkPage</h2>
|
||||||
<p class="text-body-1 mb-4">
|
<p class="text-body-1 mb-4">
|
||||||
由 <a href="https://github.com/sunwuyuan" target="_blank" class="text-decoration-none">Sunwuyuan</a> 开发
|
由 <a
|
||||||
|
href="https://github.com/sunwuyuan"
|
||||||
|
target="_blank"
|
||||||
|
class="text-decoration-none font-weight-medium"
|
||||||
|
>Sunwuyuan</a> 开发
|
||||||
</p>
|
</p>
|
||||||
<div class="d-flex justify-center gap-2">
|
<div class="d-flex justify-center gap-2 flex-wrap">
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@ -240,13 +468,15 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
href="https://github.com/SunWuyuan/homeworkpage-backend"
|
href="https://github.com/SunWuyuan/homeworkpage-backend/issues"
|
||||||
|
target="_blank"
|
||||||
|
prepend-icon="mdi-bug"
|
||||||
>
|
>
|
||||||
报告问题
|
报告问题
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<p class="mt-4 text-caption">
|
<p class="mt-4 text-caption text-medium-emphasis">
|
||||||
GPL License
|
GPL License © 2024
|
||||||
</p>
|
</p>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@ -259,12 +489,68 @@
|
|||||||
<v-snackbar v-model="snackbar">
|
<v-snackbar v-model="snackbar">
|
||||||
{{ snackbarText }}
|
{{ snackbarText }}
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
|
|
||||||
|
<v-dialog v-model="deleteDialog" max-width="300">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>确认删除</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
确定要删除学生 "{{ studentToDelete?.name }}" 吗?
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn color="primary" variant="text" @click="deleteDialog = false">
|
||||||
|
取消
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="text"
|
||||||
|
@click="removeStudent(studentToDelete?.index)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog v-model="numberDialog" max-width="300">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>设置序号</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-text-field
|
||||||
|
v-model="newPosition"
|
||||||
|
type="number"
|
||||||
|
label="新序号"
|
||||||
|
:rules="[
|
||||||
|
v => !!v || '序号不能为空',
|
||||||
|
v => v > 0 || '序号必须大于0',
|
||||||
|
v => v <= studentsList.length || `序号不能大于${studentsList.length}`
|
||||||
|
]"
|
||||||
|
@keyup.enter="applyNewPosition"
|
||||||
|
/>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn color="primary" variant="text" @click="numberDialog = false">
|
||||||
|
取消
|
||||||
|
</v-btn>
|
||||||
|
<v-btn color="primary" @click="applyNewPosition">
|
||||||
|
确定
|
||||||
|
</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { useDisplay } from 'vuetify';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
setup() {
|
||||||
|
const { mobile } = useDisplay();
|
||||||
|
return { isMobile: mobile };
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
serverDomain: '',
|
serverDomain: '',
|
||||||
@ -280,6 +566,15 @@ export default {
|
|||||||
refreshBeforeEdit: false,
|
refreshBeforeEdit: false,
|
||||||
showAdvancedEdit: false,
|
showAdvancedEdit: false,
|
||||||
newStudent: '',
|
newStudent: '',
|
||||||
|
editingIndex: -1,
|
||||||
|
editingName: '',
|
||||||
|
deleteDialog: false,
|
||||||
|
studentToDelete: null,
|
||||||
|
numberDialog: false,
|
||||||
|
newPosition: '',
|
||||||
|
studentToMove: null,
|
||||||
|
touchStartTime: 0,
|
||||||
|
touchTimeout: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -426,7 +721,13 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
removeStudent(index) {
|
removeStudent(index) {
|
||||||
|
if (index !== undefined) {
|
||||||
this.studentsList.splice(index, 1);
|
this.studentsList.splice(index, 1);
|
||||||
|
this.deleteDialog = false;
|
||||||
|
this.studentToDelete = null;
|
||||||
|
this.synced = false;
|
||||||
|
if (this.autoSave) this.saveStudents();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reloadStudentList() {
|
reloadStudentList() {
|
||||||
@ -443,20 +744,159 @@ export default {
|
|||||||
this.snackbarText = text;
|
this.snackbarText = text;
|
||||||
this.snackbar = true;
|
this.snackbar = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
startEdit(index, name) {
|
||||||
|
if (this.editingIndex !== -1 && this.editingIndex !== index) {
|
||||||
|
this.saveEdit();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editingIndex = index;
|
||||||
|
this.editingName = name;
|
||||||
|
},
|
||||||
|
|
||||||
|
saveEdit() {
|
||||||
|
if (this.editingIndex !== -1) {
|
||||||
|
const newName = this.editingName.trim();
|
||||||
|
if (newName && newName !== this.studentsList[this.editingIndex]) {
|
||||||
|
this.studentsList[this.editingIndex] = newName;
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.saveStudents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.editingIndex = -1;
|
||||||
|
this.editingName = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmDelete(index) {
|
||||||
|
this.studentToDelete = {
|
||||||
|
index,
|
||||||
|
name: this.studentsList[index]
|
||||||
|
};
|
||||||
|
this.deleteDialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
moveStudent(index, direction) {
|
||||||
|
const newIndex = direction === 'up' ? index - 1 : index + 1;
|
||||||
|
if (newIndex >= 0 && newIndex < this.studentsList.length) {
|
||||||
|
[this.studentsList[index], this.studentsList[newIndex]] =
|
||||||
|
[this.studentsList[newIndex], this.studentsList[index]];
|
||||||
|
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.saveStudents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setStudentNumber(index) {
|
||||||
|
this.studentToMove = index;
|
||||||
|
this.newPosition = String(index + 1);
|
||||||
|
this.numberDialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
applyNewPosition() {
|
||||||
|
const newPos = parseInt(this.newPosition) - 1;
|
||||||
|
if (
|
||||||
|
this.studentToMove !== null &&
|
||||||
|
newPos >= 0 &&
|
||||||
|
newPos < this.studentsList.length &&
|
||||||
|
newPos !== this.studentToMove
|
||||||
|
) {
|
||||||
|
const student = this.studentsList[this.studentToMove];
|
||||||
|
this.studentsList.splice(this.studentToMove, 1);
|
||||||
|
this.studentsList.splice(newPos, 0, student);
|
||||||
|
this.synced = false;
|
||||||
|
if (this.autoSave) this.saveStudents();
|
||||||
|
}
|
||||||
|
this.numberDialog = false;
|
||||||
|
this.studentToMove = null;
|
||||||
|
this.newPosition = '';
|
||||||
|
},
|
||||||
|
|
||||||
|
moveToTop(index) {
|
||||||
|
if (index > 0) {
|
||||||
|
const student = this.studentsList[index];
|
||||||
|
this.studentsList.splice(index, 1);
|
||||||
|
this.studentsList.unshift(student);
|
||||||
|
|
||||||
|
if (this.autoSave) {
|
||||||
|
this.saveStudents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.student-card {
|
.student-card {
|
||||||
transition: all 0.3s ease;
|
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.student-card:hover {
|
.bg-primary-subtle {
|
||||||
background-color: rgba(var(--v-theme-primary), 0.05);
|
background-color: rgb(var(--v-theme-primary), 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-1 {
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gap-2 {
|
.gap-2 {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.student-card .v-text-field {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.v-container {
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.v-col {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card.mobile {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card.mobile .v-btn {
|
||||||
|
min-width: 40px;
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card.mobile .v-text-field {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
.v-col {
|
||||||
|
padding: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card {
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.student-card:active {
|
||||||
|
background-color: rgb(var(--v-theme-primary), 0.05);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
Loading…
x
Reference in New Issue
Block a user