mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2025-10-22 02:03:10 +00:00
Use kvToken instead of siteKey in examschedule button cloud URL
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
This commit is contained in:
parent
3284138ea1
commit
92a2019566
@ -3,13 +3,18 @@
|
||||
"Component": true,
|
||||
"ComponentPublicInstance": true,
|
||||
"ComputedRef": true,
|
||||
"DirectiveBinding": true,
|
||||
"EffectScope": true,
|
||||
"ExtractDefaultPropTypes": true,
|
||||
"ExtractPropTypes": true,
|
||||
"ExtractPublicPropTypes": true,
|
||||
"InjectionKey": true,
|
||||
"MaybeRef": true,
|
||||
"MaybeRefOrGetter": true,
|
||||
"PropType": true,
|
||||
"Ref": true,
|
||||
"Slot": true,
|
||||
"Slots": true,
|
||||
"VNode": true,
|
||||
"WritableComputedRef": true,
|
||||
"computed": true,
|
||||
@ -43,6 +48,7 @@
|
||||
"onServerPrefetch": true,
|
||||
"onUnmounted": true,
|
||||
"onUpdated": true,
|
||||
"onWatcherCleanup": true,
|
||||
"provide": true,
|
||||
"reactive": true,
|
||||
"readonly": true,
|
||||
@ -60,20 +66,16 @@
|
||||
"useAttrs": true,
|
||||
"useCssModule": true,
|
||||
"useCssVars": true,
|
||||
"useId": true,
|
||||
"useLink": true,
|
||||
"useModel": true,
|
||||
"useRoute": true,
|
||||
"useRouter": true,
|
||||
"useSlots": true,
|
||||
"useTemplateRef": true,
|
||||
"watch": true,
|
||||
"watchEffect": true,
|
||||
"watchPostEffect": true,
|
||||
"watchSyncEffect": true,
|
||||
"DirectiveBinding": true,
|
||||
"MaybeRef": true,
|
||||
"MaybeRefOrGetter": true,
|
||||
"onWatcherCleanup": true,
|
||||
"useId": true,
|
||||
"useModel": true,
|
||||
"useTemplateRef": true
|
||||
"watchSyncEffect": true
|
||||
}
|
||||
}
|
||||
|
10
src/App.vue
10
src/App.vue
@ -4,8 +4,14 @@
|
||||
<kv-initialize />
|
||||
<!-- 正常路由 -->
|
||||
<router-view v-slot="{ Component, route }">
|
||||
<transition name="md3" mode="out-in">
|
||||
<component :is="Component" :key="route.path" />
|
||||
<transition
|
||||
name="md3"
|
||||
mode="out-in"
|
||||
>
|
||||
<component
|
||||
:is="Component"
|
||||
:key="route.path"
|
||||
/>
|
||||
</transition>
|
||||
</router-view>
|
||||
<global-message />
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<v-footer height="40" app>
|
||||
<v-footer
|
||||
height="40"
|
||||
app
|
||||
>
|
||||
<a
|
||||
v-for="item in items"
|
||||
:key="item.title"
|
||||
@ -9,7 +12,10 @@
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
<v-icon :icon="item.icon" :size="item.icon === 'mdi-earth' ? 24 : 16" />
|
||||
<v-icon
|
||||
:icon="item.icon"
|
||||
:size="item.icon === 'mdi-earth' ? 24 : 16"
|
||||
/>
|
||||
</a>
|
||||
|
||||
|
||||
@ -17,7 +23,6 @@
|
||||
class="text-caption text-disabled"
|
||||
style="position: absolute; right: 16px"
|
||||
>
|
||||
|
||||
<a
|
||||
class="text-decoration-none on-surface"
|
||||
href="https://github.com/ZeroCatDev/Classworks"
|
||||
|
@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<v-app-bar :elevation="2">
|
||||
<template v-slot:prepend>
|
||||
<v-app-bar-nav-icon></v-app-bar-nav-icon>
|
||||
</template>
|
||||
<v-app-bar :elevation="2">
|
||||
<template #prepend>
|
||||
<v-app-bar-nav-icon />
|
||||
</template>
|
||||
|
||||
<v-app-bar-title>作业</v-app-bar-title>
|
||||
</v-app-bar>
|
||||
<v-app-bar-title>作业</v-app-bar-title>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -2,48 +2,85 @@
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<span>缓存管理</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="error" @click="clearAllCaches" :loading="loading">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="error"
|
||||
:loading="loading"
|
||||
@click="clearAllCaches"
|
||||
>
|
||||
清除所有缓存
|
||||
</v-btn>
|
||||
<v-btn icon class="ml-2" @click="refreshCaches">
|
||||
<v-btn
|
||||
icon
|
||||
class="ml-2"
|
||||
@click="refreshCaches"
|
||||
>
|
||||
<v-icon>mdi-refresh</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-alert v-if="!serviceWorkerActive" type="warning" class="mb-4">
|
||||
<v-alert
|
||||
v-if="!serviceWorkerActive"
|
||||
type="warning"
|
||||
class="mb-4"
|
||||
>
|
||||
Service Worker 未激活,缓存管理功能不可用。
|
||||
</v-alert>
|
||||
|
||||
<v-alert v-if="message" :type="messageType" class="mb-4">
|
||||
<v-alert
|
||||
v-if="message"
|
||||
:type="messageType"
|
||||
class="mb-4"
|
||||
>
|
||||
{{ message }}
|
||||
</v-alert>
|
||||
|
||||
<v-expansion-panels v-if="caches.length > 0">
|
||||
<v-expansion-panel v-for="cache in caches" :key="cache.name">
|
||||
<v-expansion-panel
|
||||
v-for="cache in caches"
|
||||
:key="cache.name"
|
||||
>
|
||||
<v-expansion-panel-title>
|
||||
<div class="d-flex align-center">
|
||||
<span>{{ formatCacheName(cache.name) }}</span>
|
||||
<v-chip class="ml-2" size="small">{{ cache.urls.length }} 个文件</v-chip>
|
||||
<v-chip
|
||||
class="ml-2"
|
||||
size="small"
|
||||
>
|
||||
{{ cache.urls.length }} 个文件
|
||||
</v-chip>
|
||||
</div>
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<div class="d-flex justify-end mb-2">
|
||||
<v-btn color="error" size="small" @click="clearCache(cache.name)" :loading="loading">
|
||||
<v-btn
|
||||
color="error"
|
||||
size="small"
|
||||
:loading="loading"
|
||||
@click="clearCache(cache.name)"
|
||||
>
|
||||
清除此缓存
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-list lines="two">
|
||||
<v-list-item v-for="(url, index) in cache.urls" :key="index">
|
||||
<v-list-item
|
||||
v-for="(url, index) in cache.urls"
|
||||
:key="index"
|
||||
>
|
||||
<v-list-item-title class="text-truncate">
|
||||
{{ getFileName(url) }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="text-truncate">
|
||||
{{ url }}
|
||||
</v-list-item-subtitle>
|
||||
<template v-slot:append>
|
||||
<v-btn icon size="small" color="error" @click="clearUrl(cache.name, url)">
|
||||
<template #append>
|
||||
<v-btn
|
||||
icon
|
||||
size="small"
|
||||
color="error"
|
||||
@click="clearUrl(cache.name, url)"
|
||||
>
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</template>
|
||||
@ -53,9 +90,15 @@
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
|
||||
<v-skeleton-loader v-else-if="loading" type="article" />
|
||||
<v-skeleton-loader
|
||||
v-else-if="loading"
|
||||
type="article"
|
||||
/>
|
||||
|
||||
<v-alert v-else type="info">
|
||||
<v-alert
|
||||
v-else
|
||||
type="info"
|
||||
>
|
||||
没有找到缓存数据。
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
|
@ -11,7 +11,9 @@
|
||||
@click:close="error = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-alert-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-alert-circle
|
||||
</v-icon>
|
||||
{{ error }}
|
||||
</div>
|
||||
</v-alert>
|
||||
@ -27,7 +29,9 @@
|
||||
@click:close="success = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-check-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-check-circle
|
||||
</v-icon>
|
||||
{{ success }}
|
||||
</div>
|
||||
</v-alert>
|
||||
@ -43,37 +47,57 @@
|
||||
<div class="d-flex align-center">
|
||||
<span class="font-weight-bold">配置验证失败,请检查以下问题:</span>
|
||||
</div>
|
||||
<v-list density="compact" class="bg-transparent">
|
||||
<v-list
|
||||
density="compact"
|
||||
class="bg-transparent"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(error, index) in validationErrors"
|
||||
:key="index"
|
||||
class="px-0 py-0"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon size="small" color="warning">mdi-circle-small</v-icon>
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
size="small"
|
||||
color="warning"
|
||||
>
|
||||
mdi-circle-small
|
||||
</v-icon>
|
||||
</template>
|
||||
<v-list-item-title class="text-body-2">{{ error }}</v-list-item-title>
|
||||
<v-list-item-title class="text-body-2">
|
||||
{{ error }}
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-alert>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<v-card v-if="loading" class="my-4" outlined>
|
||||
<v-card
|
||||
v-if="loading"
|
||||
class="my-4"
|
||||
outlined
|
||||
>
|
||||
<v-card-text>
|
||||
<v-skeleton-loader type="article" class="mx-auto"></v-skeleton-loader>
|
||||
<v-skeleton-loader
|
||||
type="article"
|
||||
class="mx-auto"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<!-- 模式切换按钮和操作按钮 -->
|
||||
<div v-if="!loading" class="d-flex justify-space-between align-center mb-4">
|
||||
<div
|
||||
v-if="!loading"
|
||||
class="d-flex justify-space-between align-center mb-4"
|
||||
>
|
||||
<div class="d-flex align-center gap-2">
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="elevated"
|
||||
prepend-icon="mdi-open-in-new"
|
||||
@click="openConfig"
|
||||
class="mr-2 text-none"
|
||||
:disabled="!isValidConfig"
|
||||
@click="openConfig"
|
||||
>
|
||||
打开 ExamSchedule
|
||||
</v-btn>
|
||||
@ -91,23 +115,36 @@
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
divided
|
||||
> <v-btn
|
||||
>
|
||||
<v-btn
|
||||
class="text-error"
|
||||
prepend-icon="mdi-delete"
|
||||
@click="confirmDelete"
|
||||
|
||||
>
|
||||
删除配置
|
||||
</v-btn>
|
||||
<v-btn :value="false" prepend-icon="mdi-eye"> 预览 </v-btn>
|
||||
<v-btn :value="true" prepend-icon="mdi-pencil"> 编辑 </v-btn>
|
||||
<v-btn
|
||||
:value="false"
|
||||
prepend-icon="mdi-eye"
|
||||
>
|
||||
预览
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:value="true"
|
||||
prepend-icon="mdi-pencil"
|
||||
>
|
||||
编辑
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</div>
|
||||
|
||||
<!-- 预览模式 -->
|
||||
<div v-if="!loading && !isEditMode">
|
||||
<div class="mb-8">
|
||||
<div class="text-h3 font-weight-bold" style="line-height: 1.2">
|
||||
<div
|
||||
class="text-h3 font-weight-bold"
|
||||
style="line-height: 1.2"
|
||||
>
|
||||
{{ localConfig.examName || "未设置考试名称" }}
|
||||
</div>
|
||||
<div
|
||||
@ -116,8 +153,14 @@
|
||||
>
|
||||
{{ localConfig.message || "未设置考试提示" }}
|
||||
</div>
|
||||
<v-chip v-if="localConfig.room" size="large" class="px-4 py-2">
|
||||
<v-icon start>mdi-home</v-icon>
|
||||
<v-chip
|
||||
v-if="localConfig.room"
|
||||
size="large"
|
||||
class="px-4 py-2"
|
||||
>
|
||||
<v-icon start>
|
||||
mdi-home
|
||||
</v-icon>
|
||||
考场:{{ localConfig.room }}
|
||||
</v-chip>
|
||||
</div>
|
||||
@ -133,19 +176,29 @@
|
||||
md="6"
|
||||
lg="4"
|
||||
>
|
||||
<v-card variant="tonal" class="h-100" hover>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
class="h-100"
|
||||
hover
|
||||
>
|
||||
<v-card-title class="bg-primary-lighten-5 pa-4">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-book-open-page-variant</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-book-open-page-variant
|
||||
</v-icon>
|
||||
<span class="">{{ examInfo.name || "未设置科目" }}</span>
|
||||
</div>
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-4">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex align-center mb-1">
|
||||
<v-icon size="small" class="mr-2" color="success"
|
||||
>mdi-clock-start</v-icon
|
||||
<v-icon
|
||||
size="small"
|
||||
class="mr-2"
|
||||
color="success"
|
||||
>
|
||||
mdi-clock-start
|
||||
</v-icon>
|
||||
<span class="text-body-2 text-grey-darken-1">开始时间</span>
|
||||
</div>
|
||||
<div class="text-h6 font-weight-medium text-success">
|
||||
@ -154,9 +207,13 @@
|
||||
</div>
|
||||
<div>
|
||||
<div class="d-flex align-center mb-1">
|
||||
<v-icon size="small" class="mr-2" color="error"
|
||||
>mdi-clock-end</v-icon
|
||||
<v-icon
|
||||
size="small"
|
||||
class="mr-2"
|
||||
color="error"
|
||||
>
|
||||
mdi-clock-end
|
||||
</v-icon>
|
||||
<span class="text-body-2 text-grey-darken-1">结束时间</span>
|
||||
</div>
|
||||
<div class="text-h6 font-weight-medium text-error">
|
||||
@ -168,29 +225,50 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
<div v-else class="text-center py-12">
|
||||
<v-icon size="80" color="grey-lighten-2" class="mb-4">
|
||||
<div
|
||||
v-else
|
||||
class="text-center py-12"
|
||||
>
|
||||
<v-icon
|
||||
size="80"
|
||||
color="grey-lighten-2"
|
||||
class="mb-4"
|
||||
>
|
||||
mdi-calendar-blank
|
||||
</v-icon>
|
||||
<div class="text-h5 text-grey-darken-1 mb-2">暂无考试科目安排</div>
|
||||
<div class="text-h5 text-grey-darken-1 mb-2">
|
||||
暂无考试科目安排
|
||||
</div>
|
||||
<div class="text-body-1 text-grey mb-4">
|
||||
点击上方"添加科目"按钮开始配置考试时间表
|
||||
</div>
|
||||
<v-btn color="primary" variant="outlined" @click="quickEdit">
|
||||
<v-icon start>mdi-plus</v-icon>
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
@click="quickEdit"
|
||||
>
|
||||
<v-icon start>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
立即添加
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<!-- JSON预览 -->
|
||||
<v-card class="mb-4" elevation="2" border>
|
||||
<v-card
|
||||
class="mb-4"
|
||||
elevation="2"
|
||||
border
|
||||
>
|
||||
<v-card-title
|
||||
class="d-flex align-center text-white cursor-pointer"
|
||||
@click="showJsonPreview = !showJsonPreview"
|
||||
>
|
||||
<v-icon class="mr-2">mdi-code-json</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-code-json
|
||||
</v-icon>
|
||||
JSON配置预览
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="white"
|
||||
variant="outlined"
|
||||
@ -206,12 +284,17 @@
|
||||
size="small"
|
||||
:icon="showJsonPreview ? 'mdi-chevron-up' : 'mdi-chevron-down'"
|
||||
class="ml-2"
|
||||
>
|
||||
</v-btn>
|
||||
/>
|
||||
</v-card-title>
|
||||
<v-expand-transition>
|
||||
<v-card-text v-show="showJsonPreview" class="pa-4">
|
||||
<v-card variant="tonal" class="pa-4">
|
||||
<v-card-text
|
||||
v-show="showJsonPreview"
|
||||
class="pa-4"
|
||||
>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
class="pa-4"
|
||||
>
|
||||
<pre class="json-preview"><code>{{ formattedJson }}</code></pre>
|
||||
</v-card>
|
||||
</v-card-text>
|
||||
@ -222,14 +305,23 @@
|
||||
<!-- 编辑模式 -->
|
||||
<div v-if="!loading && isEditMode">
|
||||
<!-- 基本信息 -->
|
||||
<v-card class="mb-4" elevation="1" border>
|
||||
<v-card
|
||||
class="mb-4"
|
||||
elevation="1"
|
||||
border
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-information</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-information
|
||||
</v-icon>
|
||||
基本信息
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-4">
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="localConfig.examName"
|
||||
label="考试名称"
|
||||
@ -237,15 +329,18 @@
|
||||
variant="outlined"
|
||||
:rules="[(v) => !!v || '考试名称不能为空']"
|
||||
required
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="localConfig.room"
|
||||
label="考场号(标准ES尚不支持此配置)"
|
||||
prepend-inner-icon="mdi-home"
|
||||
variant="outlined"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-textarea
|
||||
@ -255,7 +350,7 @@
|
||||
variant="outlined"
|
||||
rows="3"
|
||||
placeholder="输入考试相关的提示信息..."
|
||||
></v-textarea>
|
||||
/>
|
||||
|
||||
<!-- 默认提示选项 -->
|
||||
<v-chip-group
|
||||
@ -269,26 +364,42 @@
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
size="small"
|
||||
@click="selectDefaultTip(tip)"
|
||||
class="ma-1"
|
||||
@click="selectDefaultTip(tip)"
|
||||
>
|
||||
<v-icon start size="small">mdi-plus</v-icon>
|
||||
<v-icon
|
||||
start
|
||||
size="small"
|
||||
>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
{{ tip }}
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
<div class="text-caption text-medium-emphasis ml-2">
|
||||
<v-icon size="small" class="mr-1">mdi-lightbulb-outline</v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="mr-1"
|
||||
>
|
||||
mdi-lightbulb-outline
|
||||
</v-icon>
|
||||
点击上方选项快速添加常用考试提示
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<!-- 考试科目安排 -->
|
||||
<v-card class="mb-4" elevation="1" border>
|
||||
<v-card
|
||||
class="mb-4"
|
||||
elevation="1"
|
||||
border
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-format-list-bulleted</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-format-list-bulleted
|
||||
</v-icon>
|
||||
考试科目安排
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
prepend-icon="mdi-plus"
|
||||
@ -309,7 +420,10 @@
|
||||
>
|
||||
<div class="w-100">
|
||||
<v-row>
|
||||
<v-col cols="12" md="4">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="examInfo.name"
|
||||
label="科目名称"
|
||||
@ -317,9 +431,12 @@
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:rules="[(v) => !!v || '科目名称不能为空']"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" md="3">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="3"
|
||||
>
|
||||
<v-menu
|
||||
v-model="examInfo.startDateMenu"
|
||||
:close-on-content-click="false"
|
||||
@ -327,7 +444,7 @@
|
||||
offset-y
|
||||
min-width="auto"
|
||||
>
|
||||
<template v-slot:activator="{ props }">
|
||||
<template #activator="{ props }">
|
||||
<v-text-field
|
||||
v-model="examInfo.startFormatted"
|
||||
label="开始时间"
|
||||
@ -337,7 +454,7 @@
|
||||
readonly
|
||||
v-bind="props"
|
||||
:rules="[(v) => !!v || '开始时间不能为空']"
|
||||
></v-text-field>
|
||||
/>
|
||||
</template>
|
||||
<v-card min-width="600">
|
||||
<v-card-title class="text-center py-2">
|
||||
@ -345,30 +462,33 @@
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-0">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="6" class="border-e">
|
||||
<v-col
|
||||
cols="6"
|
||||
class="border-e"
|
||||
>
|
||||
<v-date-picker
|
||||
v-model="examInfo.startDate"
|
||||
@update:model-value="updateStartDateTime(index)"
|
||||
color="primary"
|
||||
locale="zh-cn"
|
||||
show-adjacent-months
|
||||
elevation="0"
|
||||
></v-date-picker>
|
||||
@update:model-value="updateStartDateTime(index)"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<v-time-picker
|
||||
v-model="examInfo.startTime"
|
||||
@update:model-value="updateStartDateTime(index)"
|
||||
color="primary"
|
||||
format="24hr"
|
||||
scrollable
|
||||
elevation="0"
|
||||
></v-time-picker>
|
||||
@update:model-value="updateStartDateTime(index)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@ -387,7 +507,10 @@
|
||||
</v-card>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" md="3">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="3"
|
||||
>
|
||||
<v-menu
|
||||
v-model="examInfo.endDateMenu"
|
||||
:close-on-content-click="false"
|
||||
@ -395,7 +518,7 @@
|
||||
offset-y
|
||||
min-width="auto"
|
||||
>
|
||||
<template v-slot:activator="{ props }">
|
||||
<template #activator="{ props }">
|
||||
<v-text-field
|
||||
v-model="examInfo.endFormatted"
|
||||
label="结束时间"
|
||||
@ -405,7 +528,7 @@
|
||||
readonly
|
||||
v-bind="props"
|
||||
:rules="[(v) => !!v || '结束时间不能为空']"
|
||||
></v-text-field>
|
||||
/>
|
||||
</template>
|
||||
<v-card min-width="600">
|
||||
<v-card-title class="text-center py-2">
|
||||
@ -413,30 +536,33 @@
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-0">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="6" class="border-e">
|
||||
<v-col
|
||||
cols="6"
|
||||
class="border-e"
|
||||
>
|
||||
<v-date-picker
|
||||
v-model="examInfo.endDate"
|
||||
@update:model-value="updateEndDateTime(index)"
|
||||
color="primary"
|
||||
locale="zh-cn"
|
||||
show-adjacent-months
|
||||
elevation="0"
|
||||
></v-date-picker>
|
||||
@update:model-value="updateEndDateTime(index)"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<v-time-picker
|
||||
v-model="examInfo.endTime"
|
||||
@update:model-value="updateEndDateTime(index)"
|
||||
color="primary"
|
||||
format="24hr"
|
||||
scrollable
|
||||
elevation="0"
|
||||
></v-time-picker>
|
||||
@update:model-value="updateEndDateTime(index)"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@ -455,7 +581,11 @@
|
||||
</v-card>
|
||||
</v-menu>
|
||||
</v-col>
|
||||
<v-col cols="12" md="2" class="d-flex align-center">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="2"
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
color="error"
|
||||
@ -490,14 +620,25 @@
|
||||
</div>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<div v-else class="text-center py-8">
|
||||
<v-icon size="48" color="grey-lighten-1" class="mb-2">
|
||||
<div
|
||||
v-else
|
||||
class="text-center py-8"
|
||||
>
|
||||
<v-icon
|
||||
size="48"
|
||||
color="grey-lighten-1"
|
||||
class="mb-2"
|
||||
>
|
||||
mdi-book-plus
|
||||
</v-icon>
|
||||
<p class="text-body-2 text-grey-darken-1 mb-4">
|
||||
暂无考试科目,点击"添加科目"按钮开始添加
|
||||
</p>
|
||||
<v-btn color="primary" prepend-icon="mdi-plus" @click="addExamInfo">
|
||||
<v-btn
|
||||
color="primary"
|
||||
prepend-icon="mdi-plus"
|
||||
@click="addExamInfo"
|
||||
>
|
||||
添加科目
|
||||
</v-btn>
|
||||
</div>
|
||||
@ -506,10 +647,18 @@
|
||||
</div>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<v-dialog v-model="deleteDialog" max-width="400">
|
||||
<v-dialog
|
||||
v-model="deleteDialog"
|
||||
max-width="400"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon color="error" class="mr-2">mdi-delete-alert</v-icon>
|
||||
<v-icon
|
||||
color="error"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-delete-alert
|
||||
</v-icon>
|
||||
确认删除配置
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
@ -517,7 +666,7 @@
|
||||
<br><small class="text-grey">此操作不可撤销,将会删除所有相关数据</small>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@ -528,8 +677,8 @@
|
||||
<v-btn
|
||||
color="error"
|
||||
variant="outlined"
|
||||
@click="deleteConfig"
|
||||
:loading="deleting"
|
||||
@click="deleteConfig"
|
||||
>
|
||||
删除
|
||||
</v-btn>
|
||||
|
@ -6,45 +6,52 @@
|
||||
rounded="xl"
|
||||
:class="{ 'toolbar-expanded': isExpanded }"
|
||||
>
|
||||
|
||||
|
||||
<v-btn-group variant="text" class="toolbar-buttons">
|
||||
<v-btn
|
||||
icon="mdi-chevron-left"
|
||||
<v-btn-group
|
||||
variant="text"
|
||||
@click="$emit('prev-day')"
|
||||
:title="'查看昨天'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
/>
|
||||
class="toolbar-buttons"
|
||||
>
|
||||
<v-btn
|
||||
v-ripple
|
||||
icon="mdi-chevron-left"
|
||||
variant="text"
|
||||
:title="'查看昨天'"
|
||||
class="toolbar-btn"
|
||||
@click="$emit('prev-day')"
|
||||
/>
|
||||
<v-btn
|
||||
v-ripple
|
||||
icon="mdi-format-font-size-decrease"
|
||||
variant="text"
|
||||
@click="$emit('zoom', 'out')"
|
||||
:title="'缩小字体'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
@click="$emit('zoom', 'out')"
|
||||
/>
|
||||
<v-btn
|
||||
v-ripple
|
||||
icon="mdi-format-font-size-increase"
|
||||
variant="text"
|
||||
@click="$emit('zoom', 'up')"
|
||||
:title="'放大字体'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
@click="$emit('zoom', 'up')"
|
||||
/>
|
||||
<v-menu location="top" :close-on-content-click="false">
|
||||
<v-menu
|
||||
location="top"
|
||||
:close-on-content-click="false"
|
||||
>
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
v-ripple
|
||||
icon="mdi-calendar"
|
||||
variant="text"
|
||||
v-bind="props"
|
||||
:title="'选择日期'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
/>
|
||||
</template>
|
||||
<v-card border class="date-picker-card">
|
||||
<v-card
|
||||
border
|
||||
class="date-picker-card"
|
||||
>
|
||||
<v-date-picker
|
||||
:model-value="selectedDate"
|
||||
color="primary"
|
||||
@ -53,27 +60,25 @@
|
||||
</v-card>
|
||||
</v-menu>
|
||||
<v-btn
|
||||
v-ripple
|
||||
icon="mdi-refresh"
|
||||
variant="text"
|
||||
:loading="loading"
|
||||
@click="$emit('refresh')"
|
||||
:title="'刷新数据'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
@click="$emit('refresh')"
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
v-if="!isToday"
|
||||
icon="mdi-chevron-right"
|
||||
variant="text"
|
||||
@click="$emit('next-day')"
|
||||
:title="'查看明天'"
|
||||
class="toolbar-btn"
|
||||
v-ripple
|
||||
/>
|
||||
<v-btn
|
||||
v-if="!isToday"
|
||||
v-ripple
|
||||
icon="mdi-chevron-right"
|
||||
variant="text"
|
||||
:title="'查看明天'"
|
||||
class="toolbar-btn"
|
||||
@click="$emit('next-day')"
|
||||
/>
|
||||
</v-btn-group>
|
||||
|
||||
|
||||
</v-card>
|
||||
</v-slide-y-transition>
|
||||
</template>
|
||||
|
@ -8,14 +8,28 @@
|
||||
variant="tonal"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon :icon="icons[message?.type] || icons.info" class="mr-2" />
|
||||
<v-icon
|
||||
:icon="icons[message?.type] || icons.info"
|
||||
class="mr-2"
|
||||
/>
|
||||
<div>
|
||||
<div class="text-subtitle-2 font-weight-medium">{{ message?.title }}</div>
|
||||
<div v-if="message?.content" class="text-body-2">{{ message?.content }}</div>
|
||||
<div class="text-subtitle-2 font-weight-medium">
|
||||
{{ message?.title }}
|
||||
</div>
|
||||
<div
|
||||
v-if="message?.content"
|
||||
class="text-body-2"
|
||||
>
|
||||
{{ message?.content }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #actions>
|
||||
<v-btn variant="text" icon="mdi-close" @click="snackbar = false" />
|
||||
<v-btn
|
||||
variant="text"
|
||||
icon="mdi-close"
|
||||
@click="snackbar = false"
|
||||
/>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</template>
|
||||
|
@ -11,9 +11,13 @@
|
||||
/>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="text-body-2 font-weight-light mb-n1">Welcome to</div>
|
||||
<div class="text-body-2 font-weight-light mb-n1">
|
||||
Welcome to
|
||||
</div>
|
||||
|
||||
<h1 class="text-h2 font-weight-bold">Vuetify</h1>
|
||||
<h1 class="text-h2 font-weight-bold">
|
||||
Vuetify
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="py-4" />
|
||||
@ -33,7 +37,9 @@
|
||||
</template>
|
||||
|
||||
<template #title>
|
||||
<h2 class="text-h5 font-weight-bold">Get started</h2>
|
||||
<h2 class="text-h5 font-weight-bold">
|
||||
Get started
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<template #subtitle>
|
||||
|
@ -1,6 +1,11 @@
|
||||
# 创建新的作业编辑对话框组件
|
||||
<template>
|
||||
<v-dialog v-model="dialogVisible" width="auto" max-width="900" @click:outside="handleClose">
|
||||
<v-dialog
|
||||
v-model="dialogVisible"
|
||||
width="auto"
|
||||
max-width="900"
|
||||
@click:outside="handleClose"
|
||||
>
|
||||
<v-card border>
|
||||
<v-card-title>{{ title }}</v-card-title>
|
||||
<v-card-subtitle>
|
||||
@ -15,19 +20,27 @@
|
||||
auto-grow
|
||||
placeholder="使用换行表示分条"
|
||||
rows="5"
|
||||
width="480"
|
||||
@click="updateCurrentLine"
|
||||
@keyup="updateCurrentLine"
|
||||
width="480"
|
||||
/>
|
||||
|
||||
<!-- Template Buttons Section -->
|
||||
<div v-if="templateData" class="mt-4">
|
||||
<div v-if="hasTemplates" class="template-buttons">
|
||||
|
||||
|
||||
<div
|
||||
v-if="templateData"
|
||||
class="mt-4"
|
||||
>
|
||||
<div
|
||||
v-if="hasTemplates"
|
||||
class="template-buttons"
|
||||
>
|
||||
<!-- Subject specific books -->
|
||||
<template v-if="subjectBooks">
|
||||
<div v-for="(pages, book) in subjectBooks" :key="book" class="button-group">
|
||||
<div
|
||||
v-for="(pages, book) in subjectBooks"
|
||||
:key="book"
|
||||
class="button-group"
|
||||
>
|
||||
<v-chip
|
||||
class="ma-1 book-chip"
|
||||
:color="isBookSelected(book) ? 'success' : 'default'"
|
||||
@ -38,7 +51,10 @@
|
||||
</v-chip>
|
||||
|
||||
<!-- Show pages only if book is selected -->
|
||||
<div v-if="isBookSelected(book)" class="pages-container mt-2">
|
||||
<div
|
||||
v-if="isBookSelected(book)"
|
||||
class="pages-container mt-2"
|
||||
>
|
||||
<v-chip
|
||||
v-for="page in pages"
|
||||
:key="page"
|
||||
@ -55,7 +71,11 @@
|
||||
|
||||
<!-- Common books -->
|
||||
<template v-if="commonBooks">
|
||||
<div v-for="(pages, book) in commonBooks" :key="book" class="button-group">
|
||||
<div
|
||||
v-for="(pages, book) in commonBooks"
|
||||
:key="book"
|
||||
class="button-group"
|
||||
>
|
||||
<v-chip
|
||||
class="ma-1 book-chip"
|
||||
:color="isBookSelected(book) ? 'success' : 'default'"
|
||||
@ -66,7 +86,10 @@
|
||||
</v-chip>
|
||||
|
||||
<!-- Show pages only if book is selected -->
|
||||
<div v-if="isBookSelected(book)" class="pages-container mt-2">
|
||||
<div
|
||||
v-if="isBookSelected(book)"
|
||||
class="pages-container mt-2"
|
||||
>
|
||||
<v-chip
|
||||
v-for="page in pages"
|
||||
:key="page"
|
||||
@ -82,7 +105,10 @@
|
||||
</template>
|
||||
|
||||
<!-- Actions -->
|
||||
<div v-if="templateData.actions?.length" class="button-group">
|
||||
<div
|
||||
v-if="templateData.actions?.length"
|
||||
class="button-group"
|
||||
>
|
||||
<v-chip
|
||||
v-for="action in templateData.actions"
|
||||
:key="action"
|
||||
@ -95,14 +121,21 @@
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="text-center text-body-2 text-disabled mt-2">
|
||||
<div
|
||||
v-else
|
||||
class="text-center text-body-2 text-disabled mt-2"
|
||||
>
|
||||
暂无可用的模板
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Tools Section -->
|
||||
<div class="quick-tools ml-4" style="min-width: 180px;" v-if="showQuickTools">
|
||||
<div
|
||||
v-if="showQuickTools"
|
||||
class="quick-tools ml-4"
|
||||
style="min-width: 180px;"
|
||||
>
|
||||
<!-- Numeric Keypad -->
|
||||
<div class="numeric-keypad mb-4">
|
||||
<div class="keypad-row">
|
||||
@ -205,7 +238,6 @@
|
||||
<div class="text-center text-body-2 text-disabled mb-5">
|
||||
点击空白处完成编辑
|
||||
</div>
|
||||
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
@ -1,32 +1,50 @@
|
||||
<template>
|
||||
<v-navigation-drawer v-model="drawer" location="right" temporary width="400" v-if="drawer">
|
||||
<v-navigation-drawer
|
||||
v-if="drawer"
|
||||
v-model="drawer"
|
||||
location="right"
|
||||
temporary
|
||||
width="400"
|
||||
>
|
||||
<v-toolbar color="primary">
|
||||
<v-toolbar-title>消息记录</v-toolbar-title>
|
||||
|
||||
</v-toolbar>
|
||||
|
||||
<v-list>
|
||||
<v-list-item v-for="msg in messages" :key="msg.id" rounded>
|
||||
<v-list-item
|
||||
v-for="msg in messages"
|
||||
:key="msg.id"
|
||||
rounded
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon :icon="icons[msg.type]" :color="colors[msg.type]" size="20" />
|
||||
<v-icon
|
||||
:icon="icons[msg.type]"
|
||||
:color="colors[msg.type]"
|
||||
size="20"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list-item-title>{{ msg.title }}</v-list-item-title>
|
||||
<v-list-item-subtitle v-if="msg.content">{{
|
||||
msg.content
|
||||
}}</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-if="msg.content">
|
||||
{{
|
||||
msg.content
|
||||
}}
|
||||
</v-list-item-subtitle>
|
||||
<span class="text-caption text-grey">
|
||||
{{ new Date(msg.timestamp).toLocaleTimeString() }}
|
||||
</span>
|
||||
|
||||
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item v-if="!messages.length">
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-inbox" color="grey" />
|
||||
<v-icon
|
||||
icon="mdi-inbox"
|
||||
color="grey"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title class="text-grey">暂无消息</v-list-item-title>
|
||||
<v-list-item-title class="text-grey">
|
||||
暂无消息
|
||||
</v-list-item-title>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-navigation-drawer>
|
||||
|
@ -4,17 +4,23 @@
|
||||
<v-card-title>迁移设置</v-card-title>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="classNumber"
|
||||
label="班级编号"
|
||||
hint="请输入需要迁移的班级编号"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-account-group"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="machineId"
|
||||
label="设备标识 (UUID)"
|
||||
@ -22,23 +28,35 @@
|
||||
persistent-hint
|
||||
prepend-icon="mdi-identifier"
|
||||
readonly
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-radio-group v-model="migrationType" class="mt-2">
|
||||
<v-radio value="local" label="本地数据迁移"></v-radio>
|
||||
<v-radio value="server" label="服务器数据迁移"></v-radio>
|
||||
<v-radio-group
|
||||
v-model="migrationType"
|
||||
class="mt-2"
|
||||
>
|
||||
<v-radio
|
||||
value="local"
|
||||
label="本地数据迁移"
|
||||
/>
|
||||
<v-radio
|
||||
value="server"
|
||||
label="服务器数据迁移"
|
||||
/>
|
||||
</v-radio-group>
|
||||
|
||||
<div v-if="migrationType === 'server'" class="mt-4">
|
||||
<div
|
||||
v-if="migrationType === 'server'"
|
||||
class="mt-4"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="serverUrl"
|
||||
label="服务器地址"
|
||||
hint="输入服务器域名,例如:https://example.com"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-server"
|
||||
></v-text-field>
|
||||
/>
|
||||
|
||||
<v-alert
|
||||
density="compact"
|
||||
@ -46,33 +64,44 @@
|
||||
variant="outlined"
|
||||
class="mt-2"
|
||||
>
|
||||
服务器接口格式:<br />
|
||||
- 配置接口:域名/班号/config<br />
|
||||
服务器接口格式:<br>
|
||||
- 配置接口:域名/班号/config<br>
|
||||
- 作业数据接口:域名/班号/homework?date=YYYY-MM-DD
|
||||
</v-alert>
|
||||
|
||||
<div class="d-flex align-center mt-4">
|
||||
<v-icon color="warning" class="mr-2">mdi-calendar-range</v-icon>
|
||||
<v-icon
|
||||
color="warning"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-calendar-range
|
||||
</v-icon>
|
||||
<span class="text-subtitle-1">选择迁移时间范围:</span>
|
||||
</div>
|
||||
|
||||
<v-row class="mt-1">
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="startDate"
|
||||
label="开始日期"
|
||||
type="date"
|
||||
prepend-icon="mdi-calendar-start"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="endDate"
|
||||
label="结束日期"
|
||||
type="date"
|
||||
prepend-icon="mdi-calendar-end"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
@ -85,15 +114,15 @@
|
||||
<span>{{
|
||||
migrationType === "local" ? "本地数据库内容" : "服务器数据内容"
|
||||
}}</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
:loading="loading || scanning"
|
||||
@click="
|
||||
migrationType === 'local'
|
||||
? scanLocalDatabase()
|
||||
: previewServerData()
|
||||
"
|
||||
:loading="loading || scanning"
|
||||
>
|
||||
{{ migrationType === "local" ? "扫描数据" : "加载数据" }}
|
||||
</v-btn>
|
||||
@ -144,7 +173,7 @@
|
||||
<v-skeleton-loader
|
||||
v-if="loading || scanning"
|
||||
type="table"
|
||||
></v-skeleton-loader>
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@ -152,18 +181,27 @@
|
||||
<v-card-title>迁移目标</v-card-title>
|
||||
<v-card-text>
|
||||
<v-radio-group v-model="targetStorage">
|
||||
<v-radio value="kv-local" label="本地 KV 存储"></v-radio>
|
||||
<v-radio value="kv-server" label="服务器 KV 存储"></v-radio>
|
||||
<v-radio
|
||||
value="kv-local"
|
||||
label="本地 KV 存储"
|
||||
/>
|
||||
<v-radio
|
||||
value="kv-server"
|
||||
label="服务器 KV 存储"
|
||||
/>
|
||||
</v-radio-group>
|
||||
|
||||
<div v-if="targetStorage === 'kv-server'" class="mt-4">
|
||||
<div
|
||||
v-if="targetStorage === 'kv-server'"
|
||||
class="mt-4"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="targetServerUrl"
|
||||
label="目标服务器地址"
|
||||
hint="输入KV服务器地址,例如:https://example.com/kv-api"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-server-network"
|
||||
></v-text-field>
|
||||
/>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@ -171,24 +209,34 @@
|
||||
<div class="d-flex justify-end mb-6">
|
||||
<v-btn
|
||||
color="success"
|
||||
@click="startMigration"
|
||||
:loading="migrating"
|
||||
:disabled="!canMigrate"
|
||||
@click="startMigration"
|
||||
>
|
||||
开始迁移
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-dialog v-model="showResult" max-width="600">
|
||||
<v-dialog
|
||||
v-model="showResult"
|
||||
max-width="600"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon :color="migrationSuccess ? 'success' : 'error'" class="mr-2">
|
||||
<v-icon
|
||||
:color="migrationSuccess ? 'success' : 'error'"
|
||||
class="mr-2"
|
||||
>
|
||||
{{ migrationSuccess ? "mdi-check-circle" : "mdi-alert-circle" }}
|
||||
</v-icon>
|
||||
<span>{{ migrationSuccess ? "迁移成功" : "迁移失败" }}</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-alert v-if="migrationError" type="error" class="mb-4">
|
||||
<v-alert
|
||||
v-if="migrationError"
|
||||
type="error"
|
||||
class="mb-4"
|
||||
>
|
||||
{{ migrationError }}
|
||||
</v-alert>
|
||||
|
||||
@ -197,7 +245,7 @@
|
||||
成功迁移 {{ migrationStats.success }} 项数据到
|
||||
{{ targetStorage === "kv-local" ? "本地" : "服务器" }} KV 存储。
|
||||
</p>
|
||||
<v-divider class="my-4"></v-divider>
|
||||
<v-divider class="my-4" />
|
||||
<v-list>
|
||||
<v-list-subheader>迁移详情</v-list-subheader>
|
||||
<v-list-item
|
||||
@ -215,8 +263,13 @@
|
||||
</div>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" @click="showResult = false"> 关闭 </v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="showResult = false"
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
@ -5,16 +5,32 @@
|
||||
fullscreen-breakpoint="sm"
|
||||
persistent
|
||||
>
|
||||
<v-card class="random-picker-card" rounded="xl" border>
|
||||
<v-card
|
||||
class="random-picker-card"
|
||||
rounded="xl"
|
||||
border
|
||||
>
|
||||
<v-card-title class="text-h5 d-flex align-center">
|
||||
<v-icon icon="mdi-account-question" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-account-question"
|
||||
class="mr-2"
|
||||
/>
|
||||
随机点名
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="dialog = false" />
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
variant="text"
|
||||
@click="dialog = false"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text v-if="!isPickingStarted" class="text-center py-6">
|
||||
<div class="text-h6 mb-4">请选择抽取人数</div>
|
||||
<v-card-text
|
||||
v-if="!isPickingStarted"
|
||||
class="text-center py-6"
|
||||
>
|
||||
<div class="text-h6 mb-4">
|
||||
请选择抽取人数
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-center align-center counter-container">
|
||||
<v-btn
|
||||
@ -23,8 +39,8 @@
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="count <= 1"
|
||||
@click="decrementCount"
|
||||
class="counter-btn"
|
||||
@click="decrementCount"
|
||||
/>
|
||||
|
||||
<div class="count-display mx-8">
|
||||
@ -38,8 +54,8 @@
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="count >= maxAllowedCount"
|
||||
@click="incrementCount"
|
||||
class="counter-btn"
|
||||
@click="incrementCount"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -52,14 +68,29 @@
|
||||
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
|
||||
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
|
||||
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"
|
||||
@ -90,15 +121,18 @@
|
||||
size="x-large"
|
||||
color="primary"
|
||||
prepend-icon="mdi-dice-multiple"
|
||||
@click="startPicking"
|
||||
:disabled="filteredStudents.length === 0"
|
||||
class="start-btn"
|
||||
@click="startPicking"
|
||||
>
|
||||
开始抽取
|
||||
</v-btn>
|
||||
</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>
|
||||
@ -109,8 +143,11 @@
|
||||
|
||||
<div class="mt-4 text-caption">
|
||||
当前可抽取学生: {{ filteredStudents.length }}人
|
||||
<v-tooltip v-if="pickerMode === 'name'" location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-tooltip
|
||||
v-if="pickerMode === 'name'"
|
||||
location="bottom"
|
||||
>
|
||||
<template #activator="{ props }">
|
||||
<v-icon
|
||||
v-bind="props"
|
||||
icon="mdi-information-outline"
|
||||
@ -132,22 +169,25 @@
|
||||
</v-tooltip>
|
||||
|
||||
<!-- 添加临时过滤选项 -->
|
||||
<div v-if="pickerMode === 'name'" 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'"
|
||||
@click="tempFilters.excludeLate = !tempFilters.excludeLate"
|
||||
prepend-icon="mdi-clock-alert"
|
||||
class="filter-chip"
|
||||
@click="tempFilters.excludeLate = !tempFilters.excludeLate"
|
||||
>
|
||||
{{ tempFilters.excludeLate ? "排除" : "包含" }}迟到学生
|
||||
</v-chip>
|
||||
<v-chip
|
||||
:color="tempFilters.excludeAbsent ? 'error' : 'default'"
|
||||
:variant="tempFilters.excludeAbsent ? 'elevated' : 'text'"
|
||||
@click="tempFilters.excludeAbsent = !tempFilters.excludeAbsent"
|
||||
prepend-icon="mdi-account-off"
|
||||
class="filter-chip"
|
||||
@click="tempFilters.excludeAbsent = !tempFilters.excludeAbsent"
|
||||
>
|
||||
{{ tempFilters.excludeAbsent ? "排除" : "包含" }}请假学生
|
||||
</v-chip>
|
||||
@ -155,9 +195,9 @@
|
||||
<v-chip
|
||||
:color="tempFilters.excludeExcluded ? 'grey' : 'default'"
|
||||
:variant="tempFilters.excludeExcluded ? 'elevated' : 'text'"
|
||||
@click="tempFilters.excludeExcluded = !tempFilters.excludeExcluded"
|
||||
prepend-icon="mdi-account-cancel"
|
||||
class="filter-chip"
|
||||
@click="tempFilters.excludeExcluded = !tempFilters.excludeExcluded"
|
||||
>
|
||||
{{ tempFilters.excludeExcluded ? "排除" : "包含" }}不参与学生
|
||||
</v-chip>
|
||||
@ -165,8 +205,14 @@
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-else class="text-center py-6">
|
||||
<div v-if="isAnimating" class="animation-container">
|
||||
<v-card-text
|
||||
v-else
|
||||
class="text-center py-6"
|
||||
>
|
||||
<div
|
||||
v-if="isAnimating"
|
||||
class="animation-container"
|
||||
>
|
||||
<div class="animation-wrapper">
|
||||
<transition-group
|
||||
name="shuffle"
|
||||
@ -185,8 +231,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="result-container">
|
||||
<div class="text-h6 mb-4">抽取结果</div>
|
||||
<div
|
||||
v-else
|
||||
class="result-container"
|
||||
>
|
||||
<div class="text-h6 mb-4">
|
||||
抽取结果
|
||||
</div>
|
||||
<v-card
|
||||
v-for="(student, index) in pickedStudents"
|
||||
:key="index"
|
||||
@ -203,13 +254,13 @@
|
||||
variant="text"
|
||||
size="small"
|
||||
class="ml-2 refresh-btn"
|
||||
@click="refreshSingleStudent(index)"
|
||||
:disabled="remainingStudents.length === 0"
|
||||
:title="
|
||||
remainingStudents.length === 0
|
||||
? '没有更多可用学生'
|
||||
: '重新抽取此学生'
|
||||
"
|
||||
@click="refreshSingleStudent(index)"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@ -218,18 +269,18 @@
|
||||
<v-btn
|
||||
color="primary"
|
||||
prepend-icon="mdi-refresh"
|
||||
@click="resetPicker"
|
||||
size="large"
|
||||
class="mx-2"
|
||||
@click="resetPicker"
|
||||
>
|
||||
重新抽取
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="outlined"
|
||||
@click="dialog = false"
|
||||
size="large"
|
||||
class="mx-2"
|
||||
@click="dialog = false"
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
|
@ -1,21 +1,39 @@
|
||||
<template>
|
||||
<v-dialog v-model="isVisible" max-width="500" persistent>
|
||||
<v-dialog
|
||||
v-model="isVisible"
|
||||
max-width="500"
|
||||
persistent
|
||||
>
|
||||
<v-card class="rate-limit-modal">
|
||||
<v-card-title class="text-center pa-4 bg-error text-white">
|
||||
<v-icon icon="mdi-clock-alert-outline" size="large" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-clock-alert-outline"
|
||||
size="large"
|
||||
class="mr-2"
|
||||
/>
|
||||
请求频率超限
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text class="pa-6">
|
||||
<div class="text-body-1 mb-4">您的请求过于频繁,请稍后再试。</div>
|
||||
<div class="text-body-1 mb-4">
|
||||
您的请求过于频繁,请稍后再试。
|
||||
</div>
|
||||
|
||||
<v-card flat class="mb-4" v-if="activeRequests.length > 0">
|
||||
<v-card
|
||||
v-if="activeRequests.length > 0"
|
||||
flat
|
||||
class="mb-4"
|
||||
>
|
||||
<v-card-text>
|
||||
<v-list
|
||||
v-for="(request, index) in activeRequests"
|
||||
:key="index"
|
||||
class="mb-4"
|
||||
><v-list-item prepend-icon="mdi-web" color="primary">
|
||||
>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-web"
|
||||
color="primary"
|
||||
>
|
||||
<v-list-item-title>
|
||||
等待时间:
|
||||
<span class="text-primary font-weight-bold">{{
|
||||
@ -25,12 +43,12 @@
|
||||
<v-list-item-subtitle>
|
||||
{{ request.method }} {{ request.path }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item></v-list
|
||||
>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-divider
|
||||
v-if="index < activeRequests.length - 1"
|
||||
class="my-3"
|
||||
></v-divider>
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@ -40,8 +58,14 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="pa-4 pt-0">
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" variant="tonal" @click="close"> 我知道了 </v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
@click="close"
|
||||
>
|
||||
我知道了
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<v-card elevation="2" class="settings-card rounded-lg">
|
||||
<v-card
|
||||
elevation="2"
|
||||
class="settings-card rounded-lg"
|
||||
>
|
||||
<v-card-item>
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
@ -8,7 +11,9 @@
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<v-card-title class="text-h6">{{ title }}</v-card-title>
|
||||
<v-card-title class="text-h6">
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text>
|
||||
@ -21,7 +26,10 @@
|
||||
<slot />
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions v-if="$slots.actions" class="pa-4">
|
||||
<v-card-actions
|
||||
v-if="$slots.actions"
|
||||
class="pa-4"
|
||||
>
|
||||
<slot name="actions" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
@ -1,7 +1,14 @@
|
||||
<template>
|
||||
<v-card border class="settings-link-generator mb-4">
|
||||
<v-card
|
||||
border
|
||||
class="settings-link-generator mb-4"
|
||||
>
|
||||
<v-card-title class="text-h6">
|
||||
<v-icon start icon="mdi-link-variant" class="mr-2" />
|
||||
<v-icon
|
||||
start
|
||||
icon="mdi-link-variant"
|
||||
class="mr-2"
|
||||
/>
|
||||
设置分享
|
||||
</v-card-title>
|
||||
|
||||
@ -49,7 +56,10 @@
|
||||
|
||||
<!-- 选择摘要和链接 -->
|
||||
<div class="d-flex align-center mt-3 mb-3 flex-wrap gap-2">
|
||||
<v-chip color="primary" class="mr-2">
|
||||
<v-chip
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
已选 {{ selectedItems.length }} 项设置
|
||||
</v-chip>
|
||||
|
||||
@ -83,18 +93,18 @@
|
||||
|
||||
<v-expansion-panel-text>
|
||||
<v-data-table
|
||||
v-model="selectedItems"
|
||||
:items-per-page="settingItems.length"
|
||||
:headers="headers"
|
||||
:items="filteredItems"
|
||||
item-value="key"
|
||||
v-model="selectedItems"
|
||||
show-select
|
||||
density="compact"
|
||||
class="rounded setting-table"
|
||||
@update:selected="handleSelectionChange"
|
||||
:sort-by="[{ key: 'isChanged', order: 'desc' }]"
|
||||
@update:selected="handleSelectionChange"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<template #top>
|
||||
<v-text-field
|
||||
v-model="search"
|
||||
label="搜索设置"
|
||||
@ -102,12 +112,16 @@
|
||||
single-line
|
||||
hide-details
|
||||
class="mb-4"
|
||||
></v-text-field>
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #[`item.description`]="{ item }">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" :icon="item.icon" class="mr-2"></v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
:icon="item.icon"
|
||||
class="mr-2"
|
||||
/>
|
||||
{{ item.description }}
|
||||
</div>
|
||||
</template>
|
||||
@ -286,6 +300,16 @@ export default {
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 监听选择变化,自动生成链接
|
||||
selectedItems: {
|
||||
handler() {
|
||||
this.autoGenerateLink();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
/**
|
||||
* 处理表格选择变化
|
||||
@ -444,15 +468,5 @@ export default {
|
||||
return setting ? setting.description : key;
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
// 监听选择变化,自动生成链接
|
||||
selectedItems: {
|
||||
handler() {
|
||||
this.autoGenerateLink();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -1,12 +1,23 @@
|
||||
<template>
|
||||
<v-container class="fill-height">
|
||||
<v-responsive class="align-centerfill-height mx-auto" max-width="900">
|
||||
<v-img class="mb-4" height="150" src="@/assets/logo.svg" />
|
||||
<v-responsive
|
||||
class="align-centerfill-height mx-auto"
|
||||
max-width="900"
|
||||
>
|
||||
<v-img
|
||||
class="mb-4"
|
||||
height="150"
|
||||
src="@/assets/logo.svg"
|
||||
/>
|
||||
|
||||
<div class="text-center">
|
||||
<div class="text-body-2 font-weight-light mb-n1">出现了错误</div>
|
||||
<div class="text-body-2 font-weight-light mb-n1">
|
||||
出现了错误
|
||||
</div>
|
||||
|
||||
<h1 class="text-h2 font-weight-bold">404</h1>
|
||||
<h1 class="text-h2 font-weight-bold">
|
||||
404
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="py-4" />
|
||||
@ -25,11 +36,15 @@
|
||||
</template>
|
||||
|
||||
<template #title>
|
||||
<h2 class="text-h5 font-weight-bold">为什么会出现此错误?</h2>
|
||||
<h2 class="text-h5 font-weight-bold">
|
||||
为什么会出现此错误?
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<template #subtitle>
|
||||
<div class="text-subtitle-1">大概是页面未找到</div>
|
||||
<div class="text-subtitle-1">
|
||||
大概是页面未找到
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<v-overlay
|
||||
@ -66,11 +81,11 @@
|
||||
<v-card
|
||||
class="py-4"
|
||||
color="surface-variant"
|
||||
@click="this.$router.back()"
|
||||
prepend-icon="mdi-arrow-left-drop-circle"
|
||||
rounded="lg"
|
||||
title="返回上一页"
|
||||
variant="text"
|
||||
@click="$router.back()"
|
||||
>
|
||||
<v-overlay
|
||||
opacity=".06"
|
||||
|
@ -2,24 +2,41 @@
|
||||
<v-card border>
|
||||
<v-card-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-information" size="large" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-information"
|
||||
size="large"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<v-card-title class="text-h6">关于</v-card-title>
|
||||
<v-card-title class="text-h6">
|
||||
关于
|
||||
</v-card-title>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="8" class="mx-auto">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="8"
|
||||
class="mx-auto"
|
||||
>
|
||||
<div class="d-flex flex-column align-start">
|
||||
<v-avatar size="120" class="mb-4">
|
||||
<v-avatar
|
||||
size="120"
|
||||
class="mb-4"
|
||||
>
|
||||
<v-img
|
||||
src="https://github.com/SunWuyuan.png"
|
||||
alt="Sunwuyuan"
|
||||
/>
|
||||
</v-avatar>
|
||||
|
||||
<h2 class="text-h5 mb-2">Classworks</h2>
|
||||
<p class="text-body-1 mb-4">适用于班级大屏的作业板小工具</p>
|
||||
<h2 class="text-h5 mb-2">
|
||||
Classworks
|
||||
</h2>
|
||||
<p class="text-body-1 mb-4">
|
||||
适用于班级大屏的作业板小工具
|
||||
</p>
|
||||
|
||||
<div class="d-flex gap-2 flex-wrap mb-6">
|
||||
<v-btn
|
||||
@ -58,9 +75,11 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<v-divider class="mb-4 w-100"></v-divider>
|
||||
<v-divider class="mb-4 w-100" />
|
||||
|
||||
<h3 class="text-h6 mb-2">备注与致谢</h3>
|
||||
<h3 class="text-h6 mb-2">
|
||||
备注与致谢
|
||||
</h3>
|
||||
<v-list class="mb-4 bg-transparent">
|
||||
<v-list-item
|
||||
href="https://github.com/EnderWolf006/HomeworkBoard"
|
||||
@ -99,7 +118,7 @@
|
||||
新一代,开源,编程社区
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-divider class="ma-1"></v-divider>
|
||||
<v-divider class="ma-1" />
|
||||
<v-list-item
|
||||
href="https://github.com/HUSX100/IslandCaller"
|
||||
target="_blank"
|
||||
@ -142,11 +161,14 @@
|
||||
transition="dialog-bottom-transition"
|
||||
fullscreen
|
||||
>
|
||||
<v-card
|
||||
><v-toolbar>
|
||||
<v-btn icon="mdi-close" @click="showDeps = false"></v-btn>
|
||||
<v-card>
|
||||
<v-toolbar>
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
@click="showDeps = false"
|
||||
/>
|
||||
<v-toolbar-title>使用的第三方库</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
</v-toolbar>
|
||||
<v-card-text>
|
||||
<v-list>
|
||||
|
@ -1,7 +1,17 @@
|
||||
<template>
|
||||
<v-card :border="border" class="setting-group">
|
||||
<v-card-title v-if="title" class="d-flex align-center">
|
||||
<v-icon v-if="icon" :icon="icon" class="mr-2" />
|
||||
<v-card
|
||||
:border="border"
|
||||
class="setting-group"
|
||||
>
|
||||
<v-card-title
|
||||
v-if="title"
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-icon
|
||||
v-if="icon"
|
||||
:icon="icon"
|
||||
class="mr-2"
|
||||
/>
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
|
||||
@ -18,7 +28,7 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions v-if="$slots.actions">
|
||||
<slot name="actions"></slot>
|
||||
<slot name="actions" />
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<v-list-item class="setting-item" :disabled="disabled">
|
||||
<v-list-item
|
||||
class="setting-item"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon :icon="settingIcon" />
|
||||
</template>
|
||||
@ -14,7 +17,10 @@
|
||||
|
||||
<template #append>
|
||||
<div class="d-flex flex-column flex-sm-row align-center">
|
||||
<div v-if="type !== 'string' || hasOptions" class="me-2">
|
||||
<div
|
||||
v-if="type !== 'string' || hasOptions"
|
||||
class="me-2"
|
||||
>
|
||||
<!-- 根据设置类型渲染不同的控件 -->
|
||||
<v-switch
|
||||
v-if="type === 'boolean'"
|
||||
@ -35,12 +41,15 @@
|
||||
class="setting-select"
|
||||
variant="outlined"
|
||||
bg-color="surface"
|
||||
@update:model-value="updateSetting"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
@update:model-value="updateSetting"
|
||||
/>
|
||||
|
||||
<div v-else-if="type === 'number'" class="d-flex align-center">
|
||||
<div
|
||||
v-else-if="type === 'number'"
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-btn
|
||||
icon="mdi-minus"
|
||||
size="small"
|
||||
@ -76,7 +85,7 @@
|
||||
</div>
|
||||
|
||||
<v-menu location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
icon="mdi-dots-vertical"
|
||||
size="small"
|
||||
@ -88,24 +97,36 @@
|
||||
</template>
|
||||
<v-list density="compact">
|
||||
<v-list-item @click="copySettingId">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-key" size="small" />
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-key"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>复制设置ID</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="copySettingValue">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-content-copy" size="small" />
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-content-copy"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>复制设置值</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider></v-divider>
|
||||
<v-divider />
|
||||
|
||||
<v-list-item @click="resetToDefault" :disabled="isDefaultValue">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-restore" size="small" />
|
||||
<v-list-item
|
||||
:disabled="isDefaultValue"
|
||||
@click="resetToDefault"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-restore"
|
||||
size="small"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>重置为默认值</v-list-item-title>
|
||||
</v-list-item>
|
||||
@ -116,7 +137,10 @@
|
||||
</v-list-item>
|
||||
|
||||
<!-- 文本框显示在下方 -->
|
||||
<div v-if="type === 'string' && !hasOptions" class="px-4 pb-2 pt-0">
|
||||
<div
|
||||
v-if="type === 'string' && !hasOptions"
|
||||
class="px-4 pb-2 pt-0"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
density="compact"
|
||||
|
@ -1,29 +1,46 @@
|
||||
<template>
|
||||
<div class="settings-explorer">
|
||||
|
||||
|
||||
<div >
|
||||
<v-text-field v-model="searchQuery" label="搜索设置" prepend-inner-icon="mdi-magnify" clearable variant="outlined"
|
||||
density="comfortable" class="mb-4" />
|
||||
<div>
|
||||
<v-text-field
|
||||
v-model="searchQuery"
|
||||
label="搜索设置"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
clearable
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<v-list>
|
||||
<div v-for="setting in allSettings" :key="setting.key">
|
||||
<setting-item :key="setting.key" :setting-key="setting.key"
|
||||
:disabled="setting.requireDeveloper && !isDeveloperMode" @update="onSettingUpdate" @error="onSettingError" />
|
||||
<div
|
||||
v-for="setting in allSettings"
|
||||
:key="setting.key"
|
||||
>
|
||||
<setting-item
|
||||
:key="setting.key"
|
||||
:setting-key="setting.key"
|
||||
:disabled="setting.requireDeveloper && !isDeveloperMode"
|
||||
@update="onSettingUpdate"
|
||||
@error="onSettingError"
|
||||
/>
|
||||
<v-divider class="my-2" />
|
||||
</div>
|
||||
</v-list><v-card border>
|
||||
<v-card-title class="text-subtitle-1">当前配置</v-card-title>
|
||||
<v-card-title class="text-subtitle-1">
|
||||
当前配置
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<pre class="settings-json">{{ formattedSettings }}</pre>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn @click="copySettingsToClipboard">
|
||||
<v-spacer />
|
||||
<v-btn @click="copySettingsToClipboard">
|
||||
复制到剪贴板
|
||||
<v-icon right>mdi-content-copy</v-icon>
|
||||
<v-icon right>
|
||||
mdi-content-copy
|
||||
</v-icon>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
|
@ -6,17 +6,26 @@
|
||||
>
|
||||
<v-card-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-account-group" size="large" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-account-group"
|
||||
size="large"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<v-card-title class="text-h6">学生列表</v-card-title>
|
||||
<v-card-title class="text-h6">
|
||||
学生列表
|
||||
</v-card-title>
|
||||
<template #append>
|
||||
<unsaved-warning :show="unsavedChanges" message="有未保存的更改" />
|
||||
<unsaved-warning
|
||||
:show="unsavedChanges"
|
||||
message="有未保存的更改"
|
||||
/>
|
||||
<v-btn
|
||||
prepend-icon="mdi-sort-alphabetical-variant"
|
||||
variant="text"
|
||||
class="mr-2"
|
||||
@click="sortStudentsByPinyin"
|
||||
:disabled="modelValue.list.length === 0"
|
||||
@click="sortStudentsByPinyin"
|
||||
>
|
||||
按姓名首字母排序
|
||||
</v-btn>
|
||||
@ -39,7 +48,13 @@
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<v-alert v-if="error" type="error" variant="tonal" closable class="mb-4">
|
||||
<v-alert
|
||||
v-if="error"
|
||||
type="error"
|
||||
variant="tonal"
|
||||
closable
|
||||
class="mb-4"
|
||||
>
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
|
||||
@ -47,7 +62,11 @@
|
||||
<!-- 普通编辑模式 -->
|
||||
<div v-if="!modelValue.advanced">
|
||||
<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-model="newStudentName"
|
||||
label="添加学生"
|
||||
@ -88,7 +107,10 @@
|
||||
border
|
||||
>
|
||||
<v-card-text class="d-flex align-center pa-3">
|
||||
<v-menu location="bottom" :open-on-hover="!isMobile">
|
||||
<v-menu
|
||||
location="bottom"
|
||||
:open-on-hover="!isMobile"
|
||||
>
|
||||
<template #activator="{ props: menuProps }">
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
@ -100,7 +122,10 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<v-list density="compact" nav>
|
||||
<v-list
|
||||
density="compact"
|
||||
nav
|
||||
>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-arrow-up-bold"
|
||||
:disabled="index === 0"
|
||||
@ -172,7 +197,10 @@
|
||||
</div>
|
||||
|
||||
<!-- 高级编辑模式 -->
|
||||
<div v-else class="pt-2">
|
||||
<div
|
||||
v-else
|
||||
class="pt-2"
|
||||
>
|
||||
<v-textarea
|
||||
v-model="modelValue.text"
|
||||
label="批量编辑学生列表"
|
||||
@ -187,7 +215,10 @@
|
||||
</v-expand-transition>
|
||||
|
||||
<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
|
||||
color="primary"
|
||||
prepend-icon="mdi-content-save"
|
||||
|
@ -1,19 +1,33 @@
|
||||
<template>
|
||||
<v-card class="my-4" :loading="loading" :disabled="!hasNamespaceInfo">
|
||||
<v-card
|
||||
class="my-4"
|
||||
:loading="loading"
|
||||
:disabled="!hasNamespaceInfo"
|
||||
>
|
||||
<template #loader>
|
||||
<v-progress-linear v-if="loading" indeterminate color="primary" />
|
||||
<v-progress-linear
|
||||
v-if="loading"
|
||||
indeterminate
|
||||
color="primary"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-card-title>
|
||||
<v-icon class="me-2"> mdi-cloud-check </v-icon>
|
||||
<v-icon class="me-2">
|
||||
mdi-cloud-check
|
||||
</v-icon>
|
||||
设备信息
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text v-if="hasNamespaceInfo">
|
||||
<!-- 用户信息与头像 -->
|
||||
<div v-if="namespaceInfo.account" class="d-flex align-center mb-4">
|
||||
<div
|
||||
v-if="namespaceInfo.account"
|
||||
class="d-flex align-center mb-4"
|
||||
>
|
||||
<v-card
|
||||
border hover
|
||||
border
|
||||
hover
|
||||
class="w-100"
|
||||
variant="tonal"
|
||||
:prepend-avatar="namespaceInfo.account.avatarUrl"
|
||||
@ -22,36 +36,64 @@
|
||||
'此设备由贵校管理 管理员账号 ID: ' + namespaceInfo.account.id
|
||||
"
|
||||
>
|
||||
<v-card-text
|
||||
>此设备由贵校或贵单位管理,该管理员系此空间所有者,如有疑问请咨询他,对于恶意绑定、滥用行为请反馈。</v-card-text
|
||||
>
|
||||
<v-card-text>
|
||||
此设备由贵校或贵单位管理,该管理员系此空间所有者,如有疑问请咨询他,对于恶意绑定、滥用行为请反馈。
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</div>
|
||||
|
||||
<!-- 设备信息卡片 -->
|
||||
<v-card v-if="namespaceInfo.device" variant="tonal" class="mb-4" border hover>
|
||||
<v-card-title class="pb-1"> 设备信息 </v-card-title>
|
||||
<v-card
|
||||
v-if="namespaceInfo.device"
|
||||
variant="tonal"
|
||||
class="mb-4"
|
||||
border
|
||||
hover
|
||||
>
|
||||
<v-card-title class="pb-1">
|
||||
设备信息
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" class="me-2"> mdi-tag </v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
>
|
||||
mdi-tag
|
||||
</v-icon>
|
||||
<span class="font-weight-medium me-2">设备名称:</span>
|
||||
<span>{{ namespaceInfo.device.name || "未命名设备" }}</span>
|
||||
</div>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" class="me-2"> mdi-identifier </v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
>
|
||||
mdi-identifier
|
||||
</v-icon>
|
||||
<span class="font-weight-medium me-2">设备 ID:</span>
|
||||
<span>{{ namespaceInfo.device.id }}</span>
|
||||
</div>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" class="me-2"> mdi-uuid </v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
>
|
||||
mdi-uuid
|
||||
</v-icon>
|
||||
<span class="font-weight-medium me-2">UUID:</span>
|
||||
<span class="text-truncate">{{
|
||||
namespaceInfo.device.uuid || "未知"
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" class="me-2"> mdi-calendar </v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
>
|
||||
mdi-calendar
|
||||
</v-icon>
|
||||
<span class="font-weight-medium me-2">创建时间:</span>
|
||||
<span>{{ formatDate(namespaceInfo.device.createdAt) }}</span>
|
||||
</div>
|
||||
@ -59,33 +101,50 @@
|
||||
v-if="namespaceInfo.device.updatedAt"
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-icon size="small" class="me-2"> mdi-calendar-clock </v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
>
|
||||
mdi-calendar-clock
|
||||
</v-icon>
|
||||
<span class="font-weight-medium me-2">更新时间:</span>
|
||||
<span>{{ formatDate(namespaceInfo.device.updatedAt) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</v-card-text> </v-card
|
||||
><v-card title="Classworks KV" subtitle="云原生键值数据库" border hover
|
||||
><v-card-text
|
||||
>Classworks KV
|
||||
</v-card-text>
|
||||
</v-card><v-card
|
||||
title="Classworks KV"
|
||||
subtitle="云原生键值数据库"
|
||||
border
|
||||
hover
|
||||
>
|
||||
<v-card-text>
|
||||
Classworks KV
|
||||
是厚浪云推出的云原生键值数据库,其是一个开放的云应用平台,为各种应用提供存储服务。此设备正在使用其服务,如果您希望管理设备信息,请前往
|
||||
Classworks KV
|
||||
的网站,如果您在服务推出前就在使用 Classworks,您的数据已被自动迁移。
|
||||
<br/><br/>Classworks KV 的全域管理员是 <a href="https://wuyuan.dev" target="_blank">孙悟元</a></v-card-text
|
||||
><v-card-actions
|
||||
><v-btn
|
||||
<br><br>Classworks KV 的全域管理员是 <a
|
||||
href="https://wuyuan.dev"
|
||||
target="_blank"
|
||||
>孙悟元</a>
|
||||
</v-card-text><v-card-actions>
|
||||
<v-btn
|
||||
href="https://kv.wuyuan.dev"
|
||||
class="text-none"
|
||||
append-icon="mdi-open-in-new"
|
||||
target="_blank"
|
||||
>前往 Classworks KV</v-btn
|
||||
></v-card-actions
|
||||
></v-card
|
||||
>
|
||||
>
|
||||
前往 Classworks KV
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-text v-else>
|
||||
<v-alert type="info" variant="tonal">
|
||||
<v-alert
|
||||
type="info"
|
||||
variant="tonal"
|
||||
>
|
||||
<v-alert-title>未获取到设备信息</v-alert-title>
|
||||
<p>您尚未完成云端存储授权或连接失败,请点击下方按钮进行初始化。</p>
|
||||
</v-alert>
|
||||
@ -102,7 +161,10 @@
|
||||
刷新设备信息
|
||||
</v-btn>
|
||||
|
||||
<v-btn color="primary" @click="reinitializeCloudStorage">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="reinitializeCloudStorage"
|
||||
>
|
||||
重新初始化云端存储
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
|
@ -1,16 +1,22 @@
|
||||
<template>
|
||||
<settings-card title="数据源设置" icon="mdi-database-cog">
|
||||
<settings-card
|
||||
title="数据源设置"
|
||||
icon="mdi-database-cog"
|
||||
>
|
||||
<v-list>
|
||||
<!-- 服务器模式设置 -->
|
||||
<template
|
||||
v-if="
|
||||
currentProvider === 'kv-server' ||
|
||||
currentProvider === 'classworkscloud'
|
||||
currentProvider === 'classworkscloud'
|
||||
"
|
||||
>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-lan-connect"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>检查服务器连接</v-list-item-title>
|
||||
<template #append>
|
||||
@ -21,84 +27,132 @@
|
||||
>
|
||||
测试连接
|
||||
</v-btn>
|
||||
</template> </v-list-item
|
||||
><!-- 数据迁移,仅对KV本地存储有效 -->
|
||||
</template>
|
||||
</v-list-item><!-- 数据迁移,仅对KV本地存储有效 -->
|
||||
</template>
|
||||
|
||||
<!-- 本地存储设置 -->
|
||||
<template v-if="currentProvider === 'kv-local'">
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-database"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>清除数据库缓存</v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
>这将清除所有本地数据库中的数据</v-list-item-subtitle
|
||||
>
|
||||
<v-list-item-subtitle>
|
||||
这将清除所有本地数据库中的数据
|
||||
</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn color="error" variant="tonal" @click="confirmClearIndexedDB">
|
||||
<v-btn
|
||||
color="error"
|
||||
variant="tonal"
|
||||
@click="confirmClearIndexedDB"
|
||||
>
|
||||
清除
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-export" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-database-export"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>导出数据库</v-list-item-title>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" @click="exportData"> 导出 </v-btn>
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
@click="exportData"
|
||||
>
|
||||
导出
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-import" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-database-import"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>迁移旧数据</v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
>将旧的存储格式数据转移到新的KV存储</v-list-item-subtitle
|
||||
>
|
||||
<v-list-item-subtitle>
|
||||
将旧的存储格式数据转移到新的KV存储
|
||||
</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn :loading="migrateLoading" variant="tonal" @click="migrateData">
|
||||
<v-btn
|
||||
:loading="migrateLoading"
|
||||
variant="tonal"
|
||||
@click="migrateData"
|
||||
>
|
||||
迁移
|
||||
</v-btn>
|
||||
</template> </v-list-item
|
||||
><!-- 显示机器ID -->
|
||||
</template>
|
||||
</v-list-item><!-- 显示机器ID -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-identifier" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-identifier"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>本机唯一标识符</v-list-item-title>
|
||||
<v-list-item-subtitle v-if="machineId">{{
|
||||
machineId
|
||||
}}</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-else>正在加载...</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-if="machineId">
|
||||
{{
|
||||
machineId
|
||||
}}
|
||||
</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-else>
|
||||
正在加载...
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-lan-connect"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>查看本地缓存</v-list-item-title>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" to="/cachemanagement"> 查看 </v-btn>
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
to="/cachemanagement"
|
||||
>
|
||||
查看
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
<!-- 确认对话框 -->
|
||||
<v-dialog v-model="confirmDialog" max-width="400">
|
||||
<v-dialog
|
||||
v-model="confirmDialog"
|
||||
max-width="400"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title>{{ confirmTitle }}</v-card-title>
|
||||
<v-card-text>{{ confirmMessage }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" variant="text" @click="confirmDialog = false"
|
||||
>取消</v-btn
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@click="confirmDialog = false"
|
||||
>
|
||||
<v-btn color="error" variant="tonal" @click="handleConfirm"
|
||||
>确认</v-btn
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
variant="tonal"
|
||||
@click="handleConfirm"
|
||||
>
|
||||
确认
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
@ -1,34 +1,37 @@
|
||||
<template>
|
||||
<settings-card title="显示设置" icon="mdi-monitor" border>
|
||||
<v-list>
|
||||
<setting-item :setting-key="'display.emptySubjectDisplay'" />
|
||||
<settings-card
|
||||
title="显示设置"
|
||||
icon="mdi-monitor"
|
||||
border
|
||||
>
|
||||
<v-list>
|
||||
<setting-item :setting-key="'display.emptySubjectDisplay'" />
|
||||
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.dynamicSort'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.dynamicSort'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showRandomButton'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showRandomButton'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showFullscreenButton'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showFullscreenButton'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.cardHoverEffect'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.cardHoverEffect'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.enhancedTouchMode'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.enhancedTouchMode'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showQuickTools'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showQuickTools'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showAntiScreenBurnCard'" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showAntiScreenBurnCard'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showExamScheduleButton'" />
|
||||
|
||||
</v-list>
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showExamScheduleButton'" />
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
||||
|
@ -6,11 +6,20 @@
|
||||
@click="handleClick"
|
||||
>
|
||||
<v-card-text>
|
||||
<div ref="typewriter" class="typewriter-text"></div>
|
||||
<div ref="sourceWriter" class="source-text"></div>
|
||||
<div
|
||||
ref="typewriter"
|
||||
class="typewriter-text"
|
||||
/>
|
||||
<div
|
||||
ref="sourceWriter"
|
||||
class="source-text"
|
||||
/>
|
||||
</v-card-text>
|
||||
<transition name="fade">
|
||||
<v-chip v-if="currentQuote?.contributor" class="contributor">
|
||||
<v-chip
|
||||
v-if="currentQuote?.contributor"
|
||||
class="contributor"
|
||||
>
|
||||
<v-avatar start>
|
||||
<v-img :src="`https://github.com/${currentQuote.contributor}.png`" />
|
||||
</v-avatar>
|
||||
@ -49,6 +58,10 @@ export default {
|
||||
this.initTypewriters();
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
[this.typewriter, this.sourceWriter].forEach(writer => writer?.stop());
|
||||
},
|
||||
|
||||
methods: {
|
||||
initTypewriters() {
|
||||
this.typewriter = new Typewriter(this.$refs.typewriter, TYPEWRITER_CONFIG.main);
|
||||
@ -93,10 +106,6 @@ export default {
|
||||
console.error("复制失败:", err);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
[this.typewriter, this.sourceWriter].forEach(writer => writer?.stop());
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<settings-card title="编辑设置" icon="mdi-cog">
|
||||
<settings-card
|
||||
title="编辑设置"
|
||||
icon="mdi-cog"
|
||||
>
|
||||
<v-list>
|
||||
<setting-item :setting-key="'edit.autoSave'" />
|
||||
|
||||
@ -15,7 +18,6 @@
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'edit.refreshBeforeEdit'" />
|
||||
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
@ -23,8 +23,8 @@
|
||||
size="large"
|
||||
prepend-icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
@click="loadConfig"
|
||||
class="mr-2"
|
||||
@click="loadConfig"
|
||||
>
|
||||
重新加载配置
|
||||
</v-btn>
|
||||
@ -48,8 +48,15 @@
|
||||
</div>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<setting-group title="科目配置" icon="mdi-book" border>
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<setting-group
|
||||
title="科目配置"
|
||||
icon="mdi-book"
|
||||
border
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-text-field
|
||||
@ -63,8 +70,14 @@
|
||||
/>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item v-for="subject in subjectList" :key="subject">
|
||||
<v-card border class="w-100 mb-2">
|
||||
<v-list-item
|
||||
v-for="subject in subjectList"
|
||||
:key="subject"
|
||||
>
|
||||
<v-card
|
||||
border
|
||||
class="w-100 mb-2"
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-text-field
|
||||
v-model="editedSubjects[subject]"
|
||||
@ -95,17 +108,24 @@
|
||||
@keyup.enter="() => addBookType(subject)"
|
||||
/>
|
||||
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list
|
||||
density="compact"
|
||||
border
|
||||
rounded
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(books, bookType) in config.subjects[subject].books"
|
||||
:key="bookType"
|
||||
:title="bookType"
|
||||
@click="openSubjectBookDialog(subject, bookType, books)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-book-open-variant" class="mr-2" />
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-book-open-variant"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-chip
|
||||
size="small"
|
||||
class="mr-2"
|
||||
@ -130,8 +150,15 @@
|
||||
</setting-group>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<setting-group title="通用配置" icon="mdi-cog" border>
|
||||
<v-col
|
||||
cols="12"
|
||||
md="6"
|
||||
>
|
||||
<setting-group
|
||||
title="通用配置"
|
||||
icon="mdi-cog"
|
||||
border
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-text-field
|
||||
@ -146,17 +173,24 @@
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list
|
||||
density="compact"
|
||||
border
|
||||
rounded
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(books, bookType) in config.commonSubject.books"
|
||||
:key="bookType"
|
||||
:title="bookType"
|
||||
@click="openSubjectBookDialog('common', bookType, books)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-book-multiple" class="mr-2" />
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-book-multiple"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-chip
|
||||
size="small"
|
||||
class="mr-2"
|
||||
@ -191,14 +225,18 @@
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list
|
||||
density="compact"
|
||||
border
|
||||
rounded
|
||||
>
|
||||
<v-list-item
|
||||
v-for="action in config.actions"
|
||||
:key="action"
|
||||
:title="action"
|
||||
@click="openActionDialog(action)"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
@ -216,7 +254,10 @@
|
||||
</v-row>
|
||||
|
||||
<!-- 编辑弹框 -->
|
||||
<v-dialog v-model="dialog.show" max-width="600px">
|
||||
<v-dialog
|
||||
v-model="dialog.show"
|
||||
max-width="600px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 pa-4">
|
||||
{{ dialog.title }}
|
||||
@ -235,22 +276,43 @@
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" v-if="dialog.editedItem.type === 'subjectBook'">
|
||||
<div class="text-subtitle-2 mb-2">所属科目</div>
|
||||
<v-chip color="primary">{{ dialog.editedItem.subject }}</v-chip>
|
||||
<v-col
|
||||
v-if="dialog.editedItem.type === 'subjectBook'"
|
||||
cols="12"
|
||||
>
|
||||
<div class="text-subtitle-2 mb-2">
|
||||
所属科目
|
||||
</div>
|
||||
<v-chip color="primary">
|
||||
{{ dialog.editedItem.subject }}
|
||||
</v-chip>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)">
|
||||
<v-col
|
||||
v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)"
|
||||
cols="12"
|
||||
>
|
||||
<v-card variant="outlined">
|
||||
<v-card-title class="text-subtitle-1 py-2">需完成部分</v-card-title>
|
||||
<v-card-title class="text-subtitle-1 py-2">
|
||||
需完成部分
|
||||
</v-card-title>
|
||||
<v-card-text class="pt-0">
|
||||
<v-list density="compact" border rounded class="mb-2">
|
||||
<v-list
|
||||
density="compact"
|
||||
border
|
||||
rounded
|
||||
class="mb-2"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(task, index) in dialog.editedItem.tasks"
|
||||
:key="index"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-checkbox-blank-circle-outline" size="small" class="mr-2" />
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
icon="mdi-checkbox-blank-circle-outline"
|
||||
size="small"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<v-text-field
|
||||
v-model="dialog.editedItem.tasks[index]"
|
||||
@ -258,7 +320,7 @@
|
||||
density="compact"
|
||||
hide-details
|
||||
/>
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
@ -275,9 +337,9 @@
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
append-inner-icon="mdi-plus"
|
||||
class="mt-2"
|
||||
@click:append-inner="addTask"
|
||||
@keyup.enter="addTask"
|
||||
class="mt-2"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@ -287,7 +349,7 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="pa-4">
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="elevated"
|
||||
|
@ -1,15 +1,27 @@
|
||||
<template>
|
||||
<settings-card title="KV数据库管理" icon="mdi-database-edit" :loading="loading">
|
||||
<settings-card
|
||||
title="KV数据库管理"
|
||||
icon="mdi-database-edit"
|
||||
:loading="loading"
|
||||
>
|
||||
<v-list>
|
||||
<!-- 数据库连接状态 -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon :icon="connectionIcon" :color="connectionColor" class="mr-3" />
|
||||
<v-icon
|
||||
:icon="connectionIcon"
|
||||
:color="connectionColor"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>数据库状态</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ connectionStatus }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" @click="refreshConnection" :loading="loading">
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
:loading="loading"
|
||||
@click="refreshConnection"
|
||||
>
|
||||
刷新
|
||||
</v-btn>
|
||||
</template>
|
||||
@ -20,17 +32,29 @@
|
||||
<!-- 数据列表 -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-format-list-bulleted" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-format-list-bulleted"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>数据条目</v-list-item-title>
|
||||
<v-list-item-subtitle>共 {{ kvData.length }} 条记录</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn-group variant="tonal">
|
||||
<v-btn @click="loadKvData" :loading="loadingData">
|
||||
<v-btn
|
||||
:loading="loadingData"
|
||||
@click="loadKvData"
|
||||
>
|
||||
加载数据
|
||||
</v-btn>
|
||||
<v-btn @click="createNewItem" :disabled="!isKvProvider">
|
||||
<v-icon icon="mdi-plus" class="mr-1" />
|
||||
<v-btn
|
||||
:disabled="!isKvProvider"
|
||||
@click="createNewItem"
|
||||
>
|
||||
<v-icon
|
||||
icon="mdi-plus"
|
||||
class="mr-1"
|
||||
/>
|
||||
新建
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
@ -39,9 +63,16 @@
|
||||
</v-list>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<v-card v-if="kvData.length > 0" class="mt-4" variant="outlined">
|
||||
<v-card
|
||||
v-if="kvData.length > 0"
|
||||
class="mt-4"
|
||||
variant="outlined"
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-table" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-table"
|
||||
class="mr-2"
|
||||
/>
|
||||
KV数据列表
|
||||
<v-spacer />
|
||||
<v-text-field
|
||||
@ -69,32 +100,35 @@
|
||||
</template>
|
||||
|
||||
<template #[`item.actions`]="{ item }">
|
||||
<v-btn-group variant="text" density="compact">
|
||||
<v-btn-group
|
||||
variant="text"
|
||||
density="compact"
|
||||
>
|
||||
<v-btn
|
||||
icon="mdi-eye"
|
||||
size="small"
|
||||
@click="viewItem(item)"
|
||||
title="查看"
|
||||
@click="viewItem(item)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-pencil"
|
||||
size="small"
|
||||
@click="editItem(item)"
|
||||
title="编辑"
|
||||
@click="editItem(item)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-cloud-download"
|
||||
size="small"
|
||||
color="primary"
|
||||
@click="getCloudUrl(item)"
|
||||
title="获取云端地址"
|
||||
@click="getCloudUrl(item)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
color="error"
|
||||
@click="confirmDelete(item)"
|
||||
title="删除"
|
||||
@click="confirmDelete(item)"
|
||||
/>
|
||||
</v-btn-group>
|
||||
</template>
|
||||
@ -102,13 +136,23 @@
|
||||
</v-card>
|
||||
|
||||
<!-- 查看数据对话框 -->
|
||||
<v-dialog v-model="viewDialog" max-width="800px">
|
||||
<v-dialog
|
||||
v-model="viewDialog"
|
||||
max-width="800px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-eye" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-eye"
|
||||
class="mr-2"
|
||||
/>
|
||||
查看数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="viewDialog = false" />
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
variant="text"
|
||||
@click="viewDialog = false"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="selectedItem">
|
||||
@ -129,11 +173,20 @@
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="copyToClipboard(selectedItem?.value)" variant="tonal">
|
||||
<v-icon icon="mdi-content-copy" class="mr-1" />
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
@click="copyToClipboard(selectedItem?.value)"
|
||||
>
|
||||
<v-icon
|
||||
icon="mdi-content-copy"
|
||||
class="mr-1"
|
||||
/>
|
||||
复制数据
|
||||
</v-btn>
|
||||
<v-btn @click="viewDialog = false" variant="text">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="viewDialog = false"
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
@ -141,13 +194,23 @@
|
||||
</v-dialog>
|
||||
|
||||
<!-- 编辑数据对话框 -->
|
||||
<v-dialog v-model="editDialog" max-width="800px">
|
||||
<v-dialog
|
||||
v-model="editDialog"
|
||||
max-width="800px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-pencil" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-pencil"
|
||||
class="mr-2"
|
||||
/>
|
||||
编辑数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeEditDialog" />
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
variant="text"
|
||||
@click="closeEditDialog"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="editingItem">
|
||||
@ -168,15 +231,18 @@
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="closeEditDialog" variant="text">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="closeEditDialog"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="saveEditedData"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="!isValidJson"
|
||||
:loading="savingData"
|
||||
@click="saveEditedData"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
@ -185,13 +251,23 @@
|
||||
</v-dialog>
|
||||
|
||||
<!-- 新建数据对话框 -->
|
||||
<v-dialog v-model="createDialog" max-width="800px">
|
||||
<v-dialog
|
||||
v-model="createDialog"
|
||||
max-width="800px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-plus" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-plus"
|
||||
class="mr-2"
|
||||
/>
|
||||
新建数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeCreateDialog" />
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
variant="text"
|
||||
@click="closeCreateDialog"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
@ -213,21 +289,24 @@
|
||||
class="font-monospace"
|
||||
:error="!isValidNewJson"
|
||||
:error-messages="isValidNewJson ? [] : ['请输入有效的JSON格式']"
|
||||
placeholder='请输入JSON数据,如:{"name": "value"}'
|
||||
placeholder="请输入JSON数据,如:{"name": "value"}"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="closeCreateDialog" variant="text">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="closeCreateDialog"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="saveNewData"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="!isValidKey || !isValidNewJson"
|
||||
:loading="savingData"
|
||||
@click="saveNewData"
|
||||
>
|
||||
创建
|
||||
</v-btn>
|
||||
@ -236,13 +315,23 @@
|
||||
</v-dialog>
|
||||
|
||||
<!-- 云端地址对话框 -->
|
||||
<v-dialog v-model="cloudUrlDialog" max-width="800px">
|
||||
<v-dialog
|
||||
v-model="cloudUrlDialog"
|
||||
max-width="800px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-cloud-download" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-cloud-download"
|
||||
class="mr-2"
|
||||
/>
|
||||
获取云端访问地址
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="cloudUrlDialog = false" />
|
||||
<v-btn
|
||||
icon="mdi-close"
|
||||
variant="text"
|
||||
@click="cloudUrlDialog = false"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="selectedCloudItem">
|
||||
@ -250,19 +339,43 @@
|
||||
</v-card-subtitle>
|
||||
|
||||
<v-card-text>
|
||||
<v-alert v-if="cloudUrlError" type="error" variant="tonal" class="mb-4">
|
||||
<v-alert
|
||||
v-if="cloudUrlError"
|
||||
type="error"
|
||||
variant="tonal"
|
||||
class="mb-4"
|
||||
>
|
||||
{{ cloudUrlError }}
|
||||
</v-alert>
|
||||
|
||||
<v-alert v-if="cloudUrlResult && cloudUrlResult.success" type="success" variant="tonal" class="mb-4">
|
||||
<v-alert
|
||||
v-if="cloudUrlResult && cloudUrlResult.success"
|
||||
type="success"
|
||||
variant="tonal"
|
||||
class="mb-4"
|
||||
>
|
||||
<v-alert-title>云端地址获取成功</v-alert-title>
|
||||
<div class="mt-2">
|
||||
<div v-if="cloudUrlResult.migrated" class="mb-2">
|
||||
<v-icon icon="mdi-database-arrow-up" class="mr-1" color="success" />
|
||||
<div
|
||||
v-if="cloudUrlResult.migrated"
|
||||
class="mb-2"
|
||||
>
|
||||
<v-icon
|
||||
icon="mdi-database-arrow-up"
|
||||
class="mr-1"
|
||||
color="success"
|
||||
/>
|
||||
数据已从本地迁移到云端
|
||||
</div>
|
||||
<div v-if="cloudUrlResult.configured" class="mb-2">
|
||||
<v-icon icon="mdi-cog" class="mr-1" color="info" />
|
||||
<div
|
||||
v-if="cloudUrlResult.configured"
|
||||
class="mb-2"
|
||||
>
|
||||
<v-icon
|
||||
icon="mdi-cog"
|
||||
class="mr-1"
|
||||
color="info"
|
||||
/>
|
||||
云端配置已自动设置
|
||||
</div>
|
||||
</div>
|
||||
@ -279,10 +392,16 @@
|
||||
@click:append-inner="copyCloudUrl"
|
||||
/>
|
||||
|
||||
<v-expansion-panels v-if="cloudUrlResult && cloudUrlResult.url" class="mt-4">
|
||||
<v-expansion-panels
|
||||
v-if="cloudUrlResult && cloudUrlResult.url"
|
||||
class="mt-4"
|
||||
>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>
|
||||
<v-icon icon="mdi-cog" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-cog"
|
||||
class="mr-2"
|
||||
/>
|
||||
高级选项
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
@ -297,13 +416,16 @@
|
||||
density="compact"
|
||||
/>
|
||||
<v-btn
|
||||
@click="refreshCloudUrl"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:loading="gettingCloudUrl"
|
||||
class="mt-2"
|
||||
@click="refreshCloudUrl"
|
||||
>
|
||||
<v-icon icon="mdi-refresh" class="mr-1" />
|
||||
<v-icon
|
||||
icon="mdi-refresh"
|
||||
class="mr-1"
|
||||
/>
|
||||
重新获取
|
||||
</v-btn>
|
||||
</v-expansion-panel-text>
|
||||
@ -313,16 +435,22 @@
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="cloudUrlDialog = false" variant="text">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="cloudUrlDialog = false"
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="cloudUrlResult && cloudUrlResult.url"
|
||||
@click="openCloudUrl"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
@click="openCloudUrl"
|
||||
>
|
||||
<v-icon icon="mdi-open-in-new" class="mr-1" />
|
||||
<v-icon
|
||||
icon="mdi-open-in-new"
|
||||
class="mr-1"
|
||||
/>
|
||||
在新窗口打开
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
@ -330,31 +458,44 @@
|
||||
</v-dialog>
|
||||
|
||||
<!-- 删除确认对话框 -->
|
||||
<v-dialog v-model="deleteDialog" max-width="400px">
|
||||
<v-dialog
|
||||
v-model="deleteDialog"
|
||||
max-width="400px"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center text-error">
|
||||
<v-icon icon="mdi-alert" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-alert"
|
||||
class="mr-2"
|
||||
/>
|
||||
确认删除
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
确定要删除键名为 <code>{{ itemToDelete?.key }}</code> 的数据吗?
|
||||
<br><br>
|
||||
<v-alert type="warning" variant="tonal" class="mt-2">
|
||||
<v-alert
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
class="mt-2"
|
||||
>
|
||||
此操作不可撤销,请谨慎操作!
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="deleteDialog = false" variant="text">
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="deleteDialog = false"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="deleteItem"
|
||||
variant="tonal"
|
||||
color="error"
|
||||
:loading="deletingData"
|
||||
@click="deleteItem"
|
||||
>
|
||||
删除
|
||||
</v-btn>
|
||||
|
@ -1,27 +1,26 @@
|
||||
<template>
|
||||
<settings-card title="编辑设置" icon="mdi-cog">
|
||||
<v-list>
|
||||
<setting-item setting-key="randomPicker.enabled" />
|
||||
<v-divider class="my-2" />
|
||||
<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" />
|
||||
<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>
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="randomPicker.animation" />
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
|
@ -1,12 +1,20 @@
|
||||
<template>
|
||||
<settings-card title="刷新设置" icon="mdi-refresh-circle">
|
||||
<settings-card
|
||||
title="刷新设置"
|
||||
icon="mdi-refresh-circle"
|
||||
>
|
||||
<v-form>
|
||||
<v-list>
|
||||
<setting-item setting-key="refresh.auto" title="自动刷新" /> <v-divider class="my-2" />
|
||||
<setting-item
|
||||
setting-key="refresh.auto"
|
||||
title="自动刷新"
|
||||
/> <v-divider class="my-2" />
|
||||
|
||||
<setting-item setting-key="refresh.interval" title="刷新间隔" />
|
||||
<setting-item
|
||||
setting-key="refresh.interval"
|
||||
title="刷新间隔"
|
||||
/>
|
||||
</v-list>
|
||||
|
||||
</v-form>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
@ -23,8 +23,8 @@
|
||||
size="large"
|
||||
prepend-icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
@click="loadConfig"
|
||||
class="mr-2"
|
||||
@click="loadConfig"
|
||||
>
|
||||
重新加载
|
||||
</v-btn>
|
||||
@ -38,12 +38,12 @@
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
<v-btn
|
||||
<v-btn
|
||||
variant="text"
|
||||
prepend-icon="mdi-restore"
|
||||
:loading="loading"
|
||||
@click="resetToDefault"
|
||||
class="mr-2"
|
||||
@click="resetToDefault"
|
||||
>
|
||||
重置为默认
|
||||
</v-btn>
|
||||
@ -58,18 +58,24 @@
|
||||
</div>
|
||||
|
||||
<!-- 添加新科目 -->
|
||||
<v-card class="mb-4" variant="outlined">
|
||||
<v-card
|
||||
class="mb-4"
|
||||
variant="outlined"
|
||||
>
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newSubjectName"
|
||||
label="科目名称"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:rules="[v => !!v || '科目名称不能为空']"
|
||||
@keyup.enter="addSubject"
|
||||
append-inner-icon="mdi-plus"
|
||||
@keyup.enter="addSubject"
|
||||
@click:append-inner="addSubject"
|
||||
/>
|
||||
</v-col>
|
||||
@ -85,7 +91,7 @@
|
||||
v-for="(subject, index) in subjects"
|
||||
:key="subject.order"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<template #prepend>
|
||||
<div class="d-flex flex-column align-center mr-2">
|
||||
<v-btn
|
||||
icon="mdi-chevron-up"
|
||||
@ -114,7 +120,7 @@
|
||||
/>
|
||||
</v-list-item-title>
|
||||
|
||||
<template v-slot:append>
|
||||
<template #append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
|
@ -1,9 +1,15 @@
|
||||
<template>
|
||||
<settings-card title="主题设置" icon="mdi-palette">
|
||||
<settings-card
|
||||
title="主题设置"
|
||||
icon="mdi-palette"
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-theme-light-dark" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-theme-light-dark"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>主题模式</v-list-item-title>
|
||||
<v-list-item-subtitle>选择明亮或暗黑主题</v-list-item-subtitle>
|
||||
@ -14,11 +20,17 @@
|
||||
color="primary"
|
||||
>
|
||||
<v-btn value="light">
|
||||
<v-icon icon="mdi-white-balance-sunny" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-white-balance-sunny"
|
||||
class="mr-2"
|
||||
/>
|
||||
明亮
|
||||
</v-btn>
|
||||
<v-btn value="dark">
|
||||
<v-icon icon="mdi-moon-waning-crescent" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-moon-waning-crescent"
|
||||
class="mr-2"
|
||||
/>
|
||||
暗黑
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
@ -37,6 +49,11 @@ export default {
|
||||
name: 'ThemeSettingsCard',
|
||||
components: { SettingsCard },
|
||||
|
||||
setup() {
|
||||
const theme = useTheme();
|
||||
return { theme };
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
localTheme: getSetting('theme.mode')
|
||||
@ -50,11 +67,6 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
setup() {
|
||||
const theme = useTheme();
|
||||
return { theme };
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateTheme(mode) {
|
||||
this.theme.global.name.value = mode;
|
||||
|
@ -3,26 +3,57 @@
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<div class="d-flex align-center mb-6">
|
||||
<v-icon size="x-large" color="primary" class="mr-3">mdi-database-cog-outline</v-icon>
|
||||
<v-icon
|
||||
size="x-large"
|
||||
color="primary"
|
||||
class="mr-3"
|
||||
>
|
||||
mdi-database-cog-outline
|
||||
</v-icon>
|
||||
<div>
|
||||
<h1 class="text-h4 ">缓存管理</h1>
|
||||
<div class="text-subtitle-1 text-grey">管理应用的本地缓存资源</div>
|
||||
<h1 class="text-h4 ">
|
||||
缓存管理
|
||||
</h1>
|
||||
<div class="text-subtitle-1 text-grey">
|
||||
管理应用的本地缓存资源
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-card class="mb-6" variant="tonal" color="info" density="compact">
|
||||
<v-card
|
||||
class="mb-6"
|
||||
variant="tonal"
|
||||
color="info"
|
||||
density="compact"
|
||||
>
|
||||
<v-card-text class="d-flex align-center">
|
||||
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
|
||||
<v-icon
|
||||
color="info"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-information-outline
|
||||
</v-icon>
|
||||
<span>在这里您可以查看和管理应用的缓存文件。清除缓存可能会导致应用需要重新下载资源,但有助于解决某些显示问题。</span>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" md="8">
|
||||
<v-card class="mb-4" variant="tonal">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="8"
|
||||
>
|
||||
<v-card
|
||||
class="mb-4"
|
||||
variant="tonal"
|
||||
>
|
||||
<v-card-text>
|
||||
<div class="d-flex align-center mb-2">
|
||||
<v-icon color="primary" class="mr-2">mdi-information</v-icon>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-information
|
||||
</v-icon>
|
||||
<span class="text-h6">什么是缓存?</span>
|
||||
</div>
|
||||
<p>缓存是浏览器在本地存储的网站资源副本,如图片、脚本和样式表等。这些缓存可以加快页面加载速度,减少数据使用,并在离线时提供基本功能。</p>
|
||||
@ -30,11 +61,22 @@
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="4">
|
||||
<v-card class="mb-4" variant="tonal">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="4"
|
||||
>
|
||||
<v-card
|
||||
class="mb-4"
|
||||
variant="tonal"
|
||||
>
|
||||
<v-card-text>
|
||||
<div class="d-flex align-center mb-2">
|
||||
<v-icon color="warning" class="mr-2">mdi-lightbulb-outline</v-icon>
|
||||
<v-icon
|
||||
color="warning"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-lightbulb-outline
|
||||
</v-icon>
|
||||
<span class="text-h6">何时清除缓存?</span>
|
||||
</div>
|
||||
<ul class="pl-4">
|
||||
|
@ -3,24 +3,38 @@
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<div class="d-flex align-center mb-6">
|
||||
<v-icon size="x-large" color="primary" class="mr-3"
|
||||
>mdi-database-sync</v-icon
|
||||
<v-icon
|
||||
size="x-large"
|
||||
color="primary"
|
||||
class="mr-3"
|
||||
>
|
||||
mdi-database-sync
|
||||
</v-icon>
|
||||
<div>
|
||||
<h1 class="text-h4">数据迁移工具</h1>
|
||||
<h1 class="text-h4">
|
||||
数据迁移工具
|
||||
</h1>
|
||||
<div class="text-subtitle-1 text-grey">
|
||||
将现有数据迁移至 KV 存储系统
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-card class="mb-6" variant="tonal" color="info" density="compact">
|
||||
<v-card
|
||||
class="mb-6"
|
||||
variant="tonal"
|
||||
color="info"
|
||||
density="compact"
|
||||
>
|
||||
<v-card-text class="d-flex align-center">
|
||||
<v-icon color="info" class="mr-2">mdi-information-outline</v-icon>
|
||||
<span
|
||||
>使用此工具可以将数据从旧存储系统迁移到新的 KV
|
||||
存储系统,选择本地或云端迁移,以确保数据不会丢失。</span
|
||||
<v-icon
|
||||
color="info"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-information-outline
|
||||
</v-icon>
|
||||
<span>使用此工具可以将数据从旧存储系统迁移到新的 KV
|
||||
存储系统,选择本地或云端迁移,以确保数据不会丢失。</span>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@ -29,12 +43,20 @@
|
||||
</v-row>
|
||||
|
||||
<!-- 一键迁移对话框 -->
|
||||
<v-dialog v-model="showMigrationDialog" max-width="500" persistent>
|
||||
<v-dialog
|
||||
v-model="showMigrationDialog"
|
||||
max-width="500"
|
||||
persistent
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5 d-flex align-center">
|
||||
<v-icon color="primary" size="large" class="mr-3"
|
||||
>mdi-database-sync</v-icon
|
||||
<v-icon
|
||||
color="primary"
|
||||
size="large"
|
||||
class="mr-3"
|
||||
>
|
||||
mdi-database-sync
|
||||
</v-icon>
|
||||
一键数据迁移
|
||||
</v-card-title>
|
||||
<v-card-text class="mt-4">
|
||||
@ -62,7 +84,7 @@
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey-darken-1"
|
||||
variant="text"
|
||||
@ -74,11 +96,16 @@
|
||||
color="primary"
|
||||
size="large"
|
||||
variant="elevated"
|
||||
@click="startAutoMigration"
|
||||
:loading="isAutoMigrating"
|
||||
:disabled="isAutoMigrating"
|
||||
@click="startAutoMigration"
|
||||
>
|
||||
<v-icon left class="mr-2">mdi-database-export</v-icon>
|
||||
<v-icon
|
||||
left
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-database-export
|
||||
</v-icon>
|
||||
开始一键迁移
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
|
@ -1,7 +1,17 @@
|
||||
<template>
|
||||
<v-container class="fill-height" fluid>
|
||||
<v-row align="center" justify="center">
|
||||
<v-col cols="12" sm="8" md="6">
|
||||
<v-container
|
||||
class="fill-height"
|
||||
fluid
|
||||
>
|
||||
<v-row
|
||||
align="center"
|
||||
justify="center"
|
||||
>
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="8"
|
||||
md="6"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h5">
|
||||
{{ status === 'processing' ? '正在处理授权...' : status === 'success' ? '授权成功' : '授权失败' }}
|
||||
@ -12,12 +22,17 @@
|
||||
indeterminate
|
||||
color="primary"
|
||||
class="mb-4"
|
||||
></v-progress-linear>
|
||||
/>
|
||||
<p>{{ message }}</p>
|
||||
</v-card-text>
|
||||
<v-card-actions v-if="status !== 'processing'">
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" @click="goToHome">返回首页</v-btn>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="goToHome"
|
||||
>
|
||||
返回首页
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
@ -2,9 +2,17 @@
|
||||
<v-container class="fill-height">
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card class="elevation-12" border>
|
||||
<v-card
|
||||
class="elevation-12"
|
||||
border
|
||||
>
|
||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||
<v-icon color="white" class="mr-2">mdi-swap-horizontal</v-icon>
|
||||
<v-icon
|
||||
color="white"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-swap-horizontal
|
||||
</v-icon>
|
||||
课程表转换工具
|
||||
</v-card-title>
|
||||
<v-card-subtitle>
|
||||
@ -22,7 +30,9 @@
|
||||
@click:close="error = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-alert-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-alert-circle
|
||||
</v-icon>
|
||||
{{ error }}
|
||||
</div>
|
||||
</v-alert>
|
||||
@ -38,31 +48,73 @@
|
||||
@click:close="success = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-check-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-check-circle
|
||||
</v-icon>
|
||||
{{ success }}
|
||||
</div>
|
||||
</v-alert>
|
||||
|
||||
<!-- 输入方式选择 -->
|
||||
<v-tabs v-model="activeTab" class="mb-4 mx-2" color="primary" rounded>
|
||||
<v-tab value="text" class="px-5"><v-icon start>mdi-text-box</v-icon> 文本粘贴</v-tab>
|
||||
<v-tab value="file" class="px-5"><v-icon start>mdi-file-upload</v-icon> 文件上传</v-tab>
|
||||
<v-tabs
|
||||
v-model="activeTab"
|
||||
class="mb-4 mx-2"
|
||||
color="primary"
|
||||
rounded
|
||||
>
|
||||
<v-tab
|
||||
value="text"
|
||||
class="px-5"
|
||||
>
|
||||
<v-icon start>
|
||||
mdi-text-box
|
||||
</v-icon> 文本粘贴
|
||||
</v-tab>
|
||||
<v-tab
|
||||
value="file"
|
||||
class="px-5"
|
||||
>
|
||||
<v-icon start>
|
||||
mdi-file-upload
|
||||
</v-icon> 文件上传
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<!-- 格式选择 -->
|
||||
<v-btn-toggle v-model="formatMode" color="primary" class="mb-4 mx-2" mandatory density="comfortable" border rounded>
|
||||
<v-btn value="auto">自动检测</v-btn>
|
||||
<v-btn value="json">JSON</v-btn>
|
||||
<v-btn value="yaml" :disabled="!yamlLibLoaded">
|
||||
<v-btn-toggle
|
||||
v-model="formatMode"
|
||||
color="primary"
|
||||
class="mb-4 mx-2"
|
||||
mandatory
|
||||
density="comfortable"
|
||||
border
|
||||
rounded
|
||||
>
|
||||
<v-btn value="auto">
|
||||
自动检测
|
||||
</v-btn>
|
||||
<v-btn value="json">
|
||||
JSON
|
||||
</v-btn>
|
||||
<v-btn
|
||||
value="yaml"
|
||||
:disabled="!yamlLibLoaded"
|
||||
>
|
||||
YAML
|
||||
<v-tooltip activator="parent" location="bottom">
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="bottom"
|
||||
>
|
||||
{{ yamlLibLoaded ? 'YAML解析库已加载' : '正在加载YAML解析库...' }}
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
|
||||
<!-- 添加当前检测到的格式提示 -->
|
||||
<div v-if="jsonText && formatMode === 'auto'" class="text-caption mb-2">
|
||||
<div
|
||||
v-if="jsonText && formatMode === 'auto'"
|
||||
class="text-caption mb-2"
|
||||
>
|
||||
检测到的格式: {{ isYaml(jsonText) ? 'YAML' : 'JSON' }}
|
||||
</div>
|
||||
|
||||
@ -78,7 +130,7 @@
|
||||
rows="6"
|
||||
placeholder="请在此粘贴CSES格式的数据..."
|
||||
@input="handleTextChange"
|
||||
></v-textarea>
|
||||
/>
|
||||
</div>
|
||||
</v-window-item>
|
||||
<v-window-item value="file">
|
||||
@ -89,13 +141,13 @@
|
||||
prepend-icon="mdi-file-upload"
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
@change="handleFileChange"
|
||||
hint="支持JSON、YAML格式文件"
|
||||
persistent-hint
|
||||
:rules="[
|
||||
v => !v || v.size < 2000000 || '文件大小不能超过 2 MB',
|
||||
]"
|
||||
></v-file-input>
|
||||
@change="handleFileChange"
|
||||
/>
|
||||
|
||||
<v-alert
|
||||
v-if="file && formatMode === 'auto'"
|
||||
@ -111,17 +163,33 @@
|
||||
|
||||
<!-- 设置面板 -->
|
||||
<v-col cols="12">
|
||||
<v-card flat class="pa-4 rounded-lg" border>
|
||||
<v-card
|
||||
flat
|
||||
class="pa-4 rounded-lg"
|
||||
border
|
||||
>
|
||||
<div class="d-flex align-center mb-3">
|
||||
<v-icon color="primary" class="mr-2">mdi-calendar-multiselect</v-icon>
|
||||
<h3 class="text-subtitle-1 font-weight-medium mr-auto">选择导出天数</h3>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-calendar-multiselect
|
||||
</v-icon>
|
||||
<h3 class="text-subtitle-1 font-weight-medium mr-auto">
|
||||
选择导出天数
|
||||
</h3>
|
||||
<v-btn
|
||||
variant="text"
|
||||
color="primary"
|
||||
class="ml-2"
|
||||
@click="selectAllDays"
|
||||
>
|
||||
<v-icon start size="small">mdi-checkbox-multiple-marked</v-icon>
|
||||
<v-icon
|
||||
start
|
||||
size="small"
|
||||
>
|
||||
mdi-checkbox-multiple-marked
|
||||
</v-icon>
|
||||
全选
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@ -130,19 +198,37 @@
|
||||
class="ml-2"
|
||||
@click="clearSelectedDays"
|
||||
>
|
||||
<v-icon start size="small">mdi-checkbox-multiple-blank-outline</v-icon>
|
||||
<v-icon
|
||||
start
|
||||
size="small"
|
||||
>
|
||||
mdi-checkbox-multiple-blank-outline
|
||||
</v-icon>
|
||||
清除
|
||||
</v-btn>
|
||||
</div>
|
||||
<v-chip-group v-model="selectedDays" multiple class="mb-2" color="primary">
|
||||
<v-chip v-for="day in 7" :key="day" :value="day" filter variant="tonal" class="filter-chip" label>
|
||||
<v-chip-group
|
||||
v-model="selectedDays"
|
||||
multiple
|
||||
class="mb-2"
|
||||
color="primary"
|
||||
>
|
||||
<v-chip
|
||||
v-for="day in 7"
|
||||
:key="day"
|
||||
:value="day"
|
||||
filter
|
||||
variant="tonal"
|
||||
class="filter-chip"
|
||||
label
|
||||
>
|
||||
{{ dayNames[day] }}
|
||||
<v-badge
|
||||
v-if="getDaySchedule(day).length > 0"
|
||||
:content="getDaySchedule(day).length"
|
||||
color="primary"
|
||||
inline
|
||||
></v-badge>
|
||||
/>
|
||||
</v-chip>
|
||||
</v-chip-group>
|
||||
</v-card>
|
||||
@ -150,31 +236,51 @@
|
||||
|
||||
<!-- 改进设置选项卡,显示为开关组 -->
|
||||
<v-col cols="12">
|
||||
<v-card flat class="pa-4 rounded-lg" border>
|
||||
<v-card
|
||||
flat
|
||||
class="pa-4 rounded-lg"
|
||||
border
|
||||
>
|
||||
<div class="d-flex align-center mb-3">
|
||||
<v-icon color="primary" class="mr-2">mdi-cog</v-icon>
|
||||
<h3 class="text-subtitle-1 font-weight-medium">显示配置</h3>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-cog
|
||||
</v-icon>
|
||||
<h3 class="text-subtitle-1 font-weight-medium">
|
||||
显示配置
|
||||
</h3>
|
||||
</div>
|
||||
<v-row>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-switch
|
||||
v-model="settings.hideTeacherName"
|
||||
label="不显示教师姓名"
|
||||
color="primary"
|
||||
inset
|
||||
hide-details
|
||||
></v-switch>
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-switch
|
||||
v-model="settings.hideRoom"
|
||||
label="不显示教室信息"
|
||||
color="primary"
|
||||
inset
|
||||
hide-details
|
||||
></v-switch>
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="12" sm="6">
|
||||
<v-col
|
||||
cols="12"
|
||||
sm="6"
|
||||
>
|
||||
<v-text-field
|
||||
v-model.number="settings.totalWeeks"
|
||||
label="总周数"
|
||||
@ -186,19 +292,23 @@
|
||||
variant="outlined"
|
||||
prepend-inner-icon="mdi-calendar-week"
|
||||
class="mt-3"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
</v-col>
|
||||
|
||||
<!-- 添加加载状态的骨架屏 -->
|
||||
<v-card v-if="loading" class="my-4" outlined>
|
||||
<v-card
|
||||
v-if="loading"
|
||||
class="my-4"
|
||||
outlined
|
||||
>
|
||||
<v-card-text>
|
||||
<v-skeleton-loader
|
||||
type="table"
|
||||
class="mx-auto"
|
||||
></v-skeleton-loader>
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
@ -223,12 +333,31 @@
|
||||
</v-alert>
|
||||
|
||||
<!-- 课程表预览 -->
|
||||
<v-card v-if="processedData" class="my-4" elevation="1">
|
||||
<v-card
|
||||
v-if="processedData"
|
||||
class="my-4"
|
||||
elevation="1"
|
||||
>
|
||||
<v-card-title class="d-flex align-center pa-4 bg-primary-lighten-5">
|
||||
<v-icon color="primary" class="mr-2">mdi-table</v-icon>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-table
|
||||
</v-icon>
|
||||
<span class="font-weight-bold">课程表</span>
|
||||
<v-chip color="primary" class="ml-3" size="small" pill>
|
||||
<v-icon start size="x-small">mdi-book-open-variant</v-icon>
|
||||
<v-chip
|
||||
color="primary"
|
||||
class="ml-3"
|
||||
size="small"
|
||||
pill
|
||||
>
|
||||
<v-icon
|
||||
start
|
||||
size="x-small"
|
||||
>
|
||||
mdi-book-open-variant
|
||||
</v-icon>
|
||||
{{ processedData.tableData.length }} 节课程
|
||||
</v-chip>
|
||||
</v-card-title>
|
||||
@ -256,8 +385,15 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-for="day in 7" #[`item.${day}`]="{ item }" :key="day">
|
||||
<div v-if="item[day]" class="course-cell">
|
||||
<template
|
||||
v-for="day in 7"
|
||||
#[`item.${day}`]="{ item }"
|
||||
:key="day"
|
||||
>
|
||||
<div
|
||||
v-if="item[day]"
|
||||
class="course-cell"
|
||||
>
|
||||
<template v-if="Array.isArray(item[day])">
|
||||
<div
|
||||
v-for="(course, index) in item[day]"
|
||||
@ -268,12 +404,12 @@
|
||||
<span
|
||||
v-if="!settings.hideTeacherName && course.teacher"
|
||||
>
|
||||
<br />{{ course.teacher }}
|
||||
<br>{{ course.teacher }}
|
||||
</span>
|
||||
<span
|
||||
v-if="!settings.hideRoom && course.room"
|
||||
>
|
||||
<br />{{ course.room }}
|
||||
<br>{{ course.room }}
|
||||
</span>
|
||||
<span
|
||||
v-if="course.weekType"
|
||||
@ -288,17 +424,17 @@
|
||||
<span
|
||||
v-if="!settings.hideTeacherName && item[day].teacher"
|
||||
>
|
||||
<br />{{ item[day].teacher }}
|
||||
<br>{{ item[day].teacher }}
|
||||
</span>
|
||||
<span
|
||||
v-if="!settings.hideRoom && item[day].room"
|
||||
>
|
||||
<br />{{ item[day].room }}
|
||||
<br>{{ item[day].room }}
|
||||
</span>
|
||||
<span
|
||||
<span
|
||||
v-if="item[day].weekType"
|
||||
class="week-type"
|
||||
>
|
||||
class="week-type"
|
||||
>
|
||||
{{ item[day].weekType }}周
|
||||
</span>
|
||||
</template>
|
||||
@ -309,18 +445,48 @@
|
||||
</v-card>
|
||||
|
||||
<!-- 时间表 -->
|
||||
<v-card v-if="hasExportData" class="my-4" elevation="1">
|
||||
<v-card
|
||||
v-if="hasExportData"
|
||||
class="my-4"
|
||||
elevation="1"
|
||||
>
|
||||
<v-card-title class="d-flex align-center pa-4 bg-primary-lighten-5">
|
||||
<v-icon color="primary" class="mr-2">mdi-timetable</v-icon>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-timetable
|
||||
</v-icon>
|
||||
<span class="font-weight-bold">每日课程时间表</span>
|
||||
<v-chip class="ml-3" size="small" color="primary" pill>
|
||||
<v-icon start size="x-small">mdi-clock-outline</v-icon>
|
||||
<v-chip
|
||||
class="ml-3"
|
||||
size="small"
|
||||
color="primary"
|
||||
pill
|
||||
>
|
||||
<v-icon
|
||||
start
|
||||
size="x-small"
|
||||
>
|
||||
mdi-clock-outline
|
||||
</v-icon>
|
||||
{{ totalClassHours }} 课时
|
||||
</v-chip>
|
||||
<v-tooltip v-if="exportPeriods.length > 0">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-chip class="ml-2" size="small" color="info" v-bind="props" pill>
|
||||
<v-icon start size="x-small">mdi-information-outline</v-icon>
|
||||
<template #activator="{ props }">
|
||||
<v-chip
|
||||
class="ml-2"
|
||||
size="small"
|
||||
color="info"
|
||||
v-bind="props"
|
||||
pill
|
||||
>
|
||||
<v-icon
|
||||
start
|
||||
size="x-small"
|
||||
>
|
||||
mdi-information-outline
|
||||
</v-icon>
|
||||
节次已重排
|
||||
</v-chip>
|
||||
</template>
|
||||
@ -329,24 +495,47 @@
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<!-- 美化日期导航标签 -->
|
||||
<v-tabs v-if="daysWithSchedule.length > 0" v-model="activeDay" class="mb-4" color="primary" grow align-tabs="center">
|
||||
<v-tab v-for="day in daysWithSchedule" :key="day" :value="day" class="px-2 font-weight-medium">
|
||||
<v-tabs
|
||||
v-if="daysWithSchedule.length > 0"
|
||||
v-model="activeDay"
|
||||
class="mb-4"
|
||||
color="primary"
|
||||
grow
|
||||
align-tabs="center"
|
||||
>
|
||||
<v-tab
|
||||
v-for="day in daysWithSchedule"
|
||||
:key="day"
|
||||
:value="day"
|
||||
class="px-2 font-weight-medium"
|
||||
>
|
||||
{{ dayNames[day] }}
|
||||
<v-badge
|
||||
:content="getDaySchedule(day).length"
|
||||
color="primary"
|
||||
inline
|
||||
></v-badge>
|
||||
/>
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
|
||||
<!-- 当前选中日期的课程表 -->
|
||||
<v-window v-model="activeDay">
|
||||
<v-window-item v-for="day in daysWithSchedule" :key="day" :value="day">
|
||||
<v-table density="compact" class="rounded" :headers-length="6" disable-sort>
|
||||
<v-window-item
|
||||
v-for="day in daysWithSchedule"
|
||||
:key="day"
|
||||
:value="day"
|
||||
>
|
||||
<v-table
|
||||
density="compact"
|
||||
class="rounded"
|
||||
:headers-length="6"
|
||||
disable-sort
|
||||
>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="text-center">节次</th>
|
||||
<th class="text-center">
|
||||
节次
|
||||
</th>
|
||||
<th>课程</th>
|
||||
<th>时间</th>
|
||||
<th>教师</th>
|
||||
@ -355,52 +544,100 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(group, index) in groupByPeriod(getDaySchedule(day))" :key="index">
|
||||
<template
|
||||
v-for="(group, index) in groupByPeriod(getDaySchedule(day))"
|
||||
:key="index"
|
||||
>
|
||||
<tr>
|
||||
<td class="text-center font-weight-bold">
|
||||
{{ group.period }}
|
||||
<v-tooltip v-if="group.originalPeriod !== group.period">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-icon size="x-small" v-bind="props" color="info" class="ml-1">mdi-sync</v-icon>
|
||||
<template #activator="{ props }">
|
||||
<v-icon
|
||||
size="x-small"
|
||||
v-bind="props"
|
||||
color="info"
|
||||
class="ml-1"
|
||||
>
|
||||
mdi-sync
|
||||
</v-icon>
|
||||
</template>
|
||||
原节次: {{ group.originalPeriod }}
|
||||
</v-tooltip>
|
||||
</td>
|
||||
<td>
|
||||
<div v-for="(item, i) in group.items" :key="i" class="mb-1">
|
||||
<v-chip size="small" :color="getSubjectColor(item.subject)" label text-color="white" class="mr-1">
|
||||
<div
|
||||
v-for="(item, i) in group.items"
|
||||
:key="i"
|
||||
class="mb-1"
|
||||
>
|
||||
<v-chip
|
||||
size="small"
|
||||
:color="getSubjectColor(item.subject)"
|
||||
label
|
||||
text-color="white"
|
||||
class="mr-1"
|
||||
>
|
||||
{{ item.subject }}
|
||||
</v-chip>
|
||||
<v-chip v-if="group.items.length > 1" size="x-small" class="ml-1" :color="item.weekType === '单' ? 'warning' : 'success'">
|
||||
<v-chip
|
||||
v-if="group.items.length > 1"
|
||||
size="x-small"
|
||||
class="ml-1"
|
||||
:color="item.weekType === '单' ? 'warning' : 'success'"
|
||||
>
|
||||
{{ item.weekType }}周
|
||||
</v-chip>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div v-for="(timeSlot, i) in group.uniqueTimeSlots" :key="i" class="mb-1">
|
||||
<v-chip size="x-small" class="time-chip">
|
||||
<div
|
||||
v-for="(timeSlot, i) in group.uniqueTimeSlots"
|
||||
:key="i"
|
||||
class="mb-1"
|
||||
>
|
||||
<v-chip
|
||||
size="x-small"
|
||||
class="time-chip"
|
||||
>
|
||||
{{ formatTime(timeSlot.startTime) }} - {{ formatTime(timeSlot.endTime) }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="!settings.hideTeacherName">
|
||||
<div v-for="(item, i) in group.items" :key="i" class="mb-1">
|
||||
<div
|
||||
v-for="(item, i) in group.items"
|
||||
:key="i"
|
||||
class="mb-1"
|
||||
>
|
||||
{{ item.teacher || '-' }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
<template v-else>
|
||||
-
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="!settings.hideRoom">
|
||||
<div v-for="(item, i) in group.items" :key="i" class="mb-1">
|
||||
<div
|
||||
v-for="(item, i) in group.items"
|
||||
:key="i"
|
||||
class="mb-1"
|
||||
>
|
||||
{{ item.room || '-' }}
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>-</template>
|
||||
<template v-else>
|
||||
-
|
||||
</template>
|
||||
</td>
|
||||
<td>
|
||||
<div v-for="(item, i) in group.items" :key="i" class="mb-1">
|
||||
<div
|
||||
v-for="(item, i) in group.items"
|
||||
:key="i"
|
||||
class="mb-1"
|
||||
>
|
||||
{{ item.weeks }}
|
||||
</div>
|
||||
</td>
|
||||
@ -412,7 +649,11 @@
|
||||
</v-window>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<v-alert v-if="hasExportData && daysWithSchedule.length === 0" type="info" class="mt-3">
|
||||
<v-alert
|
||||
v-if="hasExportData && daysWithSchedule.length === 0"
|
||||
type="info"
|
||||
class="mt-3"
|
||||
>
|
||||
没有找到任何课程数据
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
@ -420,24 +661,24 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="">
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
:loading="loading"
|
||||
:disabled="(!jsonText && !file) || loading"
|
||||
@click="processInput"
|
||||
prepend-icon="mdi-cog-refresh"
|
||||
@click="processInput"
|
||||
>
|
||||
处理数据
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="info"
|
||||
:disabled="!hasExportData"
|
||||
@click="showExportPreview"
|
||||
class="ml-2"
|
||||
prepend-icon="mdi-eye"
|
||||
border
|
||||
@click="showExportPreview"
|
||||
>
|
||||
刷新
|
||||
</v-btn>
|
||||
@ -445,10 +686,10 @@
|
||||
color="success"
|
||||
variant="outlined"
|
||||
:disabled="!hasExportData"
|
||||
@click="downloadCSV"
|
||||
class="ml-2"
|
||||
prepend-icon="mdi-download"
|
||||
border
|
||||
@click="downloadCSV"
|
||||
>
|
||||
下载CSV
|
||||
</v-btn>
|
||||
@ -725,6 +966,22 @@ export default {
|
||||
return days;
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
// 加载YAML解析库
|
||||
try {
|
||||
await loadJsYaml();
|
||||
this.yamlLibLoaded = true;
|
||||
} catch (error) {
|
||||
this.error = error.message;
|
||||
}
|
||||
|
||||
// 监听daysWithSchedule变化,设置默认选中的日期
|
||||
this.$watch('daysWithSchedule', (newVal) => {
|
||||
if (newVal.length > 0 && !this.activeDay) {
|
||||
this.activeDay = newVal[0];
|
||||
}
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
async handleFileChange() {
|
||||
this.resetData();
|
||||
@ -1231,22 +1488,6 @@ export default {
|
||||
clearSelectedDays() {
|
||||
this.selectedDays = [];
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
// 加载YAML解析库
|
||||
try {
|
||||
await loadJsYaml();
|
||||
this.yamlLibLoaded = true;
|
||||
} catch (error) {
|
||||
this.error = error.message;
|
||||
}
|
||||
|
||||
// 监听daysWithSchedule变化,设置默认选中的日期
|
||||
this.$watch('daysWithSchedule', (newVal) => {
|
||||
if (newVal.length > 0 && !this.activeDay) {
|
||||
this.activeDay = newVal[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
@ -2,9 +2,17 @@
|
||||
<v-container class="fill-height">
|
||||
<v-row>
|
||||
<v-col cols="12">
|
||||
<v-card class="elevation-12" border>
|
||||
<v-card
|
||||
class="elevation-12"
|
||||
border
|
||||
>
|
||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||
<v-icon color="white" class="mr-2">mdi-calendar-check</v-icon>
|
||||
<v-icon
|
||||
color="white"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-calendar-check
|
||||
</v-icon>
|
||||
考试看板
|
||||
</v-card-title>
|
||||
<v-card-subtitle>
|
||||
@ -22,7 +30,9 @@
|
||||
@click:close="error = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-alert-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-alert-circle
|
||||
</v-icon>
|
||||
{{ error }}
|
||||
</div>
|
||||
</v-alert>
|
||||
@ -38,7 +48,9 @@
|
||||
@click:close="success = ''"
|
||||
>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon class="mr-2">mdi-check-circle</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-check-circle
|
||||
</v-icon>
|
||||
{{ success }}
|
||||
</div>
|
||||
</v-alert>
|
||||
@ -58,8 +70,8 @@
|
||||
color="info"
|
||||
prepend-icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
@click="loadConfigs"
|
||||
variant="outlined"
|
||||
@click="loadConfigs"
|
||||
>
|
||||
刷新
|
||||
</v-btn>
|
||||
@ -74,19 +86,29 @@
|
||||
</div>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<v-card v-if="loading" class="my-4" outlined>
|
||||
<v-card
|
||||
v-if="loading"
|
||||
class="my-4"
|
||||
outlined
|
||||
>
|
||||
<v-card-text>
|
||||
<v-skeleton-loader
|
||||
type="list-item-avatar-two-line@3"
|
||||
class="mx-auto"
|
||||
></v-skeleton-loader>
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<!-- 配置列表 -->
|
||||
<v-card v-if="!loading && configs.length > 0" class="my-4" elevation="1">
|
||||
<v-card
|
||||
v-if="!loading && configs.length > 0"
|
||||
class="my-4"
|
||||
elevation="1"
|
||||
>
|
||||
<v-card-title class="d-flex align-center pa-4 bg-primary-lighten-5">
|
||||
<v-icon class="mr-2">mdi-format-list-bulleted</v-icon>
|
||||
<v-icon class="mr-2">
|
||||
mdi-format-list-bulleted
|
||||
</v-icon>
|
||||
<span class="font-weight-bold">配置列表</span>
|
||||
</v-card-title>
|
||||
<v-list>
|
||||
@ -98,8 +120,13 @@
|
||||
@click="showEditDialog(config)"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-avatar color="primary" class="mr-2">
|
||||
<v-icon color="white">mdi-calendar-text</v-icon>
|
||||
<v-avatar
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
<v-icon color="white">
|
||||
mdi-calendar-text
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
</template>
|
||||
|
||||
@ -108,11 +135,21 @@
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle class="text-caption mt-1">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon size="small" class="mr-1">mdi-information-outline</v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="mr-1"
|
||||
>
|
||||
mdi-information-outline
|
||||
</v-icon>
|
||||
{{ config.message || '无描述' }}
|
||||
</div>
|
||||
<div class="d-flex align-center mt-1">
|
||||
<v-icon size="small" class="mr-1">mdi-book-multiple</v-icon>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="mr-1"
|
||||
>
|
||||
mdi-book-multiple
|
||||
</v-icon>
|
||||
{{ config.examInfos ? config.examInfos.length : 0 }} 堂考试
|
||||
</div>
|
||||
</v-list-item-subtitle>
|
||||
@ -140,8 +177,6 @@
|
||||
>
|
||||
<v-icon>mdi-eye</v-icon>
|
||||
</v-btn>
|
||||
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</v-list-item>
|
||||
@ -149,12 +184,22 @@
|
||||
</v-card>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<v-card v-if="!loading && configs.length === 0" class="my-4" elevation="1">
|
||||
<v-card
|
||||
v-if="!loading && configs.length === 0"
|
||||
class="my-4"
|
||||
elevation="1"
|
||||
>
|
||||
<v-card-text class="text-center py-8">
|
||||
<v-icon size="64" color="grey-lighten-1" class="mb-4">
|
||||
<v-icon
|
||||
size="64"
|
||||
color="grey-lighten-1"
|
||||
class="mb-4"
|
||||
>
|
||||
mdi-calendar-blank
|
||||
</v-icon>
|
||||
<h3 class="text-h6 mb-2 text-grey-darken-1">暂无配置</h3>
|
||||
<h3 class="text-h6 mb-2 text-grey-darken-1">
|
||||
暂无配置
|
||||
</h3>
|
||||
<p class="text-body-2 text-grey-darken-1 mb-4">
|
||||
点击"新建配置"按钮创建您的第一个考试配置
|
||||
</p>
|
||||
@ -173,10 +218,18 @@
|
||||
</v-row>
|
||||
|
||||
<!-- 重命名对话框 -->
|
||||
<v-dialog v-model="renameDialog" max-width="500">
|
||||
<v-dialog
|
||||
v-model="renameDialog"
|
||||
max-width="500"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon color="primary" class="mr-2">mdi-rename-box</v-icon>
|
||||
<v-icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-rename-box
|
||||
</v-icon>
|
||||
重命名配置
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
@ -187,10 +240,10 @@
|
||||
variant="outlined"
|
||||
:rules="[v => !!v || '配置名称不能为空']"
|
||||
@keyup.enter="renameConfig"
|
||||
></v-text-field>
|
||||
/>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@ -202,8 +255,8 @@
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
:loading="renaming"
|
||||
@click="renameConfig"
|
||||
:disabled="!newConfigName"
|
||||
@click="renameConfig"
|
||||
>
|
||||
确认
|
||||
</v-btn>
|
||||
@ -212,12 +265,21 @@
|
||||
</v-dialog>
|
||||
|
||||
<!-- 编辑配置弹框 -->
|
||||
<v-dialog v-model="editDialog" max-width="1200" persistent>
|
||||
<v-dialog
|
||||
v-model="editDialog"
|
||||
max-width="1200"
|
||||
persistent
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||
<v-icon color="white" class="mr-2">mdi-pencil</v-icon>
|
||||
<v-icon
|
||||
color="white"
|
||||
class="mr-2"
|
||||
>
|
||||
mdi-pencil
|
||||
</v-icon>
|
||||
编辑考试配置
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-chip
|
||||
v-if="editingConfig"
|
||||
color="white"
|
||||
@ -237,12 +299,14 @@
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text class="pa-4"
|
||||
style="max-height: 70vh; overflow-y: auto;">
|
||||
<v-card-text
|
||||
class="pa-4"
|
||||
style="max-height: 70vh; overflow-y: auto;"
|
||||
>
|
||||
<ExamConfigEditor
|
||||
v-if="editingConfig"
|
||||
:config-id="editingConfig.id"
|
||||
ref="configEditor"
|
||||
:config-id="editingConfig.id"
|
||||
:dialog-mode="true"
|
||||
@saved="onConfigSaved"
|
||||
@error="onConfigError"
|
||||
@ -259,7 +323,7 @@ style="max-height: 70vh; overflow-y: auto;">
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
<v-spacer></v-spacer>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="outlined"
|
||||
|
@ -14,14 +14,24 @@
|
||||
:badge-color="unreadCount ? 'error' : undefined"
|
||||
@click="$refs.messageLog.drawer = true"
|
||||
/>
|
||||
<v-btn icon="mdi-cog" variant="text" @click="$router.push('/settings')" />
|
||||
<v-btn
|
||||
icon="mdi-cog"
|
||||
variant="text"
|
||||
@click="$router.push('/settings')"
|
||||
/>
|
||||
</template>
|
||||
</v-app-bar>
|
||||
<div class="d-flex">
|
||||
<!-- 主要内容区域 -->
|
||||
<v-container class="main-window flex-grow-1 no-select" fluid>
|
||||
<v-container
|
||||
class="main-window flex-grow-1 no-select"
|
||||
fluid
|
||||
>
|
||||
<!-- 有内容的科目卡片 -->
|
||||
<div ref="gridContainer" class="grid-masonry">
|
||||
<div
|
||||
ref="gridContainer"
|
||||
class="grid-masonry"
|
||||
>
|
||||
<TransitionGroup name="grid">
|
||||
<div
|
||||
v-for="item in sortedItems"
|
||||
@ -59,19 +69,27 @@
|
||||
<!-- 单独显示空科目 -->
|
||||
<div class="empty-subjects mt-4">
|
||||
<template v-if="emptySubjectDisplay === 'button'">
|
||||
<v-btn-group divided variant="outlined">
|
||||
<v-btn-group
|
||||
divided
|
||||
variant="outlined"
|
||||
>
|
||||
<v-btn
|
||||
v-for="subject in unusedSubjects"
|
||||
:key="subject.name"
|
||||
:disabled="isEditingDisabled"
|
||||
@click="openDialog(subject.name)"
|
||||
>
|
||||
<v-icon start> mdi-plus </v-icon>
|
||||
<v-icon start>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
{{ subject.name }}
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
</template>
|
||||
<div v-else class="empty-subjects-grid">
|
||||
<div
|
||||
v-else
|
||||
class="empty-subjects-grid"
|
||||
>
|
||||
<TransitionGroup name="v-list">
|
||||
<v-card
|
||||
v-for="subject in unusedSubjects"
|
||||
@ -85,8 +103,15 @@
|
||||
{{ subject.name }}
|
||||
</v-card-title>
|
||||
<v-card-text class="text-center">
|
||||
<v-icon size="small" color="grey"> mdi-plus </v-icon>
|
||||
<div class="text-caption text-grey">点击添加作业</div>
|
||||
<v-icon
|
||||
size="small"
|
||||
color="grey"
|
||||
>
|
||||
mdi-plus
|
||||
</v-icon>
|
||||
<div class="text-caption text-grey">
|
||||
点击添加作业
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</TransitionGroup>
|
||||
@ -102,7 +127,12 @@
|
||||
>
|
||||
上传
|
||||
</v-btn>
|
||||
<v-btn v-else color="success" size="large" @click="showSyncMessage">
|
||||
<v-btn
|
||||
v-else
|
||||
color="success"
|
||||
size="large"
|
||||
@click="showSyncMessage"
|
||||
>
|
||||
同步完成
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@ -157,7 +187,11 @@
|
||||
variant="tonal"
|
||||
>
|
||||
<v-card-title class="text-subtitle-1">
|
||||
<v-icon start icon="mdi-shield-check" size="small" />
|
||||
<v-icon
|
||||
start
|
||||
icon="mdi-shield-check"
|
||||
size="small"
|
||||
/>
|
||||
屏幕保护技术已启用
|
||||
</v-card-title>
|
||||
<v-card-text class="text-body-2">
|
||||
@ -168,7 +202,7 @@
|
||||
*研究显示动态像素偏移技术可以修复屏幕坏点,起到保护屏幕的作用,数据来自实验室。<a
|
||||
href="https://patentscope.wipo.int/search/zh/detail.jsf?docId=CN232281523&_cid=P20-M8L0YX-67061-1"
|
||||
target="_blank"
|
||||
>专利号CN108648692
|
||||
>专利号CN108648692
|
||||
</a>
|
||||
</p>
|
||||
<p class="text-caption text-grey">
|
||||
@ -187,66 +221,73 @@
|
||||
>
|
||||
<h1>出勤</h1>
|
||||
<h2>
|
||||
<snap style="white-space: nowrap"> 应到 </snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
应到
|
||||
</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
{{
|
||||
state.studentList.length -
|
||||
state.boardData.attendance.exclude.length
|
||||
state.boardData.attendance.exclude.length
|
||||
}}人
|
||||
</snap>
|
||||
</h2>
|
||||
<h2>
|
||||
<snap style="white-space: nowrap"> 实到 </snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
实到
|
||||
</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
{{
|
||||
state.studentList.length -
|
||||
state.boardData.attendance.absent.length -
|
||||
state.boardData.attendance.late.length -
|
||||
state.boardData.attendance.exclude.length
|
||||
state.boardData.attendance.absent.length -
|
||||
state.boardData.attendance.late.length -
|
||||
state.boardData.attendance.exclude.length
|
||||
}}人
|
||||
</snap>
|
||||
</h2>
|
||||
<h2>
|
||||
<snap style="white-space: nowrap"> 请假 </snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
请假
|
||||
</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
{{ state.boardData.attendance.absent.length }}人
|
||||
</snap>
|
||||
</h2>
|
||||
<h3
|
||||
class="gray-text"
|
||||
v-for="(name, index) in state.boardData.attendance.absent"
|
||||
:key="'absent-' + index"
|
||||
class="gray-text"
|
||||
>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span
|
||||
><span style="white-space: nowrap">{{ name }}</span>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||
</h3>
|
||||
<h2>
|
||||
<snap style="white-space: nowrap">迟到</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
迟到
|
||||
</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
{{ state.boardData.attendance.late.length }}人
|
||||
</snap>
|
||||
</h2>
|
||||
<h3
|
||||
class="gray-text"
|
||||
v-for="(name, index) in state.boardData.attendance.late"
|
||||
:key="'late-' + index"
|
||||
class="gray-text"
|
||||
>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span
|
||||
><span style="white-space: nowrap">{{ name }}</span>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||
</h3>
|
||||
<h2>
|
||||
<snap style="white-space: nowrap">不参与</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
不参与
|
||||
</snap>:
|
||||
<snap style="white-space: nowrap">
|
||||
{{ state.boardData.attendance.exclude.length }}人
|
||||
</snap>
|
||||
</h2>
|
||||
<h3
|
||||
class="gray-text"
|
||||
v-for="(name, index) in state.boardData.attendance.exclude"
|
||||
:key="'exclude-' + index"
|
||||
class="gray-text"
|
||||
>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span
|
||||
><span style="white-space: nowrap">{{ name }}</span>
|
||||
<span v-if="useDisplay().lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||
</h3>
|
||||
</v-col>
|
||||
</div>
|
||||
@ -259,7 +300,10 @@
|
||||
@save="handleHomeworkSave"
|
||||
/>
|
||||
|
||||
<v-snackbar v-model="state.snackbar" :timeout="2000">
|
||||
<v-snackbar
|
||||
v-model="state.snackbar"
|
||||
:timeout="2000"
|
||||
>
|
||||
{{ state.snackbarText }}
|
||||
</v-snackbar>
|
||||
|
||||
@ -271,10 +315,17 @@
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-account-group" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-account-group"
|
||||
class="mr-2"
|
||||
/>
|
||||
出勤状态管理
|
||||
<v-spacer />
|
||||
<v-chip color="primary" size="small" class="ml-2">
|
||||
<v-chip
|
||||
color="primary"
|
||||
size="small"
|
||||
class="ml-2"
|
||||
>
|
||||
{{ state.dateString }}
|
||||
</v-chip>
|
||||
</v-card-title>
|
||||
@ -282,7 +333,10 @@
|
||||
<v-card-text>
|
||||
<!-- 批量操作和搜索 -->
|
||||
<v-row class="mb-4">
|
||||
<v-col cols="12" md="12">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="12"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="attendanceSearch"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
@ -324,11 +378,11 @@
|
||||
attendanceFilter.includes('present') ? 'elevated' : 'tonal'
|
||||
"
|
||||
class="px-2 filter-chip"
|
||||
@click="toggleFilter('present')"
|
||||
prepend-icon="mdi-account-check"
|
||||
:append-icon="
|
||||
attendanceFilter.includes('present') ? 'mdi-check' : ''
|
||||
"
|
||||
@click="toggleFilter('present')"
|
||||
>
|
||||
到课
|
||||
</v-chip>
|
||||
@ -340,11 +394,11 @@
|
||||
attendanceFilter.includes('absent') ? 'elevated' : 'tonal'
|
||||
"
|
||||
class="px-2 filter-chip"
|
||||
@click="toggleFilter('absent')"
|
||||
prepend-icon="mdi-account-off"
|
||||
:append-icon="
|
||||
attendanceFilter.includes('absent') ? 'mdi-check' : ''
|
||||
"
|
||||
@click="toggleFilter('absent')"
|
||||
>
|
||||
请假
|
||||
</v-chip>
|
||||
@ -355,11 +409,11 @@
|
||||
attendanceFilter.includes('late') ? 'elevated' : 'tonal'
|
||||
"
|
||||
class="px-2 filter-chip"
|
||||
@click="toggleFilter('late')"
|
||||
prepend-icon="mdi-clock-alert"
|
||||
:append-icon="
|
||||
attendanceFilter.includes('late') ? 'mdi-check' : ''
|
||||
"
|
||||
@click="toggleFilter('late')"
|
||||
>
|
||||
迟到
|
||||
</v-chip>
|
||||
@ -370,11 +424,11 @@
|
||||
attendanceFilter.includes('exclude') ? 'elevated' : 'tonal'
|
||||
"
|
||||
class="px-2 filter-chip"
|
||||
@click="toggleFilter('exclude')"
|
||||
prepend-icon="mdi-account-cancel"
|
||||
:append-icon="
|
||||
attendanceFilter.includes('exclude') ? 'mdi-check' : ''
|
||||
"
|
||||
@click="toggleFilter('exclude')"
|
||||
>
|
||||
不参与
|
||||
</v-chip>
|
||||
@ -391,7 +445,10 @@
|
||||
md="6"
|
||||
lg="4"
|
||||
>
|
||||
<v-card class="student-card" border>
|
||||
<v-card
|
||||
class="student-card"
|
||||
border
|
||||
>
|
||||
<v-card-text class="d-flex align-center pa-2">
|
||||
<div class="flex-grow-1">
|
||||
<div class="d-flex align-center">
|
||||
@ -404,11 +461,15 @@
|
||||
size="24"
|
||||
class="mr-2"
|
||||
>
|
||||
<v-icon size="small">{{
|
||||
getStudentStatusIcon(state.studentList.indexOf(student))
|
||||
}}</v-icon>
|
||||
<v-icon size="small">
|
||||
{{
|
||||
getStudentStatusIcon(state.studentList.indexOf(student))
|
||||
}}
|
||||
</v-icon>
|
||||
</v-avatar>
|
||||
<div class="text-subtitle-1">{{ student }}</div>
|
||||
<div class="text-subtitle-1">
|
||||
{{ student }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="attendance-actions">
|
||||
@ -421,8 +482,8 @@
|
||||
icon="mdi-account-check"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="setPresent(state.studentList.indexOf(student))"
|
||||
:title="'设为到课'"
|
||||
@click="setPresent(state.studentList.indexOf(student))"
|
||||
/>
|
||||
<v-btn
|
||||
:color="
|
||||
@ -433,8 +494,8 @@
|
||||
icon="mdi-account-off"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="setAbsent(state.studentList.indexOf(student))"
|
||||
:title="'设为请假'"
|
||||
@click="setAbsent(state.studentList.indexOf(student))"
|
||||
/>
|
||||
<v-btn
|
||||
:color="
|
||||
@ -445,8 +506,8 @@
|
||||
icon="mdi-clock-alert"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="setLate(state.studentList.indexOf(student))"
|
||||
:title="'设为迟到'"
|
||||
@click="setLate(state.studentList.indexOf(student))"
|
||||
/>
|
||||
<v-btn
|
||||
:color="
|
||||
@ -457,8 +518,8 @@
|
||||
icon="mdi-account-cancel"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="setExclude(state.studentList.indexOf(student))"
|
||||
:title="'设为不参与'"
|
||||
@click="setExclude(state.studentList.indexOf(student))"
|
||||
/>
|
||||
</div>
|
||||
</v-card-text>
|
||||
@ -466,10 +527,19 @@
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col cols="12" md="12">
|
||||
<v-card variant="tonal" color="primary" class="mb-4">
|
||||
<v-col
|
||||
cols="12"
|
||||
md="12"
|
||||
>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
class="mb-4"
|
||||
>
|
||||
<v-card-text>
|
||||
<div class="text-subtitle-2 mb-2">批量操作</div>
|
||||
<div class="text-subtitle-2 mb-2">
|
||||
批量操作
|
||||
</div>
|
||||
<v-btn-group>
|
||||
<v-btn
|
||||
color="success"
|
||||
@ -504,8 +574,8 @@
|
||||
</v-btn-group>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-col></v-row
|
||||
>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card-text>
|
||||
|
||||
<v-divider />
|
||||
@ -513,8 +583,13 @@
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
|
||||
<v-btn color="primary" @click="saveAttendance">
|
||||
<v-icon start>mdi-content-save</v-icon>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="saveAttendance"
|
||||
>
|
||||
<v-icon start>
|
||||
mdi-content-save
|
||||
</v-icon>
|
||||
保存
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
@ -542,18 +617,32 @@
|
||||
<FloatingICP />
|
||||
|
||||
<!-- 添加确认对话框 -->
|
||||
<v-dialog v-model="confirmDialog.show" max-width="400">
|
||||
<v-dialog
|
||||
v-model="confirmDialog.show"
|
||||
max-width="400"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h6"> 确认保存 </v-card-title>
|
||||
<v-card-title class="text-h6">
|
||||
确认保存
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
您正在修改 {{ state.dateString }} 的数据,确定要保存吗?
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn color="grey" variant="text" @click="confirmDialog.reject">
|
||||
<v-btn
|
||||
color="grey"
|
||||
variant="text"
|
||||
@click="confirmDialog.reject"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="primary" @click="confirmDialog.resolve"> 确认保存 </v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="confirmDialog.resolve"
|
||||
>
|
||||
确认保存
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
@ -566,9 +655,14 @@
|
||||
/>
|
||||
|
||||
<!-- 添加URL配置确认对话框 -->
|
||||
<v-dialog v-model="urlConfigDialog.show" max-width="500">
|
||||
<v-dialog
|
||||
v-model="urlConfigDialog.show"
|
||||
max-width="500"
|
||||
>
|
||||
<v-card>
|
||||
<v-card-title class="text-h6"> 确认应用URL配置 </v-card-title>
|
||||
<v-card-title class="text-h6">
|
||||
确认应用URL配置
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<p>以下配置将应用于当前班级:</p>
|
||||
<v-list density="compact">
|
||||
@ -577,17 +671,30 @@
|
||||
:key="change.key"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon :icon="change.icon" size="small" class="mr-2" />
|
||||
<v-icon
|
||||
:icon="change.icon"
|
||||
size="small"
|
||||
class="mr-2"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title class="d-flex align-center">
|
||||
<span class="text-subtitle-1">{{ change.name }}</span>
|
||||
<v-tooltip activator="parent" location="top">{{
|
||||
change.description || change.key
|
||||
}}</v-tooltip>
|
||||
<v-tooltip
|
||||
activator="parent"
|
||||
location="top"
|
||||
>
|
||||
{{
|
||||
change.description || change.key
|
||||
}}
|
||||
</v-tooltip>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
<span class="text-grey-darken-1">{{ change.oldValue }}</span>
|
||||
<v-icon icon="mdi-arrow-right" size="small" class="mx-1" />
|
||||
<v-icon
|
||||
icon="mdi-arrow-right"
|
||||
size="small"
|
||||
class="mx-1"
|
||||
/>
|
||||
<span class="text-primary font-weight-medium">{{
|
||||
change.newValue
|
||||
}}</span>
|
||||
@ -604,12 +711,15 @@
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="primary" @click="urlConfigDialog.confirmHandler">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@click="urlConfigDialog.confirmHandler"
|
||||
>
|
||||
确认应用
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog><br/><br/><br/><br/><br/><br/>
|
||||
</v-dialog><br><br><br><br><br><br>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -1,261 +1,347 @@
|
||||
<template><v-app-bar elevation="1">
|
||||
<template #prepend>
|
||||
<v-btn
|
||||
icon="mdi-arrow-left"
|
||||
variant="text"
|
||||
@click="$router.push('/')"
|
||||
/>
|
||||
</template>
|
||||
<v-app-bar-title class="text-h6" v-if="list && !isRenaming">{{ list.name }}</v-app-bar-title>
|
||||
<v-app-bar-title class="text-h6" v-else>列表</v-app-bar-title>
|
||||
</v-app-bar>
|
||||
<template>
|
||||
<v-app-bar elevation="1">
|
||||
<template #prepend>
|
||||
<v-btn
|
||||
icon="mdi-arrow-left"
|
||||
variant="text"
|
||||
@click="$router.push('/')"
|
||||
/>
|
||||
</template>
|
||||
<v-app-bar-title
|
||||
v-if="list && !isRenaming"
|
||||
class="text-h6"
|
||||
>
|
||||
{{ list.name }}
|
||||
</v-app-bar-title>
|
||||
<v-app-bar-title
|
||||
v-else
|
||||
class="text-h6"
|
||||
>
|
||||
列表
|
||||
</v-app-bar-title>
|
||||
</v-app-bar>
|
||||
<v-container>
|
||||
|
||||
<div class="d-flex align-center mb-4">
|
||||
<div class="d-flex align-center mb-4">
|
||||
<v-btn
|
||||
icon
|
||||
class="mr-2"
|
||||
to="/list"
|
||||
border
|
||||
>
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
</v-btn>
|
||||
<h1 v-if="list && !isRenaming">
|
||||
{{ list.name }}
|
||||
<v-btn
|
||||
icon
|
||||
class="mr-2"
|
||||
to="/list"
|
||||
size="small"
|
||||
border
|
||||
@click="startRenaming"
|
||||
>
|
||||
<v-icon>mdi-arrow-left</v-icon>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<h1 v-if="list && !isRenaming">
|
||||
{{ list.name }}
|
||||
<v-btn icon size="small" @click="startRenaming" border>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
</h1>
|
||||
<div v-else-if="list && isRenaming" class="d-flex align-center">
|
||||
<v-text-field
|
||||
v-model="newListName"
|
||||
label="列表名称"
|
||||
hide-details
|
||||
density="compact"
|
||||
class="mr-2"
|
||||
style="min-width: 200px;"
|
||||
autofocus
|
||||
@keyup.enter="saveListName"
|
||||
></v-text-field>
|
||||
<v-btn color="primary" size="small" class="mr-2" @click="saveListName">
|
||||
<v-icon>mdi-check</v-icon>
|
||||
</v-btn>
|
||||
<v-btn color="error" size="small" @click="cancelRenaming">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<h1 v-else>
|
||||
加载中...
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<v-card class="mb-5" border rounded="xl">
|
||||
<v-card-title class="d-flex align-center">
|
||||
项目列表
|
||||
<v-spacer />
|
||||
<v-btn-toggle
|
||||
v-model="sortType"
|
||||
mandatory
|
||||
>
|
||||
<v-btn value="default">
|
||||
<v-icon>mdi-sort-alphabetical-ascending</v-icon>
|
||||
</v-btn>
|
||||
<v-btn value="completed">
|
||||
<v-icon>mdi-check-circle-outline</v-icon>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="sortedItems.length === 0">
|
||||
暂无项目,请添加新项目
|
||||
</v-card-text>
|
||||
<v-list
|
||||
v-else
|
||||
select-strategy="leaf"
|
||||
</h1>
|
||||
<div
|
||||
v-else-if="list && isRenaming"
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="newListName"
|
||||
label="列表名称"
|
||||
hide-details
|
||||
density="compact"
|
||||
class="mr-2"
|
||||
style="min-width: 200px;"
|
||||
autofocus
|
||||
@keyup.enter="saveListName"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
size="small"
|
||||
class="mr-2"
|
||||
@click="saveListName"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in sortedItems"
|
||||
:key="item.id"
|
||||
:class="{ 'text-decoration-line-through': item.completed }"
|
||||
@click="openItemDetails(item)"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-list-item-action start>
|
||||
<v-checkbox-btn
|
||||
:model-value="item.completed"
|
||||
@update:model-value="updateItemStatus(item.id, $event)"
|
||||
@click.stop
|
||||
/>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
{{ item.name }}
|
||||
<v-list-item-subtitle>{{ item.description }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-actions v-if="sortedItems.length > 0">
|
||||
<v-icon>mdi-check</v-icon>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
size="small"
|
||||
@click="cancelRenaming"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
<h1 v-else>
|
||||
加载中...
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
|
||||
<v-card
|
||||
class="mb-5"
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
项目列表
|
||||
<v-spacer />
|
||||
<v-btn-toggle
|
||||
v-model="sortType"
|
||||
mandatory
|
||||
>
|
||||
<v-btn value="default">
|
||||
<v-icon>mdi-sort-alphabetical-ascending</v-icon>
|
||||
</v-btn>
|
||||
<v-btn value="completed">
|
||||
<v-icon>mdi-check-circle-outline</v-icon>
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
</v-card-title>
|
||||
<v-card-text v-if="sortedItems.length === 0">
|
||||
暂无项目,请添加新项目
|
||||
</v-card-text>
|
||||
<v-list
|
||||
v-else
|
||||
select-strategy="leaf"
|
||||
>
|
||||
<v-list-item
|
||||
v-for="(item, index) in sortedItems"
|
||||
:key="item.id"
|
||||
:class="{ 'text-decoration-line-through': item.completed }"
|
||||
@click="openItemDetails(item)"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-list-item-action start>
|
||||
<v-checkbox-btn
|
||||
:model-value="item.completed"
|
||||
@update:model-value="updateItemStatus(item.id, $event)"
|
||||
@click.stop
|
||||
/>
|
||||
</v-list-item-action>
|
||||
</template>
|
||||
{{ item.name }}
|
||||
<v-list-item-subtitle>{{ item.description }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
{{ index + 1 }}
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
<v-card-actions v-if="sortedItems.length > 0">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="error"
|
||||
prepend-icon="mdi-delete-sweep"
|
||||
:disabled="!hasCompletedItems"
|
||||
@click="confirmDeleteCompleted"
|
||||
>
|
||||
删除已完成项目
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card><v-card
|
||||
class="mb-5"
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>添加新项目</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="newItemName"
|
||||
label="项目名称"
|
||||
:rules="[(v) => !!v || '名称不能为空']"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:disabled="!newItemName"
|
||||
@click="addItem"
|
||||
>
|
||||
添加
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<v-card
|
||||
class="mb-5"
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>列表排序</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="sortSeed"
|
||||
label="排序种子 (任意数字或文本)"
|
||||
hint="输入相同的种子值可以得到相同的排序结果"
|
||||
persistent-hint
|
||||
class="mb-3"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
@click="randomSort"
|
||||
>
|
||||
随机排序
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="resetSort"
|
||||
>
|
||||
撤销
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
|
||||
<!-- 确认删除对话框 -->
|
||||
<v-dialog
|
||||
v-model="deleteDialog.show"
|
||||
max-width="500"
|
||||
>
|
||||
<v-card
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>{{ deleteDialog.title }}</v-card-title>
|
||||
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
@click="deleteDialog.show = false"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
prepend-icon="mdi-delete-sweep"
|
||||
@click="confirmDeleteCompleted"
|
||||
:disabled="!hasCompletedItems"
|
||||
variant="text"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
删除已完成项目
|
||||
确认删除
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card><v-card class="mb-5" border rounded="xl">
|
||||
<v-card-title>添加新项目</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="newItemName"
|
||||
label="项目名称"
|
||||
:rules="[(v) => !!v || '名称不能为空']"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:disabled="!newItemName"
|
||||
@click="addItem"
|
||||
>
|
||||
添加
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 项目详情对话框 -->
|
||||
<v-dialog
|
||||
v-model="itemDialog.show"
|
||||
max-width="600"
|
||||
>
|
||||
<v-card
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>
|
||||
<span v-if="!itemDialog.isEditing">项目详情</span>
|
||||
<span v-else>编辑项目</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card class="mb-5" border rounded="xl">
|
||||
<v-card-title>列表排序</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="sortSeed"
|
||||
label="排序种子 (任意数字或文本)"
|
||||
hint="输入相同的种子值可以得到相同的排序结果"
|
||||
persistent-hint
|
||||
class="mb-3"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
@click="randomSort"
|
||||
>
|
||||
随机排序
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="resetSort"
|
||||
>
|
||||
撤销
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<div v-if="!itemDialog.isEditing && itemDialog.item">
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">
|
||||
{{ itemDialog.item.name }}
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ itemDialog.item.id }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<!-- 确认删除对话框 -->
|
||||
<v-dialog v-model="deleteDialog.show" max-width="500">
|
||||
<v-card border rounded="xl">
|
||||
<v-card-title>{{ deleteDialog.title }}</v-card-title>
|
||||
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" variant="text" @click="deleteDialog.show = false">
|
||||
<v-list-item>
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">
|
||||
状态
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
<v-chip
|
||||
:color="itemDialog.item.completed ? 'success' : 'warning'"
|
||||
size="small"
|
||||
>
|
||||
{{ itemDialog.item.completed ? '已完成' : '未完成' }}
|
||||
</v-chip>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item v-if="itemDialog.item.description">
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">
|
||||
描述
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ itemDialog.item.description }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="itemDialog.isEditing && itemDialog.item"
|
||||
class="pa-2"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="itemDialog.editedItem.name"
|
||||
label="名称"
|
||||
variant="outlined"
|
||||
class="mb-3"
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="itemDialog.editedItem.description"
|
||||
label="描述"
|
||||
variant="outlined"
|
||||
rows="3"
|
||||
class="mb-3"
|
||||
/>
|
||||
|
||||
|
||||
<v-switch
|
||||
v-model="itemDialog.editedItem.completed"
|
||||
label="已完成"
|
||||
color="success"
|
||||
hide-details
|
||||
/>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
|
||||
<template v-if="!itemDialog.isEditing">
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
@click="startEditingItem"
|
||||
>
|
||||
编辑
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="error"
|
||||
variant="text"
|
||||
@click="confirmDeleteItem(itemDialog.item?.id)"
|
||||
>
|
||||
删除
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="secondary"
|
||||
variant="text"
|
||||
@click="itemDialog.show = false"
|
||||
>
|
||||
关闭
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<v-btn
|
||||
color="success"
|
||||
variant="text"
|
||||
@click="saveItemChanges"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="secondary"
|
||||
variant="text"
|
||||
@click="cancelEditingItem"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="error" variant="text" @click="confirmDelete">
|
||||
确认删除
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<!-- 项目详情对话框 -->
|
||||
<v-dialog v-model="itemDialog.show" max-width="600">
|
||||
<v-card border rounded="xl">
|
||||
<v-card-title>
|
||||
<span v-if="!itemDialog.isEditing">项目详情</span>
|
||||
<span v-else>编辑项目</span>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div v-if="!itemDialog.isEditing && itemDialog.item">
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">{{ itemDialog.item.name }}</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ itemDialog.item.id }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">状态</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
<v-chip
|
||||
:color="itemDialog.item.completed ? 'success' : 'warning'"
|
||||
size="small"
|
||||
>
|
||||
{{ itemDialog.item.completed ? '已完成' : '未完成' }}
|
||||
</v-chip>
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item v-if="itemDialog.item.description">
|
||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">描述</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ itemDialog.item.description }}</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
|
||||
</v-list>
|
||||
</div>
|
||||
|
||||
<div v-else-if="itemDialog.isEditing && itemDialog.item" class="pa-2">
|
||||
<v-text-field
|
||||
v-model="itemDialog.editedItem.name"
|
||||
label="名称"
|
||||
variant="outlined"
|
||||
class="mb-3"
|
||||
></v-text-field>
|
||||
|
||||
<v-textarea
|
||||
v-model="itemDialog.editedItem.description"
|
||||
label="描述"
|
||||
variant="outlined"
|
||||
rows="3"
|
||||
class="mb-3"
|
||||
></v-textarea>
|
||||
|
||||
|
||||
<v-switch
|
||||
v-model="itemDialog.editedItem.completed"
|
||||
label="已完成"
|
||||
color="success"
|
||||
hide-details
|
||||
></v-switch>
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
|
||||
<template v-if="!itemDialog.isEditing">
|
||||
<v-btn color="primary" variant="text" @click="startEditingItem">
|
||||
编辑
|
||||
</v-btn>
|
||||
<v-btn color="error" variant="text" @click="confirmDeleteItem(itemDialog.item?.id)">
|
||||
删除
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="text" @click="itemDialog.show = false">
|
||||
关闭
|
||||
</v-btn>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<v-btn color="success" variant="text" @click="saveItemChanges">
|
||||
保存
|
||||
</v-btn>
|
||||
<v-btn color="secondary" variant="text" @click="cancelEditingItem">
|
||||
取消
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
</template>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
<template><v-app-bar elevation="1">
|
||||
<template>
|
||||
<v-app-bar elevation="1">
|
||||
<template #prepend>
|
||||
<v-btn
|
||||
icon="mdi-arrow-left"
|
||||
@ -6,13 +7,15 @@
|
||||
@click="$router.push('/')"
|
||||
/>
|
||||
</template>
|
||||
<v-app-bar-title class="text-h6">列表</v-app-bar-title>
|
||||
<v-app-bar-title class="text-h6">
|
||||
列表
|
||||
</v-app-bar-title>
|
||||
</v-app-bar><v-container>
|
||||
|
||||
|
||||
|
||||
|
||||
<v-card border class="mb-5" rounded="xl">
|
||||
<v-card
|
||||
border
|
||||
class="mb-5"
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>现有列表</v-card-title>
|
||||
<v-card-text v-if="lists.length === 0">
|
||||
暂无列表,请创建新列表
|
||||
@ -27,7 +30,10 @@
|
||||
<div v-if="list.id !== editingListId">
|
||||
<v-list-item-title>{{ list.name }}</v-list-item-title>
|
||||
</div>
|
||||
<div v-else class="d-flex align-center w-100">
|
||||
<div
|
||||
v-else
|
||||
class="d-flex align-center w-100"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="editListName"
|
||||
label="列表名称"
|
||||
@ -36,21 +42,41 @@
|
||||
class="mr-2"
|
||||
autofocus
|
||||
@keyup.enter="saveListName"
|
||||
></v-text-field>
|
||||
<v-btn icon color="primary" @click.stop.prevent="saveListName" class="mr-2" border>
|
||||
/>
|
||||
<v-btn
|
||||
icon
|
||||
color="primary"
|
||||
class="mr-2"
|
||||
border
|
||||
@click.stop.prevent="saveListName"
|
||||
>
|
||||
<v-icon>mdi-check</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon color="error" @click.stop.prevent="cancelEditing" border>
|
||||
<v-btn
|
||||
icon
|
||||
color="error"
|
||||
border
|
||||
@click.stop.prevent="cancelEditing"
|
||||
>
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
<template #append>
|
||||
<div v-if="list.id !== editingListId">
|
||||
<v-btn icon @click.stop.prevent="startEditing(list.id)" class="mr-2" border>
|
||||
<v-btn
|
||||
icon
|
||||
class="mr-2"
|
||||
border
|
||||
@click.stop.prevent="startEditing(list.id)"
|
||||
>
|
||||
<v-icon>mdi-pencil</v-icon>
|
||||
</v-btn>
|
||||
<v-btn icon @click.stop.prevent="confirmDeleteList(list.id)" border>
|
||||
<v-btn
|
||||
icon
|
||||
border
|
||||
@click.stop.prevent="confirmDeleteList(list.id)"
|
||||
>
|
||||
<v-icon>mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
@ -58,36 +84,55 @@
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-card>
|
||||
<v-card class="mb-5" border rounded="xl">
|
||||
<v-card
|
||||
class="mb-5"
|
||||
border
|
||||
rounded="xl"
|
||||
>
|
||||
<v-card-title>创建新列表</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="newListName"
|
||||
label="列表名称"
|
||||
:rules="[v => !!v || '名称不能为空']"
|
||||
></v-text-field>
|
||||
<v-btn color="primary" @click="createNewList" :disabled="!newListName">
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
:disabled="!newListName"
|
||||
@click="createNewList"
|
||||
>
|
||||
创建列表
|
||||
</v-btn>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<!-- 确认删除对话框 -->
|
||||
<v-dialog v-model="deleteDialog.show" max-width="500">
|
||||
<v-dialog
|
||||
v-model="deleteDialog.show"
|
||||
max-width="500"
|
||||
>
|
||||
<v-card border>
|
||||
<v-card-title>删除列表</v-card-title>
|
||||
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="primary" variant="text" @click="deleteDialog.show = false">
|
||||
<v-spacer />
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="text"
|
||||
@click="deleteDialog.show = false"
|
||||
>
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn color="error" variant="text" @click="confirmDelete">
|
||||
<v-btn
|
||||
color="error"
|
||||
variant="text"
|
||||
@click="confirmDelete"
|
||||
>
|
||||
确认删除
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-container>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -10,11 +10,13 @@
|
||||
<v-btn
|
||||
icon="mdi-menu"
|
||||
variant="text"
|
||||
@click="drawer = !drawer"
|
||||
class="d-md-none"
|
||||
@click="drawer = !drawer"
|
||||
/>
|
||||
</template>
|
||||
<v-app-bar-title class="text-h6">设置</v-app-bar-title>
|
||||
<v-app-bar-title class="text-h6">
|
||||
设置
|
||||
</v-app-bar-title>
|
||||
</v-app-bar>
|
||||
|
||||
<v-container fluid>
|
||||
@ -27,11 +29,11 @@
|
||||
<v-list-item
|
||||
v-for="tab in settingsTabs"
|
||||
:key="tab.value"
|
||||
@click="settingsTab = tab.value"
|
||||
:active="settingsTab === tab.value"
|
||||
:prepend-icon="tab.icon"
|
||||
class="rounded-e-xl"
|
||||
:color="settingsTab === tab.value ? 'primary' : 'default'"
|
||||
@click="settingsTab = tab.value"
|
||||
>
|
||||
<v-list-item-title>{{ tab.title }}</v-list-item-title>
|
||||
</v-list-item>
|
||||
@ -44,36 +46,41 @@
|
||||
direction="vertical"
|
||||
>
|
||||
<v-tabs-window-item value="index">
|
||||
<v-card title="Classworks" subtitle="设置" class="rounded-xl" border>
|
||||
<v-card
|
||||
title="Classworks"
|
||||
subtitle="设置"
|
||||
class="rounded-xl"
|
||||
border
|
||||
>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
color="error"
|
||||
variant="tonal"
|
||||
icon="mdi-alert-circle"
|
||||
class="rounded-xl"
|
||||
>Classworks
|
||||
>
|
||||
Classworks
|
||||
是开源免费的软件,官方没有提供任何形式的付费支持服务,源代码仓库地址在
|
||||
<a
|
||||
href="https://github.com/ZeroCatDev/Classworks"
|
||||
target="_blank"
|
||||
>https://github.com/ZeroCatDev/Classworks</a
|
||||
>。如果您通过有偿协助等付费方式取得本应用,在遇到问题时请在与卖家约定的服务框架下,优先向卖家求助。如果卖家没有提供您预期的服务,请退款或通过其它形式积极维护您的合法权益。</v-alert
|
||||
>
|
||||
>https://github.com/ZeroCatDev/Classworks</a>。如果您通过有偿协助等付费方式取得本应用,在遇到问题时请在与卖家约定的服务框架下,优先向卖家求助。如果卖家没有提供您预期的服务,请退款或通过其它形式积极维护您的合法权益。
|
||||
</v-alert>
|
||||
<v-alert
|
||||
class="mt-4 rounded-xl"
|
||||
color="info"
|
||||
variant="tonal"
|
||||
icon="mdi-information"
|
||||
>请不要使用浏览器清除缓存功能,否则会导致配置丢失。<del
|
||||
>恶意的操作可能导致您受到贵校教师的处理</del
|
||||
></v-alert
|
||||
>
|
||||
请不要使用浏览器清除缓存功能,否则会导致配置丢失。<del>恶意的操作可能导致您受到贵校教师的处理</del>
|
||||
</v-alert>
|
||||
<v-alert
|
||||
class="mt-4 rounded-xl"
|
||||
color="warning"
|
||||
variant="tonal"
|
||||
icon="mdi-information"
|
||||
><p>
|
||||
>
|
||||
<p>
|
||||
请不要使用包括但不限于360极速浏览器、360安全浏览器、夸克浏览器、QQ浏览器等浏览器使用
|
||||
Classworks
|
||||
,这些浏览器过时且存在严重的一致性问题。在Windows上,使用新版
|
||||
@ -83,16 +90,17 @@
|
||||
上述浏览器商标为其所属公司所有,Classworks™
|
||||
与上述浏览器所属公司暂无竞争关系。
|
||||
</p>
|
||||
<br /><v-btn
|
||||
<br><v-btn
|
||||
href="https://www.microsoft.com/zh-cn/windows/microsoft-edge"
|
||||
target="_blank"
|
||||
color="warning"
|
||||
variant="tonal"
|
||||
class="text-none rounded-xl"
|
||||
append-icon="mdi-open-in-new"
|
||||
>下载 Microsoft Edge(微软边缘浏览器)</v-btn
|
||||
></v-alert
|
||||
>
|
||||
>
|
||||
下载 Microsoft Edge(微软边缘浏览器)
|
||||
</v-btn>
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-tabs-window-item>
|
||||
@ -103,15 +111,27 @@
|
||||
:loading="loading.server"
|
||||
@saved="onSettingsSaved"
|
||||
/>
|
||||
<data-provider-settings-card border class="mt-4" />
|
||||
<kv-database-card border class="mt-4" />
|
||||
<data-provider-settings-card
|
||||
border
|
||||
class="mt-4"
|
||||
/>
|
||||
<kv-database-card
|
||||
border
|
||||
class="mt-4"
|
||||
/>
|
||||
</v-tabs-window-item>
|
||||
|
||||
<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 value="share">
|
||||
<settings-link-generator border class="mt-4" />
|
||||
<settings-link-generator
|
||||
border
|
||||
class="mt-4"
|
||||
/>
|
||||
</v-tabs-window-item>
|
||||
|
||||
<v-tabs-window-item value="refresh">
|
||||
@ -148,24 +168,34 @@
|
||||
|
||||
|
||||
<v-tabs-window-item value="randomPicker">
|
||||
<random-picker-card border :is-mobile="isMobile" />
|
||||
<random-picker-card
|
||||
border
|
||||
:is-mobile="isMobile"
|
||||
/>
|
||||
</v-tabs-window-item>
|
||||
<v-tabs-window-item value="subject">
|
||||
<subject-management-card border /> <br />
|
||||
<subject-management-card border /> <br>
|
||||
<homework-template-card border />
|
||||
</v-tabs-window-item>
|
||||
|
||||
<v-tabs-window-item value="developer"
|
||||
><settings-card border title="开发者选项" icon="mdi-developer-board">
|
||||
<v-tabs-window-item value="developer">
|
||||
<settings-card
|
||||
border
|
||||
title="开发者选项"
|
||||
icon="mdi-developer-board"
|
||||
>
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-code-tags" class="mr-3" />
|
||||
<v-icon
|
||||
icon="mdi-code-tags"
|
||||
class="mr-3"
|
||||
/>
|
||||
</template>
|
||||
<v-list-item-title>启用开发者选项</v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
>启用后可以查看和修改开发者设置</v-list-item-subtitle
|
||||
>
|
||||
<v-list-item-subtitle>
|
||||
启用后可以查看和修改开发者设置
|
||||
</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-switch
|
||||
v-model="settings.developer.enabled"
|
||||
@ -183,9 +213,15 @@
|
||||
@saved="onSettingsSaved"
|
||||
/>
|
||||
<template v-if="settings.developer.enabled">
|
||||
<v-card border class="mt-4 rounded-lg">
|
||||
<v-card
|
||||
border
|
||||
class="mt-4 rounded-lg"
|
||||
>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-cog-outline" class="mr-2" />
|
||||
<v-icon
|
||||
icon="mdi-cog-outline"
|
||||
class="mr-2"
|
||||
/>
|
||||
所有设置
|
||||
</v-card-title>
|
||||
<v-card-subtitle> 浏览和修改所有可用设置 </v-card-subtitle>
|
||||
@ -194,12 +230,18 @@
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
<v-col v-if="settings.developer.enabled" cols="12"> </v-col>
|
||||
<v-col
|
||||
v-if="settings.developer.enabled"
|
||||
cols="12"
|
||||
/>
|
||||
</v-tabs-window-item>
|
||||
|
||||
<v-tabs-window-item value="about">
|
||||
<about-card />
|
||||
<echo-chamber-card border class="mt-4" />
|
||||
<echo-chamber-card
|
||||
border
|
||||
class="mt-4"
|
||||
/>
|
||||
</v-tabs-window-item>
|
||||
</v-tabs-window>
|
||||
</v-container>
|
||||
|
@ -94,6 +94,7 @@ export default {
|
||||
* 1. 如果用户选择本地存储,则将本地键数据读取并存储到云端
|
||||
* 2. 如果云端配置为空或错误则自动改成classworksCloudDefaults的配置
|
||||
* 3. 根据网站验证情况(私有则添加token,公开或受保护则不需要)拼接键的get路径并返回
|
||||
* 4. Token优先使用kvToken(KV授权令牌),若不存在则使用siteKey(网站令牌)作为后备
|
||||
*
|
||||
* @param {string} key - 要获取地址的键名
|
||||
* @param {Object} options - 选项配置
|
||||
@ -175,6 +176,7 @@ export default {
|
||||
try {
|
||||
let serverUrl = getSetting("server.domain");
|
||||
let siteKey = getSetting("server.siteKey");
|
||||
let kvToken = getSetting("server.kvToken");
|
||||
const machineId = getSetting("device.uuid");
|
||||
let configured = false;
|
||||
|
||||
@ -242,9 +244,11 @@ export default {
|
||||
const { accessType } = namespaceInfo;
|
||||
|
||||
// 如果是私有访问,添加token参数
|
||||
if (accessType === 'private' && siteKey) {
|
||||
// 优先使用kvToken,若不存在则使用siteKey
|
||||
const token = kvToken || siteKey;
|
||||
if (accessType === 'private' && token) {
|
||||
const urlObj = new URL(url);
|
||||
urlObj.searchParams.set('token', siteKey);
|
||||
urlObj.searchParams.set('token', token);
|
||||
url = urlObj.toString();
|
||||
}
|
||||
// 公开或受保护访问不需要token参数
|
||||
|
Loading…
x
Reference in New Issue
Block a user