mirror of
https://github.com/ZeroCatDev/Classworks.git
synced 2026-02-04 16:03:10 +00:00
Implement server failover mechanism for classworks cloud service
Co-authored-by: Sunwuyuan <88357633+Sunwuyuan@users.noreply.github.com>
This commit is contained in:
parent
c785fe9d14
commit
fd145e455c
10
src/App.vue
10
src/App.vue
@ -2,8 +2,14 @@
|
|||||||
<v-app>
|
<v-app>
|
||||||
<!-- 正常路由 -->
|
<!-- 正常路由 -->
|
||||||
<router-view v-slot="{ Component, route }">
|
<router-view v-slot="{ Component, route }">
|
||||||
<transition mode="out-in" name="md3">
|
<transition
|
||||||
<component :is="Component" :key="route.path" />
|
mode="out-in"
|
||||||
|
name="md3"
|
||||||
|
>
|
||||||
|
<component
|
||||||
|
:is="Component"
|
||||||
|
:key="route.path"
|
||||||
|
/>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
<global-message />
|
<global-message />
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app-bar :elevation="2">
|
<v-app-bar :elevation="2">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-app-bar-nav-icon></v-app-bar-nav-icon>
|
<v-app-bar-nav-icon />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-app-bar-title>作业</v-app-bar-title>
|
<v-app-bar-title>作业</v-app-bar-title>
|
||||||
|
|||||||
@ -2,48 +2,85 @@
|
|||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<span>缓存管理</span>
|
<span>缓存管理</span>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn :loading="loading" color="error" @click="clearAllCaches">
|
<v-btn
|
||||||
|
:loading="loading"
|
||||||
|
color="error"
|
||||||
|
@click="clearAllCaches"
|
||||||
|
>
|
||||||
清除所有缓存
|
清除所有缓存
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn class="ml-2" icon @click="refreshCaches">
|
<v-btn
|
||||||
|
class="ml-2"
|
||||||
|
icon
|
||||||
|
@click="refreshCaches"
|
||||||
|
>
|
||||||
<v-icon>mdi-refresh</v-icon>
|
<v-icon>mdi-refresh</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-alert v-if="!serviceWorkerActive" class="mb-4" type="warning">
|
<v-alert
|
||||||
|
v-if="!serviceWorkerActive"
|
||||||
|
class="mb-4"
|
||||||
|
type="warning"
|
||||||
|
>
|
||||||
Service Worker 未激活,缓存管理功能不可用。
|
Service Worker 未激活,缓存管理功能不可用。
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<v-alert v-if="message" :type="messageType" class="mb-4">
|
<v-alert
|
||||||
|
v-if="message"
|
||||||
|
:type="messageType"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
{{ message }}
|
{{ message }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<v-expansion-panels v-if="caches.length > 0">
|
<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>
|
<v-expansion-panel-title>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<span>{{ formatCacheName(cache.name) }}</span>
|
<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>
|
</div>
|
||||||
</v-expansion-panel-title>
|
</v-expansion-panel-title>
|
||||||
<v-expansion-panel-text>
|
<v-expansion-panel-text>
|
||||||
<div class="d-flex justify-end mb-2">
|
<div class="d-flex justify-end mb-2">
|
||||||
<v-btn :loading="loading" color="error" size="small" @click="clearCache(cache.name)">
|
<v-btn
|
||||||
|
:loading="loading"
|
||||||
|
color="error"
|
||||||
|
size="small"
|
||||||
|
@click="clearCache(cache.name)"
|
||||||
|
>
|
||||||
清除此缓存
|
清除此缓存
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<v-list lines="two">
|
<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">
|
<v-list-item-title class="text-truncate">
|
||||||
{{ getFileName(url) }}
|
{{ getFileName(url) }}
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle class="text-truncate">
|
<v-list-item-subtitle class="text-truncate">
|
||||||
{{ url }}
|
{{ url }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-btn color="error" icon size="small" @click="clearUrl(cache.name, url)">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
icon
|
||||||
|
size="small"
|
||||||
|
@click="clearUrl(cache.name, url)"
|
||||||
|
>
|
||||||
<v-icon>mdi-delete</v-icon>
|
<v-icon>mdi-delete</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
@ -53,9 +90,15 @@
|
|||||||
</v-expansion-panel>
|
</v-expansion-panel>
|
||||||
</v-expansion-panels>
|
</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-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|||||||
@ -11,7 +11,9 @@
|
|||||||
@click:close="error = ''"
|
@click:close="error = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -27,7 +29,9 @@
|
|||||||
@click:close="success = ''"
|
@click:close="success = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ success }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -43,29 +47,49 @@
|
|||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<span class="font-weight-bold">配置验证失败,请检查以下问题:</span>
|
<span class="font-weight-bold">配置验证失败,请检查以下问题:</span>
|
||||||
</div>
|
</div>
|
||||||
<v-list class="bg-transparent" density="compact">
|
<v-list
|
||||||
|
class="bg-transparent"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="(error, index) in validationErrors"
|
v-for="(error, index) in validationErrors"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="px-0 py-0"
|
class="px-0 py-0"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon color="warning" size="small">mdi-circle-small</v-icon>
|
<v-icon
|
||||||
|
color="warning"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-circle-small
|
||||||
|
</v-icon>
|
||||||
</template>
|
</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-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<!-- 加载状态 -->
|
<!-- 加载状态 -->
|
||||||
<v-card v-if="loading" class="my-4" outlined>
|
<v-card
|
||||||
|
v-if="loading"
|
||||||
|
class="my-4"
|
||||||
|
outlined
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-skeleton-loader class="mx-auto" type="article"></v-skeleton-loader>
|
<v-skeleton-loader
|
||||||
|
class="mx-auto"
|
||||||
|
type="article"
|
||||||
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</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">
|
<div class="d-flex align-center gap-2">
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!isValidConfig"
|
:disabled="!isValidConfig"
|
||||||
@ -140,19 +164,31 @@
|
|||||||
class="text-error"
|
class="text-error"
|
||||||
prepend-icon="mdi-delete"
|
prepend-icon="mdi-delete"
|
||||||
@click="confirmDelete"
|
@click="confirmDelete"
|
||||||
|
|
||||||
>
|
>
|
||||||
删除配置
|
删除配置
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn :value="false" prepend-icon="mdi-eye"> 预览</v-btn>
|
<v-btn
|
||||||
<v-btn :value="true" prepend-icon="mdi-pencil"> 编辑</v-btn>
|
:value="false"
|
||||||
|
prepend-icon="mdi-eye"
|
||||||
|
>
|
||||||
|
预览
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
:value="true"
|
||||||
|
prepend-icon="mdi-pencil"
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 预览模式 -->
|
<!-- 预览模式 -->
|
||||||
<div v-if="!loading && !isEditMode">
|
<div v-if="!loading && !isEditMode">
|
||||||
<div class="mb-8">
|
<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 || "未设置考试名称" }}
|
{{ localConfig.examName || "未设置考试名称" }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -161,8 +197,14 @@
|
|||||||
>
|
>
|
||||||
{{ localConfig.message || "未设置考试提示" }}
|
{{ localConfig.message || "未设置考试提示" }}
|
||||||
</div>
|
</div>
|
||||||
<v-chip v-if="localConfig.room" class="px-4 py-2" size="large">
|
<v-chip
|
||||||
<v-icon start>mdi-home</v-icon>
|
v-if="localConfig.room"
|
||||||
|
class="px-4 py-2"
|
||||||
|
size="large"
|
||||||
|
>
|
||||||
|
<v-icon start>
|
||||||
|
mdi-home
|
||||||
|
</v-icon>
|
||||||
考场:{{ localConfig.room }}
|
考场:{{ localConfig.room }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
@ -178,20 +220,29 @@
|
|||||||
lg="4"
|
lg="4"
|
||||||
md="6"
|
md="6"
|
||||||
>
|
>
|
||||||
<v-card class="h-100" hover variant="tonal">
|
<v-card
|
||||||
|
class="h-100"
|
||||||
|
hover
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-title class="bg-primary-lighten-5 pa-4">
|
<v-card-title class="bg-primary-lighten-5 pa-4">
|
||||||
<div class="d-flex align-center">
|
<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>
|
<span class="">{{ examInfo.name || "未设置科目" }}</span>
|
||||||
</div>
|
</div>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-4">
|
<v-card-text class="pa-4">
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="d-flex align-center mb-1">
|
<div class="d-flex align-center mb-1">
|
||||||
<v-icon class="mr-2" color="success" size="small"
|
<v-icon
|
||||||
>mdi-clock-start
|
class="mr-2"
|
||||||
</v-icon
|
color="success"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
|
mdi-clock-start
|
||||||
|
</v-icon>
|
||||||
<span class="text-body-2 text-grey-darken-1">开始时间</span>
|
<span class="text-body-2 text-grey-darken-1">开始时间</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-h6 font-weight-medium text-success">
|
<div class="text-h6 font-weight-medium text-success">
|
||||||
@ -200,10 +251,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="d-flex align-center mb-1">
|
<div class="d-flex align-center mb-1">
|
||||||
<v-icon class="mr-2" color="error" size="small"
|
<v-icon
|
||||||
>mdi-clock-end
|
class="mr-2"
|
||||||
</v-icon
|
color="error"
|
||||||
|
size="small"
|
||||||
>
|
>
|
||||||
|
mdi-clock-end
|
||||||
|
</v-icon>
|
||||||
<span class="text-body-2 text-grey-darken-1">结束时间</span>
|
<span class="text-body-2 text-grey-darken-1">结束时间</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-h6 font-weight-medium text-error">
|
<div class="text-h6 font-weight-medium text-error">
|
||||||
@ -215,29 +269,50 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-center py-12">
|
<div
|
||||||
<v-icon class="mb-4" color="grey-lighten-2" size="80">
|
v-else
|
||||||
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mb-4"
|
||||||
|
color="grey-lighten-2"
|
||||||
|
size="80"
|
||||||
|
>
|
||||||
mdi-calendar-blank
|
mdi-calendar-blank
|
||||||
</v-icon>
|
</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 class="text-body-1 text-grey mb-4">
|
||||||
点击上方"添加科目"按钮开始配置考试时间表
|
点击上方"添加科目"按钮开始配置考试时间表
|
||||||
</div>
|
</div>
|
||||||
<v-btn color="primary" variant="outlined" @click="quickEdit">
|
<v-btn
|
||||||
<v-icon start>mdi-plus</v-icon>
|
color="primary"
|
||||||
|
variant="outlined"
|
||||||
|
@click="quickEdit"
|
||||||
|
>
|
||||||
|
<v-icon start>
|
||||||
|
mdi-plus
|
||||||
|
</v-icon>
|
||||||
立即添加
|
立即添加
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- JSON预览 -->
|
<!-- JSON预览 -->
|
||||||
<v-card border class="mb-4" elevation="2">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-4"
|
||||||
|
elevation="2"
|
||||||
|
>
|
||||||
<v-card-title
|
<v-card-title
|
||||||
class="d-flex align-center text-white cursor-pointer"
|
class="d-flex align-center text-white cursor-pointer"
|
||||||
@click="showJsonPreview = !showJsonPreview"
|
@click="showJsonPreview = !showJsonPreview"
|
||||||
>
|
>
|
||||||
<v-icon class="mr-2">mdi-code-json</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
mdi-code-json
|
||||||
|
</v-icon>
|
||||||
配置预览
|
配置预览
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
color="white"
|
color="white"
|
||||||
@ -255,12 +330,17 @@
|
|||||||
color="white"
|
color="white"
|
||||||
size="small"
|
size="small"
|
||||||
variant="text"
|
variant="text"
|
||||||
>
|
/>
|
||||||
</v-btn>
|
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-expand-transition>
|
<v-expand-transition>
|
||||||
<v-card-text v-show="showJsonPreview" class="pa-4">
|
<v-card-text
|
||||||
<v-card class="pa-4" variant="tonal">
|
v-show="showJsonPreview"
|
||||||
|
class="pa-4"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
class="pa-4"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<pre class="json-preview"><code>{{ formattedStorageJson }}</code></pre>
|
<pre class="json-preview"><code>{{ formattedStorageJson }}</code></pre>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@ -271,14 +351,23 @@
|
|||||||
<!-- 编辑模式 -->
|
<!-- 编辑模式 -->
|
||||||
<div v-if="!loading && isEditMode">
|
<div v-if="!loading && isEditMode">
|
||||||
<!-- 基本信息 -->
|
<!-- 基本信息 -->
|
||||||
<v-card border class="mb-4" elevation="1">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-4"
|
||||||
|
elevation="1"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center bg-primary-lighten-5 pa-4">
|
<v-card-title class="d-flex align-center bg-primary-lighten-5 pa-4">
|
||||||
<v-icon class="mr-2">mdi-information</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
mdi-information
|
||||||
|
</v-icon>
|
||||||
<span class="font-weight-bold">基本信息</span>
|
<span class="font-weight-bold">基本信息</span>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-6">
|
<v-card-text class="pa-6">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="localConfig.examName"
|
v-model="localConfig.examName"
|
||||||
:rules="[
|
:rules="[
|
||||||
@ -293,9 +382,12 @@
|
|||||||
prepend-inner-icon="mdi-calendar-text"
|
prepend-inner-icon="mdi-calendar-text"
|
||||||
required
|
required
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-text-field>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="localConfig.room"
|
v-model="localConfig.room"
|
||||||
clearable
|
clearable
|
||||||
@ -304,13 +396,16 @@
|
|||||||
placeholder="如:一号考场"
|
placeholder="如:一号考场"
|
||||||
prepend-inner-icon="mdi-home"
|
prepend-inner-icon="mdi-home"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-text-field>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<span class="text-subtitle-2 font-weight-bold d-block mb-2">
|
<span class="text-subtitle-2 font-weight-bold d-block mb-2">
|
||||||
<v-icon size="small" class="mr-1">mdi-message-text</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
class="mr-1"
|
||||||
|
>mdi-message-text</v-icon>
|
||||||
考试提示
|
考试提示
|
||||||
</span>
|
</span>
|
||||||
<v-textarea
|
<v-textarea
|
||||||
@ -326,10 +421,13 @@
|
|||||||
placeholder="例如:请保持卷面整洁,诚信应考。在听到终考铃时立刻停止作答。"
|
placeholder="例如:请保持卷面整洁,诚信应考。在听到终考铃时立刻停止作答。"
|
||||||
rows="3"
|
rows="3"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-textarea>
|
/>
|
||||||
|
|
||||||
<!-- 默认提示选项 -->
|
<!-- 默认提示选项 -->
|
||||||
<div v-if="!localConfig.message || localConfig.message.trim() === ''" class="mt-3">
|
<div
|
||||||
|
v-if="!localConfig.message || localConfig.message.trim() === ''"
|
||||||
|
class="mt-3"
|
||||||
|
>
|
||||||
<v-chip-group
|
<v-chip-group
|
||||||
class="d-flex gap-2"
|
class="d-flex gap-2"
|
||||||
column
|
column
|
||||||
@ -343,12 +441,22 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
@click="selectDefaultTip(tip)"
|
@click="selectDefaultTip(tip)"
|
||||||
>
|
>
|
||||||
<v-icon size="small" start>mdi-plus</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-plus
|
||||||
|
</v-icon>
|
||||||
{{ tip.substring(0, 20) }}...
|
{{ tip.substring(0, 20) }}...
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-chip-group>
|
</v-chip-group>
|
||||||
<div class="text-caption text-medium-emphasis mt-2 ml-2">
|
<div class="text-caption text-medium-emphasis mt-2 ml-2">
|
||||||
<v-icon class="mr-1" size="x-small">mdi-lightbulb-outline</v-icon>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
size="x-small"
|
||||||
|
>
|
||||||
|
mdi-lightbulb-outline
|
||||||
|
</v-icon>
|
||||||
点击上方选项快速添加常用考试提示
|
点击上方选项快速添加常用考试提示
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -358,11 +466,17 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 考试科目安排 -->
|
<!-- 考试科目安排 -->
|
||||||
<v-card border class="mb-4" elevation="1">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-4"
|
||||||
|
elevation="1"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center bg-success-lighten-5 pa-4">
|
<v-card-title class="d-flex align-center bg-success-lighten-5 pa-4">
|
||||||
<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>
|
<span class="font-weight-bold">考试科目安排</span>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
|
|
||||||
<!-- 提醒时间开关 -->
|
<!-- 提醒时间开关 -->
|
||||||
<div class="d-flex align-center mr-4">
|
<div class="d-flex align-center mr-4">
|
||||||
@ -373,7 +487,7 @@
|
|||||||
hide-details
|
hide-details
|
||||||
@change="toggleAlertTimeMode"
|
@change="toggleAlertTimeMode"
|
||||||
>
|
>
|
||||||
<template v-slot:label>
|
<template #label>
|
||||||
<span class="text-body-2">自定义提醒时间</span>
|
<span class="text-body-2">自定义提醒时间</span>
|
||||||
</template>
|
</template>
|
||||||
</v-switch>
|
</v-switch>
|
||||||
@ -408,14 +522,19 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
class="mr-3"
|
class="mr-3"
|
||||||
>
|
>
|
||||||
<v-icon start size="small">mdi-numeric-{{ index + 1 }}-circle</v-icon>
|
<v-icon
|
||||||
|
start
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-numeric-{{ index + 1 }}-circle
|
||||||
|
</v-icon>
|
||||||
第 {{ index + 1 }} 科目
|
第 {{ index + 1 }} 科目
|
||||||
</v-chip>
|
</v-chip>
|
||||||
|
|
||||||
<!-- 考试时长显示 -->
|
<!-- 考试时长显示 -->
|
||||||
|
|
||||||
|
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<div class="d-flex gap-1">
|
<div class="d-flex gap-1">
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="index > 0"
|
v-if="index > 0"
|
||||||
@ -425,7 +544,12 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="moveExamInfo(index, -1)"
|
@click="moveExamInfo(index, -1)"
|
||||||
>
|
>
|
||||||
<v-tooltip activator="parent" location="bottom">上移</v-tooltip>
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
上移
|
||||||
|
</v-tooltip>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="index < localConfig.examInfos.length - 1"
|
v-if="index < localConfig.examInfos.length - 1"
|
||||||
@ -435,7 +559,12 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="moveExamInfo(index, 1)"
|
@click="moveExamInfo(index, 1)"
|
||||||
>
|
>
|
||||||
<v-tooltip activator="parent" location="bottom">下移</v-tooltip>
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
下移
|
||||||
|
</v-tooltip>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
@ -444,13 +573,21 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="removeExamInfo(index)"
|
@click="removeExamInfo(index)"
|
||||||
>
|
>
|
||||||
<v-tooltip activator="parent" location="bottom">删除</v-tooltip>
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</v-tooltip>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-row class="align-start">
|
<v-row class="align-start">
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
<!-- 科目名称自动完成选择器 -->
|
<!-- 科目名称自动完成选择器 -->
|
||||||
<v-autocomplete
|
<v-autocomplete
|
||||||
v-model="examInfo.name"
|
v-model="examInfo.name"
|
||||||
@ -467,20 +604,23 @@
|
|||||||
prepend-inner-icon="mdi-book"
|
prepend-inner-icon="mdi-book"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend-item>
|
<template #prepend-item>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-if="customSubjectInput"
|
v-if="customSubjectInput"
|
||||||
title="自定义:"
|
title="自定义:"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<span class="text-primary font-weight-bold">{{ customSubjectInput }}</span>
|
<span class="text-primary font-weight-bold">{{ customSubjectInput }}</span>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-divider v-if="customSubjectInput"></v-divider>
|
<v-divider v-if="customSubjectInput" />
|
||||||
</template>
|
</template>
|
||||||
</v-autocomplete>
|
</v-autocomplete>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="3">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
<v-menu
|
<v-menu
|
||||||
v-model="examInfo.startDateMenu"
|
v-model="examInfo.startDateMenu"
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
@ -488,7 +628,7 @@
|
|||||||
offset-y
|
offset-y
|
||||||
transition="scale-transition"
|
transition="scale-transition"
|
||||||
>
|
>
|
||||||
<template v-slot:activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="examInfo.startFormatted"
|
v-model="examInfo.startFormatted"
|
||||||
:rules="[
|
:rules="[
|
||||||
@ -504,19 +644,27 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
@blur="updateStartDateTimeFromInput(index)"
|
@blur="updateStartDateTimeFromInput(index)"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-icon>mdi-calendar-clock</v-icon>
|
<v-icon>mdi-calendar-clock</v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
</template>
|
</template>
|
||||||
<v-card min-width="500">
|
<v-card min-width="500">
|
||||||
<v-card-title class="text-center py-3 bg-primary-lighten-5">
|
<v-card-title class="text-center py-3 bg-primary-lighten-5">
|
||||||
<v-icon class="mr-2" color="primary">mdi-clock-start</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
mdi-clock-start
|
||||||
|
</v-icon>
|
||||||
选择开始时间
|
选择开始时间
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-0">
|
<v-card-text class="pa-0">
|
||||||
<v-row no-gutters>
|
<v-row no-gutters>
|
||||||
<v-col class="border-e" cols="6">
|
<v-col
|
||||||
|
class="border-e"
|
||||||
|
cols="6"
|
||||||
|
>
|
||||||
<v-date-picker
|
<v-date-picker
|
||||||
v-model="examInfo.startDate"
|
v-model="examInfo.startDate"
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -524,7 +672,7 @@
|
|||||||
locale="zh-cn"
|
locale="zh-cn"
|
||||||
show-adjacent-months
|
show-adjacent-months
|
||||||
@update:model-value="updateStartDateTime(index)"
|
@update:model-value="updateStartDateTime(index)"
|
||||||
></v-date-picker>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-time-picker
|
<v-time-picker
|
||||||
@ -534,12 +682,12 @@
|
|||||||
format="24hr"
|
format="24hr"
|
||||||
scrollable
|
scrollable
|
||||||
@update:model-value="updateStartDateTime(index)"
|
@update:model-value="updateStartDateTime(index)"
|
||||||
></v-time-picker>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="grey"
|
color="grey"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -551,7 +699,10 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="3">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="3"
|
||||||
|
>
|
||||||
<v-menu
|
<v-menu
|
||||||
v-model="examInfo.endDateMenu"
|
v-model="examInfo.endDateMenu"
|
||||||
:close-on-content-click="false"
|
:close-on-content-click="false"
|
||||||
@ -559,7 +710,7 @@
|
|||||||
offset-y
|
offset-y
|
||||||
transition="scale-transition"
|
transition="scale-transition"
|
||||||
>
|
>
|
||||||
<template v-slot:activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="examInfo.endFormatted"
|
v-model="examInfo.endFormatted"
|
||||||
:rules="[
|
:rules="[
|
||||||
@ -576,19 +727,27 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
@blur="updateEndDateTimeFromInput(index)"
|
@blur="updateEndDateTimeFromInput(index)"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-icon>mdi-calendar-clock</v-icon>
|
<v-icon>mdi-calendar-clock</v-icon>
|
||||||
</template>
|
</template>
|
||||||
</v-text-field>
|
</v-text-field>
|
||||||
</template>
|
</template>
|
||||||
<v-card min-width="500">
|
<v-card min-width="500">
|
||||||
<v-card-title class="text-center py-3 bg-error-lighten-5">
|
<v-card-title class="text-center py-3 bg-error-lighten-5">
|
||||||
<v-icon class="mr-2" color="error">mdi-clock-end</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
mdi-clock-end
|
||||||
|
</v-icon>
|
||||||
选择结束时间
|
选择结束时间
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-0">
|
<v-card-text class="pa-0">
|
||||||
<v-row no-gutters>
|
<v-row no-gutters>
|
||||||
<v-col class="border-e" cols="6">
|
<v-col
|
||||||
|
class="border-e"
|
||||||
|
cols="6"
|
||||||
|
>
|
||||||
<v-date-picker
|
<v-date-picker
|
||||||
v-model="examInfo.endDate"
|
v-model="examInfo.endDate"
|
||||||
color="error"
|
color="error"
|
||||||
@ -596,7 +755,7 @@
|
|||||||
locale="zh-cn"
|
locale="zh-cn"
|
||||||
show-adjacent-months
|
show-adjacent-months
|
||||||
@update:model-value="updateEndDateTime(index)"
|
@update:model-value="updateEndDateTime(index)"
|
||||||
></v-date-picker>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-time-picker
|
<v-time-picker
|
||||||
@ -606,12 +765,12 @@
|
|||||||
format="24hr"
|
format="24hr"
|
||||||
scrollable
|
scrollable
|
||||||
@update:model-value="updateEndDateTime(index)"
|
@update:model-value="updateEndDateTime(index)"
|
||||||
></v-time-picker>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="grey"
|
color="grey"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -623,7 +782,10 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
</v-menu>
|
</v-menu>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="2">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="2"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="examInfo.durationMinutes"
|
v-model="examInfo.durationMinutes"
|
||||||
:rules="[
|
:rules="[
|
||||||
@ -647,7 +809,11 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 提醒时间输入框(仅在启用自定义时显示) -->
|
<!-- 提醒时间输入框(仅在启用自定义时显示) -->
|
||||||
<v-col v-if="enableCustomAlertTime" cols="12" md="2">
|
<v-col
|
||||||
|
v-if="enableCustomAlertTime"
|
||||||
|
cols="12"
|
||||||
|
md="2"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="examInfo.alertTime"
|
v-model="examInfo.alertTime"
|
||||||
:rules="[
|
:rules="[
|
||||||
@ -672,11 +838,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
<div v-else class="text-center py-12">
|
<div
|
||||||
<v-icon class="mb-4" color="grey-lighten-2" size="80">
|
v-else
|
||||||
|
class="text-center py-12"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mb-4"
|
||||||
|
color="grey-lighten-2"
|
||||||
|
size="80"
|
||||||
|
>
|
||||||
mdi-calendar-blank
|
mdi-calendar-blank
|
||||||
</v-icon>
|
</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 class="text-body-1 text-grey mb-4">
|
||||||
点击上方"添加科目"按钮开始配置
|
点击上方"添加科目"按钮开始配置
|
||||||
</div>
|
</div>
|
||||||
@ -695,10 +870,18 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 删除确认对话框 -->
|
<!-- 删除确认对话框 -->
|
||||||
<v-dialog v-model="deleteDialog" max-width="400">
|
<v-dialog
|
||||||
|
v-model="deleteDialog"
|
||||||
|
max-width="400"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" color="error">mdi-delete-alert</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
mdi-delete-alert
|
||||||
|
</v-icon>
|
||||||
确认删除配置
|
确认删除配置
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -706,7 +889,7 @@
|
|||||||
<br><small class="text-grey">此操作不可撤销,将会删除所有相关数据</small>
|
<br><small class="text-grey">此操作不可撤销,将会删除所有相关数据</small>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="grey"
|
color="grey"
|
||||||
variant="text"
|
variant="text"
|
||||||
|
|||||||
@ -7,7 +7,10 @@
|
|||||||
elevation="4"
|
elevation="4"
|
||||||
rounded="xl"
|
rounded="xl"
|
||||||
>
|
>
|
||||||
<v-btn-group class="toolbar-buttons" variant="text">
|
<v-btn-group
|
||||||
|
class="toolbar-buttons"
|
||||||
|
variant="text"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
v-ripple
|
v-ripple
|
||||||
:title="'查看昨天'"
|
:title="'查看昨天'"
|
||||||
@ -32,7 +35,10 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="$emit('zoom', 'up')"
|
@click="$emit('zoom', 'up')"
|
||||||
/>
|
/>
|
||||||
<v-menu :close-on-content-click="false" location="top">
|
<v-menu
|
||||||
|
:close-on-content-click="false"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
<template #activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn
|
<v-btn
|
||||||
v-ripple
|
v-ripple
|
||||||
@ -43,7 +49,10 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-card border class="date-picker-card">
|
<v-card
|
||||||
|
border
|
||||||
|
class="date-picker-card"
|
||||||
|
>
|
||||||
<v-date-picker
|
<v-date-picker
|
||||||
:model-value="selectedDate"
|
:model-value="selectedDate"
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -88,7 +97,9 @@
|
|||||||
size="large"
|
size="large"
|
||||||
text="复制作业内容到今天"
|
text="复制作业内容到今天"
|
||||||
@click="$emit('copy-to-today')"
|
@click="$emit('copy-to-today')"
|
||||||
>复制到今天</v-btn>
|
>
|
||||||
|
复制到今天
|
||||||
|
</v-btn>
|
||||||
</v-slide-x-reverse-transition>
|
</v-slide-x-reverse-transition>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -8,14 +8,28 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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>
|
||||||
<div class="text-subtitle-2 font-weight-medium">{{ message?.title }}</div>
|
<div class="text-subtitle-2 font-weight-medium">
|
||||||
<div v-if="message?.content" class="text-body-2">{{ message?.content }}</div>
|
{{ message?.title }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="message?.content"
|
||||||
|
class="text-body-2"
|
||||||
|
>
|
||||||
|
{{ message?.content }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<v-btn icon="mdi-close" variant="text" @click="snackbar = false"/>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
@click="snackbar = false"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -11,12 +11,16 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="text-center">
|
<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
|
||||||
<h1 class="text-h2 font-weight-bold">Vuetify</h1>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-4"/>
|
<h1 class="text-h2 font-weight-bold">
|
||||||
|
Vuetify
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-4" />
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
@ -29,17 +33,20 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
>
|
>
|
||||||
<template #image>
|
<template #image>
|
||||||
<v-img position="top right"/>
|
<v-img position="top right" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<h2 class="text-h5 font-weight-bold">Get started</h2>
|
<h2 class="text-h5 font-weight-bold">
|
||||||
|
Get started
|
||||||
|
</h2>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #subtitle>
|
<template #subtitle>
|
||||||
<div class="text-subtitle-1">
|
<div class="text-subtitle-1">
|
||||||
Replace this page by removing
|
Replace this page by removing
|
||||||
<v-kbd>{{ `
|
<v-kbd>
|
||||||
|
{{ `
|
||||||
<HelloWorld/>
|
<HelloWorld/>
|
||||||
` }}
|
` }}
|
||||||
</v-kbd>
|
</v-kbd>
|
||||||
|
|||||||
@ -1,15 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<setting-group title="一言设置" icon="mdi-comment-quote">
|
<setting-group
|
||||||
|
title="一言设置"
|
||||||
|
icon="mdi-comment-quote"
|
||||||
|
>
|
||||||
<setting-item setting-key="hitokoto.enabled" />
|
<setting-item setting-key="hitokoto.enabled" />
|
||||||
<setting-item setting-key="hitokoto.refreshInterval" />
|
<setting-item setting-key="hitokoto.refreshInterval" />
|
||||||
</setting-group>
|
</setting-group>
|
||||||
|
|
||||||
<setting-group title="数据源配置" icon="mdi-cloud-sync" class="mt-4">
|
<setting-group
|
||||||
<div class="text-caption text-grey px-4 pt-2 pb-2">以下配置将同步到云端,对所有连接此班级的设备生效。</div>
|
title="数据源配置"
|
||||||
|
icon="mdi-cloud-sync"
|
||||||
|
class="mt-4"
|
||||||
|
>
|
||||||
|
<div class="text-caption text-grey px-4 pt-2 pb-2">
|
||||||
|
以下配置将同步到云端,对所有连接此班级的设备生效。
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-list-item-title class="mb-2">启用数据源</v-list-item-title>
|
<v-list-item-title class="mb-2">
|
||||||
|
启用数据源
|
||||||
|
</v-list-item-title>
|
||||||
<div class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
v-model="kvConfig.sources"
|
v-model="kvConfig.sources"
|
||||||
@ -42,7 +53,13 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-caption text-orange mt-2">
|
<div class="text-caption text-orange mt-2">
|
||||||
<v-icon size="x-small" color="orange" class="mr-1">mdi-alert</v-icon>
|
<v-icon
|
||||||
|
size="x-small"
|
||||||
|
color="orange"
|
||||||
|
class="mr-1"
|
||||||
|
>
|
||||||
|
mdi-alert
|
||||||
|
</v-icon>
|
||||||
一言(Hitokoto)数据源已收到关于存在负面内容的大量反馈,请用户谨慎启用。
|
一言(Hitokoto)数据源已收到关于存在负面内容的大量反馈,请用户谨慎启用。
|
||||||
</div>
|
</div>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -99,39 +116,62 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
|
v-model="enableCloudSensitiveWords"
|
||||||
label="启用云端敏感词列表"
|
label="启用云端敏感词列表"
|
||||||
hide-details
|
hide-details
|
||||||
v-model="enableCloudSensitiveWords"
|
|
||||||
density="compact"
|
density="compact"
|
||||||
disabled
|
disabled
|
||||||
class="mb-2"
|
class="mb-2"
|
||||||
/>
|
/>
|
||||||
<div class="text-caption text-grey">
|
<div class="text-caption text-grey">
|
||||||
已启用的数据源将在获取一言时随机尝试,直到成功获取内容为止。<br/>
|
已启用的数据源将在获取一言时随机尝试,直到成功获取内容为止。<br>
|
||||||
敏感词过滤会将包含任意敏感词的句子过滤掉,避免显示不当内容。<br/>
|
敏感词过滤会将包含任意敏感词的句子过滤掉,避免显示不当内容。<br>
|
||||||
</div>
|
</div>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<div v-if="loading" class="text-center pb-4">
|
<div
|
||||||
<v-progress-circular indeterminate size="24" color="primary" />
|
v-if="loading"
|
||||||
|
class="text-center pb-4"
|
||||||
|
>
|
||||||
|
<v-progress-circular
|
||||||
|
indeterminate
|
||||||
|
size="24"
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
<span class="ml-2 text-caption">正在同步配置...</span>
|
<span class="ml-2 text-caption">正在同步配置...</span>
|
||||||
</div>
|
</div>
|
||||||
</setting-group>
|
</setting-group>
|
||||||
|
|
||||||
<v-dialog v-model="testResultDialog" max-width="600">
|
<v-dialog
|
||||||
<v-card v-if="testResultData" class="rounded-lg">
|
v-model="testResultDialog"
|
||||||
|
max-width="600"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
v-if="testResultData"
|
||||||
|
class="rounded-lg"
|
||||||
|
>
|
||||||
<v-card-text class="pa-0">
|
<v-card-text class="pa-0">
|
||||||
<v-list lines="two" class="py-0">
|
<v-list
|
||||||
|
lines="two"
|
||||||
|
class="py-0"
|
||||||
|
>
|
||||||
<v-list-item class="px-4 py-3">
|
<v-list-item class="px-4 py-3">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-avatar color="primary" variant="tonal" class="mr-2">
|
<v-avatar
|
||||||
|
color="primary"
|
||||||
|
variant="tonal"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
<v-icon icon="mdi-key-variant" />
|
<v-icon icon="mdi-key-variant" />
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title class="text-subtitle-2 font-weight-bold mb-1">Token</v-list-item-title>
|
<v-list-item-title class="text-subtitle-2 font-weight-bold mb-1">
|
||||||
<v-list-item-subtitle class="text-body-2 text-high-emphasis" style="word-break: break-all;">
|
Token
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-subtitle
|
||||||
|
class="text-body-2 text-high-emphasis"
|
||||||
|
style="word-break: break-all;"
|
||||||
|
>
|
||||||
{{ testResultData.data.token }}
|
{{ testResultData.data.token }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -141,20 +181,36 @@
|
|||||||
<v-row no-gutters>
|
<v-row no-gutters>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-list-item class="px-4 py-2">
|
<v-list-item class="px-4 py-2">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-ip-network" color="grey-darken-1" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-ip-network"
|
||||||
|
color="grey-darken-1"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title class="text-caption text-grey-darken-1">IP 地址</v-list-item-title>
|
<v-list-item-title class="text-caption text-grey-darken-1">
|
||||||
<v-list-item-subtitle class="text-body-2">{{ testResultData.data.ip }}</v-list-item-subtitle>
|
IP 地址
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-subtitle class="text-body-2">
|
||||||
|
{{ testResultData.data.ip }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-list-item class="px-4 py-2">
|
<v-list-item class="px-4 py-2">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-map-marker-radius" color="grey-darken-1" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-map-marker-radius"
|
||||||
|
color="grey-darken-1"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title class="text-caption text-grey-darken-1">地区</v-list-item-title>
|
<v-list-item-title class="text-caption text-grey-darken-1">
|
||||||
<v-list-item-subtitle class="text-body-2">{{ testResultData.data.region }}</v-list-item-subtitle>
|
地区
|
||||||
|
</v-list-item-title>
|
||||||
|
<v-list-item-subtitle class="text-body-2">
|
||||||
|
{{ testResultData.data.region }}
|
||||||
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@ -165,59 +221,123 @@
|
|||||||
|
|
||||||
<v-container class="px-4 py-3">
|
<v-container class="px-4 py-3">
|
||||||
<v-row dense>
|
<v-row dense>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-thermometer" color="orange" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-thermometer"
|
||||||
|
color="orange"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">温度</div>
|
<div class="text-caption text-grey">
|
||||||
<div class="text-body-1 font-weight-medium">{{ testResultData.data.weatherData.temperature }}°C</div>
|
温度
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1 font-weight-medium">
|
||||||
|
{{ testResultData.data.weatherData.temperature }}°C
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-weather-cloudy" color="blue-grey" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-weather-cloudy"
|
||||||
|
color="blue-grey"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">天气</div>
|
<div class="text-caption text-grey">
|
||||||
<div class="text-body-1 font-weight-medium">{{ testResultData.data.weatherData.weather }}</div>
|
天气
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1 font-weight-medium">
|
||||||
|
{{ testResultData.data.weatherData.weather }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-water-percent" color="blue" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-water-percent"
|
||||||
|
color="blue"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">湿度</div>
|
<div class="text-caption text-grey">
|
||||||
<div class="text-body-1 font-weight-medium">{{ testResultData.data.weatherData.humidity }}%</div>
|
湿度
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1 font-weight-medium">
|
||||||
|
{{ testResultData.data.weatherData.humidity }}%
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-weather-windy" color="teal" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-weather-windy"
|
||||||
|
color="teal"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">风向/风力</div>
|
<div class="text-caption text-grey">
|
||||||
|
风向/风力
|
||||||
|
</div>
|
||||||
<div class="text-body-2 font-weight-medium">
|
<div class="text-body-2 font-weight-medium">
|
||||||
{{ testResultData.data.weatherData.windDirection }} {{ testResultData.data.weatherData.windPower }}级
|
{{ testResultData.data.weatherData.windDirection }} {{ testResultData.data.weatherData.windPower }}级
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-blur" color="grey" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-blur"
|
||||||
|
color="grey"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">PM2.5</div>
|
<div class="text-caption text-grey">
|
||||||
<div class="text-body-1 font-weight-medium">{{ testResultData.data.weatherData.pm25 }}</div>
|
PM2.5
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1 font-weight-medium">
|
||||||
|
{{ testResultData.data.weatherData.pm25 }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6" sm="4">
|
<v-col
|
||||||
|
cols="6"
|
||||||
|
sm="4"
|
||||||
|
>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon icon="mdi-eye" color="indigo" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-eye"
|
||||||
|
color="indigo"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-caption text-grey">能见度</div>
|
<div class="text-caption text-grey">
|
||||||
<div class="text-body-1 font-weight-medium">{{ testResultData.data.weatherData.visibility }}</div>
|
能见度
|
||||||
|
</div>
|
||||||
|
<div class="text-body-1 font-weight-medium">
|
||||||
|
{{ testResultData.data.weatherData.visibility }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -227,7 +347,9 @@
|
|||||||
<v-divider />
|
<v-divider />
|
||||||
|
|
||||||
<div class="px-4 py-3">
|
<div class="px-4 py-3">
|
||||||
<div class="text-caption text-grey mb-2">环境标签</div>
|
<div class="text-caption text-grey mb-2">
|
||||||
|
环境标签
|
||||||
|
</div>
|
||||||
<div class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<v-chip
|
<v-chip
|
||||||
v-for="tag in testResultData.data.tags"
|
v-for="tag in testResultData.data.tags"
|
||||||
@ -245,8 +367,12 @@
|
|||||||
<v-divider />
|
<v-divider />
|
||||||
|
|
||||||
<v-list-item class="px-4 py-2">
|
<v-list-item class="px-4 py-2">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-clock-outline" size="small" class="mr-2" />
|
<v-icon
|
||||||
|
icon="mdi-clock-outline"
|
||||||
|
size="small"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title class="text-caption text-grey-darken-1">
|
<v-list-item-title class="text-caption text-grey-darken-1">
|
||||||
北京时间: {{ new Date(testResultData.data.beijingTime).toLocaleString() }}
|
北京时间: {{ new Date(testResultData.data.beijingTime).toLocaleString() }}
|
||||||
@ -254,8 +380,6 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
|
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -11,7 +11,11 @@
|
|||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-btn icon="mdi-close" variant="text" @click="handleClose" />
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
@click="handleClose"
|
||||||
|
/>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-subtitle>
|
<v-card-subtitle>
|
||||||
{{ autoSave ? autoSavePromptText : manualSavePromptText }}
|
{{ autoSave ? autoSavePromptText : manualSavePromptText }}
|
||||||
@ -31,13 +35,21 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Template Buttons Section -->
|
<!-- Template Buttons Section -->
|
||||||
<div v-if="templateData" class="mt-4">
|
<div
|
||||||
<div v-if="hasTemplates" class="template-buttons">
|
v-if="templateData"
|
||||||
|
class="mt-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="hasTemplates"
|
||||||
|
class="template-buttons"
|
||||||
|
>
|
||||||
<!-- Subject specific books -->
|
<!-- Subject specific books -->
|
||||||
<template v-if="subjectBooks">
|
<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
|
<v-chip
|
||||||
:color="isBookSelected(book) ? 'success' : 'default'"
|
:color="isBookSelected(book) ? 'success' : 'default'"
|
||||||
:variant="isBookSelected(book) ? 'elevated' : 'flat'"
|
:variant="isBookSelected(book) ? 'elevated' : 'flat'"
|
||||||
@ -48,7 +60,10 @@
|
|||||||
</v-chip>
|
</v-chip>
|
||||||
|
|
||||||
<!-- Show pages only if book is selected -->
|
<!-- 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-chip
|
||||||
v-for="page in pages"
|
v-for="page in pages"
|
||||||
:key="page"
|
:key="page"
|
||||||
@ -65,7 +80,11 @@
|
|||||||
|
|
||||||
<!-- Common books -->
|
<!-- Common books -->
|
||||||
<template v-if="commonBooks">
|
<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
|
<v-chip
|
||||||
:color="isBookSelected(book) ? 'success' : 'default'"
|
:color="isBookSelected(book) ? 'success' : 'default'"
|
||||||
:variant="isBookSelected(book) ? 'elevated' : 'flat'"
|
:variant="isBookSelected(book) ? 'elevated' : 'flat'"
|
||||||
@ -76,7 +95,10 @@
|
|||||||
</v-chip>
|
</v-chip>
|
||||||
|
|
||||||
<!-- Show pages only if book is selected -->
|
<!-- 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-chip
|
||||||
v-for="page in pages"
|
v-for="page in pages"
|
||||||
:key="page"
|
:key="page"
|
||||||
@ -92,7 +114,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<div v-if="templateData.actions?.length" class="button-group">
|
<div
|
||||||
|
v-if="templateData.actions?.length"
|
||||||
|
class="button-group"
|
||||||
|
>
|
||||||
<v-chip
|
<v-chip
|
||||||
v-for="action in templateData.actions"
|
v-for="action in templateData.actions"
|
||||||
:key="action"
|
:key="action"
|
||||||
@ -105,14 +130,21 @@
|
|||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Quick Tools Section -->
|
<!-- Quick Tools Section -->
|
||||||
<div v-if="showQuickTools && !isMobile" class="quick-tools ml-4" style="min-width: 180px;">
|
<div
|
||||||
|
v-if="showQuickTools && !isMobile"
|
||||||
|
class="quick-tools ml-4"
|
||||||
|
style="min-width: 180px;"
|
||||||
|
>
|
||||||
<!-- Numeric Keypad -->
|
<!-- Numeric Keypad -->
|
||||||
<div class="numeric-keypad mb-4">
|
<div class="numeric-keypad mb-4">
|
||||||
<div class="keypad-row">
|
<div class="keypad-row">
|
||||||
@ -223,10 +255,11 @@
|
|||||||
border-color="warning"
|
border-color="warning"
|
||||||
prominent
|
prominent
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend />
|
||||||
</template>
|
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<div class="text-h6 mb-1">你打算修改历史?</div>
|
<div class="text-h6 mb-1">
|
||||||
|
你打算修改历史?
|
||||||
|
</div>
|
||||||
<div class="text-body-2">
|
<div class="text-body-2">
|
||||||
这是 {{ new Date(currentDateString.slice(0,4), currentDateString.slice(4,6)-1, currentDateString.slice(6,8)).toLocaleDateString() }} 的作业 • 请谨慎操作,确保不会覆盖重要数据
|
这是 {{ new Date(currentDateString.slice(0,4), currentDateString.slice(4,6)-1, currentDateString.slice(6,8)).toLocaleDateString() }} 的作业 • 请谨慎操作,确保不会覆盖重要数据
|
||||||
</div>
|
</div>
|
||||||
@ -236,7 +269,6 @@
|
|||||||
<div class="text-center text-body-2 text-disabled mb-5">
|
<div class="text-center text-body-2 text-disabled mb-5">
|
||||||
点击空白处完成编辑
|
点击空白处完成编辑
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,33 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-navigation-drawer v-if="drawer" v-model="drawer" location="right" temporary width="400">
|
<v-navigation-drawer
|
||||||
|
v-if="drawer"
|
||||||
|
v-model="drawer"
|
||||||
|
location="right"
|
||||||
|
temporary
|
||||||
|
width="400"
|
||||||
|
>
|
||||||
<v-toolbar color="primary">
|
<v-toolbar color="primary">
|
||||||
<v-toolbar-title>消息记录</v-toolbar-title>
|
<v-toolbar-title>消息记录</v-toolbar-title>
|
||||||
|
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
|
|
||||||
<v-list>
|
<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>
|
<template #prepend>
|
||||||
<v-icon :color="colors[msg.type]" :icon="icons[msg.type]" size="20"/>
|
<v-icon
|
||||||
|
:color="colors[msg.type]"
|
||||||
|
:icon="icons[msg.type]"
|
||||||
|
size="20"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-list-item-title>{{ msg.title }}</v-list-item-title>
|
<v-list-item-title>{{ msg.title }}</v-list-item-title>
|
||||||
<v-list-item-subtitle v-if="msg.content">{{
|
<v-list-item-subtitle v-if="msg.content">
|
||||||
|
{{
|
||||||
msg.content
|
msg.content
|
||||||
}}
|
}}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
<span class="text-caption text-grey">
|
<span class="text-caption text-grey">
|
||||||
{{ new Date(msg.timestamp).toLocaleTimeString() }}
|
{{ new Date(msg.timestamp).toLocaleTimeString() }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item v-if="!messages.length">
|
<v-list-item v-if="!messages.length">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon color="grey" icon="mdi-inbox"/>
|
<v-icon
|
||||||
|
color="grey"
|
||||||
|
icon="mdi-inbox"
|
||||||
|
/>
|
||||||
</template>
|
</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-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-navigation-drawer>
|
</v-navigation-drawer>
|
||||||
|
|||||||
@ -16,7 +16,10 @@
|
|||||||
</v-card-subtitle>
|
</v-card-subtitle>
|
||||||
|
|
||||||
<v-card-text class="pt-0 pb-1">
|
<v-card-text class="pt-0 pb-1">
|
||||||
<v-list density="comfortable" lines="two">
|
<v-list
|
||||||
|
density="comfortable"
|
||||||
|
lines="two"
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="item in chipList"
|
v-for="item in chipList"
|
||||||
:key="item.key"
|
:key="item.key"
|
||||||
@ -24,8 +27,12 @@
|
|||||||
@click="() => handleSingleRequest(item.key)"
|
@click="() => handleSingleRequest(item.key)"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-avatar :color="chipColors[item.status]" size="32" variant="tonal">
|
<v-avatar
|
||||||
<v-icon :icon="statusIcons[item.status]"></v-icon>
|
:color="chipColors[item.status]"
|
||||||
|
size="32"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
<v-icon :icon="statusIcons[item.status]" />
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -33,7 +40,12 @@
|
|||||||
<v-list-item-subtitle>{{ item.description }}</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ item.description }}</v-list-item-subtitle>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-chip :color="chipColors[item.status]" size="small" variant="tonal" class="me-2">
|
<v-chip
|
||||||
|
:color="chipColors[item.status]"
|
||||||
|
size="small"
|
||||||
|
variant="tonal"
|
||||||
|
class="me-2"
|
||||||
|
>
|
||||||
{{ statusText[item.status] }}
|
{{ statusText[item.status] }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -42,7 +54,7 @@
|
|||||||
size="small"
|
size="small"
|
||||||
:disabled="isRequesting"
|
:disabled="isRequesting"
|
||||||
@click.stop="() => openHelp(item.key)"
|
@click.stop="() => openHelp(item.key)"
|
||||||
></v-btn>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
@ -76,15 +88,25 @@
|
|||||||
size="100"
|
size="100"
|
||||||
rounded="0"
|
rounded="0"
|
||||||
>
|
>
|
||||||
<v-icon icon="mdi-monitor-cellphone" size="80"></v-icon>
|
<v-icon
|
||||||
|
icon="mdi-monitor-cellphone"
|
||||||
|
size="80"
|
||||||
|
/>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-dialog v-model="helpDialog" max-width="520">
|
<v-dialog
|
||||||
|
v-model="helpDialog"
|
||||||
|
max-width="520"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h6">{{ helpContent.title }}</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
{{ helpContent.title }}
|
||||||
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<p class="mb-3">{{ helpContent.message }}</p>
|
<p class="mb-3">
|
||||||
|
{{ helpContent.message }}
|
||||||
|
</p>
|
||||||
<v-list density="comfortable">
|
<v-list density="comfortable">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="(link, index) in helpContent.links"
|
v-for="(link, index) in helpContent.links"
|
||||||
@ -99,8 +121,13 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="helpDialog = false">我知道了</v-btn>
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="helpDialog = false"
|
||||||
|
>
|
||||||
|
我知道了
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -5,16 +5,32 @@
|
|||||||
max-width="600"
|
max-width="600"
|
||||||
persistent
|
persistent
|
||||||
>
|
>
|
||||||
<v-card border class="random-picker-card" rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
class="random-picker-card"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title class="text-h5 d-flex align-center">
|
<v-card-title class="text-h5 d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-account-question"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-account-question"
|
||||||
|
/>
|
||||||
随机点名
|
随机点名
|
||||||
<v-spacer/>
|
<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-title>
|
||||||
|
|
||||||
<v-card-text v-if="!isPickingStarted" class="text-center py-6">
|
<v-card-text
|
||||||
<div class="text-h6 mb-4">请选择抽取人数</div>
|
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">
|
<div class="d-flex justify-center align-center counter-container">
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -52,14 +68,29 @@
|
|||||||
mandatory
|
mandatory
|
||||||
rounded="pill"
|
rounded="pill"
|
||||||
>
|
>
|
||||||
<v-btn prepend-icon="mdi-account" value="name">姓名模式</v-btn>
|
<v-btn
|
||||||
<v-btn prepend-icon="mdi-numeric" value="number">学号模式</v-btn>
|
prepend-icon="mdi-account"
|
||||||
|
value="name"
|
||||||
|
>
|
||||||
|
姓名模式
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
prepend-icon="mdi-numeric"
|
||||||
|
value="number"
|
||||||
|
>
|
||||||
|
学号模式
|
||||||
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 学号范围设置 -->
|
<!-- 学号范围设置 -->
|
||||||
<div v-if="pickerMode === 'number'" class="number-range-container mt-4">
|
<div
|
||||||
<div class="text-subtitle-1 mb-2">学号范围设置</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">
|
<div class="d-flex justify-center align-center gap-4">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model.number="minNumber"
|
v-model.number="minNumber"
|
||||||
@ -98,7 +129,10 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="filteredStudents.length === 0" class="mt-4 text-error">
|
<div
|
||||||
|
v-if="filteredStudents.length === 0"
|
||||||
|
class="mt-4 text-error"
|
||||||
|
>
|
||||||
<template v-if="pickerMode === 'name'">
|
<template v-if="pickerMode === 'name'">
|
||||||
没有可抽取的学生,请调整过滤选项
|
没有可抽取的学生,请调整过滤选项
|
||||||
</template>
|
</template>
|
||||||
@ -109,8 +143,11 @@
|
|||||||
|
|
||||||
<div class="mt-4 text-caption">
|
<div class="mt-4 text-caption">
|
||||||
当前可抽取学生: {{ filteredStudents.length }}人
|
当前可抽取学生: {{ filteredStudents.length }}人
|
||||||
<v-tooltip v-if="pickerMode === 'name'" location="bottom">
|
<v-tooltip
|
||||||
<template v-slot:activator="{ props }">
|
v-if="pickerMode === 'name'"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
|
<template #activator="{ props }">
|
||||||
<v-icon
|
<v-icon
|
||||||
class="ml-1"
|
class="ml-1"
|
||||||
icon="mdi-information-outline"
|
icon="mdi-information-outline"
|
||||||
@ -132,7 +169,10 @@
|
|||||||
</v-tooltip>
|
</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
|
<v-chip
|
||||||
:color="tempFilters.excludeLate ? 'warning' : 'default'"
|
:color="tempFilters.excludeLate ? 'warning' : 'default'"
|
||||||
:variant="tempFilters.excludeLate ? 'elevated' : 'text'"
|
:variant="tempFilters.excludeLate ? 'elevated' : 'text'"
|
||||||
@ -165,8 +205,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-text v-else class="text-center py-6">
|
<v-card-text
|
||||||
<div v-if="isAnimating" class="animation-container">
|
v-else
|
||||||
|
class="text-center py-6"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="isAnimating"
|
||||||
|
class="animation-container"
|
||||||
|
>
|
||||||
<div class="animation-wrapper">
|
<div class="animation-wrapper">
|
||||||
<transition-group
|
<transition-group
|
||||||
class="shuffle-container"
|
class="shuffle-container"
|
||||||
@ -185,8 +231,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="result-container">
|
<div
|
||||||
<div class="text-h6 mb-4">抽取结果</div>
|
v-else
|
||||||
|
class="result-container"
|
||||||
|
>
|
||||||
|
<div class="text-h6 mb-4">
|
||||||
|
抽取结果
|
||||||
|
</div>
|
||||||
<v-card
|
<v-card
|
||||||
v-for="(student, index) in pickedStudents"
|
v-for="(student, index) in pickedStudents"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|||||||
@ -1,22 +1,39 @@
|
|||||||
<template>
|
<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 class="rate-limit-modal">
|
||||||
<v-card-title class="text-center pa-4 bg-error text-white">
|
<v-card-title class="text-center pa-4 bg-error text-white">
|
||||||
<v-icon class="mr-2" icon="mdi-clock-alert-outline" size="large"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-clock-alert-outline"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
请求频率超限
|
请求频率超限
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text class="pa-6">
|
<v-card-text class="pa-6">
|
||||||
<div class="text-body-1 mb-4">您的请求过于频繁,请稍后再试。</div>
|
<div class="text-body-1 mb-4">
|
||||||
|
您的请求过于频繁,请稍后再试。
|
||||||
|
</div>
|
||||||
|
|
||||||
<v-card v-if="activeRequests.length > 0" class="mb-4" flat>
|
<v-card
|
||||||
|
v-if="activeRequests.length > 0"
|
||||||
|
class="mb-4"
|
||||||
|
flat
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-list
|
<v-list
|
||||||
v-for="(request, index) in activeRequests"
|
v-for="(request, index) in activeRequests"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
>
|
>
|
||||||
<v-list-item color="primary" prepend-icon="mdi-web">
|
<v-list-item
|
||||||
|
color="primary"
|
||||||
|
prepend-icon="mdi-web"
|
||||||
|
>
|
||||||
<v-list-item-title>
|
<v-list-item-title>
|
||||||
等待时间:
|
等待时间:
|
||||||
<span class="text-primary font-weight-bold">{{
|
<span class="text-primary font-weight-bold">{{
|
||||||
@ -27,12 +44,11 @@
|
|||||||
{{ request.method }} {{ request.path }}
|
{{ request.method }} {{ request.path }}
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list
|
</v-list>
|
||||||
>
|
|
||||||
<v-divider
|
<v-divider
|
||||||
v-if="index < activeRequests.length - 1"
|
v-if="index < activeRequests.length - 1"
|
||||||
class="my-3"
|
class="my-3"
|
||||||
></v-divider>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
@ -42,8 +58,14 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions class="pa-4 pt-0">
|
<v-card-actions class="pa-4 pt-0">
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" variant="tonal" @click="close"> 我知道了</v-btn>
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="tonal"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
我知道了
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
@click:close="dismissed = true"
|
@click:close="dismissed = true"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-lock-alert"/>
|
<v-icon icon="mdi-lock-alert" />
|
||||||
</template>
|
</template>
|
||||||
<v-alert-title>当前使用只读 Token</v-alert-title>
|
<v-alert-title>当前使用只读 Token</v-alert-title>
|
||||||
<div class="text-body-2">
|
<div class="text-body-2">
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card class="settings-card rounded-lg" elevation="2">
|
<v-card
|
||||||
|
class="settings-card rounded-lg"
|
||||||
|
elevation="2"
|
||||||
|
>
|
||||||
<v-card-item>
|
<v-card-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon
|
<v-icon
|
||||||
@ -8,7 +11,9 @@
|
|||||||
size="large"
|
size="large"
|
||||||
/>
|
/>
|
||||||
</template>
|
</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-item>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -18,11 +23,14 @@
|
|||||||
color="primary"
|
color="primary"
|
||||||
indeterminate
|
indeterminate
|
||||||
/>
|
/>
|
||||||
<slot/>
|
<slot />
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions v-if="$slots.actions" class="pa-4">
|
<v-card-actions
|
||||||
<slot name="actions"/>
|
v-if="$slots.actions"
|
||||||
|
class="pa-4"
|
||||||
|
>
|
||||||
|
<slot name="actions" />
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!-- 统一链接生成器卡片 -->
|
<!-- 统一链接生成器卡片 -->
|
||||||
<v-card border class="unified-link-generator">
|
<v-card
|
||||||
|
border
|
||||||
|
class="unified-link-generator"
|
||||||
|
>
|
||||||
<v-card-title class="text-h6">
|
<v-card-title class="text-h6">
|
||||||
<v-icon class="mr-2" icon="mdi-link-variant" start/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-link-variant"
|
||||||
|
start
|
||||||
|
/>
|
||||||
统一链接生成器
|
统一链接生成器
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
@ -13,15 +20,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 预配置认证信息部分 -->
|
<!-- 预配置认证信息部分 -->
|
||||||
<v-card class="mb-4" variant="tonal">
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon start>mdi-account-key</v-icon>
|
<v-icon start>
|
||||||
|
mdi-account-key
|
||||||
|
</v-icon>
|
||||||
预配置认证信息
|
预配置认证信息
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="preconfigForm.namespace"
|
v-model="preconfigForm.namespace"
|
||||||
hint="设备的命名空间标识符"
|
hint="设备的命名空间标识符"
|
||||||
@ -32,7 +47,10 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="preconfigForm.authCode"
|
v-model="preconfigForm.authCode"
|
||||||
hint="留空则需要用户手动输入"
|
hint="留空则需要用户手动输入"
|
||||||
@ -64,9 +82,19 @@
|
|||||||
type="info"
|
type="info"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<div class="text-subtitle-2 mb-2">预配置信息:</div>
|
<div class="text-subtitle-2 mb-2">
|
||||||
<v-chip class="mr-2 mb-1" size="small">
|
预配置信息:
|
||||||
<v-icon size="small" start>mdi-identifier</v-icon>
|
</div>
|
||||||
|
<v-chip
|
||||||
|
class="mr-2 mb-1"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-identifier
|
||||||
|
</v-icon>
|
||||||
命名空间: {{ preconfigForm.namespace }}
|
命名空间: {{ preconfigForm.namespace }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip
|
<v-chip
|
||||||
@ -75,12 +103,27 @@
|
|||||||
color="warning"
|
color="warning"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<v-icon size="small" start>mdi-lock</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-lock
|
||||||
|
</v-icon>
|
||||||
认证码: {{ preconfigForm.authCode.length > 8 ? preconfigForm.authCode.substring(0, 8) + "..." :
|
认证码: {{ preconfigForm.authCode.length > 8 ? preconfigForm.authCode.substring(0, 8) + "..." :
|
||||||
preconfigForm.authCode }}
|
preconfigForm.authCode }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip v-else class="mr-2 mb-1" color="grey" size="small">
|
<v-chip
|
||||||
<v-icon size="small" start>mdi-lock-open</v-icon>
|
v-else
|
||||||
|
class="mr-2 mb-1"
|
||||||
|
color="grey"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-lock-open
|
||||||
|
</v-icon>
|
||||||
无认证码
|
无认证码
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip
|
<v-chip
|
||||||
@ -88,7 +131,11 @@
|
|||||||
class="mr-2 mb-1"
|
class="mr-2 mb-1"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<v-icon size="small" start>{{
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
{{
|
||||||
preconfigForm.autoExecute ? "mdi-play-circle" : "mdi-hand-back-left"
|
preconfigForm.autoExecute ? "mdi-play-circle" : "mdi-hand-back-left"
|
||||||
}}
|
}}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
@ -99,9 +146,14 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 设置分享部分 -->
|
<!-- 设置分享部分 -->
|
||||||
<v-card class="mb-4" variant="tonal">
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon start>mdi-cog-transfer</v-icon>
|
<v-icon start>
|
||||||
|
mdi-cog-transfer
|
||||||
|
</v-icon>
|
||||||
设置分享(可选)
|
设置分享(可选)
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
@ -152,7 +204,10 @@
|
|||||||
|
|
||||||
<!-- 选择摘要 -->
|
<!-- 选择摘要 -->
|
||||||
<div class="d-flex align-center mb-3 flex-wrap gap-2">
|
<div class="d-flex align-center mb-3 flex-wrap gap-2">
|
||||||
<v-chip class="mr-2" color="primary">
|
<v-chip
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
已选 {{ selectedItems.length }} 项设置
|
已选 {{ selectedItems.length }} 项设置
|
||||||
</v-chip>
|
</v-chip>
|
||||||
|
|
||||||
@ -183,7 +238,9 @@
|
|||||||
<v-expansion-panel-title>
|
<v-expansion-panel-title>
|
||||||
<template #default="{ expanded }">
|
<template #default="{ expanded }">
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<v-icon class="mr-2">{{ expanded ? 'mdi-chevron-up' : 'mdi-chevron-down' }}</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
{{ expanded ? 'mdi-chevron-up' : 'mdi-chevron-down' }}
|
||||||
|
</v-icon>
|
||||||
显示设置列表详情
|
显示设置列表详情
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -261,9 +318,14 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 链接生成和操作部分 -->
|
<!-- 链接生成和操作部分 -->
|
||||||
<v-card class="mb-4" variant="outlined">
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon start>mdi-link</v-icon>
|
<v-icon start>
|
||||||
|
mdi-link
|
||||||
|
</v-icon>
|
||||||
生成的统一链接
|
生成的统一链接
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
@ -317,10 +379,20 @@
|
|||||||
type="success"
|
type="success"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<div class="text-subtitle-2 mb-2">链接包含内容:</div>
|
<div class="text-subtitle-2 mb-2">
|
||||||
|
链接包含内容:
|
||||||
|
</div>
|
||||||
<div class="d-flex flex-wrap gap-1">
|
<div class="d-flex flex-wrap gap-1">
|
||||||
<v-chip color="primary" size="small">
|
<v-chip
|
||||||
<v-icon size="small" start>mdi-account-key</v-icon>
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-account-key
|
||||||
|
</v-icon>
|
||||||
预配置认证
|
预配置认证
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip
|
<v-chip
|
||||||
@ -328,11 +400,25 @@
|
|||||||
color="secondary"
|
color="secondary"
|
||||||
size="small"
|
size="small"
|
||||||
>
|
>
|
||||||
<v-icon size="small" start>mdi-cog</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-cog
|
||||||
|
</v-icon>
|
||||||
{{ selectedItems.length }} 项设置
|
{{ selectedItems.length }} 项设置
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip v-else color="grey" size="small">
|
<v-chip
|
||||||
<v-icon size="small" start>mdi-cog-off</v-icon>
|
v-else
|
||||||
|
color="grey"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
>
|
||||||
|
mdi-cog-off
|
||||||
|
</v-icon>
|
||||||
无额外设置
|
无额外设置
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
@ -341,8 +427,13 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 安全提醒 -->
|
<!-- 安全提醒 -->
|
||||||
<v-alert type="warning" variant="tonal">
|
<v-alert
|
||||||
<div class="text-subtitle-2 mb-2">⚠️ 安全提醒</div>
|
type="warning"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
<div class="text-subtitle-2 mb-2">
|
||||||
|
⚠️ 安全提醒
|
||||||
|
</div>
|
||||||
<ul class="text-body-2 pl-4">
|
<ul class="text-body-2 pl-4">
|
||||||
<li>认证码和设置信息会在URL中传输,请谨慎分发</li>
|
<li>认证码和设置信息会在URL中传输,请谨慎分发</li>
|
||||||
<li>建议仅在受信任的网络环境中使用</li>
|
<li>建议仅在受信任的网络环境中使用</li>
|
||||||
@ -509,6 +600,45 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
// 监听选择变化,自动生成统一链接
|
||||||
|
selectedItems: {
|
||||||
|
handler() {
|
||||||
|
if (this.preconfigForm.namespace.trim()) {
|
||||||
|
this.generateUnifiedLink();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 监听预配置表单变化,自动生成统一链接
|
||||||
|
"preconfigForm.namespace": {
|
||||||
|
handler() {
|
||||||
|
if (this.preconfigForm.namespace.trim()) {
|
||||||
|
this.generateUnifiedLink();
|
||||||
|
} else {
|
||||||
|
this.unifiedLink = "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"preconfigForm.authCode": {
|
||||||
|
handler() {
|
||||||
|
if (this.preconfigForm.namespace.trim()) {
|
||||||
|
this.generateUnifiedLink();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"preconfigForm.autoExecute": {
|
||||||
|
handler() {
|
||||||
|
if (this.preconfigForm.namespace.trim()) {
|
||||||
|
this.generateUnifiedLink();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* 处理表格选择变化
|
* 处理表格选择变化
|
||||||
@ -782,44 +912,5 @@ export default {
|
|||||||
this.linkCopied = false;
|
this.linkCopied = false;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
|
||||||
// 监听选择变化,自动生成统一链接
|
|
||||||
selectedItems: {
|
|
||||||
handler() {
|
|
||||||
if (this.preconfigForm.namespace.trim()) {
|
|
||||||
this.generateUnifiedLink();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deep: true,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 监听预配置表单变化,自动生成统一链接
|
|
||||||
"preconfigForm.namespace": {
|
|
||||||
handler() {
|
|
||||||
if (this.preconfigForm.namespace.trim()) {
|
|
||||||
this.generateUnifiedLink();
|
|
||||||
} else {
|
|
||||||
this.unifiedLink = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"preconfigForm.authCode": {
|
|
||||||
handler() {
|
|
||||||
if (this.preconfigForm.namespace.trim()) {
|
|
||||||
this.generateUnifiedLink();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"preconfigForm.autoExecute": {
|
|
||||||
handler() {
|
|
||||||
if (this.preconfigForm.namespace.trim()) {
|
|
||||||
this.generateUnifiedLink();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -35,7 +35,6 @@
|
|||||||
|
|
||||||
<!-- 教师模式 -->
|
<!-- 教师模式 -->
|
||||||
<template v-else-if="isTeacherToken">
|
<template v-else-if="isTeacherToken">
|
||||||
|
|
||||||
<!-- 名称输入框 -->
|
<!-- 名称输入框 -->
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="teacherForm.name"
|
v-model="teacherForm.name"
|
||||||
@ -48,7 +47,6 @@
|
|||||||
|
|
||||||
class="mt-2 mb-4"
|
class="mt-2 mb-4"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<v-chip
|
<v-chip
|
||||||
v-for="teacher in filteredTeacherSuggestions"
|
v-for="teacher in filteredTeacherSuggestions"
|
||||||
|
|||||||
@ -22,11 +22,21 @@
|
|||||||
|
|
||||||
|
|
||||||
<!-- 多通知导航 -->
|
<!-- 多通知导航 -->
|
||||||
<div v-if="hasMultipleNotifications" class="navigation-controls mt-6">
|
<div
|
||||||
<v-card variant="flat" color="rgba(255,255,255,0.1)">
|
v-if="hasMultipleNotifications"
|
||||||
|
class="navigation-controls mt-6"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
variant="flat"
|
||||||
|
color="rgba(255,255,255,0.1)"
|
||||||
|
>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<div class="notification-counter mb-3">
|
<div class="notification-counter mb-3">
|
||||||
<v-chip color="white" variant="flat" size="small">
|
<v-chip
|
||||||
|
color="white"
|
||||||
|
variant="flat"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
{{ notificationCountText }}
|
{{ notificationCountText }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
@ -59,8 +69,15 @@
|
|||||||
|
|
||||||
<!-- 操作按钮 -->
|
<!-- 操作按钮 -->
|
||||||
<div class="mt-8">
|
<div class="mt-8">
|
||||||
<v-btn color="white" size="large" variant="flat" @click="close">
|
<v-btn
|
||||||
<v-icon left> mdi-check </v-icon>
|
color="white"
|
||||||
|
size="large"
|
||||||
|
variant="flat"
|
||||||
|
@click="close"
|
||||||
|
>
|
||||||
|
<v-icon left>
|
||||||
|
mdi-check
|
||||||
|
</v-icon>
|
||||||
我知道了
|
我知道了
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -28,8 +28,6 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card>
|
<v-card>
|
||||||
|
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-form>
|
<v-form>
|
||||||
<v-row>
|
<v-row>
|
||||||
@ -42,15 +40,14 @@
|
|||||||
label="强调通知"
|
label="强调通知"
|
||||||
color="red"
|
color="red"
|
||||||
inset
|
inset
|
||||||
>
|
/>
|
||||||
</v-switch>
|
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
v-model="notificationForm.isPersistent"
|
v-model="notificationForm.isPersistent"
|
||||||
label="常驻展示"
|
label="常驻展示"
|
||||||
color="primary"
|
color="primary"
|
||||||
hide-details
|
hide-details
|
||||||
class="mt-0"
|
class="mt-0"
|
||||||
></v-checkbox>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-textarea
|
<v-textarea
|
||||||
@ -81,8 +78,6 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
|
|
||||||
|
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -93,11 +88,16 @@
|
|||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
<v-icon class="mr-2">mdi-pin</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
mdi-pin
|
||||||
|
</v-icon>
|
||||||
常驻通知管理
|
常驻通知管理
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div v-if="persistentNotifications.length === 0" class="text-center text-grey py-4">
|
<div
|
||||||
|
v-if="persistentNotifications.length === 0"
|
||||||
|
class="text-center text-grey py-4"
|
||||||
|
>
|
||||||
暂无常驻通知
|
暂无常驻通知
|
||||||
</div>
|
</div>
|
||||||
<v-list v-else>
|
<v-list v-else>
|
||||||
@ -108,14 +108,25 @@
|
|||||||
:subtitle="formatTime(item.timestamp)"
|
:subtitle="formatTime(item.timestamp)"
|
||||||
lines="two"
|
lines="two"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon :color="item.isUrgent ? 'error' : 'primary'">
|
<v-icon :color="item.isUrgent ? 'error' : 'primary'">
|
||||||
{{ item.isUrgent ? 'mdi-alert-circle' : 'mdi-information' }}
|
{{ item.isUrgent ? 'mdi-alert-circle' : 'mdi-information' }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-btn icon="mdi-pencil" variant="text" size="small" @click="openEditDialog(item)"></v-btn>
|
<v-btn
|
||||||
<v-btn icon="mdi-delete" variant="text" color="error" size="small" @click="deletePersistentNotification(item.id)"></v-btn>
|
icon="mdi-pencil"
|
||||||
|
variant="text"
|
||||||
|
size="small"
|
||||||
|
@click="openEditDialog(item)"
|
||||||
|
/>
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-delete"
|
||||||
|
variant="text"
|
||||||
|
color="error"
|
||||||
|
size="small"
|
||||||
|
@click="deletePersistentNotification(item.id)"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
@ -201,17 +212,14 @@
|
|||||||
>
|
>
|
||||||
<v-card-text class="pa-2">
|
<v-card-text class="pa-2">
|
||||||
<div class="align-center">
|
<div class="align-center">
|
||||||
|
|
||||||
<span class="text-body-2 font-weight-medium">{{ device.deviceName }} </span>
|
<span class="text-body-2 font-weight-medium">{{ device.deviceName }} </span>
|
||||||
<br/>
|
<br>
|
||||||
|
|
||||||
{{ device.deviceType }}
|
{{ device.deviceType }}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-caption mt-1">
|
<div class="text-caption mt-1">
|
||||||
已读于 {{ formatDeviceTime(device.timestamp) }}
|
已读于 {{ formatDeviceTime(device.timestamp) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
@ -226,7 +234,6 @@
|
|||||||
>
|
>
|
||||||
<v-card-text class="pa-2">
|
<v-card-text class="pa-2">
|
||||||
<div class="align-center">
|
<div class="align-center">
|
||||||
|
|
||||||
<span class="text-body-2 font-weight-medium">{{ device.deviceName }}</span>
|
<span class="text-body-2 font-weight-medium">{{ device.deviceName }}</span>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<span class="text-caption text-grey">
|
<span class="text-caption text-grey">
|
||||||
@ -238,9 +245,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div v-else> <v-card
|
<div v-else>
|
||||||
|
<v-card
|
||||||
|
|
||||||
color="info-lighten-4"
|
color="info-lighten-4"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@ -249,9 +256,10 @@
|
|||||||
title="无设备在线"
|
title="无设备在线"
|
||||||
>
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
如果数秒后任然显示这个提示,则可能没有任何设备在线接收通知。
|
如果数秒后任然显示这个提示,则可能没有任何设备在线接收通知。
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card></div>
|
</v-card>
|
||||||
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@ -266,12 +274,22 @@
|
|||||||
<EventSender ref="eventSender" />
|
<EventSender ref="eventSender" />
|
||||||
|
|
||||||
<!-- 编辑常驻通知对话框 -->
|
<!-- 编辑常驻通知对话框 -->
|
||||||
<v-dialog v-model="editDialog" max-width="500" :fullscreen="$vuetify.display.xs">
|
<v-dialog
|
||||||
|
v-model="editDialog"
|
||||||
|
max-width="500"
|
||||||
|
:fullscreen="$vuetify.display.xs"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-toolbar flat density="compact">
|
<v-toolbar
|
||||||
|
flat
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
<v-toolbar-title>编辑常驻通知</v-toolbar-title>
|
<v-toolbar-title>编辑常驻通知</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn icon="mdi-close" @click="editDialog = false"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
@click="editDialog = false"
|
||||||
|
/>
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-form>
|
<v-form>
|
||||||
@ -280,38 +298,66 @@
|
|||||||
label="通知内容"
|
label="通知内容"
|
||||||
rows="3"
|
rows="3"
|
||||||
auto-grow
|
auto-grow
|
||||||
></v-textarea>
|
/>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="editForm.isUrgent"
|
v-model="editForm.isUrgent"
|
||||||
label="强调通知"
|
label="强调通知"
|
||||||
color="error"
|
color="error"
|
||||||
hide-details
|
hide-details
|
||||||
></v-switch>
|
/>
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
v-model="editForm.resend"
|
v-model="editForm.resend"
|
||||||
label="保存并重新发送通知"
|
label="保存并重新发送通知"
|
||||||
hint="勾选后将作为新通知发送给所有在线设备"
|
hint="勾选后将作为新通知发送给所有在线设备"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
></v-checkbox>
|
/>
|
||||||
</v-form>
|
</v-form>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="editDialog = false">取消</v-btn>
|
<v-btn
|
||||||
<v-btn color="primary" :loading="savingEdit" @click="saveEdit">保存</v-btn>
|
variant="text"
|
||||||
|
@click="editDialog = false"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
:loading="savingEdit"
|
||||||
|
@click="saveEdit"
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 删除确认对话框 -->
|
<!-- 删除确认对话框 -->
|
||||||
<v-dialog v-model="deleteConfirmDialog" max-width="400">
|
<v-dialog
|
||||||
|
v-model="deleteConfirmDialog"
|
||||||
|
max-width="400"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h5">确认删除</v-card-title>
|
<v-card-title class="text-h5">
|
||||||
|
确认删除
|
||||||
|
</v-card-title>
|
||||||
<v-card-text>确定要删除这条常驻通知吗?此操作无法撤销。</v-card-text>
|
<v-card-text>确定要删除这条常驻通知吗?此操作无法撤销。</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="grey-darken-1" variant="text" @click="deleteConfirmDialog = false">取消</v-btn>
|
<v-btn
|
||||||
<v-btn color="error" variant="text" @click="executeDelete">删除</v-btn>
|
color="grey-darken-1"
|
||||||
|
variant="text"
|
||||||
|
@click="deleteConfirmDialog = false"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="text"
|
||||||
|
@click="executeDelete"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -8,19 +8,35 @@
|
|||||||
>
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-account-group" />
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-account-group"
|
||||||
|
/>
|
||||||
考勤
|
考勤
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-chip v-if="!isMobile" class="ml-2" color="primary" size="small">
|
<v-chip
|
||||||
|
v-if="!isMobile"
|
||||||
|
class="ml-2"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
{{ dateString }}
|
{{ dateString }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-btn v-if="isMobile" icon="mdi-close" variant="text" @click="$emit('update:modelValue', false)" />
|
<v-btn
|
||||||
|
v-if="isMobile"
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
@click="$emit('update:modelValue', false)"
|
||||||
|
/>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<!-- 批量操作和搜索 -->
|
<!-- 批量操作和搜索 -->
|
||||||
<v-row class="mb-4">
|
<v-row class="mb-4">
|
||||||
<v-col cols="12" md="12">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="12"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="attendanceSearch"
|
v-model="attendanceSearch"
|
||||||
clearable
|
clearable
|
||||||
@ -128,7 +144,10 @@
|
|||||||
md="6"
|
md="6"
|
||||||
sm="6"
|
sm="6"
|
||||||
>
|
>
|
||||||
<v-card border class="student-card">
|
<v-card
|
||||||
|
border
|
||||||
|
class="student-card"
|
||||||
|
>
|
||||||
<v-card-text class="d-flex align-center pa-2">
|
<v-card-text class="d-flex align-center pa-2">
|
||||||
<div class="flex-grow-1">
|
<div class="flex-grow-1">
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
@ -137,11 +156,13 @@
|
|||||||
class="mr-2"
|
class="mr-2"
|
||||||
size="24"
|
size="24"
|
||||||
>
|
>
|
||||||
<v-icon size="small"
|
<v-icon size="small">
|
||||||
>{{ getStudentStatusIcon(student) }}
|
{{ getStudentStatusIcon(student) }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
<div class="text-subtitle-1">{{ student }}</div>
|
<div class="text-subtitle-1">
|
||||||
|
{{ student }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="attendance-actions">
|
<div class="attendance-actions">
|
||||||
@ -183,10 +204,19 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="12">
|
<v-col
|
||||||
<v-card class="mb-4" color="primary" variant="tonal">
|
cols="12"
|
||||||
|
md="12"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
color="primary"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="text-subtitle-2 mb-2">批量操作</div>
|
<div class="text-subtitle-2 mb-2">
|
||||||
|
批量操作
|
||||||
|
</div>
|
||||||
<div class="d-flex flex-wrap gap-2">
|
<div class="d-flex flex-wrap gap-2">
|
||||||
<v-btn
|
<v-btn
|
||||||
class="flex-grow-1"
|
class="flex-grow-1"
|
||||||
@ -232,8 +262,13 @@
|
|||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
|
|
||||||
<v-btn color="primary" @click="$emit('save')">
|
<v-btn
|
||||||
<v-icon start>mdi-content-save</v-icon>
|
color="primary"
|
||||||
|
@click="$emit('save')"
|
||||||
|
>
|
||||||
|
<v-icon start>
|
||||||
|
mdi-content-save
|
||||||
|
</v-icon>
|
||||||
保存
|
保存
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
|
|||||||
@ -45,8 +45,7 @@
|
|||||||
:key="'absent-' + index"
|
:key="'absent-' + index"
|
||||||
class="gray-text"
|
class="gray-text"
|
||||||
>
|
>
|
||||||
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span
|
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||||
><span style="white-space: nowrap">{{ name }}</span>
|
|
||||||
</h3>
|
</h3>
|
||||||
<h2>
|
<h2>
|
||||||
<span style="white-space: nowrap">迟到</span>
|
<span style="white-space: nowrap">迟到</span>
|
||||||
@ -60,8 +59,7 @@
|
|||||||
:key="'late-' + index"
|
:key="'late-' + index"
|
||||||
class="gray-text"
|
class="gray-text"
|
||||||
>
|
>
|
||||||
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span
|
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||||
><span style="white-space: nowrap">{{ name }}</span>
|
|
||||||
</h3>
|
</h3>
|
||||||
<h2>
|
<h2>
|
||||||
<span style="white-space: nowrap">不参与</span>
|
<span style="white-space: nowrap">不参与</span>
|
||||||
@ -75,8 +73,7 @@
|
|||||||
:key="'exclude-' + index"
|
:key="'exclude-' + index"
|
||||||
class="gray-text"
|
class="gray-text"
|
||||||
>
|
>
|
||||||
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span
|
<span v-if="display.lgAndUp.value">{{ `${index + 1}. ` }}</span><span style="white-space: nowrap">{{ name }}</span>
|
||||||
><span style="white-space: nowrap">{{ name }}</span>
|
|
||||||
</h3>
|
</h3>
|
||||||
</v-col>
|
</v-col>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
</v-alert>
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="showCancel"
|
v-if="showCancel"
|
||||||
variant="text"
|
variant="text"
|
||||||
|
|||||||
@ -41,9 +41,7 @@
|
|||||||
label="命名空间"
|
label="命名空间"
|
||||||
prepend-inner-icon="mdi-identifier"
|
prepend-inner-icon="mdi-identifier"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
>
|
/>
|
||||||
|
|
||||||
</v-text-field>
|
|
||||||
|
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="form.password"
|
v-model="form.password"
|
||||||
@ -51,9 +49,7 @@
|
|||||||
prepend-inner-icon="mdi-lock-outline"
|
prepend-inner-icon="mdi-lock-outline"
|
||||||
type="text"
|
type="text"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
>
|
/>
|
||||||
|
|
||||||
</v-text-field>
|
|
||||||
|
|
||||||
<v-alert
|
<v-alert
|
||||||
v-if="error"
|
v-if="error"
|
||||||
@ -77,7 +73,7 @@
|
|||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!form.namespace || authenticating"
|
:disabled="!form.namespace || authenticating"
|
||||||
:loading="authenticating"
|
:loading="authenticating"
|
||||||
|
|||||||
@ -139,8 +139,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 步骤 3: 询问使用场景 -->
|
<!-- 步骤 3: 询问使用场景 -->
|
||||||
@ -553,7 +551,7 @@
|
|||||||
</v-icon>
|
</v-icon>
|
||||||
上一步
|
上一步
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="currentStep < totalSteps && currentStep !== 4"
|
v-if="currentStep < totalSteps && currentStep !== 4"
|
||||||
:disabled="currentStep === 3 && !storageType"
|
:disabled="currentStep === 3 && !storageType"
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-information"/>
|
<v-icon icon="mdi-information" />
|
||||||
</template>
|
</template>
|
||||||
系统将自动为您创建设备并获取访问令牌,无需手动配置
|
系统将自动为您创建设备并获取访问令牌,无需手动配置
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -52,7 +52,7 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-check-circle"/>
|
<v-icon icon="mdi-check-circle" />
|
||||||
</template>
|
</template>
|
||||||
设备注册成功!已自动获取访问令牌
|
设备注册成功!已自动获取访问令牌
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -60,7 +60,7 @@
|
|||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-identifier"/>
|
<v-icon icon="mdi-identifier" />
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>设备名称</v-list-item-title>
|
<v-list-item-title>设备名称</v-list-item-title>
|
||||||
<v-list-item-subtitle>{{ deviceInfo.deviceName }}</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ deviceInfo.deviceName }}</v-list-item-subtitle>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-key"/>
|
<v-icon icon="mdi-key" />
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>设备 UUID</v-list-item-title>
|
<v-list-item-title>设备 UUID</v-list-item-title>
|
||||||
<v-list-item-subtitle class="font-mono text-caption">
|
<v-list-item-subtitle class="font-mono text-caption">
|
||||||
@ -83,7 +83,7 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-information"/>
|
<v-icon icon="mdi-information" />
|
||||||
</template>
|
</template>
|
||||||
您可以点击下方按钮访问云端控制台来设置密码和管理高级功能
|
您可以点击下方按钮访问云端控制台来设置密码和管理高级功能
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -97,7 +97,7 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-alert-circle"/>
|
<v-icon icon="mdi-alert-circle" />
|
||||||
</template>
|
</template>
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -105,7 +105,7 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
|
|
||||||
<!-- 注册按钮 -->
|
<!-- 注册按钮 -->
|
||||||
<v-btn
|
<v-btn
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
</v-alert>
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="showCancel"
|
v-if="showCancel"
|
||||||
variant="text"
|
variant="text"
|
||||||
|
|||||||
@ -1,15 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container class="fill-height">
|
<v-container class="fill-height">
|
||||||
<v-responsive class="align-centerfill-height mx-auto" max-width="900">
|
<v-responsive
|
||||||
<v-img class="mb-4" height="150" src="@/assets/logo.svg"/>
|
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-center">
|
||||||
<div class="text-body-2 font-weight-light mb-n1">出现了错误</div>
|
<div class="text-body-2 font-weight-light mb-n1">
|
||||||
|
出现了错误
|
||||||
<h1 class="text-h2 font-weight-bold">404</h1>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="py-4"/>
|
<h1 class="text-h2 font-weight-bold">
|
||||||
|
404
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="py-4" />
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
@ -21,15 +32,19 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
>
|
>
|
||||||
<template #image>
|
<template #image>
|
||||||
<v-img position="top right"/>
|
<v-img position="top right" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #title>
|
<template #title>
|
||||||
<h2 class="text-h5 font-weight-bold">为什么会出现此错误?</h2>
|
<h2 class="text-h5 font-weight-bold">
|
||||||
|
为什么会出现此错误?
|
||||||
|
</h2>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #subtitle>
|
<template #subtitle>
|
||||||
<div class="text-subtitle-1">大概是页面未找到</div>
|
<div class="text-subtitle-1">
|
||||||
|
大概是页面未找到
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-overlay
|
<v-overlay
|
||||||
@ -70,7 +85,7 @@
|
|||||||
rounded="lg"
|
rounded="lg"
|
||||||
title="返回上一页"
|
title="返回上一页"
|
||||||
variant="text"
|
variant="text"
|
||||||
@click="this.$router.back()"
|
@click="$router.back()"
|
||||||
>
|
>
|
||||||
<v-overlay
|
<v-overlay
|
||||||
contained
|
contained
|
||||||
|
|||||||
@ -11,13 +11,19 @@
|
|||||||
<span class="text-truncate">{{ exam?.examName || "加载中..." }}</span>
|
<span class="text-truncate">{{ exam?.examName || "加载中..." }}</span>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text class="flex-grow-1 pa-4 overflow-y-auto" :style="contentStyle">
|
<v-card-text
|
||||||
<div v-if="loading" class="d-flex justify-center align-center py-4">
|
class="flex-grow-1 pa-4 overflow-y-auto"
|
||||||
|
:style="contentStyle"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="loading"
|
||||||
|
class="d-flex justify-center align-center py-4"
|
||||||
|
>
|
||||||
<v-progress-circular
|
<v-progress-circular
|
||||||
indeterminate
|
indeterminate
|
||||||
size="24"
|
size="24"
|
||||||
color="primary"
|
color="primary"
|
||||||
></v-progress-circular>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-else-if="exam">
|
<template v-else-if="exam">
|
||||||
@ -26,7 +32,11 @@
|
|||||||
</div>-->
|
</div>-->
|
||||||
|
|
||||||
<div class="d-flex flex-column">
|
<div class="d-flex flex-column">
|
||||||
<div v-for="(group, gIndex) in groupedExamInfos" :key="gIndex" class="mb-3">
|
<div
|
||||||
|
v-for="(group, gIndex) in groupedExamInfos"
|
||||||
|
:key="gIndex"
|
||||||
|
class="mb-3"
|
||||||
|
>
|
||||||
<div class="text-subtitle-2 font-weight-bold text-primary mb-1">
|
<div class="text-subtitle-2 font-weight-bold text-primary mb-1">
|
||||||
<RelativeTimeDisplay :time="group.date" />
|
<RelativeTimeDisplay :time="group.date" />
|
||||||
</div>
|
</div>
|
||||||
@ -39,7 +49,10 @@
|
|||||||
'text-grey': isPast(info.end),
|
'text-grey': isPast(info.end),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="font-weight-bold mr-2" style="font-size: 1.1em">
|
<div
|
||||||
|
class="font-weight-bold mr-2"
|
||||||
|
style="font-size: 1.1em"
|
||||||
|
>
|
||||||
{{ info.name }}
|
{{ info.name }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
@ -54,7 +67,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-else class="text-center text-caption text-grey py-2">无法加载</div>
|
<div
|
||||||
|
v-else
|
||||||
|
class="text-center text-caption text-grey py-2"
|
||||||
|
>
|
||||||
|
无法加载
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,15 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card class="fill-height d-flex flex-column rounded-xl" elevation="2">
|
<v-card
|
||||||
|
class="fill-height d-flex flex-column rounded-xl"
|
||||||
|
elevation="2"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center py-3 px-4 bg-primary text-white">
|
<v-card-title class="d-flex align-center py-3 px-4 bg-primary text-white">
|
||||||
<v-icon class="mr-2">mdi-calendar-clock</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
mdi-calendar-clock
|
||||||
|
</v-icon>
|
||||||
<span class="text-truncate">{{ exam?.examName || '加载中...' }}</span>
|
<span class="text-truncate">{{ exam?.examName || '加载中...' }}</span>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn icon="mdi-close" variant="text" density="comfortable" @click="$emit('close')"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
density="comfortable"
|
||||||
|
@click="$emit('close')"
|
||||||
|
/>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text class="flex-grow-1 pa-4 overflow-y-auto" :style="contentStyle">
|
<v-card-text
|
||||||
<div v-if="loading" class="d-flex justify-center align-center fill-height" style="min-height: 200px;">
|
class="flex-grow-1 pa-4 overflow-y-auto"
|
||||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
:style="contentStyle"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="loading"
|
||||||
|
class="d-flex justify-center align-center fill-height"
|
||||||
|
style="min-height: 200px;"
|
||||||
|
>
|
||||||
|
<v-progress-circular
|
||||||
|
indeterminate
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-else-if="exam">
|
<template v-else-if="exam">
|
||||||
@ -24,10 +44,22 @@
|
|||||||
{{ exam.message }}
|
{{ exam.message }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<v-list density="comfortable" class="pa-0 bg-transparent">
|
<v-list
|
||||||
<v-list-item v-for="(info, index) in exam.examInfos" :key="index" class="px-0 mb-3">
|
density="comfortable"
|
||||||
|
class="pa-0 bg-transparent"
|
||||||
|
>
|
||||||
|
<v-list-item
|
||||||
|
v-for="(info, index) in exam.examInfos"
|
||||||
|
:key="index"
|
||||||
|
class="px-0 mb-3"
|
||||||
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-avatar color="primary" variant="tonal" size="large" class="mr-3 font-weight-bold elevation-1">
|
<v-avatar
|
||||||
|
color="primary"
|
||||||
|
variant="tonal"
|
||||||
|
size="large"
|
||||||
|
class="mr-3 font-weight-bold elevation-1"
|
||||||
|
>
|
||||||
{{ info.name.charAt(0) }}
|
{{ info.name.charAt(0) }}
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
@ -38,11 +70,23 @@
|
|||||||
|
|
||||||
<v-list-item-subtitle class="text-body-1">
|
<v-list-item-subtitle class="text-body-1">
|
||||||
<div class="d-flex align-center mb-1">
|
<div class="d-flex align-center mb-1">
|
||||||
<v-icon size="small" color="success" class="mr-2">mdi-clock-start</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
color="success"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
mdi-clock-start
|
||||||
|
</v-icon>
|
||||||
<span class="font-weight-medium">{{ formatTime(info.start) }}</span>
|
<span class="font-weight-medium">{{ formatTime(info.start) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<v-icon size="small" color="error" class="mr-2">mdi-clock-end</v-icon>
|
<v-icon
|
||||||
|
size="small"
|
||||||
|
color="error"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
mdi-clock-end
|
||||||
|
</v-icon>
|
||||||
<span class="font-weight-medium">{{ formatTime(info.end) }}</span>
|
<span class="font-weight-medium">{{ formatTime(info.end) }}</span>
|
||||||
</div>
|
</div>
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
@ -50,8 +94,16 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div v-else class="d-flex flex-column align-center justify-center fill-height text-grey mt-4">
|
<div
|
||||||
<v-icon size="large" class="mb-2">mdi-alert-circle-outline</v-icon>
|
v-else
|
||||||
|
class="d-flex flex-column align-center justify-center fill-height text-grey mt-4"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
size="large"
|
||||||
|
class="mb-2"
|
||||||
|
>
|
||||||
|
mdi-alert-circle-outline
|
||||||
|
</v-icon>
|
||||||
无法加载考试信息
|
无法加载考试信息
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|||||||
@ -10,7 +10,12 @@
|
|||||||
>
|
>
|
||||||
上传
|
上传
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn v-else color="success" size="large" @click="$emit('show-sync-message')">
|
<v-btn
|
||||||
|
v-else
|
||||||
|
color="success"
|
||||||
|
size="large"
|
||||||
|
@click="$emit('show-sync-message')"
|
||||||
|
>
|
||||||
同步完成
|
同步完成
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -86,7 +91,11 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
>
|
>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon icon="mdi-shield-check" size="small" start />
|
<v-icon
|
||||||
|
icon="mdi-shield-check"
|
||||||
|
size="small"
|
||||||
|
start
|
||||||
|
/>
|
||||||
屏幕保护技术已启用
|
屏幕保护技术已启用
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="text-body-2">
|
<v-card-text class="text-body-2">
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div ref="gridContainer" class="grid-masonry">
|
<div
|
||||||
|
ref="gridContainer"
|
||||||
|
class="grid-masonry"
|
||||||
|
>
|
||||||
<TransitionGroup name="grid">
|
<TransitionGroup name="grid">
|
||||||
<div
|
<div
|
||||||
v-for="item in sortedItems"
|
v-for="item in sortedItems"
|
||||||
@ -12,12 +15,18 @@
|
|||||||
class="grid-item"
|
class="grid-item"
|
||||||
>
|
>
|
||||||
<!-- 一言卡片 -->
|
<!-- 一言卡片 -->
|
||||||
<div v-if="item.type === 'hitokoto'" style="height: 100%">
|
<div
|
||||||
|
v-if="item.type === 'hitokoto'"
|
||||||
|
style="height: 100%"
|
||||||
|
>
|
||||||
<hitokoto-card />
|
<hitokoto-card />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 考试卡片 -->
|
<!-- 考试卡片 -->
|
||||||
<div v-else-if="item.type === 'exam'" style="height: 100%">
|
<div
|
||||||
|
v-else-if="item.type === 'exam'"
|
||||||
|
style="height: 100%"
|
||||||
|
>
|
||||||
<concise-exam-card
|
<concise-exam-card
|
||||||
:exam-id="item.data.examId"
|
:exam-id="item.data.examId"
|
||||||
:content-style="contentStyle"
|
:content-style="contentStyle"
|
||||||
@ -37,7 +46,11 @@
|
|||||||
@touchmove="handleTouchMove"
|
@touchmove="handleTouchMove"
|
||||||
>
|
>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" color="primary" icon="mdi-account-group" />
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
icon="mdi-account-group"
|
||||||
|
/>
|
||||||
出勤统计
|
出勤统计
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -54,28 +67,70 @@
|
|||||||
</div>
|
</div>
|
||||||
<v-divider class="mb-2" />
|
<v-divider class="mb-2" />
|
||||||
|
|
||||||
<div v-if="item.data.absent.length > 0" class="mb-2">
|
<div
|
||||||
<div class="text-error text-caption mb-1">请假 ({{ item.data.absent.length }})</div>
|
v-if="item.data.absent.length > 0"
|
||||||
<div class="d-flex flex-wrap" style="gap: 4px">
|
class="mb-2"
|
||||||
<v-chip v-for="name in item.data.absent" :key="name" color="error" size="x-small" variant="flat">
|
>
|
||||||
|
<div class="text-error text-caption mb-1">
|
||||||
|
请假 ({{ item.data.absent.length }})
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="d-flex flex-wrap"
|
||||||
|
style="gap: 4px"
|
||||||
|
>
|
||||||
|
<v-chip
|
||||||
|
v-for="name in item.data.absent"
|
||||||
|
:key="name"
|
||||||
|
color="error"
|
||||||
|
size="x-small"
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="item.data.late.length > 0" class="mb-2">
|
<div
|
||||||
<div class="text-warning text-caption mb-1">迟到 ({{ item.data.late.length }})</div>
|
v-if="item.data.late.length > 0"
|
||||||
<div class="d-flex flex-wrap" style="gap: 4px">
|
class="mb-2"
|
||||||
<v-chip v-for="name in item.data.late" :key="name" color="warning" size="x-small" variant="flat">
|
>
|
||||||
|
<div class="text-warning text-caption mb-1">
|
||||||
|
迟到 ({{ item.data.late.length }})
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="d-flex flex-wrap"
|
||||||
|
style="gap: 4px"
|
||||||
|
>
|
||||||
|
<v-chip
|
||||||
|
v-for="name in item.data.late"
|
||||||
|
:key="name"
|
||||||
|
color="warning"
|
||||||
|
size="x-small"
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="item.data.exclude.length > 0" class="mb-2">
|
<div
|
||||||
<div class="text-grey text-caption mb-1">不参与 ({{ item.data.exclude.length }})</div>
|
v-if="item.data.exclude.length > 0"
|
||||||
<div class="d-flex flex-wrap" style="gap: 4px">
|
class="mb-2"
|
||||||
<v-chip v-for="name in item.data.exclude" :key="name" color="grey" size="x-small" variant="flat">
|
>
|
||||||
|
<div class="text-grey text-caption mb-1">
|
||||||
|
不参与 ({{ item.data.exclude.length }})
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="d-flex flex-wrap"
|
||||||
|
style="gap: 4px"
|
||||||
|
>
|
||||||
|
<v-chip
|
||||||
|
v-for="name in item.data.exclude"
|
||||||
|
:key="name"
|
||||||
|
color="grey"
|
||||||
|
size="x-small"
|
||||||
|
variant="flat"
|
||||||
|
>
|
||||||
{{ name }}
|
{{ name }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
@ -106,7 +161,11 @@
|
|||||||
@touchmove="handleTouchMove"
|
@touchmove="handleTouchMove"
|
||||||
>
|
>
|
||||||
<v-card-title class="text-primary">
|
<v-card-title class="text-primary">
|
||||||
<v-icon class="mr-2" icon="mdi-card-text-outline" size="small" />
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-card-text-outline"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text :style="contentStyle">
|
<v-card-text :style="contentStyle">
|
||||||
@ -144,7 +203,10 @@
|
|||||||
<!-- 单独显示空科目 -->
|
<!-- 单独显示空科目 -->
|
||||||
<div class="empty-subjects mt-4">
|
<div class="empty-subjects mt-4">
|
||||||
<!-- 移动端优化视图 -->
|
<!-- 移动端优化视图 -->
|
||||||
<div v-if="isMobile" class="d-flex flex-wrap justify-center">
|
<div
|
||||||
|
v-if="isMobile"
|
||||||
|
class="d-flex flex-wrap justify-center"
|
||||||
|
>
|
||||||
<v-chip
|
<v-chip
|
||||||
v-for="subject in unusedSubjects"
|
v-for="subject in unusedSubjects"
|
||||||
:key="subject.name"
|
:key="subject.name"
|
||||||
@ -153,7 +215,10 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click="handleCardClick('dialog', subject.name)"
|
@click="handleCardClick('dialog', subject.name)"
|
||||||
>
|
>
|
||||||
<v-icon start size="small">
|
<v-icon
|
||||||
|
start
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
{{ isReadOnlyToken ? 'mdi-cancel' : 'mdi-plus' }}
|
{{ isReadOnlyToken ? 'mdi-cancel' : 'mdi-plus' }}
|
||||||
</v-icon>
|
</v-icon>
|
||||||
{{ subject.name }}
|
{{ subject.name }}
|
||||||
@ -161,7 +226,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-else-if="emptySubjectDisplay === 'button'">
|
<template v-else-if="emptySubjectDisplay === 'button'">
|
||||||
<v-btn-group divided variant="tonal">
|
<v-btn-group
|
||||||
|
divided
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
v-for="subject in unusedSubjects"
|
v-for="subject in unusedSubjects"
|
||||||
:key="subject.name"
|
:key="subject.name"
|
||||||
@ -174,7 +242,10 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
</template>
|
</template>
|
||||||
<div v-else class="empty-subjects-grid">
|
<div
|
||||||
|
v-else
|
||||||
|
class="empty-subjects-grid"
|
||||||
|
>
|
||||||
<TransitionGroup name="v-list">
|
<TransitionGroup name="v-list">
|
||||||
<v-card
|
<v-card
|
||||||
v-for="subject in unusedSubjects"
|
v-for="subject in unusedSubjects"
|
||||||
@ -188,12 +259,26 @@
|
|||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<template v-if="isReadOnlyToken">
|
<template v-if="isReadOnlyToken">
|
||||||
<v-icon color="grey" size="small"> mdi-cancel </v-icon>
|
<v-icon
|
||||||
<div class="text-caption text-grey"> 当日无作业 </div>
|
color="grey"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-cancel
|
||||||
|
</v-icon>
|
||||||
|
<div class="text-caption text-grey">
|
||||||
|
当日无作业
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<v-icon color="grey" size="small"> mdi-plus </v-icon>
|
<v-icon
|
||||||
<div class="text-caption text-grey"> 点击添加作业 </div>
|
color="grey"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-plus
|
||||||
|
</v-icon>
|
||||||
|
<div class="text-caption text-grey">
|
||||||
|
点击添加作业
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
@ -209,11 +294,6 @@ import {getSetting} from "@/utils/settings.js";
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "HomeworkGrid",
|
name: "HomeworkGrid",
|
||||||
computed: {
|
|
||||||
settings() {
|
|
||||||
return settings
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
components: {
|
||||||
HitokotoCard,
|
HitokotoCard,
|
||||||
ConciseExamCard,
|
ConciseExamCard,
|
||||||
@ -254,6 +334,11 @@ export default {
|
|||||||
isReadOnlyToken: false,
|
isReadOnlyToken: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
settings() {
|
||||||
|
return settings
|
||||||
|
}
|
||||||
|
},
|
||||||
async mounted() {
|
async mounted() {
|
||||||
/* eslint-disable no-undef */
|
/* eslint-disable no-undef */
|
||||||
this.resizeObserver = new ResizeObserver(() => {
|
this.resizeObserver = new ResizeObserver(() => {
|
||||||
|
|||||||
@ -1,25 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card border hover rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
hover
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-item>
|
<v-card-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-information" size="large"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-information"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-card-title class="text-h6">关于</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
关于
|
||||||
|
</v-card-title>
|
||||||
</v-card-item>
|
</v-card-item>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col class="mx-auto" cols="12" md="8">
|
<v-col
|
||||||
|
class="mx-auto"
|
||||||
|
cols="12"
|
||||||
|
md="8"
|
||||||
|
>
|
||||||
<div class="d-flex flex-column align-start">
|
<div class="d-flex flex-column align-start">
|
||||||
<v-avatar class="mb-4" size="120">
|
<v-avatar
|
||||||
|
class="mb-4"
|
||||||
|
size="120"
|
||||||
|
>
|
||||||
<v-img
|
<v-img
|
||||||
alt="Classworks"
|
alt="Classworks"
|
||||||
src="../../assets/cslogo.png"
|
src="../../assets/cslogo.png"
|
||||||
/>
|
/>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
|
|
||||||
<h2 class="text-h5 mb-2">Classworks</h2>
|
<h2 class="text-h5 mb-2">
|
||||||
<p class="text-body-1 mb-4">适用于班级大屏的作业板小工具</p>
|
Classworks
|
||||||
|
</h2>
|
||||||
|
<p class="text-body-1 mb-4">
|
||||||
|
适用于班级大屏的作业板小工具
|
||||||
|
</p>
|
||||||
|
|
||||||
<div class="d-flex gap-2 flex-wrap mb-6">
|
<div class="d-flex gap-2 flex-wrap mb-6">
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -57,9 +78,11 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</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 class="mb-4 bg-transparent">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
append-icon="mdi-link"
|
append-icon="mdi-link"
|
||||||
@ -98,7 +121,7 @@
|
|||||||
新一代,开源,编程社区
|
新一代,开源,编程社区
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-divider class="ma-1"></v-divider>
|
<v-divider class="ma-1" />
|
||||||
<v-list-item
|
<v-list-item
|
||||||
append-icon="mdi-link"
|
append-icon="mdi-link"
|
||||||
href="https://github.com/HUSX100/IslandCaller"
|
href="https://github.com/HUSX100/IslandCaller"
|
||||||
@ -141,12 +164,14 @@
|
|||||||
fullscreen
|
fullscreen
|
||||||
transition="dialog-bottom-transition"
|
transition="dialog-bottom-transition"
|
||||||
>
|
>
|
||||||
<v-card
|
<v-card>
|
||||||
>
|
|
||||||
<v-toolbar>
|
<v-toolbar>
|
||||||
<v-btn icon="mdi-close" @click="showDeps = false"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
@click="showDeps = false"
|
||||||
|
/>
|
||||||
<v-toolbar-title>使用的第三方库</v-toolbar-title>
|
<v-toolbar-title>使用的第三方库</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-list>
|
<v-list>
|
||||||
@ -170,45 +195,108 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 报告问题对话框 -->
|
<!-- 报告问题对话框 -->
|
||||||
<v-dialog v-model="showReportDialog" max-width="640">
|
<v-dialog
|
||||||
|
v-model="showReportDialog"
|
||||||
|
max-width="640"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-toolbar density="compact">
|
<v-toolbar density="compact">
|
||||||
<v-btn icon="mdi-close" @click="showReportDialog = false"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
@click="showReportDialog = false"
|
||||||
|
/>
|
||||||
<v-toolbar-title>报告问题</v-toolbar-title>
|
<v-toolbar-title>报告问题</v-toolbar-title>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<p class="mb-4">
|
<p class="mb-4">
|
||||||
调试ID与下方的浏览器环境信息将帮助我们快速定位问题,请在反馈中一并附上。
|
调试ID与下方的浏览器环境信息将帮助我们快速定位问题,请在反馈中一并附上。
|
||||||
</p>
|
</p>
|
||||||
<v-sheet class="mb-3 pa-3 bg-grey-lighten-4 rounded" style="max-height: 260px; overflow: auto;">
|
<v-sheet
|
||||||
<pre class="text-body-2" style="white-space: pre-wrap; margin: 0;">{{ envBoxText }}</pre>
|
class="mb-3 pa-3 bg-grey-lighten-4 rounded"
|
||||||
|
style="max-height: 260px; overflow: auto;"
|
||||||
|
>
|
||||||
|
<pre
|
||||||
|
class="text-body-2"
|
||||||
|
style="white-space: pre-wrap; margin: 0;"
|
||||||
|
>{{ envBoxText }}</pre>
|
||||||
</v-sheet>
|
</v-sheet>
|
||||||
<div class="d-flex gap-2 flex-wrap mb-4">
|
<div class="d-flex gap-2 flex-wrap mb-4">
|
||||||
<v-btn size="small" variant="text" prepend-icon="mdi-refresh" @click="reloadVisitorId" :loading="visitorLoading">刷新</v-btn>
|
<v-btn
|
||||||
<v-btn size="small" variant="text" prepend-icon="mdi-content-copy" @click="copyEnvInfo">复制信息</v-btn>
|
size="small"
|
||||||
<v-btn size="small" variant="text" prepend-icon="mdi-open-in-new" @click="goToDebug">查看 /debug 页面</v-btn>
|
variant="text"
|
||||||
|
prepend-icon="mdi-refresh"
|
||||||
|
:loading="visitorLoading"
|
||||||
|
@click="reloadVisitorId"
|
||||||
|
>
|
||||||
|
刷新
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
prepend-icon="mdi-content-copy"
|
||||||
|
@click="copyEnvInfo"
|
||||||
|
>
|
||||||
|
复制信息
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
size="small"
|
||||||
|
variant="text"
|
||||||
|
prepend-icon="mdi-open-in-new"
|
||||||
|
@click="goToDebug"
|
||||||
|
>
|
||||||
|
查看 /debug 页面
|
||||||
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<v-alert v-if="copyOk" type="success" density="compact" class="mb-4">已复制到剪贴板</v-alert>
|
<v-alert
|
||||||
<h4 class="text-subtitle-1 mb-2">反馈渠道</h4>
|
v-if="copyOk"
|
||||||
<v-list lines="one" class="bg-transparent">
|
type="success"
|
||||||
<v-list-item :href="qqGroupLink" target="_blank" prepend-icon="mdi-qqchat">
|
density="compact"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
|
已复制到剪贴板
|
||||||
|
</v-alert>
|
||||||
|
<h4 class="text-subtitle-1 mb-2">
|
||||||
|
反馈渠道
|
||||||
|
</h4>
|
||||||
|
<v-list
|
||||||
|
lines="one"
|
||||||
|
class="bg-transparent"
|
||||||
|
>
|
||||||
|
<v-list-item
|
||||||
|
:href="qqGroupLink"
|
||||||
|
target="_blank"
|
||||||
|
prepend-icon="mdi-qqchat"
|
||||||
|
>
|
||||||
<v-list-item-title>QQ群 ({{ qqGroupNumber }})</v-list-item-title>
|
<v-list-item-title>QQ群 ({{ qqGroupNumber }})</v-list-item-title>
|
||||||
<v-list-item-subtitle>964979747</v-list-item-subtitle>
|
<v-list-item-subtitle>964979747</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item :href="githubIssueUrl" target="_blank" prepend-icon="mdi-github">
|
<v-list-item
|
||||||
|
:href="githubIssueUrl"
|
||||||
|
target="_blank"
|
||||||
|
prepend-icon="mdi-github"
|
||||||
|
>
|
||||||
<v-list-item-title>GitHub Issue</v-list-item-title>
|
<v-list-item-title>GitHub Issue</v-list-item-title>
|
||||||
<v-list-item-subtitle>ZeroCatDev/Classworks</v-list-item-subtitle>
|
<v-list-item-subtitle>ZeroCatDev/Classworks</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item :href="mailtoLink" target="_blank" prepend-icon="mdi-email">
|
<v-list-item
|
||||||
|
:href="mailtoLink"
|
||||||
|
target="_blank"
|
||||||
|
prepend-icon="mdi-email"
|
||||||
|
>
|
||||||
<v-list-item-title>邮件</v-list-item-title>
|
<v-list-item-title>邮件</v-list-item-title>
|
||||||
<v-list-item-subtitle>sun@wuyuan.dev</v-list-item-subtitle>
|
<v-list-item-subtitle>sun@wuyuan.dev</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="showReportDialog = false">关闭</v-btn>
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="showReportDialog = false"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -1,17 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-dialog v-model="dialog" max-width="600" scrollable>
|
<v-dialog
|
||||||
|
v-model="dialog"
|
||||||
|
max-width="600"
|
||||||
|
scrollable
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>迁移到云端</v-card-title>
|
<v-card-title>迁移到云端</v-card-title>
|
||||||
<v-card-text style="height: 400px;">
|
<v-card-text style="height: 400px;">
|
||||||
<div v-if="loading" class="d-flex justify-center align-center fill-height">
|
<div
|
||||||
<v-progress-circular indeterminate color="primary"></v-progress-circular>
|
v-if="loading"
|
||||||
|
class="d-flex justify-center align-center fill-height"
|
||||||
|
>
|
||||||
|
<v-progress-circular
|
||||||
|
indeterminate
|
||||||
|
color="primary"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="keys.length === 0" class="d-flex justify-center align-center fill-height">
|
<div
|
||||||
|
v-else-if="keys.length === 0"
|
||||||
|
class="d-flex justify-center align-center fill-height"
|
||||||
|
>
|
||||||
没有找到本地数据
|
没有找到本地数据
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<!-- Category Selection -->
|
<!-- Category Selection -->
|
||||||
<v-list select-strategy="classic" class="mb-4">
|
<v-list
|
||||||
|
select-strategy="classic"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
<v-list-subheader>选择数据类型</v-list-subheader>
|
<v-list-subheader>选择数据类型</v-list-subheader>
|
||||||
|
|
||||||
<v-list-item
|
<v-list-item
|
||||||
@ -19,32 +35,38 @@
|
|||||||
:key="category.id"
|
:key="category.id"
|
||||||
@click="toggleCategory(category)"
|
@click="toggleCategory(category)"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-checkbox-btn
|
<v-checkbox-btn
|
||||||
:model-value="getCategoryState(category)"
|
:model-value="getCategoryState(category)"
|
||||||
:indeterminate="getCategoryIndeterminate(category)"
|
:indeterminate="getCategoryIndeterminate(category)"
|
||||||
@click.stop="toggleCategory(category)"
|
@click.stop="toggleCategory(category)"
|
||||||
></v-checkbox-btn>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>{{ category.label }}</v-list-item-title>
|
<v-list-item-title>{{ category.label }}</v-list-item-title>
|
||||||
<v-list-item-subtitle>{{ category.description }} ({{ getCategoryCount(category) }} 项)</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ category.description }} ({{ getCategoryCount(category) }} 项)</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
|
||||||
<v-divider class="mb-4"></v-divider>
|
<v-divider class="mb-4" />
|
||||||
|
|
||||||
<!-- Individual Keys Expansion -->
|
<!-- Individual Keys Expansion -->
|
||||||
<v-expansion-panels>
|
<v-expansion-panels>
|
||||||
<v-expansion-panel title="详细数据列表">
|
<v-expansion-panel title="详细数据列表">
|
||||||
<v-expansion-panel-text>
|
<v-expansion-panel-text>
|
||||||
<v-list select-strategy="classic" density="compact">
|
<v-list
|
||||||
|
select-strategy="classic"
|
||||||
|
density="compact"
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="key in keys"
|
v-for="key in keys"
|
||||||
:key="key"
|
:key="key"
|
||||||
:value="key"
|
:value="key"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-checkbox-btn v-model="selectedKeys" :value="key"></v-checkbox-btn>
|
<v-checkbox-btn
|
||||||
|
v-model="selectedKeys"
|
||||||
|
:value="key"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>{{ key }}</v-list-item-title>
|
<v-list-item-title>{{ key }}</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -54,14 +76,24 @@
|
|||||||
</v-expansion-panels>
|
</v-expansion-panels>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider></v-divider>
|
<v-divider />
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<div class="text-caption ml-4 text-medium-emphasis">
|
<div class="text-caption ml-4 text-medium-emphasis">
|
||||||
已选择 {{ selectedKeys.length }} 项
|
已选择 {{ selectedKeys.length }} 项
|
||||||
</div>
|
</div>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="dialog = false">取消</v-btn>
|
<v-btn
|
||||||
<v-btn color="primary" @click="migrate" :loading="migrating" :disabled="selectedKeys.length === 0">
|
variant="text"
|
||||||
|
@click="dialog = false"
|
||||||
|
>
|
||||||
|
取消
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
:loading="migrating"
|
||||||
|
:disabled="selectedKeys.length === 0"
|
||||||
|
@click="migrate"
|
||||||
|
>
|
||||||
开始迁移
|
开始迁移
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
@ -69,7 +101,10 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- Result Dialog -->
|
<!-- Result Dialog -->
|
||||||
<v-dialog v-model="resultDialog" max-width="500">
|
<v-dialog
|
||||||
|
v-model="resultDialog"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>迁移结果</v-card-title>
|
<v-card-title>迁移结果</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -79,12 +114,19 @@
|
|||||||
<p>失败: {{ result.summary.failed }}</p>
|
<p>失败: {{ result.summary.failed }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="error">
|
<div v-else-if="error">
|
||||||
<p class="text-error">{{ error }}</p>
|
<p class="text-error">
|
||||||
|
{{ error }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" @click="resultDialog = false">关闭</v-btn>
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="resultDialog = false"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -15,7 +15,9 @@
|
|||||||
@click:close="showAutoplayWarning = false"
|
@click:close="showAutoplayWarning = false"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<v-icon class="mr-2">mdi-information</v-icon>
|
<v-icon class="mr-2">
|
||||||
|
mdi-information
|
||||||
|
</v-icon>
|
||||||
<span>首次使用请点击试听按钮测试音频播放是否正常</span>
|
<span>首次使用请点击试听按钮测试音频播放是否正常</span>
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -25,7 +27,9 @@
|
|||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon left>mdi-bell-ring</v-icon>
|
<v-icon left>
|
||||||
|
mdi-bell-ring
|
||||||
|
</v-icon>
|
||||||
单次通知铃声
|
单次通知铃声
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -66,13 +70,17 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click="previewSound(singleSound)"
|
@click="previewSound(singleSound)"
|
||||||
>
|
>
|
||||||
<v-icon left>mdi-play</v-icon>
|
<v-icon left>
|
||||||
|
mdi-play
|
||||||
|
</v-icon>
|
||||||
试听
|
试听
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@click="resetSingleSound"
|
@click="resetSingleSound"
|
||||||
>
|
>
|
||||||
<v-icon left>mdi-restore</v-icon>
|
<v-icon left>
|
||||||
|
mdi-restore
|
||||||
|
</v-icon>
|
||||||
恢复
|
恢复
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -84,7 +92,12 @@
|
|||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title class="text-subtitle-1">
|
<v-card-title class="text-subtitle-1">
|
||||||
<v-icon left color="error">mdi-bell-alert</v-icon>
|
<v-icon
|
||||||
|
left
|
||||||
|
color="error"
|
||||||
|
>
|
||||||
|
mdi-bell-alert
|
||||||
|
</v-icon>
|
||||||
紧急通知铃声
|
紧急通知铃声
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -125,13 +138,17 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click="previewSound(urgentSound)"
|
@click="previewSound(urgentSound)"
|
||||||
>
|
>
|
||||||
<v-icon left>mdi-play</v-icon>
|
<v-icon left>
|
||||||
|
mdi-play
|
||||||
|
</v-icon>
|
||||||
试听
|
试听
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@click="resetUrgentSound"
|
@click="resetUrgentSound"
|
||||||
>
|
>
|
||||||
<v-icon left>mdi-restore</v-icon>
|
<v-icon left>
|
||||||
|
mdi-restore
|
||||||
|
</v-icon>
|
||||||
恢复
|
恢复
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,7 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card :border="border" class="setting-group">
|
<v-card
|
||||||
<v-card-title v-if="title" class="d-flex align-center">
|
:border="border"
|
||||||
<v-icon v-if="icon" :icon="icon" class="mr-2"/>
|
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 }}
|
{{ title }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
@ -18,7 +28,7 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions v-if="$slots.actions">
|
<v-card-actions v-if="$slots.actions">
|
||||||
<slot name="actions"></slot>
|
<slot name="actions" />
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-list-item :disabled="disabled" class="setting-item">
|
<v-list-item
|
||||||
|
:disabled="disabled"
|
||||||
|
class="setting-item"
|
||||||
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon :icon="settingIcon"/>
|
<v-icon :icon="settingIcon" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-list-item-title class="text-wrap">
|
<v-list-item-title class="text-wrap">
|
||||||
@ -14,7 +17,10 @@
|
|||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="d-flex flex-column flex-sm-row align-center">
|
<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-switch
|
||||||
v-if="type === 'boolean'"
|
v-if="type === 'boolean'"
|
||||||
@ -40,7 +46,10 @@
|
|||||||
@update:model-value="updateSetting"
|
@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
|
<v-btn
|
||||||
:disabled="disabled || localValue <= minValue"
|
:disabled="disabled || localValue <= minValue"
|
||||||
icon="mdi-minus"
|
icon="mdi-minus"
|
||||||
@ -76,7 +85,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-menu location="bottom">
|
<v-menu location="bottom">
|
||||||
<template v-slot:activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
@ -88,24 +97,36 @@
|
|||||||
</template>
|
</template>
|
||||||
<v-list density="compact">
|
<v-list density="compact">
|
||||||
<v-list-item @click="copySettingId">
|
<v-list-item @click="copySettingId">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-key" size="small"/>
|
<v-icon
|
||||||
|
icon="mdi-key"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>复制设置ID</v-list-item-title>
|
<v-list-item-title>复制设置ID</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item @click="copySettingValue">
|
<v-list-item @click="copySettingValue">
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon icon="mdi-content-copy" size="small"/>
|
<v-icon
|
||||||
|
icon="mdi-content-copy"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>复制设置值</v-list-item-title>
|
<v-list-item-title>复制设置值</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-divider></v-divider>
|
<v-divider />
|
||||||
|
|
||||||
<v-list-item :disabled="isDefaultValue" @click="resetToDefault">
|
<v-list-item
|
||||||
<template v-slot:prepend>
|
:disabled="isDefaultValue"
|
||||||
<v-icon icon="mdi-restore" size="small"/>
|
@click="resetToDefault"
|
||||||
|
>
|
||||||
|
<template #prepend>
|
||||||
|
<v-icon
|
||||||
|
icon="mdi-restore"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>重置为默认值</v-list-item-title>
|
<v-list-item-title>重置为默认值</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -116,7 +137,10 @@
|
|||||||
</v-list-item>
|
</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-text-field
|
||||||
v-model="localValue"
|
v-model="localValue"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
|
|||||||
@ -1,30 +1,46 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="settings-explorer">
|
<div class="settings-explorer">
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<v-text-field v-model="searchQuery" class="mb-4" clearable density="comfortable" label="搜索设置"
|
<v-text-field
|
||||||
prepend-inner-icon="mdi-magnify" variant="outlined"/>
|
v-model="searchQuery"
|
||||||
|
class="mb-4"
|
||||||
|
clearable
|
||||||
|
density="comfortable"
|
||||||
|
label="搜索设置"
|
||||||
|
prepend-inner-icon="mdi-magnify"
|
||||||
|
variant="outlined"
|
||||||
|
/>
|
||||||
|
|
||||||
|
|
||||||
<v-list>
|
<v-list>
|
||||||
<div v-for="setting in allSettings" :key="setting.key">
|
<div
|
||||||
<setting-item :key="setting.key" :disabled="setting.requireDeveloper && !isDeveloperMode"
|
v-for="setting in allSettings"
|
||||||
:setting-key="setting.key" @error="onSettingError"
|
:key="setting.key"
|
||||||
@update="onSettingUpdate"/>
|
>
|
||||||
<v-divider class="my-2"/>
|
<setting-item
|
||||||
|
:key="setting.key"
|
||||||
|
:disabled="setting.requireDeveloper && !isDeveloperMode"
|
||||||
|
:setting-key="setting.key"
|
||||||
|
@error="onSettingError"
|
||||||
|
@update="onSettingUpdate"
|
||||||
|
/>
|
||||||
|
<v-divider class="my-2" />
|
||||||
</div>
|
</div>
|
||||||
</v-list>
|
</v-list>
|
||||||
<v-card border>
|
<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>
|
<v-card-text>
|
||||||
<pre class="settings-json">{{ formattedSettings }}</pre>
|
<pre class="settings-json">{{ formattedSettings }}</pre>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn @click="copySettingsToClipboard">
|
<v-btn @click="copySettingsToClipboard">
|
||||||
复制到剪贴板
|
复制到剪贴板
|
||||||
<v-icon right>mdi-content-copy</v-icon>
|
<v-icon right>
|
||||||
|
mdi-content-copy
|
||||||
|
</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|||||||
@ -6,11 +6,20 @@
|
|||||||
>
|
>
|
||||||
<v-card-item>
|
<v-card-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-account-group" size="large"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-account-group"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-card-title class="text-h6">学生列表</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
学生列表
|
||||||
|
</v-card-title>
|
||||||
<template #append>
|
<template #append>
|
||||||
<unsaved-warning :show="unsavedChanges" message="有未保存的更改"/>
|
<unsaved-warning
|
||||||
|
:show="unsavedChanges"
|
||||||
|
message="有未保存的更改"
|
||||||
|
/>
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="modelValue.list.length === 0"
|
:disabled="modelValue.list.length === 0"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
@ -39,7 +48,13 @@
|
|||||||
indeterminate
|
indeterminate
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-alert v-if="error" class="mb-4" closable type="error" variant="tonal">
|
<v-alert
|
||||||
|
v-if="error"
|
||||||
|
class="mb-4"
|
||||||
|
closable
|
||||||
|
type="error"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
@ -47,7 +62,11 @@
|
|||||||
<!-- 普通编辑模式 -->
|
<!-- 普通编辑模式 -->
|
||||||
<div v-if="!modelValue.advanced">
|
<div v-if="!modelValue.advanced">
|
||||||
<v-row class="mb-6">
|
<v-row class="mb-6">
|
||||||
<v-col cols="12" md="4" sm="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newStudentName"
|
v-model="newStudentName"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
@ -88,7 +107,10 @@
|
|||||||
v-bind="props"
|
v-bind="props"
|
||||||
>
|
>
|
||||||
<v-card-text class="d-flex align-center pa-3">
|
<v-card-text class="d-flex align-center pa-3">
|
||||||
<v-menu :open-on-hover="!isMobile" location="bottom">
|
<v-menu
|
||||||
|
:open-on-hover="!isMobile"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
<template #activator="{ props: menuProps }">
|
<template #activator="{ props: menuProps }">
|
||||||
<v-btn
|
<v-btn
|
||||||
class="mr-3 font-weight-medium"
|
class="mr-3 font-weight-medium"
|
||||||
@ -100,7 +122,10 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-list density="compact" nav>
|
<v-list
|
||||||
|
density="compact"
|
||||||
|
nav
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
:disabled="index === 0"
|
:disabled="index === 0"
|
||||||
prepend-icon="mdi-arrow-up-bold"
|
prepend-icon="mdi-arrow-up-bold"
|
||||||
@ -108,7 +133,7 @@
|
|||||||
>
|
>
|
||||||
置顶
|
置顶
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-divider/>
|
<v-divider />
|
||||||
<v-list-item
|
<v-list-item
|
||||||
:disabled="index === 0"
|
:disabled="index === 0"
|
||||||
prepend-icon="mdi-arrow-up"
|
prepend-icon="mdi-arrow-up"
|
||||||
@ -172,7 +197,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 高级编辑模式 -->
|
<!-- 高级编辑模式 -->
|
||||||
<div v-else class="pt-2">
|
<div
|
||||||
|
v-else
|
||||||
|
class="pt-2"
|
||||||
|
>
|
||||||
<v-textarea
|
<v-textarea
|
||||||
v-model="modelValue.text"
|
v-model="modelValue.text"
|
||||||
hint="使用文本编辑模式批量编辑学生名单,保存时会自动去除空行"
|
hint="使用文本编辑模式批量编辑学生名单,保存时会自动去除空行"
|
||||||
@ -187,7 +215,10 @@
|
|||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-row class="mt-6">
|
<v-row class="mt-6">
|
||||||
<v-col class="d-flex gap-2" cols="12">
|
<v-col
|
||||||
|
class="d-flex gap-2"
|
||||||
|
cols="12"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
|||||||
@ -6,11 +6,20 @@
|
|||||||
>
|
>
|
||||||
<v-card-item>
|
<v-card-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-account-tie" size="large"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-account-tie"
|
||||||
|
size="large"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-card-title class="text-h6">教师列表</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
教师列表
|
||||||
|
</v-card-title>
|
||||||
<template #append>
|
<template #append>
|
||||||
<unsaved-warning :show="unsavedChanges" message="有未保存的更改"/>
|
<unsaved-warning
|
||||||
|
:show="unsavedChanges"
|
||||||
|
message="有未保存的更改"
|
||||||
|
/>
|
||||||
<v-btn
|
<v-btn
|
||||||
:color="modelValue.advanced ? 'primary' : undefined"
|
:color="modelValue.advanced ? 'primary' : undefined"
|
||||||
prepend-icon="mdi-code-braces"
|
prepend-icon="mdi-code-braces"
|
||||||
@ -30,7 +39,13 @@
|
|||||||
indeterminate
|
indeterminate
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-alert v-if="error" class="mb-4" closable type="error" variant="tonal">
|
<v-alert
|
||||||
|
v-if="error"
|
||||||
|
class="mb-4"
|
||||||
|
closable
|
||||||
|
type="error"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
@ -38,10 +53,16 @@
|
|||||||
<!-- 普通编辑模式 -->
|
<!-- 普通编辑模式 -->
|
||||||
<div v-if="!modelValue.advanced">
|
<div v-if="!modelValue.advanced">
|
||||||
<!-- 添加教师表单 -->
|
<!-- 添加教师表单 -->
|
||||||
<v-card class="mb-6" variant="outlined">
|
<v-card
|
||||||
|
class="mb-6"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newTeacher.name"
|
v-model="newTeacher.name"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
@ -52,7 +73,10 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="5">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="5"
|
||||||
|
>
|
||||||
<v-combobox
|
<v-combobox
|
||||||
v-model="newTeacher.subjects"
|
v-model="newTeacher.subjects"
|
||||||
:items="commonSubjects"
|
:items="commonSubjects"
|
||||||
@ -68,7 +92,11 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="3" class="d-flex align-center gap-2">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="3"
|
||||||
|
class="d-flex align-center gap-2"
|
||||||
|
>
|
||||||
<v-checkbox
|
<v-checkbox
|
||||||
v-model="newTeacher.isHeadTeacher"
|
v-model="newTeacher.isHeadTeacher"
|
||||||
density="comfortable"
|
density="comfortable"
|
||||||
@ -91,7 +119,10 @@
|
|||||||
<!-- 教师列表 -->
|
<!-- 教师列表 -->
|
||||||
<v-row v-if="modelValue.list.length === 0">
|
<v-row v-if="modelValue.list.length === 0">
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-alert type="info" variant="tonal">
|
<v-alert
|
||||||
|
type="info"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
暂无教师信息,请添加教师
|
暂无教师信息,请添加教师
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -155,7 +186,10 @@
|
|||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="editState.index === index" class="mt-2">
|
<div
|
||||||
|
v-if="editState.index === index"
|
||||||
|
class="mt-2"
|
||||||
|
>
|
||||||
<v-combobox
|
<v-combobox
|
||||||
v-model="editState.teacher.subjects"
|
v-model="editState.teacher.subjects"
|
||||||
:items="commonSubjects"
|
:items="commonSubjects"
|
||||||
@ -175,7 +209,10 @@
|
|||||||
label="班主任"
|
label="班主任"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="mt-1">
|
<div
|
||||||
|
v-else
|
||||||
|
class="mt-1"
|
||||||
|
>
|
||||||
<v-chip
|
<v-chip
|
||||||
v-for="(subject, sIndex) in teacher.subjects"
|
v-for="(subject, sIndex) in teacher.subjects"
|
||||||
:key="sIndex"
|
:key="sIndex"
|
||||||
@ -235,13 +272,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 高级编辑模式 -->
|
<!-- 高级编辑模式 -->
|
||||||
<div v-else class="pt-2">
|
<div
|
||||||
|
v-else
|
||||||
|
class="pt-2"
|
||||||
|
>
|
||||||
<v-textarea
|
<v-textarea
|
||||||
v-model="modelValue.text"
|
v-model="modelValue.text"
|
||||||
hint="JSON 格式编辑教师列表。每个教师需包含 name、subjects(数组)、isHeadTeacher(布尔值)"
|
hint="JSON 格式编辑教师列表。每个教师需包含 name、subjects(数组)、isHeadTeacher(布尔值)"
|
||||||
label="批量编辑教师列表 (JSON)"
|
label="批量编辑教师列表 (JSON)"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
placeholder='[{"name":"教师姓名","subjects":["语文","数学"],"isHeadTeacher":true}]'
|
placeholder="[{"name":"教师姓名","subjects":["语文","数学"],"isHeadTeacher":true}]"
|
||||||
rows="15"
|
rows="15"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@update:model-value="handleTextInput"
|
@update:model-value="handleTextInput"
|
||||||
@ -250,7 +290,10 @@
|
|||||||
</v-expand-transition>
|
</v-expand-transition>
|
||||||
|
|
||||||
<v-row class="mt-6">
|
<v-row class="mt-6">
|
||||||
<v-col class="d-flex gap-2" cols="12">
|
<v-col
|
||||||
|
class="d-flex gap-2"
|
||||||
|
cols="12"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
|
|||||||
@ -1,7 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-card :disabled="!hasNamespaceInfo" :loading="loading" class="my-4">
|
<v-card
|
||||||
|
:disabled="!hasNamespaceInfo"
|
||||||
|
:loading="loading"
|
||||||
|
class="my-4"
|
||||||
|
>
|
||||||
<template #loader>
|
<template #loader>
|
||||||
<v-progress-linear v-if="loading" color="primary" indeterminate/>
|
<v-progress-linear
|
||||||
|
v-if="loading"
|
||||||
|
color="primary"
|
||||||
|
indeterminate
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@ -175,7 +183,7 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -213,7 +221,7 @@
|
|||||||
<p>您确定要重新初始化云端存储吗?</p>
|
<p>您确定要重新初始化云端存储吗?</p>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
variant="text"
|
||||||
@click="showReinitDialog = false"
|
@click="showReinitDialog = false"
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card icon="mdi-database-cog" title="数据源设置">
|
<settings-card
|
||||||
|
icon="mdi-database-cog"
|
||||||
|
title="数据源设置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<!-- 服务器模式设置 -->
|
<!-- 服务器模式设置 -->
|
||||||
<template
|
<template
|
||||||
@ -10,7 +13,10 @@
|
|||||||
>
|
>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-lan-connect"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-lan-connect"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>检查服务器连接</v-list-item-title>
|
<v-list-item-title>检查服务器连接</v-list-item-title>
|
||||||
<template #append>
|
<template #append>
|
||||||
@ -22,64 +28,94 @@
|
|||||||
测试连接
|
测试连接
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item
|
</v-list-item><!-- 数据迁移,仅对KV本地存储有效 -->
|
||||||
><!-- 数据迁移,仅对KV本地存储有效 -->
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 本地存储设置 -->
|
<!-- 本地存储设置 -->
|
||||||
<template v-if="currentProvider === 'kv-local'">
|
<template v-if="currentProvider === 'kv-local'">
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-database"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-database"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>清除数据库缓存</v-list-item-title>
|
<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>
|
<template #append>
|
||||||
<v-btn color="error" variant="tonal" @click="confirmClearIndexedDB">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="tonal"
|
||||||
|
@click="confirmClearIndexedDB"
|
||||||
|
>
|
||||||
清除
|
清除
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-database-export"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-database-export"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>导出数据库</v-list-item-title>
|
<v-list-item-title>导出数据库</v-list-item-title>
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-btn variant="tonal" @click="exportData"> 导出</v-btn>
|
<v-btn
|
||||||
|
variant="tonal"
|
||||||
|
@click="exportData"
|
||||||
|
>
|
||||||
|
导出
|
||||||
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-lan-connect"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-lan-connect"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>查看本地缓存</v-list-item-title>
|
<v-list-item-title>查看本地缓存</v-list-item-title>
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-btn to="/cachemanagement" variant="tonal"> 查看</v-btn>
|
<v-btn
|
||||||
|
to="/cachemanagement"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
查看
|
||||||
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
|
|
||||||
<!-- 确认对话框 -->
|
<!-- 确认对话框 -->
|
||||||
<v-dialog v-model="confirmDialog" max-width="400">
|
<v-dialog
|
||||||
|
v-model="confirmDialog"
|
||||||
|
max-width="400"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title>{{ confirmTitle }}</v-card-title>
|
<v-card-title>{{ confirmTitle }}</v-card-title>
|
||||||
<v-card-text>{{ confirmMessage }}</v-card-text>
|
<v-card-text>{{ confirmMessage }}</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="grey" variant="text" @click="confirmDialog = false"
|
<v-btn
|
||||||
>取消
|
color="grey"
|
||||||
</v-btn
|
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-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|||||||
@ -1,39 +1,42 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card border icon="mdi-monitor" title="显示设置">
|
<settings-card
|
||||||
|
border
|
||||||
|
icon="mdi-monitor"
|
||||||
|
title="显示设置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<setting-item :setting-key="'display.emptySubjectDisplay'"/>
|
<setting-item :setting-key="'display.emptySubjectDisplay'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.dynamicSort'"/>
|
<setting-item :setting-key="'display.dynamicSort'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.showRandomButton'"/>
|
<setting-item :setting-key="'display.showRandomButton'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.showFullscreenButton'"/>
|
<setting-item :setting-key="'display.showFullscreenButton'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.cardHoverEffect'"/>
|
<setting-item :setting-key="'display.cardHoverEffect'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.enhancedTouchMode'"/>
|
<setting-item :setting-key="'display.enhancedTouchMode'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.showQuickTools'"/>
|
<setting-item :setting-key="'display.showQuickTools'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.showAntiScreenBurnCard'"/>
|
<setting-item :setting-key="'display.showAntiScreenBurnCard'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.showExamScheduleButton'"/>
|
<setting-item :setting-key="'display.showExamScheduleButton'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'display.forceDesktopMode'"/>
|
<setting-item :setting-key="'display.forceDesktopMode'" />
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
|
||||||
<setting-item :setting-key="'display.lateStudentsArePresent'"/>
|
|
||||||
|
|
||||||
|
<v-divider class="my-2" />
|
||||||
|
<setting-item :setting-key="'display.lateStudentsArePresent'" />
|
||||||
</v-list>
|
</v-list>
|
||||||
</settings-card>
|
</settings-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -6,13 +6,22 @@
|
|||||||
@click="handleClick"
|
@click="handleClick"
|
||||||
>
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div ref="typewriter" class="typewriter-text"></div>
|
<div
|
||||||
<div ref="sourceWriter" class="source-text"></div>
|
ref="typewriter"
|
||||||
|
class="typewriter-text"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
ref="sourceWriter"
|
||||||
|
class="source-text"
|
||||||
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<v-chip v-if="currentQuote?.contributor" class="contributor">
|
<v-chip
|
||||||
|
v-if="currentQuote?.contributor"
|
||||||
|
class="contributor"
|
||||||
|
>
|
||||||
<v-avatar start>
|
<v-avatar start>
|
||||||
<v-img :src="`https://github.com/${currentQuote.contributor}.png`"/>
|
<v-img :src="`https://github.com/${currentQuote.contributor}.png`" />
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
{{ currentQuote.contributor }}
|
{{ currentQuote.contributor }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
@ -49,6 +58,10 @@ export default {
|
|||||||
this.initTypewriters();
|
this.initTypewriters();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
beforeUnmount() {
|
||||||
|
[this.typewriter, this.sourceWriter].forEach(writer => writer?.stop());
|
||||||
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
initTypewriters() {
|
initTypewriters() {
|
||||||
this.typewriter = new Typewriter(this.$refs.typewriter, TYPEWRITER_CONFIG.main);
|
this.typewriter = new Typewriter(this.$refs.typewriter, TYPEWRITER_CONFIG.main);
|
||||||
@ -93,10 +106,6 @@ export default {
|
|||||||
console.error("复制失败:", err);
|
console.error("复制失败:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
beforeUnmount() {
|
|
||||||
[this.typewriter, this.sourceWriter].forEach(writer => writer?.stop());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,28 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card icon="mdi-cog" title="编辑设置">
|
<settings-card
|
||||||
|
icon="mdi-cog"
|
||||||
|
title="编辑设置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<setting-item :setting-key="'edit.autoSave'"/>
|
<setting-item :setting-key="'edit.autoSave'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'edit.blockNonTodayAutoSave'"/>
|
<setting-item :setting-key="'edit.blockNonTodayAutoSave'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'edit.confirmNonTodaySave'"/>
|
<setting-item :setting-key="'edit.confirmNonTodaySave'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'edit.refreshBeforeEdit'"/>
|
<setting-item :setting-key="'edit.refreshBeforeEdit'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'edit.autoSavePromptText'"/>
|
<setting-item :setting-key="'edit.autoSavePromptText'" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item :setting-key="'edit.manualSavePromptText'"/>
|
<setting-item :setting-key="'edit.manualSavePromptText'" />
|
||||||
|
|
||||||
</v-list>
|
</v-list>
|
||||||
</settings-card>
|
</settings-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -48,8 +48,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
<setting-group border icon="mdi-book" title="科目配置">
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
|
<setting-group
|
||||||
|
border
|
||||||
|
icon="mdi-book"
|
||||||
|
title="科目配置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -63,8 +70,14 @@
|
|||||||
/>
|
/>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item v-for="subject in subjectList" :key="subject">
|
<v-list-item
|
||||||
<v-card border class="w-100 mb-2">
|
v-for="subject in subjectList"
|
||||||
|
:key="subject"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
border
|
||||||
|
class="w-100 mb-2"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="editedSubjects[subject]"
|
v-model="editedSubjects[subject]"
|
||||||
@ -74,7 +87,7 @@
|
|||||||
variant="plain"
|
variant="plain"
|
||||||
@blur="updateSubject(subject)"
|
@blur="updateSubject(subject)"
|
||||||
/>
|
/>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
icon="mdi-delete"
|
icon="mdi-delete"
|
||||||
@ -95,17 +108,24 @@
|
|||||||
@keyup.enter="() => addBookType(subject)"
|
@keyup.enter="() => addBookType(subject)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-list border density="compact" rounded>
|
<v-list
|
||||||
|
border
|
||||||
|
density="compact"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="(books, bookType) in config.subjects[subject].books"
|
v-for="(books, bookType) in config.subjects[subject].books"
|
||||||
:key="bookType"
|
:key="bookType"
|
||||||
:title="bookType"
|
:title="bookType"
|
||||||
@click="openSubjectBookDialog(subject, bookType, books)"
|
@click="openSubjectBookDialog(subject, bookType, books)"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-book-open-variant"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-book-open-variant"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-chip
|
<v-chip
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
color="info"
|
color="info"
|
||||||
@ -130,8 +150,15 @@
|
|||||||
</setting-group>
|
</setting-group>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
<setting-group border icon="mdi-cog" title="通用配置">
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
|
<setting-group
|
||||||
|
border
|
||||||
|
icon="mdi-cog"
|
||||||
|
title="通用配置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -146,17 +173,24 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-list border density="compact" rounded>
|
<v-list
|
||||||
|
border
|
||||||
|
density="compact"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="(books, bookType) in config.commonSubject.books"
|
v-for="(books, bookType) in config.commonSubject.books"
|
||||||
:key="bookType"
|
:key="bookType"
|
||||||
:title="bookType"
|
:title="bookType"
|
||||||
@click="openSubjectBookDialog('common', bookType, books)"
|
@click="openSubjectBookDialog('common', bookType, books)"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-book-multiple"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-book-multiple"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-chip
|
<v-chip
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
color="info"
|
color="info"
|
||||||
@ -176,7 +210,7 @@
|
|||||||
</v-list>
|
</v-list>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -191,14 +225,18 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-list border density="compact" rounded>
|
<v-list
|
||||||
|
border
|
||||||
|
density="compact"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="action in config.actions"
|
v-for="action in config.actions"
|
||||||
:key="action"
|
:key="action"
|
||||||
:title="action"
|
:title="action"
|
||||||
@click="openActionDialog(action)"
|
@click="openActionDialog(action)"
|
||||||
>
|
>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
icon="mdi-delete"
|
icon="mdi-delete"
|
||||||
@ -216,7 +254,10 @@
|
|||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<!-- 编辑弹框 -->
|
<!-- 编辑弹框 -->
|
||||||
<v-dialog v-model="dialog.show" max-width="600px">
|
<v-dialog
|
||||||
|
v-model="dialog.show"
|
||||||
|
max-width="600px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h5 pa-4">
|
<v-card-title class="text-h5 pa-4">
|
||||||
{{ dialog.title }}
|
{{ dialog.title }}
|
||||||
@ -235,22 +276,43 @@
|
|||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col v-if="dialog.editedItem.type === 'subjectBook'" cols="12">
|
<v-col
|
||||||
<div class="text-subtitle-2 mb-2">所属科目</div>
|
v-if="dialog.editedItem.type === 'subjectBook'"
|
||||||
<v-chip color="primary">{{ dialog.editedItem.subject }}</v-chip>
|
cols="12"
|
||||||
|
>
|
||||||
|
<div class="text-subtitle-2 mb-2">
|
||||||
|
所属科目
|
||||||
|
</div>
|
||||||
|
<v-chip color="primary">
|
||||||
|
{{ dialog.editedItem.subject }}
|
||||||
|
</v-chip>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)" cols="12">
|
<v-col
|
||||||
|
v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)"
|
||||||
|
cols="12"
|
||||||
|
>
|
||||||
<v-card variant="outlined">
|
<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-card-text class="pt-0">
|
||||||
<v-list border class="mb-2" density="compact" rounded>
|
<v-list
|
||||||
|
border
|
||||||
|
class="mb-2"
|
||||||
|
density="compact"
|
||||||
|
rounded
|
||||||
|
>
|
||||||
<v-list-item
|
<v-list-item
|
||||||
v-for="(task, index) in dialog.editedItem.tasks"
|
v-for="(task, index) in dialog.editedItem.tasks"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-2" icon="mdi-checkbox-blank-circle-outline" size="small"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-checkbox-blank-circle-outline"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="dialog.editedItem.tasks[index]"
|
v-model="dialog.editedItem.tasks[index]"
|
||||||
@ -258,7 +320,7 @@
|
|||||||
hide-details
|
hide-details
|
||||||
variant="plain"
|
variant="plain"
|
||||||
/>
|
/>
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
icon="mdi-delete"
|
icon="mdi-delete"
|
||||||
@ -287,7 +349,7 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions class="pa-4">
|
<v-card-actions class="pa-4">
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="elevated"
|
variant="elevated"
|
||||||
|
|||||||
@ -1,40 +1,67 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card :loading="loading" icon="mdi-database-edit" title="KV数据库管理">
|
<settings-card
|
||||||
|
:loading="loading"
|
||||||
|
icon="mdi-database-edit"
|
||||||
|
title="KV数据库管理"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<!-- 数据库连接状态 -->
|
<!-- 数据库连接状态 -->
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon :color="connectionColor" :icon="connectionIcon" class="mr-3"/>
|
<v-icon
|
||||||
|
:color="connectionColor"
|
||||||
|
:icon="connectionIcon"
|
||||||
|
class="mr-3"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>数据库状态</v-list-item-title>
|
<v-list-item-title>数据库状态</v-list-item-title>
|
||||||
<v-list-item-subtitle>{{ connectionStatus }}</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ connectionStatus }}</v-list-item-subtitle>
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-btn :loading="loading" variant="tonal" @click="refreshConnection">
|
<v-btn
|
||||||
|
:loading="loading"
|
||||||
|
variant="tonal"
|
||||||
|
@click="refreshConnection"
|
||||||
|
>
|
||||||
刷新
|
刷新
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
|
|
||||||
<!-- 数据列表 -->
|
<!-- 数据列表 -->
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-format-list-bulleted"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-format-list-bulleted"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>数据条目</v-list-item-title>
|
<v-list-item-title>数据条目</v-list-item-title>
|
||||||
<v-list-item-subtitle>共 {{ kvData.length }} 条记录</v-list-item-subtitle>
|
<v-list-item-subtitle>共 {{ kvData.length }} 条记录</v-list-item-subtitle>
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-btn-group variant="tonal">
|
<v-btn-group variant="tonal">
|
||||||
<v-btn :loading="loadingData" @click="loadKvData">
|
<v-btn
|
||||||
|
:loading="loadingData"
|
||||||
|
@click="loadKvData"
|
||||||
|
>
|
||||||
加载数据
|
加载数据
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn :disabled="!isKvProvider" @click="createNewItem">
|
<v-btn
|
||||||
<v-icon class="mr-1" icon="mdi-plus"/>
|
:disabled="!isKvProvider"
|
||||||
|
@click="createNewItem"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
icon="mdi-plus"
|
||||||
|
/>
|
||||||
新建
|
新建
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn @click="showMigrationDialog = true">
|
<v-btn @click="showMigrationDialog = true">
|
||||||
<v-icon class="mr-1" icon="mdi-cloud-upload"/>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
icon="mdi-cloud-upload"
|
||||||
|
/>
|
||||||
从本地迁移
|
从本地迁移
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
@ -43,11 +70,18 @@
|
|||||||
</v-list>
|
</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-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-table"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-table"
|
||||||
|
/>
|
||||||
KV数据列表
|
KV数据列表
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="searchQuery"
|
v-model="searchQuery"
|
||||||
clearable
|
clearable
|
||||||
@ -73,7 +107,10 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #[`item.actions`]="{ item }">
|
<template #[`item.actions`]="{ item }">
|
||||||
<v-btn-group density="compact" variant="text">
|
<v-btn-group
|
||||||
|
density="compact"
|
||||||
|
variant="text"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
icon="mdi-eye"
|
icon="mdi-eye"
|
||||||
size="small"
|
size="small"
|
||||||
@ -106,13 +143,23 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 查看数据对话框 -->
|
<!-- 查看数据对话框 -->
|
||||||
<v-dialog v-model="viewDialog" max-width="800px">
|
<v-dialog
|
||||||
|
v-model="viewDialog"
|
||||||
|
max-width="800px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-eye"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-eye"
|
||||||
|
/>
|
||||||
查看数据
|
查看数据
|
||||||
<v-spacer/>
|
<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-title>
|
||||||
|
|
||||||
<v-card-subtitle v-if="selectedItem">
|
<v-card-subtitle v-if="selectedItem">
|
||||||
@ -132,12 +179,21 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn variant="tonal" @click="copyToClipboard(selectedItem?.value)">
|
<v-btn
|
||||||
<v-icon class="mr-1" icon="mdi-content-copy"/>
|
variant="tonal"
|
||||||
|
@click="copyToClipboard(selectedItem?.value)"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
icon="mdi-content-copy"
|
||||||
|
/>
|
||||||
复制数据
|
复制数据
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn variant="text" @click="viewDialog = false">
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="viewDialog = false"
|
||||||
|
>
|
||||||
关闭
|
关闭
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
@ -145,13 +201,23 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 编辑数据对话框 -->
|
<!-- 编辑数据对话框 -->
|
||||||
<v-dialog v-model="editDialog" max-width="800px">
|
<v-dialog
|
||||||
|
v-model="editDialog"
|
||||||
|
max-width="800px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-pencil"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-pencil"
|
||||||
|
/>
|
||||||
编辑数据
|
编辑数据
|
||||||
<v-spacer/>
|
<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-title>
|
||||||
|
|
||||||
<v-card-subtitle v-if="editingItem">
|
<v-card-subtitle v-if="editingItem">
|
||||||
@ -171,8 +237,11 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="closeEditDialog">
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="closeEditDialog"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -189,13 +258,23 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 新建数据对话框 -->
|
<!-- 新建数据对话框 -->
|
||||||
<v-dialog v-model="createDialog" max-width="800px">
|
<v-dialog
|
||||||
|
v-model="createDialog"
|
||||||
|
max-width="800px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-plus"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-plus"
|
||||||
|
/>
|
||||||
新建数据
|
新建数据
|
||||||
<v-spacer/>
|
<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-title>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -215,15 +294,18 @@
|
|||||||
:error-messages="isValidNewJson ? [] : ['请输入有效的JSON格式']"
|
:error-messages="isValidNewJson ? [] : ['请输入有效的JSON格式']"
|
||||||
class="font-monospace"
|
class="font-monospace"
|
||||||
label="数据内容 (JSON格式)"
|
label="数据内容 (JSON格式)"
|
||||||
placeholder='请输入JSON数据,如:{"name": "value"}'
|
placeholder="请输入JSON数据,如:{"name": "value"}"
|
||||||
rows="15"
|
rows="15"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="closeCreateDialog">
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="closeCreateDialog"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -240,13 +322,23 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 云端地址对话框 -->
|
<!-- 云端地址对话框 -->
|
||||||
<v-dialog v-model="cloudUrlDialog" max-width="800px">
|
<v-dialog
|
||||||
|
v-model="cloudUrlDialog"
|
||||||
|
max-width="800px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-cloud-download"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-cloud-download"
|
||||||
|
/>
|
||||||
获取云端访问地址
|
获取云端访问地址
|
||||||
<v-spacer/>
|
<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-title>
|
||||||
|
|
||||||
<v-card-subtitle v-if="selectedCloudItem">
|
<v-card-subtitle v-if="selectedCloudItem">
|
||||||
@ -254,19 +346,43 @@
|
|||||||
</v-card-subtitle>
|
</v-card-subtitle>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-alert v-if="cloudUrlError" class="mb-4" type="error" variant="tonal">
|
<v-alert
|
||||||
|
v-if="cloudUrlError"
|
||||||
|
class="mb-4"
|
||||||
|
type="error"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
{{ cloudUrlError }}
|
{{ cloudUrlError }}
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<v-alert v-if="cloudUrlResult && cloudUrlResult.success" class="mb-4" type="success" variant="tonal">
|
<v-alert
|
||||||
|
v-if="cloudUrlResult && cloudUrlResult.success"
|
||||||
|
class="mb-4"
|
||||||
|
type="success"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-alert-title>云端地址获取成功</v-alert-title>
|
<v-alert-title>云端地址获取成功</v-alert-title>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<div v-if="cloudUrlResult.migrated" class="mb-2">
|
<div
|
||||||
<v-icon class="mr-1" color="success" icon="mdi-database-arrow-up"/>
|
v-if="cloudUrlResult.migrated"
|
||||||
|
class="mb-2"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
color="success"
|
||||||
|
icon="mdi-database-arrow-up"
|
||||||
|
/>
|
||||||
数据已从本地迁移到云端
|
数据已从本地迁移到云端
|
||||||
</div>
|
</div>
|
||||||
<div v-if="cloudUrlResult.configured" class="mb-2">
|
<div
|
||||||
<v-icon class="mr-1" color="info" icon="mdi-cog"/>
|
v-if="cloudUrlResult.configured"
|
||||||
|
class="mb-2"
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
color="info"
|
||||||
|
icon="mdi-cog"
|
||||||
|
/>
|
||||||
云端配置已自动设置
|
云端配置已自动设置
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -283,10 +399,16 @@
|
|||||||
@click:append-inner="copyCloudUrl"
|
@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>
|
||||||
<v-expansion-panel-title>
|
<v-expansion-panel-title>
|
||||||
<v-icon class="mr-2" icon="mdi-cog"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-cog"
|
||||||
|
/>
|
||||||
高级选项
|
高级选项
|
||||||
</v-expansion-panel-title>
|
</v-expansion-panel-title>
|
||||||
<v-expansion-panel-text>
|
<v-expansion-panel-text>
|
||||||
@ -307,7 +429,10 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click="refreshCloudUrl"
|
@click="refreshCloudUrl"
|
||||||
>
|
>
|
||||||
<v-icon class="mr-1" icon="mdi-refresh"/>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
icon="mdi-refresh"
|
||||||
|
/>
|
||||||
重新获取
|
重新获取
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-expansion-panel-text>
|
</v-expansion-panel-text>
|
||||||
@ -316,8 +441,11 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="cloudUrlDialog = false">
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="cloudUrlDialog = false"
|
||||||
|
>
|
||||||
关闭
|
关闭
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -326,7 +454,10 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
@click="openCloudUrl"
|
@click="openCloudUrl"
|
||||||
>
|
>
|
||||||
<v-icon class="mr-1" icon="mdi-open-in-new"/>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
icon="mdi-open-in-new"
|
||||||
|
/>
|
||||||
在新窗口打开
|
在新窗口打开
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
@ -334,24 +465,37 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 删除确认对话框 -->
|
<!-- 删除确认对话框 -->
|
||||||
<v-dialog v-model="deleteDialog" max-width="400px">
|
<v-dialog
|
||||||
|
v-model="deleteDialog"
|
||||||
|
max-width="400px"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center text-error">
|
<v-card-title class="d-flex align-center text-error">
|
||||||
<v-icon class="mr-2" icon="mdi-alert"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-alert"
|
||||||
|
/>
|
||||||
确认删除
|
确认删除
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
确定要删除键名为 <code>{{ itemToDelete?.key }}</code> 的数据吗?
|
确定要删除键名为 <code>{{ itemToDelete?.key }}</code> 的数据吗?
|
||||||
<br><br>
|
<br><br>
|
||||||
<v-alert class="mt-2" type="warning" variant="tonal">
|
<v-alert
|
||||||
|
class="mt-2"
|
||||||
|
type="warning"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
此操作不可撤销,请谨慎操作!
|
此操作不可撤销,请谨慎操作!
|
||||||
</v-alert>
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn variant="text" @click="deleteDialog = false">
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="deleteDialog = false"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
|||||||
@ -1,22 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card icon="mdi-cog" title="编辑设置">
|
<settings-card
|
||||||
|
icon="mdi-cog"
|
||||||
|
title="编辑设置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<setting-item setting-key="randomPicker.enabled"/>
|
<setting-item setting-key="randomPicker.enabled" />
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
|
|
||||||
<setting-item setting-key="randomPicker.mode"/>
|
<setting-item setting-key="randomPicker.mode" />
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item setting-key="randomPicker.minNumber"/>
|
<setting-item setting-key="randomPicker.minNumber" />
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item setting-key="randomPicker.maxNumber"/>
|
<setting-item setting-key="randomPicker.maxNumber" />
|
||||||
<v-divider class="my-2"/>
|
<v-divider class="my-2" />
|
||||||
<setting-item setting-key="randomPicker.defaultCount"/>
|
<setting-item setting-key="randomPicker.defaultCount" />
|
||||||
|
|
||||||
|
|
||||||
<v-divider class="my-2"/>
|
|
||||||
<setting-item setting-key="randomPicker.animation"/>
|
|
||||||
|
|
||||||
|
|
||||||
|
<v-divider class="my-2" />
|
||||||
|
<setting-item setting-key="randomPicker.animation" />
|
||||||
</v-list>
|
</v-list>
|
||||||
</settings-card>
|
</settings-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,13 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card icon="mdi-refresh-circle" title="刷新设置">
|
<settings-card
|
||||||
|
icon="mdi-refresh-circle"
|
||||||
|
title="刷新设置"
|
||||||
|
>
|
||||||
<v-form>
|
<v-form>
|
||||||
<v-list>
|
<v-list>
|
||||||
<setting-item setting-key="refresh.auto" title="自动刷新"/>
|
<setting-item
|
||||||
<v-divider class="my-2"/>
|
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-list>
|
||||||
|
|
||||||
</v-form>
|
</v-form>
|
||||||
</settings-card>
|
</settings-card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -58,10 +58,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 添加新科目 -->
|
<!-- 添加新科目 -->
|
||||||
<v-card class="mb-4" variant="outlined">
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" sm="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newSubjectName"
|
v-model="newSubjectName"
|
||||||
:rules="[v => !!v || '科目名称不能为空']"
|
:rules="[v => !!v || '科目名称不能为空']"
|
||||||
@ -85,7 +91,7 @@
|
|||||||
v-for="(subject, index) in subjects"
|
v-for="(subject, index) in subjects"
|
||||||
:key="subject.order"
|
:key="subject.order"
|
||||||
>
|
>
|
||||||
<template v-slot:prepend>
|
<template #prepend>
|
||||||
<div class="d-flex flex-column align-center mr-2">
|
<div class="d-flex flex-column align-center mr-2">
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="index === 0"
|
:disabled="index === 0"
|
||||||
@ -114,7 +120,7 @@
|
|||||||
/>
|
/>
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
|
|
||||||
<template v-slot:append>
|
<template #append>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
icon="mdi-delete"
|
icon="mdi-delete"
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<settings-card icon="mdi-palette" title="主题设置">
|
<settings-card
|
||||||
|
icon="mdi-palette"
|
||||||
|
title="主题设置"
|
||||||
|
>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-theme-light-dark"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-theme-light-dark"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>主题模式</v-list-item-title>
|
<v-list-item-title>主题模式</v-list-item-title>
|
||||||
<v-list-item-subtitle>选择明亮或暗黑主题</v-list-item-subtitle>
|
<v-list-item-subtitle>选择明亮或暗黑主题</v-list-item-subtitle>
|
||||||
@ -14,11 +20,17 @@
|
|||||||
density="comfortable"
|
density="comfortable"
|
||||||
>
|
>
|
||||||
<v-btn value="light">
|
<v-btn value="light">
|
||||||
<v-icon class="mr-2" icon="mdi-white-balance-sunny"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-white-balance-sunny"
|
||||||
|
/>
|
||||||
明亮
|
明亮
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn value="dark">
|
<v-btn value="dark">
|
||||||
<v-icon class="mr-2" icon="mdi-moon-waning-crescent"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-moon-waning-crescent"
|
||||||
|
/>
|
||||||
暗黑
|
暗黑
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle>
|
||||||
@ -37,6 +49,11 @@ export default {
|
|||||||
name: 'ThemeSettingsCard',
|
name: 'ThemeSettingsCard',
|
||||||
components: {SettingsCard},
|
components: {SettingsCard},
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const theme = useTheme();
|
||||||
|
return {theme};
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
localTheme: getSetting('theme.mode')
|
localTheme: getSetting('theme.mode')
|
||||||
@ -50,11 +67,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setup() {
|
|
||||||
const theme = useTheme();
|
|
||||||
return {theme};
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
updateTheme(mode) {
|
updateTheme(mode) {
|
||||||
this.theme.global.name.value = mode;
|
this.theme.global.name.value = mode;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-app>
|
<v-app>
|
||||||
<v-main>
|
<v-main>
|
||||||
<router-view/>
|
<router-view />
|
||||||
</v-main>
|
</v-main>
|
||||||
</v-app>
|
</v-app>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<error404/>
|
<error404 />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|||||||
@ -3,39 +3,82 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<div class="d-flex align-center mb-6">
|
<div class="d-flex align-center mb-6">
|
||||||
<v-icon class="mr-3" color="primary" size="x-large">mdi-database-cog-outline</v-icon>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
color="primary"
|
||||||
|
size="x-large"
|
||||||
|
>
|
||||||
|
mdi-database-cog-outline
|
||||||
|
</v-icon>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-h4 ">缓存管理</h1>
|
<h1 class="text-h4 ">
|
||||||
<div class="text-subtitle-1 text-grey">管理应用的本地缓存资源</div>
|
缓存管理
|
||||||
|
</h1>
|
||||||
|
<div class="text-subtitle-1 text-grey">
|
||||||
|
管理应用的本地缓存资源
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card class="mb-6" color="info" density="compact" variant="tonal">
|
<v-card
|
||||||
|
class="mb-6"
|
||||||
|
color="info"
|
||||||
|
density="compact"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-text class="d-flex align-center">
|
<v-card-text class="d-flex align-center">
|
||||||
<v-icon class="mr-2" color="info">mdi-information-outline</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="info"
|
||||||
|
>
|
||||||
|
mdi-information-outline
|
||||||
|
</v-icon>
|
||||||
<span>在这里您可以查看和管理应用的缓存文件。清除缓存可能会导致应用需要重新下载资源,但有助于解决某些显示问题。</span>
|
<span>在这里您可以查看和管理应用的缓存文件。清除缓存可能会导致应用需要重新下载资源,但有助于解决某些显示问题。</span>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="8">
|
<v-col
|
||||||
<v-card class="mb-4" variant="tonal">
|
cols="12"
|
||||||
|
md="8"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon class="mr-2" color="primary">mdi-information</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
mdi-information
|
||||||
|
</v-icon>
|
||||||
<span class="text-h6">什么是缓存?</span>
|
<span class="text-h6">什么是缓存?</span>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
缓存是浏览器在本地存储的网站资源副本,如图片、脚本和样式表等。这些缓存可以加快页面加载速度,减少数据使用,并在离线时提供基本功能。</p>
|
缓存是浏览器在本地存储的网站资源副本,如图片、脚本和样式表等。这些缓存可以加快页面加载速度,减少数据使用,并在离线时提供基本功能。
|
||||||
|
</p>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
<v-card class="mb-4" variant="tonal">
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
class="mb-4"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="d-flex align-center mb-2">
|
<div class="d-flex align-center mb-2">
|
||||||
<v-icon class="mr-2" color="warning">mdi-lightbulb-outline</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="warning"
|
||||||
|
>
|
||||||
|
mdi-lightbulb-outline
|
||||||
|
</v-icon>
|
||||||
<span class="text-h6">何时清除缓存?</span>
|
<span class="text-h6">何时清除缓存?</span>
|
||||||
</div>
|
</div>
|
||||||
<ul class="pl-4">
|
<ul class="pl-4">
|
||||||
@ -48,7 +91,7 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<CacheManager/>
|
<CacheManager />
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|||||||
@ -1,7 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container class="fill-height" fluid>
|
<v-container
|
||||||
<v-row align="center" justify="center">
|
class="fill-height"
|
||||||
<v-col cols="12" md="6" sm="8">
|
fluid
|
||||||
|
>
|
||||||
|
<v-row
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
sm="8"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h5">
|
<v-card-title class="text-h5">
|
||||||
{{ status === 'processing' ? '正在处理授权...' : status === 'success' ? '授权成功' : '授权失败' }}
|
{{ status === 'processing' ? '正在处理授权...' : status === 'success' ? '授权成功' : '授权失败' }}
|
||||||
@ -12,12 +22,17 @@
|
|||||||
class="mb-4"
|
class="mb-4"
|
||||||
color="primary"
|
color="primary"
|
||||||
indeterminate
|
indeterminate
|
||||||
></v-progress-linear>
|
/>
|
||||||
<p>{{ message }}</p>
|
<p>{{ message }}</p>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions v-if="status !== 'processing'">
|
<v-card-actions v-if="status !== 'processing'">
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" @click="goToHome">返回首页</v-btn>
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="goToHome"
|
||||||
|
>
|
||||||
|
返回首页
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|||||||
@ -2,9 +2,17 @@
|
|||||||
<v-container class="fill-height">
|
<v-container class="fill-height">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<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-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-title>
|
||||||
<v-card-subtitle>
|
<v-card-subtitle>
|
||||||
@ -22,7 +30,9 @@
|
|||||||
@click:close="error = ''"
|
@click:close="error = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -38,38 +48,75 @@
|
|||||||
@click:close="success = ''"
|
@click:close="success = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ success }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
|
|
||||||
<!-- 输入方式选择 -->
|
<!-- 输入方式选择 -->
|
||||||
<v-tabs v-model="activeTab" class="mb-4 mx-2" color="primary" rounded>
|
<v-tabs
|
||||||
<v-tab value="text" class="px-5">
|
v-model="activeTab"
|
||||||
<v-icon start>mdi-text-box</v-icon>
|
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>
|
||||||
<v-tab value="file" class="px-5">
|
<v-tab
|
||||||
<v-icon start>mdi-file-upload</v-icon>
|
value="file"
|
||||||
|
class="px-5"
|
||||||
|
>
|
||||||
|
<v-icon start>
|
||||||
|
mdi-file-upload
|
||||||
|
</v-icon>
|
||||||
文件上传
|
文件上传
|
||||||
</v-tab>
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
<!-- 格式选择 -->
|
<!-- 格式选择 -->
|
||||||
<v-btn-toggle v-model="formatMode" color="primary" class="mb-4 mx-2" mandatory density="comfortable" border
|
<v-btn-toggle
|
||||||
rounded>
|
v-model="formatMode"
|
||||||
<v-btn value="auto">自动检测</v-btn>
|
color="primary"
|
||||||
<v-btn value="json">JSON</v-btn>
|
class="mb-4 mx-2"
|
||||||
<v-btn value="yaml" :disabled="!yamlLibLoaded">
|
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
|
YAML
|
||||||
<v-tooltip activator="parent" location="bottom">
|
<v-tooltip
|
||||||
|
activator="parent"
|
||||||
|
location="bottom"
|
||||||
|
>
|
||||||
{{ yamlLibLoaded ? 'YAML解析库已加载' : '正在加载YAML解析库...' }}
|
{{ yamlLibLoaded ? 'YAML解析库已加载' : '正在加载YAML解析库...' }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</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' }}
|
检测到的格式: {{ isYaml(jsonText) ? 'YAML' : 'JSON' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -85,7 +132,7 @@
|
|||||||
rows="6"
|
rows="6"
|
||||||
placeholder="请在此粘贴CSES格式的数据..."
|
placeholder="请在此粘贴CSES格式的数据..."
|
||||||
@input="handleTextChange"
|
@input="handleTextChange"
|
||||||
></v-textarea>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</v-window-item>
|
</v-window-item>
|
||||||
<v-window-item value="file">
|
<v-window-item value="file">
|
||||||
@ -96,13 +143,13 @@
|
|||||||
prepend-icon="mdi-file-upload"
|
prepend-icon="mdi-file-upload"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:disabled="loading"
|
:disabled="loading"
|
||||||
@change="handleFileChange"
|
|
||||||
hint="支持JSON、YAML格式文件"
|
hint="支持JSON、YAML格式文件"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
:rules="[
|
:rules="[
|
||||||
v => !v || v.size < 2000000 || '文件大小不能超过 2 MB',
|
v => !v || v.size < 2000000 || '文件大小不能超过 2 MB',
|
||||||
]"
|
]"
|
||||||
></v-file-input>
|
@change="handleFileChange"
|
||||||
|
/>
|
||||||
|
|
||||||
<v-alert
|
<v-alert
|
||||||
v-if="file && formatMode === 'auto'"
|
v-if="file && formatMode === 'auto'"
|
||||||
@ -118,17 +165,33 @@
|
|||||||
|
|
||||||
<!-- 设置面板 -->
|
<!-- 设置面板 -->
|
||||||
<v-col cols="12">
|
<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">
|
<div class="d-flex align-center mb-3">
|
||||||
<v-icon color="primary" class="mr-2">mdi-calendar-multiselect</v-icon>
|
<v-icon
|
||||||
<h3 class="text-subtitle-1 font-weight-medium mr-auto">选择导出天数</h3>
|
color="primary"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
mdi-calendar-multiselect
|
||||||
|
</v-icon>
|
||||||
|
<h3 class="text-subtitle-1 font-weight-medium mr-auto">
|
||||||
|
选择导出天数
|
||||||
|
</h3>
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
variant="text"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
@click="selectAllDays"
|
@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>
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -137,19 +200,37 @@
|
|||||||
class="ml-2"
|
class="ml-2"
|
||||||
@click="clearSelectedDays"
|
@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>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<v-chip-group v-model="selectedDays" multiple class="mb-2" color="primary">
|
<v-chip-group
|
||||||
<v-chip v-for="day in 7" :key="day" :value="day" filter variant="tonal" class="filter-chip" label>
|
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] }}
|
{{ dayNames[day] }}
|
||||||
<v-badge
|
<v-badge
|
||||||
v-if="getDaySchedule(day).length > 0"
|
v-if="getDaySchedule(day).length > 0"
|
||||||
:content="getDaySchedule(day).length"
|
:content="getDaySchedule(day).length"
|
||||||
color="primary"
|
color="primary"
|
||||||
inline
|
inline
|
||||||
></v-badge>
|
/>
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-chip-group>
|
</v-chip-group>
|
||||||
</v-card>
|
</v-card>
|
||||||
@ -157,31 +238,51 @@
|
|||||||
|
|
||||||
<!-- 改进设置选项卡,显示为开关组 -->
|
<!-- 改进设置选项卡,显示为开关组 -->
|
||||||
<v-col cols="12">
|
<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">
|
<div class="d-flex align-center mb-3">
|
||||||
<v-icon color="primary" class="mr-2">mdi-cog</v-icon>
|
<v-icon
|
||||||
<h3 class="text-subtitle-1 font-weight-medium">显示配置</h3>
|
color="primary"
|
||||||
|
class="mr-2"
|
||||||
|
>
|
||||||
|
mdi-cog
|
||||||
|
</v-icon>
|
||||||
|
<h3 class="text-subtitle-1 font-weight-medium">
|
||||||
|
显示配置
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" sm="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="settings.hideTeacherName"
|
v-model="settings.hideTeacherName"
|
||||||
label="不显示教师姓名"
|
label="不显示教师姓名"
|
||||||
color="primary"
|
color="primary"
|
||||||
inset
|
inset
|
||||||
hide-details
|
hide-details
|
||||||
></v-switch>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" sm="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="settings.hideRoom"
|
v-model="settings.hideRoom"
|
||||||
label="不显示教室信息"
|
label="不显示教室信息"
|
||||||
color="primary"
|
color="primary"
|
||||||
inset
|
inset
|
||||||
hide-details
|
hide-details
|
||||||
></v-switch>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" sm="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
sm="6"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model.number="settings.totalWeeks"
|
v-model.number="settings.totalWeeks"
|
||||||
label="总周数"
|
label="总周数"
|
||||||
@ -193,19 +294,23 @@
|
|||||||
variant="outlined"
|
variant="outlined"
|
||||||
prepend-inner-icon="mdi-calendar-week"
|
prepend-inner-icon="mdi-calendar-week"
|
||||||
class="mt-3"
|
class="mt-3"
|
||||||
></v-text-field>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 添加加载状态的骨架屏 -->
|
<!-- 添加加载状态的骨架屏 -->
|
||||||
<v-card v-if="loading" class="my-4" outlined>
|
<v-card
|
||||||
|
v-if="loading"
|
||||||
|
class="my-4"
|
||||||
|
outlined
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-skeleton-loader
|
<v-skeleton-loader
|
||||||
type="table"
|
type="table"
|
||||||
class="mx-auto"
|
class="mx-auto"
|
||||||
></v-skeleton-loader>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
@ -230,12 +335,31 @@
|
|||||||
</v-alert>
|
</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-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>
|
<span class="font-weight-bold">课程表</span>
|
||||||
<v-chip color="primary" class="ml-3" size="small" pill>
|
<v-chip
|
||||||
<v-icon start size="x-small">mdi-book-open-variant</v-icon>
|
color="primary"
|
||||||
|
class="ml-3"
|
||||||
|
size="small"
|
||||||
|
pill
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
start
|
||||||
|
size="x-small"
|
||||||
|
>
|
||||||
|
mdi-book-open-variant
|
||||||
|
</v-icon>
|
||||||
{{ processedData.tableData.length }} 节课程
|
{{ processedData.tableData.length }} 节课程
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
@ -263,8 +387,15 @@
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-for="day in 7" #[`item.${day}`]="{ item }" :key="day">
|
<template
|
||||||
<div v-if="item[day]" class="course-cell">
|
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])">
|
<template v-if="Array.isArray(item[day])">
|
||||||
<div
|
<div
|
||||||
v-for="(course, index) in item[day]"
|
v-for="(course, index) in item[day]"
|
||||||
@ -275,12 +406,12 @@
|
|||||||
<span
|
<span
|
||||||
v-if="!settings.hideTeacherName && course.teacher"
|
v-if="!settings.hideTeacherName && course.teacher"
|
||||||
>
|
>
|
||||||
<br/>{{ course.teacher }}
|
<br>{{ course.teacher }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="!settings.hideRoom && course.room"
|
v-if="!settings.hideRoom && course.room"
|
||||||
>
|
>
|
||||||
<br/>{{ course.room }}
|
<br>{{ course.room }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="course.weekType"
|
v-if="course.weekType"
|
||||||
@ -295,12 +426,12 @@
|
|||||||
<span
|
<span
|
||||||
v-if="!settings.hideTeacherName && item[day].teacher"
|
v-if="!settings.hideTeacherName && item[day].teacher"
|
||||||
>
|
>
|
||||||
<br/>{{ item[day].teacher }}
|
<br>{{ item[day].teacher }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="!settings.hideRoom && item[day].room"
|
v-if="!settings.hideRoom && item[day].room"
|
||||||
>
|
>
|
||||||
<br/>{{ item[day].room }}
|
<br>{{ item[day].room }}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
v-if="item[day].weekType"
|
v-if="item[day].weekType"
|
||||||
@ -316,18 +447,48 @@
|
|||||||
</v-card>
|
</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-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>
|
<span class="font-weight-bold">每日课程时间表</span>
|
||||||
<v-chip class="ml-3" size="small" color="primary" pill>
|
<v-chip
|
||||||
<v-icon start size="x-small">mdi-clock-outline</v-icon>
|
class="ml-3"
|
||||||
|
size="small"
|
||||||
|
color="primary"
|
||||||
|
pill
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
start
|
||||||
|
size="x-small"
|
||||||
|
>
|
||||||
|
mdi-clock-outline
|
||||||
|
</v-icon>
|
||||||
{{ totalClassHours }} 课时
|
{{ totalClassHours }} 课时
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-tooltip v-if="exportPeriods.length > 0">
|
<v-tooltip v-if="exportPeriods.length > 0">
|
||||||
<template v-slot:activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-chip class="ml-2" size="small" color="info" v-bind="props" pill>
|
<v-chip
|
||||||
<v-icon start size="x-small">mdi-information-outline</v-icon>
|
class="ml-2"
|
||||||
|
size="small"
|
||||||
|
color="info"
|
||||||
|
v-bind="props"
|
||||||
|
pill
|
||||||
|
>
|
||||||
|
<v-icon
|
||||||
|
start
|
||||||
|
size="x-small"
|
||||||
|
>
|
||||||
|
mdi-information-outline
|
||||||
|
</v-icon>
|
||||||
节次已重排
|
节次已重排
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</template>
|
</template>
|
||||||
@ -336,25 +497,47 @@
|
|||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<!-- 美化日期导航标签 -->
|
<!-- 美化日期导航标签 -->
|
||||||
<v-tabs v-if="daysWithSchedule.length > 0" v-model="activeDay" class="mb-4" color="primary" grow
|
<v-tabs
|
||||||
align-tabs="center">
|
v-if="daysWithSchedule.length > 0"
|
||||||
<v-tab v-for="day in daysWithSchedule" :key="day" :value="day" class="px-2 font-weight-medium">
|
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] }}
|
{{ dayNames[day] }}
|
||||||
<v-badge
|
<v-badge
|
||||||
:content="getDaySchedule(day).length"
|
:content="getDaySchedule(day).length"
|
||||||
color="primary"
|
color="primary"
|
||||||
inline
|
inline
|
||||||
></v-badge>
|
/>
|
||||||
</v-tab>
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
|
||||||
<!-- 当前选中日期的课程表 -->
|
<!-- 当前选中日期的课程表 -->
|
||||||
<v-window v-model="activeDay">
|
<v-window v-model="activeDay">
|
||||||
<v-window-item v-for="day in daysWithSchedule" :key="day" :value="day">
|
<v-window-item
|
||||||
<v-table density="compact" class="rounded" :headers-length="6" disable-sort>
|
v-for="day in daysWithSchedule"
|
||||||
|
:key="day"
|
||||||
|
:value="day"
|
||||||
|
>
|
||||||
|
<v-table
|
||||||
|
density="compact"
|
||||||
|
class="rounded"
|
||||||
|
:headers-length="6"
|
||||||
|
disable-sort
|
||||||
|
>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="text-center">节次</th>
|
<th class="text-center">
|
||||||
|
节次
|
||||||
|
</th>
|
||||||
<th>课程</th>
|
<th>课程</th>
|
||||||
<th>时间</th>
|
<th>时间</th>
|
||||||
<th>教师</th>
|
<th>教师</th>
|
||||||
@ -363,54 +546,100 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<template v-for="(group, index) in groupByPeriod(getDaySchedule(day))" :key="index">
|
<template
|
||||||
|
v-for="(group, index) in groupByPeriod(getDaySchedule(day))"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center font-weight-bold">
|
<td class="text-center font-weight-bold">
|
||||||
{{ group.period }}
|
{{ group.period }}
|
||||||
<v-tooltip v-if="group.originalPeriod !== group.period">
|
<v-tooltip v-if="group.originalPeriod !== group.period">
|
||||||
<template v-slot:activator="{ props }">
|
<template #activator="{ props }">
|
||||||
<v-icon size="x-small" v-bind="props" color="info" class="ml-1">mdi-sync</v-icon>
|
<v-icon
|
||||||
|
size="x-small"
|
||||||
|
v-bind="props"
|
||||||
|
color="info"
|
||||||
|
class="ml-1"
|
||||||
|
>
|
||||||
|
mdi-sync
|
||||||
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
原节次: {{ group.originalPeriod }}
|
原节次: {{ group.originalPeriod }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div v-for="(item, i) in group.items" :key="i" class="mb-1">
|
<div
|
||||||
<v-chip size="small" :color="getSubjectColor(item.subject)" label text-color="white"
|
v-for="(item, i) in group.items"
|
||||||
class="mr-1">
|
:key="i"
|
||||||
|
class="mb-1"
|
||||||
|
>
|
||||||
|
<v-chip
|
||||||
|
size="small"
|
||||||
|
:color="getSubjectColor(item.subject)"
|
||||||
|
label
|
||||||
|
text-color="white"
|
||||||
|
class="mr-1"
|
||||||
|
>
|
||||||
{{ item.subject }}
|
{{ item.subject }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-chip v-if="group.items.length > 1" size="x-small" class="ml-1"
|
<v-chip
|
||||||
:color="item.weekType === '单' ? 'warning' : 'success'">
|
v-if="group.items.length > 1"
|
||||||
|
size="x-small"
|
||||||
|
class="ml-1"
|
||||||
|
:color="item.weekType === '单' ? 'warning' : 'success'"
|
||||||
|
>
|
||||||
{{ item.weekType }}周
|
{{ item.weekType }}周
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div v-for="(timeSlot, i) in group.uniqueTimeSlots" :key="i" class="mb-1">
|
<div
|
||||||
<v-chip size="x-small" class="time-chip">
|
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) }}
|
{{ formatTime(timeSlot.startTime) }} - {{ formatTime(timeSlot.endTime) }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="!settings.hideTeacherName">
|
<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 || '-' }}
|
{{ item.teacher || '-' }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>-</template>
|
<template v-else>
|
||||||
|
-
|
||||||
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<template v-if="!settings.hideRoom">
|
<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 || '-' }}
|
{{ item.room || '-' }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>-</template>
|
<template v-else>
|
||||||
|
-
|
||||||
|
</template>
|
||||||
</td>
|
</td>
|
||||||
<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 }}
|
{{ item.weeks }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@ -422,7 +651,11 @@
|
|||||||
</v-window>
|
</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-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
@ -430,24 +663,24 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions class="">
|
<v-card-actions class="">
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:disabled="(!jsonText && !file) || loading"
|
:disabled="(!jsonText && !file) || loading"
|
||||||
@click="processInput"
|
|
||||||
prepend-icon="mdi-cog-refresh"
|
prepend-icon="mdi-cog-refresh"
|
||||||
|
@click="processInput"
|
||||||
>
|
>
|
||||||
处理数据
|
处理数据
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn
|
<v-btn
|
||||||
color="info"
|
color="info"
|
||||||
:disabled="!hasExportData"
|
:disabled="!hasExportData"
|
||||||
@click="showExportPreview"
|
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
prepend-icon="mdi-eye"
|
prepend-icon="mdi-eye"
|
||||||
border
|
border
|
||||||
|
@click="showExportPreview"
|
||||||
>
|
>
|
||||||
刷新
|
刷新
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@ -455,10 +688,10 @@
|
|||||||
color="success"
|
color="success"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
:disabled="!hasExportData"
|
:disabled="!hasExportData"
|
||||||
@click="downloadCSV"
|
|
||||||
class="ml-2"
|
class="ml-2"
|
||||||
prepend-icon="mdi-download"
|
prepend-icon="mdi-download"
|
||||||
border
|
border
|
||||||
|
@click="downloadCSV"
|
||||||
>
|
>
|
||||||
下载CSV
|
下载CSV
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@ -735,6 +968,22 @@ export default {
|
|||||||
return days;
|
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: {
|
methods: {
|
||||||
async handleFileChange() {
|
async handleFileChange() {
|
||||||
this.resetData();
|
this.resetData();
|
||||||
@ -1241,22 +1490,6 @@ export default {
|
|||||||
clearSelectedDays() {
|
clearSelectedDays() {
|
||||||
this.selectedDays = [];
|
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>
|
</script>
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
label="server.authDomain"
|
label="server.authDomain"
|
||||||
/>
|
/>
|
||||||
</v-form>
|
</v-form>
|
||||||
<v-divider class="my-4"/>
|
<v-divider class="my-4" />
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
class="me-2"
|
class="me-2"
|
||||||
|
|||||||
@ -42,7 +42,7 @@
|
|||||||
<v-list-item-subtitle>{{ currentDataKey }}</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ currentDataKey }}</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
<v-divider class="my-4"/>
|
<v-divider class="my-4" />
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col
|
<v-col
|
||||||
cols="12"
|
cols="12"
|
||||||
@ -83,11 +83,17 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
<v-divider class="my-4"/>
|
<v-divider class="my-4" />
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card border color="primary" variant="tonal">
|
<v-card
|
||||||
<v-card-title class="text-subtitle-1">聊天室消息</v-card-title>
|
border
|
||||||
|
color="primary"
|
||||||
|
variant="tonal"
|
||||||
|
>
|
||||||
|
<v-card-title class="text-subtitle-1">
|
||||||
|
聊天室消息
|
||||||
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-textarea
|
<v-textarea
|
||||||
v-model="chatInput"
|
v-model="chatInput"
|
||||||
@ -97,7 +103,7 @@
|
|||||||
rows="2"
|
rows="2"
|
||||||
/>
|
/>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!canSendChat"
|
:disabled="!canSendChat"
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -178,7 +184,7 @@
|
|||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
事件日志
|
事件日志
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
size="small"
|
size="small"
|
||||||
|
|||||||
@ -6,13 +6,19 @@
|
|||||||
请将这个ID复制并私聊给开发者,以便进行问题排查。
|
请将这个ID复制并私聊给开发者,以便进行问题排查。
|
||||||
</v-card-subtitle>
|
</v-card-subtitle>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="text-h6 mb-2">访客 ID</div>
|
<div class="text-h6 mb-2">
|
||||||
|
访客 ID
|
||||||
|
</div>
|
||||||
<v-code class="d-block pa-2 bg-grey-lighten-4 rounded mb-4">
|
<v-code class="d-block pa-2 bg-grey-lighten-4 rounded mb-4">
|
||||||
{{ visitorId || '加载中...' }}
|
{{ visitorId || '加载中...' }}
|
||||||
</v-code>
|
</v-code>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn color="primary" @click="loadData" :loading="loading">
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
:loading="loading"
|
||||||
|
@click="loadData"
|
||||||
|
>
|
||||||
Refresh
|
Refresh
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
|
|||||||
@ -11,7 +11,7 @@
|
|||||||
<v-app-bar-title class="text-h6">
|
<v-app-bar-title class="text-h6">
|
||||||
编辑考试配置
|
编辑考试配置
|
||||||
</v-app-bar-title>
|
</v-app-bar-title>
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
color="success"
|
color="success"
|
||||||
|
|||||||
@ -2,9 +2,17 @@
|
|||||||
<v-container class="fill-height">
|
<v-container class="fill-height">
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card border class="elevation-12">
|
<v-card
|
||||||
|
border
|
||||||
|
class="elevation-12"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||||
<v-icon class="mr-2" color="white">mdi-calendar-check</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="white"
|
||||||
|
>
|
||||||
|
mdi-calendar-check
|
||||||
|
</v-icon>
|
||||||
考试看板
|
考试看板
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-subtitle>
|
<v-card-subtitle>
|
||||||
@ -22,7 +30,9 @@
|
|||||||
@click:close="error = ''"
|
@click:close="error = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -38,7 +48,9 @@
|
|||||||
@click:close="success = ''"
|
@click:close="success = ''"
|
||||||
>
|
>
|
||||||
<div class="d-flex align-center">
|
<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 }}
|
{{ success }}
|
||||||
</div>
|
</div>
|
||||||
</v-alert>
|
</v-alert>
|
||||||
@ -92,19 +104,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 加载状态 -->
|
<!-- 加载状态 -->
|
||||||
<v-card v-if="loading" class="my-4" outlined>
|
<v-card
|
||||||
|
v-if="loading"
|
||||||
|
class="my-4"
|
||||||
|
outlined
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-skeleton-loader
|
<v-skeleton-loader
|
||||||
class="mx-auto"
|
class="mx-auto"
|
||||||
type="list-item-avatar-two-line@3"
|
type="list-item-avatar-two-line@3"
|
||||||
></v-skeleton-loader>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</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-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>
|
<span class="font-weight-bold">配置列表</span>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-list>
|
<v-list>
|
||||||
@ -116,8 +138,13 @@
|
|||||||
@click="showEditDialog(config)"
|
@click="showEditDialog(config)"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-avatar class="mr-2" color="primary">
|
<v-avatar
|
||||||
<v-icon color="white">mdi-calendar-text</v-icon>
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<v-icon color="white">
|
||||||
|
mdi-calendar-text
|
||||||
|
</v-icon>
|
||||||
</v-avatar>
|
</v-avatar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -126,11 +153,21 @@
|
|||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle class="text-caption mt-1">
|
<v-list-item-subtitle class="text-caption mt-1">
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<v-icon class="mr-1" size="small">mdi-information-outline</v-icon>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-information-outline
|
||||||
|
</v-icon>
|
||||||
{{ config.message || '无描述' }}
|
{{ config.message || '无描述' }}
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex align-center mt-1">
|
<div class="d-flex align-center mt-1">
|
||||||
<v-icon class="mr-1" size="small">mdi-book-multiple</v-icon>
|
<v-icon
|
||||||
|
class="mr-1"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
mdi-book-multiple
|
||||||
|
</v-icon>
|
||||||
{{ config.examInfos ? config.examInfos.length : 0 }} 堂考试
|
{{ config.examInfos ? config.examInfos.length : 0 }} 堂考试
|
||||||
</div>
|
</div>
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
@ -158,8 +195,6 @@
|
|||||||
>
|
>
|
||||||
<v-icon>mdi-eye</v-icon>
|
<v-icon>mdi-eye</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -167,12 +202,22 @@
|
|||||||
</v-card>
|
</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-card-text class="text-center py-8">
|
||||||
<v-icon class="mb-4" color="grey-lighten-1" size="64">
|
<v-icon
|
||||||
|
class="mb-4"
|
||||||
|
color="grey-lighten-1"
|
||||||
|
size="64"
|
||||||
|
>
|
||||||
mdi-calendar-blank
|
mdi-calendar-blank
|
||||||
</v-icon>
|
</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 class="text-body-2 text-grey-darken-1 mb-4">
|
||||||
点击"新建配置"按钮创建您的第一个考试配置
|
点击"新建配置"按钮创建您的第一个考试配置
|
||||||
</p>
|
</p>
|
||||||
@ -191,10 +236,18 @@
|
|||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<!-- 重命名对话框 -->
|
<!-- 重命名对话框 -->
|
||||||
<v-dialog v-model="renameDialog" max-width="500">
|
<v-dialog
|
||||||
|
v-model="renameDialog"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" color="primary">mdi-rename-box</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
mdi-rename-box
|
||||||
|
</v-icon>
|
||||||
重命名配置
|
重命名配置
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -205,10 +258,10 @@
|
|||||||
prepend-inner-icon="mdi-calendar-text"
|
prepend-inner-icon="mdi-calendar-text"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
@keyup.enter="renameConfig"
|
@keyup.enter="renameConfig"
|
||||||
></v-text-field>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="grey"
|
color="grey"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -230,12 +283,21 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 编辑配置弹框 -->
|
<!-- 编辑配置弹框 -->
|
||||||
<v-dialog v-model="editDialog" max-width="1200" persistent>
|
<v-dialog
|
||||||
|
v-model="editDialog"
|
||||||
|
max-width="1200"
|
||||||
|
persistent
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||||
<v-icon class="mr-2" color="white">mdi-pencil</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="white"
|
||||||
|
>
|
||||||
|
mdi-pencil
|
||||||
|
</v-icon>
|
||||||
编辑考试配置
|
编辑考试配置
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-chip
|
<v-chip
|
||||||
v-if="editingConfig"
|
v-if="editingConfig"
|
||||||
class="mr-2"
|
class="mr-2"
|
||||||
@ -255,8 +317,10 @@
|
|||||||
<v-icon>mdi-close</v-icon>
|
<v-icon>mdi-close</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-4"
|
<v-card-text
|
||||||
style="max-height: 70vh; overflow-y: auto;">
|
class="pa-4"
|
||||||
|
style="max-height: 70vh; overflow-y: auto;"
|
||||||
|
>
|
||||||
<ExamConfigEditor
|
<ExamConfigEditor
|
||||||
v-if="editingConfig"
|
v-if="editingConfig"
|
||||||
ref="configEditor"
|
ref="configEditor"
|
||||||
@ -277,7 +341,7 @@
|
|||||||
>
|
>
|
||||||
关闭
|
关闭
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:loading="saving"
|
:loading="saving"
|
||||||
color="success"
|
color="success"
|
||||||
@ -292,12 +356,21 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 导入配置弹框 -->
|
<!-- 导入配置弹框 -->
|
||||||
<v-dialog v-model="importDialog" max-width="800" persistent>
|
<v-dialog
|
||||||
|
v-model="importDialog"
|
||||||
|
max-width="800"
|
||||||
|
persistent
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||||
<v-icon class="mr-2" color="white">mdi-import</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="white"
|
||||||
|
>
|
||||||
|
mdi-import
|
||||||
|
</v-icon>
|
||||||
导入考试配置
|
导入考试配置
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="white"
|
color="white"
|
||||||
icon="mdi-close"
|
icon="mdi-close"
|
||||||
@ -324,22 +397,22 @@
|
|||||||
v-model="importJson"
|
v-model="importJson"
|
||||||
:rules="[v => !!v || 'JSON内容不能为空']"
|
:rules="[v => !!v || 'JSON内容不能为空']"
|
||||||
label="请输入JSON配置"
|
label="请输入JSON配置"
|
||||||
placeholder='{
|
placeholder="{
|
||||||
"examName": "期末考试",
|
"examName": "期末考试",
|
||||||
"message": "考试信息",
|
"message": "考试信息",
|
||||||
"room": "01",
|
"room": "01",
|
||||||
"examInfos": [
|
"examInfos": [
|
||||||
{
|
{
|
||||||
"name": "语文",
|
"name": "语文",
|
||||||
"start": "2025/12/14 09:00",
|
"start": "2025/12/14 09:00",
|
||||||
"end": "2025/12/14 11:00"
|
"end": "2025/12/14 11:00"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}'
|
}"
|
||||||
prepend-inner-icon="mdi-code-json"
|
prepend-inner-icon="mdi-code-json"
|
||||||
rows="15"
|
rows="15"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-textarea>
|
/>
|
||||||
|
|
||||||
<v-alert
|
<v-alert
|
||||||
border="start"
|
border="start"
|
||||||
@ -368,7 +441,7 @@
|
|||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!importJson"
|
:disabled="!importJson"
|
||||||
:loading="importing"
|
:loading="importing"
|
||||||
@ -384,10 +457,19 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 日期选择弹框 -->
|
<!-- 日期选择弹框 -->
|
||||||
<v-dialog v-model="datePickerDialog" max-width="500" persistent>
|
<v-dialog
|
||||||
|
v-model="datePickerDialog"
|
||||||
|
max-width="500"
|
||||||
|
persistent
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
<v-card-title class="d-flex align-center primary lighten-1 white--text py-3 px-4">
|
||||||
<v-icon class="mr-2" color="white">mdi-calendar</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="white"
|
||||||
|
>
|
||||||
|
mdi-calendar
|
||||||
|
</v-icon>
|
||||||
选择起始日期
|
选择起始日期
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="pa-4">
|
<v-card-text class="pa-4">
|
||||||
@ -401,7 +483,7 @@
|
|||||||
prepend-inner-icon="mdi-calendar"
|
prepend-inner-icon="mdi-calendar"
|
||||||
type="date"
|
type="date"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-text-field>
|
/>
|
||||||
|
|
||||||
<v-alert
|
<v-alert
|
||||||
v-if="virtualDateInfo"
|
v-if="virtualDateInfo"
|
||||||
@ -425,7 +507,7 @@
|
|||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!baseDate"
|
:disabled="!baseDate"
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -440,12 +522,21 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- AI生成提示词弹框 -->
|
<!-- AI生成提示词弹框 -->
|
||||||
<v-dialog v-model="aiDialog" max-width="900" persistent>
|
<v-dialog
|
||||||
|
v-model="aiDialog"
|
||||||
|
max-width="900"
|
||||||
|
persistent
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="d-flex align-center purple lighten-1 white--text py-3 px-4">
|
<v-card-title class="d-flex align-center purple lighten-1 white--text py-3 px-4">
|
||||||
<v-icon class="mr-2" color="white">mdi-brain</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="white"
|
||||||
|
>
|
||||||
|
mdi-brain
|
||||||
|
</v-icon>
|
||||||
AI生成考试配置
|
AI生成考试配置
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="white"
|
color="white"
|
||||||
icon="mdi-close"
|
icon="mdi-close"
|
||||||
@ -471,7 +562,9 @@
|
|||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<div class="d-flex justify-space-between align-center mb-2">
|
<div class="d-flex justify-space-between align-center mb-2">
|
||||||
<h3 class="text-h6">提示词模板</h3>
|
<h3 class="text-h6">
|
||||||
|
提示词模板
|
||||||
|
</h3>
|
||||||
<v-btn
|
<v-btn
|
||||||
:color="copied ? 'success' : 'primary'"
|
:color="copied ? 'success' : 'primary'"
|
||||||
:prepend-icon="copied ? 'mdi-check' : 'mdi-content-copy'"
|
:prepend-icon="copied ? 'mdi-check' : 'mdi-content-copy'"
|
||||||
@ -483,12 +576,13 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-card class="pa-4" variant="outlined">
|
<v-card
|
||||||
|
class="pa-4"
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
<pre class="ai-prompt-text">{{ aiPrompt }}</pre>
|
<pre class="ai-prompt-text">{{ aiPrompt }}</pre>
|
||||||
</v-card>
|
</v-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions class="pa-4">
|
<v-card-actions class="pa-4">
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -499,7 +593,7 @@
|
|||||||
>
|
>
|
||||||
关闭
|
关闭
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="success"
|
color="success"
|
||||||
prepend-icon="mdi-import"
|
prepend-icon="mdi-import"
|
||||||
@ -552,9 +646,6 @@ export default {
|
|||||||
copied: false
|
copied: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async mounted() {
|
|
||||||
await this.loadConfigs()
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
/**
|
||||||
* AI生成提示词
|
* AI生成提示词
|
||||||
@ -603,6 +694,9 @@ Date and Time Handling:
|
|||||||
Now please generate the exam configuration based on the above rules:`
|
Now please generate the exam configuration based on the above rules:`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async mounted() {
|
||||||
|
await this.loadConfigs()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
/**
|
/**
|
||||||
* 根据当前日期推算考试类型
|
* 根据当前日期推算考试类型
|
||||||
|
|||||||
@ -34,11 +34,16 @@
|
|||||||
<v-btn
|
<v-btn
|
||||||
v-if="shouldShowUrgentTestButton"
|
v-if="shouldShowUrgentTestButton"
|
||||||
prepend-icon="mdi-chat"
|
prepend-icon="mdi-chat"
|
||||||
@click="urgentTestDialog = true"
|
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>发送通知</v-btn
|
@click="urgentTestDialog = true"
|
||||||
>
|
>
|
||||||
<v-btn icon="mdi-chat" variant="text" @click="isChatOpen = true" />
|
发送通知
|
||||||
|
</v-btn>
|
||||||
|
<v-btn
|
||||||
|
icon="mdi-chat"
|
||||||
|
variant="text"
|
||||||
|
@click="isChatOpen = true"
|
||||||
|
/>
|
||||||
<v-btn
|
<v-btn
|
||||||
:badge="unreadCount || undefined"
|
:badge="unreadCount || undefined"
|
||||||
:badge-color="unreadCount ? 'error' : undefined"
|
:badge-color="unreadCount ? 'error' : undefined"
|
||||||
@ -46,7 +51,11 @@
|
|||||||
variant="text"
|
variant="text"
|
||||||
@click="$refs.messageLog.drawer = true"
|
@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>
|
</template>
|
||||||
</v-app-bar>
|
</v-app-bar>
|
||||||
<!-- 初始化选择卡片,仅在首页且需要授权时显示;不影响顶栏 -->
|
<!-- 初始化选择卡片,仅在首页且需要授权时显示;不影响顶栏 -->
|
||||||
@ -63,11 +72,20 @@
|
|||||||
@token-info-updated="updateTokenDisplayInfo"
|
@token-info-updated="updateTokenDisplayInfo"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-if="!shouldShowInit" class="d-flex">
|
<div
|
||||||
|
v-if="!shouldShowInit"
|
||||||
|
class="d-flex"
|
||||||
|
>
|
||||||
<!-- 主要内容区域 -->
|
<!-- 主要内容区域 -->
|
||||||
<v-container class="main-window flex-grow-1 no-select bloom-container" fluid>
|
<v-container
|
||||||
|
class="main-window flex-grow-1 no-select bloom-container"
|
||||||
|
fluid
|
||||||
|
>
|
||||||
<!-- 常驻通知区域 -->
|
<!-- 常驻通知区域 -->
|
||||||
<v-row v-if="persistentNotifications.length > 0" class="mb-4">
|
<v-row
|
||||||
|
v-if="persistentNotifications.length > 0"
|
||||||
|
class="mb-4"
|
||||||
|
>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card
|
<v-card
|
||||||
v-for="notification in persistentNotifications"
|
v-for="notification in persistentNotifications"
|
||||||
@ -78,31 +96,49 @@
|
|||||||
@click="showNotificationDetail(notification)"
|
@click="showNotificationDetail(notification)"
|
||||||
>
|
>
|
||||||
<v-card-text class="d-flex align-center py-3">
|
<v-card-text class="d-flex align-center py-3">
|
||||||
|
|
||||||
<span class="text-h6 text-truncate font-weight-bold">{{ notification.message }}</span>
|
<span class="text-h6 text-truncate font-weight-bold">{{ notification.message }}</span>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn icon="mdi-chevron-right" variant="text"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-chevron-right"
|
||||||
|
variant="text"
|
||||||
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<!-- 通知详情对话框 -->
|
<!-- 通知详情对话框 -->
|
||||||
<v-dialog v-model="notificationDetailDialog" max-width="700" scrollable>
|
<v-dialog
|
||||||
<v-card v-if="currentNotification" class="rounded-xl">
|
v-model="notificationDetailDialog"
|
||||||
|
max-width="700"
|
||||||
|
scrollable
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
v-if="currentNotification"
|
||||||
|
class="rounded-xl"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center pa-4 text-h5">
|
<v-card-title class="d-flex align-center pa-4 text-h5">
|
||||||
|
<span
|
||||||
<span :class="currentNotification.isUrgent ? 'text-error' : ''" class="font-weight-bold">
|
:class="currentNotification.isUrgent ? 'text-error' : ''"
|
||||||
|
class="font-weight-bold"
|
||||||
|
>
|
||||||
{{ currentNotification.isUrgent ? '强调通知' : '通知详情' }}
|
{{ currentNotification.isUrgent ? '强调通知' : '通知详情' }}
|
||||||
</span>
|
</span>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn icon="mdi-close" variant="text" @click="notificationDetailDialog = false"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
@click="notificationDetailDialog = false"
|
||||||
|
/>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
|
|
||||||
<v-divider></v-divider>
|
<v-divider />
|
||||||
|
|
||||||
<v-card-text class="pa-6">
|
<v-card-text class="pa-6">
|
||||||
<div class="text-h4 font-weight-medium mb-4" style="line-height: 1.5;">
|
<div
|
||||||
|
class="text-h4 font-weight-medium mb-4"
|
||||||
|
style="line-height: 1.5;"
|
||||||
|
>
|
||||||
{{ currentNotification.message }}
|
{{ currentNotification.message }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-subtitle-1 text-grey">
|
<div class="text-subtitle-1 text-grey">
|
||||||
@ -110,7 +146,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-divider></v-divider>
|
<v-divider />
|
||||||
|
|
||||||
<v-card-actions class="pa-4">
|
<v-card-actions class="pa-4">
|
||||||
<v-btn
|
<v-btn
|
||||||
@ -123,7 +159,7 @@
|
|||||||
>
|
>
|
||||||
删除通知
|
删除通知
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
size="x-large"
|
size="x-large"
|
||||||
@ -226,7 +262,10 @@
|
|||||||
@save="handleHomeworkSave"
|
@save="handleHomeworkSave"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<v-snackbar v-model="state.snackbar" :timeout="2000">
|
<v-snackbar
|
||||||
|
v-model="state.snackbar"
|
||||||
|
:timeout="2000"
|
||||||
|
>
|
||||||
{{ state.snackbarText }}
|
{{ state.snackbarText }}
|
||||||
</v-snackbar>
|
</v-snackbar>
|
||||||
|
|
||||||
@ -262,24 +301,41 @@
|
|||||||
<FloatingICP />
|
<FloatingICP />
|
||||||
|
|
||||||
<!-- 设备聊天室(右下角浮窗) -->
|
<!-- 设备聊天室(右下角浮窗) -->
|
||||||
<ChatWidget v-model="isChatOpen" :show-button="false" />
|
<ChatWidget
|
||||||
|
v-model="isChatOpen"
|
||||||
|
:show-button="false"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 紧急通知测试对话框 -->
|
<!-- 紧急通知测试对话框 -->
|
||||||
<UrgentTestDialog v-model="urgentTestDialog" />
|
<UrgentTestDialog v-model="urgentTestDialog" />
|
||||||
|
|
||||||
<!-- 添加确认对话框 -->
|
<!-- 添加确认对话框 -->
|
||||||
<v-dialog v-model="confirmDialog.show" max-width="400">
|
<v-dialog
|
||||||
|
v-model="confirmDialog.show"
|
||||||
|
max-width="400"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h6"> 确认保存</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
确认保存
|
||||||
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
您正在修改 {{ state.dateString }} 的数据,确定要保存吗?
|
您正在修改 {{ state.dateString }} 的数据,确定要保存吗?
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-btn color="grey" variant="text" @click="confirmDialog.reject">
|
<v-btn
|
||||||
|
color="grey"
|
||||||
|
variant="text"
|
||||||
|
@click="confirmDialog.reject"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</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-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
@ -292,9 +348,14 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 添加URL配置确认对话框 -->
|
<!-- 添加URL配置确认对话框 -->
|
||||||
<v-dialog v-model="urlConfigDialog.show" max-width="500">
|
<v-dialog
|
||||||
|
v-model="urlConfigDialog.show"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
<v-card>
|
<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>
|
<v-card-text>
|
||||||
<p>以下配置将应用于当前班级:</p>
|
<p>以下配置将应用于当前班级:</p>
|
||||||
<v-list density="compact">
|
<v-list density="compact">
|
||||||
@ -303,17 +364,28 @@
|
|||||||
:key="change.key"
|
:key="change.key"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon :icon="change.icon" class="mr-2" size="small" />
|
<v-icon
|
||||||
|
:icon="change.icon"
|
||||||
|
class="mr-2"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title class="d-flex align-center">
|
<v-list-item-title class="d-flex align-center">
|
||||||
<span class="text-subtitle-1">{{ change.name }}</span>
|
<span class="text-subtitle-1">{{ change.name }}</span>
|
||||||
<v-tooltip activator="parent" location="top"
|
<v-tooltip
|
||||||
>{{ change.description || change.key }}
|
activator="parent"
|
||||||
|
location="top"
|
||||||
|
>
|
||||||
|
{{ change.description || change.key }}
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle>
|
<v-list-item-subtitle>
|
||||||
<span class="text-grey-darken-1">{{ change.oldValue }}</span>
|
<span class="text-grey-darken-1">{{ change.oldValue }}</span>
|
||||||
<v-icon class="mx-1" icon="mdi-arrow-right" size="small" />
|
<v-icon
|
||||||
|
class="mx-1"
|
||||||
|
icon="mdi-arrow-right"
|
||||||
|
size="small"
|
||||||
|
/>
|
||||||
<span class="text-primary font-weight-medium">{{
|
<span class="text-primary font-weight-medium">{{
|
||||||
change.newValue
|
change.newValue
|
||||||
}}</span>
|
}}</span>
|
||||||
@ -330,7 +402,10 @@
|
|||||||
>
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="primary" @click="urlConfigDialog.confirmHandler">
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="urlConfigDialog.confirmHandler"
|
||||||
|
>
|
||||||
确认应用
|
确认应用
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
@ -338,14 +413,25 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 考试详情/编辑对话框 -->
|
<!-- 考试详情/编辑对话框 -->
|
||||||
<v-dialog v-model="showExamDetailDialog" persistent fullscreen>
|
<v-dialog
|
||||||
|
v-model="showExamDetailDialog"
|
||||||
|
persistent
|
||||||
|
fullscreen
|
||||||
|
>
|
||||||
<v-card v-if="selectedExamId">
|
<v-card v-if="selectedExamId">
|
||||||
<v-card-title class="d-flex align-center pa-4">
|
<v-card-title class="d-flex align-center pa-4">
|
||||||
编辑考试配置
|
编辑考试配置
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn icon="mdi-close" variant="text" @click="showExamDetailDialog = false"></v-btn>
|
<v-btn
|
||||||
|
icon="mdi-close"
|
||||||
|
variant="text"
|
||||||
|
@click="showExamDetailDialog = false"
|
||||||
|
/>
|
||||||
</v-card-title>
|
</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;"
|
||||||
|
>
|
||||||
<exam-config-editor
|
<exam-config-editor
|
||||||
:config-id="selectedExamId"
|
:config-id="selectedExamId"
|
||||||
:dialog-mode="true"
|
:dialog-mode="true"
|
||||||
@ -353,7 +439,7 @@
|
|||||||
@deleted="onExamConfigDeleted"
|
@deleted="onExamConfigDeleted"
|
||||||
/>
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-divider></v-divider>
|
<v-divider />
|
||||||
<v-card-actions class="pa-4">
|
<v-card-actions class="pa-4">
|
||||||
<v-btn
|
<v-btn
|
||||||
color="error"
|
color="error"
|
||||||
@ -363,7 +449,7 @@
|
|||||||
>
|
>
|
||||||
移除卡片
|
移除卡片
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
color="primary"
|
color="primary"
|
||||||
variant="text"
|
variant="text"
|
||||||
@ -376,9 +462,14 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 添加考试卡片对话框 -->
|
<!-- 添加考试卡片对话框 -->
|
||||||
<v-dialog v-model="showAddExamDialog" max-width="500">
|
<v-dialog
|
||||||
|
v-model="showAddExamDialog"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-title class="text-h6">预览考试看板</v-card-title>
|
<v-card-title class="text-h6">
|
||||||
|
预览考试看板
|
||||||
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-list v-if="examStore.examList.length > 0">
|
<v-list v-if="examStore.examList.length > 0">
|
||||||
<v-list-item
|
<v-list-item
|
||||||
@ -389,44 +480,72 @@
|
|||||||
@click="addExamCard(exam.id)"
|
@click="addExamCard(exam.id)"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon color="primary">mdi-calendar-text</v-icon>
|
<v-icon color="primary">
|
||||||
|
mdi-calendar-text
|
||||||
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #append>
|
<template #append>
|
||||||
<v-btn
|
<v-btn
|
||||||
:icon="isExamCardAdded(exam.id) ? 'mdi-check' : 'mdi-plus'"
|
:icon="isExamCardAdded(exam.id) ? 'mdi-check' : 'mdi-plus'"
|
||||||
:color="isExamCardAdded(exam.id) ? 'success' : 'grey'"
|
:color="isExamCardAdded(exam.id) ? 'success' : 'grey'"
|
||||||
variant="text"
|
variant="text"
|
||||||
></v-btn>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
<div v-else class="text-center py-4 text-grey">
|
<div
|
||||||
|
v-else
|
||||||
|
class="text-center py-4 text-grey"
|
||||||
|
>
|
||||||
暂无考试配置
|
暂无考试配置
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" variant="text" @click="showAddExamDialog = false">关闭</v-btn>
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
@click="showAddExamDialog = false"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
<!-- 通知详情对话框 -->
|
<!-- 通知详情对话框 -->
|
||||||
<v-dialog v-model="notificationDetailDialog" max-width="600">
|
<v-dialog
|
||||||
|
v-model="notificationDetailDialog"
|
||||||
|
max-width="600"
|
||||||
|
>
|
||||||
<v-card v-if="currentNotification">
|
<v-card v-if="currentNotification">
|
||||||
<v-card-title class="headline" :class="currentNotification.isUrgent ? 'text-error' : 'text-primary'">
|
<v-card-title
|
||||||
|
class="headline"
|
||||||
|
:class="currentNotification.isUrgent ? 'text-error' : 'text-primary'"
|
||||||
|
>
|
||||||
{{ currentNotification.isUrgent ? '强调通知' : '通知详情' }}
|
{{ currentNotification.isUrgent ? '强调通知' : '通知详情' }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text class="text-h5 py-4">
|
<v-card-text class="text-h5 py-4">
|
||||||
{{ currentNotification.message }}
|
{{ currentNotification.message }}
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-btn color="error" variant="text" @click="removePersistentNotification(currentNotification.id)">删除</v-btn>
|
<v-btn
|
||||||
<v-spacer></v-spacer>
|
color="error"
|
||||||
<v-btn color="primary" @click="notificationDetailDialog = false">关闭</v-btn>
|
variant="text"
|
||||||
|
@click="removePersistentNotification(currentNotification.id)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</v-btn>
|
||||||
|
<v-spacer />
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
@click="notificationDetailDialog = false"
|
||||||
|
>
|
||||||
|
关闭
|
||||||
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
<br /><br /><br />
|
<br><br><br>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@ -7,11 +7,20 @@
|
|||||||
@click="$router.push('/')"
|
@click="$router.push('/')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-app-bar-title v-if="list && !isRenaming" class="text-h6">{{ list.name }}</v-app-bar-title>
|
<v-app-bar-title
|
||||||
<v-app-bar-title v-else class="text-h6">列表</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-app-bar>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
|
||||||
<div class="d-flex align-center mb-4">
|
<div class="d-flex align-center mb-4">
|
||||||
<v-btn
|
<v-btn
|
||||||
border
|
border
|
||||||
@ -23,11 +32,19 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
<h1 v-if="list && !isRenaming">
|
<h1 v-if="list && !isRenaming">
|
||||||
{{ list.name }}
|
{{ list.name }}
|
||||||
<v-btn border icon size="small" @click="startRenaming">
|
<v-btn
|
||||||
|
border
|
||||||
|
icon
|
||||||
|
size="small"
|
||||||
|
@click="startRenaming"
|
||||||
|
>
|
||||||
<v-icon>mdi-pencil</v-icon>
|
<v-icon>mdi-pencil</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</h1>
|
</h1>
|
||||||
<div v-else-if="list && isRenaming" class="d-flex align-center">
|
<div
|
||||||
|
v-else-if="list && isRenaming"
|
||||||
|
class="d-flex align-center"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newListName"
|
v-model="newListName"
|
||||||
autofocus
|
autofocus
|
||||||
@ -37,11 +54,20 @@
|
|||||||
label="列表名称"
|
label="列表名称"
|
||||||
style="min-width: 200px;"
|
style="min-width: 200px;"
|
||||||
@keyup.enter="saveListName"
|
@keyup.enter="saveListName"
|
||||||
></v-text-field>
|
/>
|
||||||
<v-btn class="mr-2" color="primary" size="small" @click="saveListName">
|
<v-btn
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
size="small"
|
||||||
|
@click="saveListName"
|
||||||
|
>
|
||||||
<v-icon>mdi-check</v-icon>
|
<v-icon>mdi-check</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="error" size="small" @click="cancelRenaming">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
size="small"
|
||||||
|
@click="cancelRenaming"
|
||||||
|
>
|
||||||
<v-icon>mdi-close</v-icon>
|
<v-icon>mdi-close</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -51,10 +77,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<v-card border class="mb-5" rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-5"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
项目列表
|
项目列表
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn-toggle
|
<v-btn-toggle
|
||||||
v-model="sortType"
|
v-model="sortType"
|
||||||
mandatory
|
mandatory
|
||||||
@ -97,7 +127,7 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
<v-card-actions v-if="sortedItems.length > 0">
|
<v-card-actions v-if="sortedItems.length > 0">
|
||||||
<v-spacer/>
|
<v-spacer />
|
||||||
<v-btn
|
<v-btn
|
||||||
:disabled="!hasCompletedItems"
|
:disabled="!hasCompletedItems"
|
||||||
color="error"
|
color="error"
|
||||||
@ -108,7 +138,11 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-card border class="mb-5" rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-5"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>添加新项目</v-card-title>
|
<v-card-title>添加新项目</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -126,7 +160,11 @@
|
|||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<v-card border class="mb-5" rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-5"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>列表排序</v-card-title>
|
<v-card-title>列表排序</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
@ -153,16 +191,30 @@
|
|||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- 确认删除对话框 -->
|
<!-- 确认删除对话框 -->
|
||||||
<v-dialog v-model="deleteDialog.show" max-width="500">
|
<v-dialog
|
||||||
<v-card border rounded="xl">
|
v-model="deleteDialog.show"
|
||||||
|
max-width="500"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
border
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>{{ deleteDialog.title }}</v-card-title>
|
<v-card-title>{{ deleteDialog.title }}</v-card-title>
|
||||||
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" variant="text" @click="deleteDialog.show = false">
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
@click="deleteDialog.show = false"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="error" variant="text" @click="confirmDelete">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="text"
|
||||||
|
@click="confirmDelete"
|
||||||
|
>
|
||||||
确认删除
|
确认删除
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
@ -170,8 +222,14 @@
|
|||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<!-- 项目详情对话框 -->
|
<!-- 项目详情对话框 -->
|
||||||
<v-dialog v-model="itemDialog.show" max-width="600">
|
<v-dialog
|
||||||
<v-card border rounded="xl">
|
v-model="itemDialog.show"
|
||||||
|
max-width="600"
|
||||||
|
>
|
||||||
|
<v-card
|
||||||
|
border
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
<span v-if="!itemDialog.isEditing">项目详情</span>
|
<span v-if="!itemDialog.isEditing">项目详情</span>
|
||||||
<span v-else>编辑项目</span>
|
<span v-else>编辑项目</span>
|
||||||
@ -181,13 +239,16 @@
|
|||||||
<div v-if="!itemDialog.isEditing && itemDialog.item">
|
<div v-if="!itemDialog.isEditing && itemDialog.item">
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">{{ itemDialog.item.name }}
|
<v-list-item-title class="text-subtitle-1 font-weight-bold">
|
||||||
|
{{ itemDialog.item.name }}
|
||||||
</v-list-item-title>
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle>{{ itemDialog.item.id }}</v-list-item-subtitle>
|
<v-list-item-subtitle>{{ itemDialog.item.id }}</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<v-list-item-title class="text-subtitle-1 font-weight-bold">状态</v-list-item-title>
|
<v-list-item-title class="text-subtitle-1 font-weight-bold">
|
||||||
|
状态
|
||||||
|
</v-list-item-title>
|
||||||
<v-list-item-subtitle>
|
<v-list-item-subtitle>
|
||||||
<v-chip
|
<v-chip
|
||||||
:color="itemDialog.item.completed ? 'success' : 'warning'"
|
:color="itemDialog.item.completed ? 'success' : 'warning'"
|
||||||
@ -199,20 +260,24 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
<v-list-item v-if="itemDialog.item.description">
|
<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-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-subtitle>{{ itemDialog.item.description }}</v-list-item-subtitle>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
|
||||||
</v-list>
|
</v-list>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="itemDialog.isEditing && itemDialog.item" class="pa-2">
|
<div
|
||||||
|
v-else-if="itemDialog.isEditing && itemDialog.item"
|
||||||
|
class="pa-2"
|
||||||
|
>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="itemDialog.editedItem.name"
|
v-model="itemDialog.editedItem.name"
|
||||||
class="mb-3"
|
class="mb-3"
|
||||||
label="名称"
|
label="名称"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-text-field>
|
/>
|
||||||
|
|
||||||
<v-textarea
|
<v-textarea
|
||||||
v-model="itemDialog.editedItem.description"
|
v-model="itemDialog.editedItem.description"
|
||||||
@ -220,7 +285,7 @@
|
|||||||
label="描述"
|
label="描述"
|
||||||
rows="3"
|
rows="3"
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
></v-textarea>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<v-switch
|
<v-switch
|
||||||
@ -228,37 +293,56 @@
|
|||||||
color="success"
|
color="success"
|
||||||
hide-details
|
hide-details
|
||||||
label="已完成"
|
label="已完成"
|
||||||
></v-switch>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
|
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
|
|
||||||
<template v-if="!itemDialog.isEditing">
|
<template v-if="!itemDialog.isEditing">
|
||||||
<v-btn color="primary" variant="text" @click="startEditingItem">
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
@click="startEditingItem"
|
||||||
|
>
|
||||||
编辑
|
编辑
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="error" variant="text" @click="confirmDeleteItem(itemDialog.item?.id)">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="text"
|
||||||
|
@click="confirmDeleteItem(itemDialog.item?.id)"
|
||||||
|
>
|
||||||
删除
|
删除
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="secondary" variant="text" @click="itemDialog.show = false">
|
<v-btn
|
||||||
|
color="secondary"
|
||||||
|
variant="text"
|
||||||
|
@click="itemDialog.show = false"
|
||||||
|
>
|
||||||
关闭
|
关闭
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<v-btn color="success" variant="text" @click="saveItemChanges">
|
<v-btn
|
||||||
|
color="success"
|
||||||
|
variant="text"
|
||||||
|
@click="saveItemChanges"
|
||||||
|
>
|
||||||
保存
|
保存
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="secondary" variant="text" @click="cancelEditingItem">
|
<v-btn
|
||||||
|
color="secondary"
|
||||||
|
variant="text"
|
||||||
|
@click="cancelEditingItem"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -7,12 +7,16 @@
|
|||||||
@click="$router.push('/')"
|
@click="$router.push('/')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</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-app-bar>
|
||||||
<v-container>
|
<v-container>
|
||||||
|
<v-card
|
||||||
|
border
|
||||||
<v-card border class="mb-5" rounded="xl">
|
class="mb-5"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>现有列表</v-card-title>
|
<v-card-title>现有列表</v-card-title>
|
||||||
<v-card-text v-if="lists.length === 0">
|
<v-card-text v-if="lists.length === 0">
|
||||||
暂无列表,请创建新列表
|
暂无列表,请创建新列表
|
||||||
@ -27,7 +31,10 @@
|
|||||||
<div v-if="list.id !== editingListId">
|
<div v-if="list.id !== editingListId">
|
||||||
<v-list-item-title>{{ list.name }}</v-list-item-title>
|
<v-list-item-title>{{ list.name }}</v-list-item-title>
|
||||||
</div>
|
</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-text-field
|
||||||
v-model="editListName"
|
v-model="editListName"
|
||||||
autofocus
|
autofocus
|
||||||
@ -36,21 +43,41 @@
|
|||||||
hide-details
|
hide-details
|
||||||
label="列表名称"
|
label="列表名称"
|
||||||
@keyup.enter="saveListName"
|
@keyup.enter="saveListName"
|
||||||
></v-text-field>
|
/>
|
||||||
<v-btn border class="mr-2" color="primary" icon @click.stop.prevent="saveListName">
|
<v-btn
|
||||||
|
border
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
icon
|
||||||
|
@click.stop.prevent="saveListName"
|
||||||
|
>
|
||||||
<v-icon>mdi-check</v-icon>
|
<v-icon>mdi-check</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn border color="error" icon @click.stop.prevent="cancelEditing">
|
<v-btn
|
||||||
|
border
|
||||||
|
color="error"
|
||||||
|
icon
|
||||||
|
@click.stop.prevent="cancelEditing"
|
||||||
|
>
|
||||||
<v-icon>mdi-close</v-icon>
|
<v-icon>mdi-close</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div v-if="list.id !== editingListId">
|
<div v-if="list.id !== editingListId">
|
||||||
<v-btn border class="mr-2" icon @click.stop.prevent="startEditing(list.id)">
|
<v-btn
|
||||||
|
border
|
||||||
|
class="mr-2"
|
||||||
|
icon
|
||||||
|
@click.stop.prevent="startEditing(list.id)"
|
||||||
|
>
|
||||||
<v-icon>mdi-pencil</v-icon>
|
<v-icon>mdi-pencil</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn border icon @click.stop.prevent="confirmDeleteList(list.id)">
|
<v-btn
|
||||||
|
border
|
||||||
|
icon
|
||||||
|
@click.stop.prevent="confirmDeleteList(list.id)"
|
||||||
|
>
|
||||||
<v-icon>mdi-delete</v-icon>
|
<v-icon>mdi-delete</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
@ -58,30 +85,49 @@
|
|||||||
</v-list-item>
|
</v-list-item>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-card border class="mb-5" rounded="xl">
|
<v-card
|
||||||
|
border
|
||||||
|
class="mb-5"
|
||||||
|
rounded="xl"
|
||||||
|
>
|
||||||
<v-card-title>创建新列表</v-card-title>
|
<v-card-title>创建新列表</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field
|
<v-text-field
|
||||||
v-model="newListName"
|
v-model="newListName"
|
||||||
:rules="[v => !!v || '名称不能为空']"
|
:rules="[v => !!v || '名称不能为空']"
|
||||||
label="列表名称"
|
label="列表名称"
|
||||||
></v-text-field>
|
/>
|
||||||
<v-btn :disabled="!newListName" color="primary" @click="createNewList">
|
<v-btn
|
||||||
|
:disabled="!newListName"
|
||||||
|
color="primary"
|
||||||
|
@click="createNewList"
|
||||||
|
>
|
||||||
创建列表
|
创建列表
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</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 border>
|
||||||
<v-card-title>删除列表</v-card-title>
|
<v-card-title>删除列表</v-card-title>
|
||||||
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
<v-card-text>{{ deleteDialog.text }}</v-card-text>
|
||||||
<v-card-actions>
|
<v-card-actions>
|
||||||
<v-spacer></v-spacer>
|
<v-spacer />
|
||||||
<v-btn color="primary" variant="text" @click="deleteDialog.show = false">
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
variant="text"
|
||||||
|
@click="deleteDialog.show = false"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn color="error" variant="text" @click="confirmDelete">
|
<v-btn
|
||||||
|
color="error"
|
||||||
|
variant="text"
|
||||||
|
@click="confirmDelete"
|
||||||
|
>
|
||||||
确认删除
|
确认删除
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-card-actions>
|
</v-card-actions>
|
||||||
|
|||||||
@ -11,10 +11,11 @@
|
|||||||
icon="mdi-menu"
|
icon="mdi-menu"
|
||||||
variant="text"
|
variant="text"
|
||||||
@click="drawer = !drawer"
|
@click="drawer = !drawer"
|
||||||
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</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-app-bar>
|
||||||
|
|
||||||
<v-container fluid>
|
<v-container fluid>
|
||||||
@ -43,14 +44,23 @@
|
|||||||
direction="vertical"
|
direction="vertical"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<v-tabs-window-item value="index"
|
<v-tabs-window-item value="index">
|
||||||
|
<v-card
|
||||||
|
border
|
||||||
|
class="service-card gradient-right clickable mb-4"
|
||||||
|
color="primary"
|
||||||
|
elevation="8"
|
||||||
|
hover
|
||||||
|
rounded="xl"
|
||||||
|
variant="tonal"
|
||||||
|
@click="openClassworksKV"
|
||||||
>
|
>
|
||||||
<v-card border class="service-card gradient-right clickable mb-4" color="primary" elevation="8" hover
|
|
||||||
rounded="xl" variant="tonal" @click="openClassworksKV">
|
|
||||||
<v-card-item>
|
<v-card-item>
|
||||||
<div class="card-title">
|
<div class="card-title">
|
||||||
<div>
|
<div>
|
||||||
<div class="text-h6">在寻找 Classworks KV ?</div>
|
<div class="text-h6">
|
||||||
|
在寻找 Classworks KV ?
|
||||||
|
</div>
|
||||||
<div class="text-caption text-medium-emphasis">
|
<div class="text-caption text-medium-emphasis">
|
||||||
文档形键值数据库
|
文档形键值数据库
|
||||||
</div>
|
</div>
|
||||||
@ -71,40 +81,43 @@
|
|||||||
</div>
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
<v-card border class="rounded-xl mb-4" subtitle="设置" title="Classworks">
|
<v-card
|
||||||
|
border
|
||||||
|
class="rounded-xl mb-4"
|
||||||
|
subtitle="设置"
|
||||||
|
title="Classworks"
|
||||||
|
>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-alert
|
<v-alert
|
||||||
class="rounded-xl"
|
class="rounded-xl"
|
||||||
color="error"
|
color="error"
|
||||||
icon="mdi-alert-circle"
|
icon="mdi-alert-circle"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>Classworks
|
>
|
||||||
|
Classworks
|
||||||
是开源免费的软件,官方没有提供任何形式的付费支持服务,源代码仓库地址在
|
是开源免费的软件,官方没有提供任何形式的付费支持服务,源代码仓库地址在
|
||||||
<a
|
<a
|
||||||
href="https://github.com/ZeroCatDev/Classworks"
|
href="https://github.com/ZeroCatDev/Classworks"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>https://github.com/ZeroCatDev/Classworks</a
|
>https://github.com/ZeroCatDev/Classworks</a>。如果您通过有偿协助等付费方式取得本应用,在遇到问题时请在与卖家约定的服务框架下,优先向卖家求助。如果卖家没有提供您预期的服务,请退款或通过其它形式积极维护您的合法权益。
|
||||||
>。如果您通过有偿协助等付费方式取得本应用,在遇到问题时请在与卖家约定的服务框架下,优先向卖家求助。如果卖家没有提供您预期的服务,请退款或通过其它形式积极维护您的合法权益。
|
</v-alert>
|
||||||
</v-alert
|
|
||||||
>
|
|
||||||
<v-alert
|
<v-alert
|
||||||
class="mt-4 rounded-xl"
|
class="mt-4 rounded-xl"
|
||||||
color="info"
|
color="info"
|
||||||
icon="mdi-information"
|
icon="mdi-information"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>请不要使用浏览器清除缓存功能,否则会导致配置丢失。
|
|
||||||
<del
|
|
||||||
>恶意的操作可能导致您受到贵校教师的处理
|
|
||||||
</del
|
|
||||||
>
|
|
||||||
</v-alert
|
|
||||||
>
|
>
|
||||||
|
请不要使用浏览器清除缓存功能,否则会导致配置丢失。
|
||||||
|
<del>恶意的操作可能导致您受到贵校教师的处理
|
||||||
|
</del>
|
||||||
|
</v-alert>
|
||||||
<v-alert
|
<v-alert
|
||||||
class="mt-4 rounded-xl"
|
class="mt-4 rounded-xl"
|
||||||
color="warning"
|
color="warning"
|
||||||
icon="mdi-information"
|
icon="mdi-information"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
><p>
|
>
|
||||||
|
<p>
|
||||||
请不要使用包括但不限于360极速浏览器、360安全浏览器、夸克浏览器、QQ浏览器等浏览器使用
|
请不要使用包括但不限于360极速浏览器、360安全浏览器、夸克浏览器、QQ浏览器等浏览器使用
|
||||||
Classworks
|
Classworks
|
||||||
,这些浏览器过时且存在严重的一致性问题。在Windows上,使用新版
|
,这些浏览器过时且存在严重的一致性问题。在Windows上,使用新版
|
||||||
@ -114,7 +127,7 @@
|
|||||||
上述浏览器商标为其所属公司所有,Classworks™
|
上述浏览器商标为其所属公司所有,Classworks™
|
||||||
与上述浏览器所属公司无竞争关系。
|
与上述浏览器所属公司无竞争关系。
|
||||||
</p>
|
</p>
|
||||||
<br/>
|
<br>
|
||||||
<v-btn
|
<v-btn
|
||||||
append-icon="mdi-open-in-new"
|
append-icon="mdi-open-in-new"
|
||||||
class="text-none rounded-xl"
|
class="text-none rounded-xl"
|
||||||
@ -122,14 +135,13 @@
|
|||||||
href="https://www.microsoft.com/zh-cn/windows/microsoft-edge"
|
href="https://www.microsoft.com/zh-cn/windows/microsoft-edge"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
>下载 Microsoft Edge(微软边缘浏览器)
|
|
||||||
</v-btn
|
|
||||||
>
|
|
||||||
</v-alert
|
|
||||||
>
|
>
|
||||||
|
下载 Microsoft Edge(微软边缘浏览器)
|
||||||
|
</v-btn>
|
||||||
|
</v-alert>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
<about-card/>
|
<about-card />
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
|
|
||||||
<v-tabs-window-item value="server">
|
<v-tabs-window-item value="server">
|
||||||
@ -138,16 +150,32 @@
|
|||||||
border
|
border
|
||||||
@saved="onSettingsSaved"
|
@saved="onSettingsSaved"
|
||||||
/>
|
/>
|
||||||
<data-provider-settings-card border class="mt-4"/>
|
<data-provider-settings-card
|
||||||
<kv-database-card border class="mt-4"/>
|
border
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
|
<kv-database-card
|
||||||
|
border
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
|
|
||||||
<v-tabs-window-item value="student">
|
<v-tabs-window-item value="student">
|
||||||
<student-list-card :is-mobile="isMobile" border/>
|
<student-list-card
|
||||||
<teacher-list-card :is-mobile="isMobile" border class="mt-4"/>
|
:is-mobile="isMobile"
|
||||||
|
border
|
||||||
|
/>
|
||||||
|
<teacher-list-card
|
||||||
|
:is-mobile="isMobile"
|
||||||
|
border
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
<v-tabs-window-item value="share">
|
<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>
|
||||||
|
|
||||||
<v-tabs-window-item value="refresh">
|
<v-tabs-window-item value="refresh">
|
||||||
@ -191,27 +219,35 @@
|
|||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
|
|
||||||
<v-tabs-window-item value="randomPicker">
|
<v-tabs-window-item value="randomPicker">
|
||||||
<random-picker-card :is-mobile="isMobile" border/>
|
<random-picker-card
|
||||||
|
:is-mobile="isMobile"
|
||||||
|
border
|
||||||
|
/>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
<v-tabs-window-item value="subject">
|
<v-tabs-window-item value="subject">
|
||||||
<subject-management-card border/>
|
<subject-management-card border />
|
||||||
<br/>
|
<br>
|
||||||
<homework-template-card border/>
|
<homework-template-card border />
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
|
|
||||||
<v-tabs-window-item value="developer"
|
<v-tabs-window-item value="developer">
|
||||||
|
<settings-card
|
||||||
|
border
|
||||||
|
icon="mdi-developer-board"
|
||||||
|
title="开发者选项"
|
||||||
>
|
>
|
||||||
<settings-card border icon="mdi-developer-board" title="开发者选项">
|
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item>
|
<v-list-item>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon class="mr-3" icon="mdi-code-tags"/>
|
<v-icon
|
||||||
|
class="mr-3"
|
||||||
|
icon="mdi-code-tags"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>启用开发者选项</v-list-item-title>
|
<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>
|
<template #append>
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="settings.developer.enabled"
|
v-model="settings.developer.enabled"
|
||||||
@ -229,29 +265,41 @@
|
|||||||
@saved="onSettingsSaved"
|
@saved="onSettingsSaved"
|
||||||
/>
|
/>
|
||||||
<template v-if="settings.developer.enabled">
|
<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-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" icon="mdi-cog-outline"/>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
icon="mdi-cog-outline"
|
||||||
|
/>
|
||||||
所有设置
|
所有设置
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-subtitle> 浏览和修改所有可用设置</v-card-subtitle>
|
<v-card-subtitle> 浏览和修改所有可用设置</v-card-subtitle>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<settings-explorer @update="onSettingUpdate"/>
|
<settings-explorer @update="onSettingUpdate" />
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</template>
|
</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>
|
||||||
|
|
||||||
<v-tabs-window-item value="about">
|
<v-tabs-window-item value="about">
|
||||||
<about-card/>
|
<about-card />
|
||||||
<echo-chamber-card border class="mt-4"/>
|
<echo-chamber-card
|
||||||
|
border
|
||||||
|
class="mt-4"
|
||||||
|
/>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
</v-tabs-window>
|
</v-tabs-window>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
<!-- 消息记录组件 -->
|
<!-- 消息记录组件 -->
|
||||||
<message-log ref="messageLog"/>
|
<message-log ref="messageLog" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,18 @@
|
|||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title class="d-flex align-center">
|
<v-card-title class="d-flex align-center">
|
||||||
<v-icon class="mr-2" color="primary">mdi-network</v-icon>
|
<v-icon
|
||||||
|
class="mr-2"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
mdi-network
|
||||||
|
</v-icon>
|
||||||
Socket.IO 连接调试器
|
Socket.IO 连接调试器
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
<v-chip :color="connectionStatus.color" size="small">
|
<v-chip
|
||||||
|
:color="connectionStatus.color"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
{{ connectionStatus.text }}
|
{{ connectionStatus.text }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
@ -16,7 +24,10 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 连接信息卡片 -->
|
<!-- 连接信息卡片 -->
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title>连接信息</v-card-title>
|
<v-card-title>连接信息</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -43,7 +54,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<v-list-item-title>传输方式</v-list-item-title>
|
<v-list-item-title>传输方式</v-list-item-title>
|
||||||
<v-list-item-subtitle>
|
<v-list-item-subtitle>
|
||||||
<v-chip size="x-small" :color="transportColor">
|
<v-chip
|
||||||
|
size="x-small"
|
||||||
|
:color="transportColor"
|
||||||
|
>
|
||||||
{{ transport || '未知' }}
|
{{ transport || '未知' }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
</v-list-item-subtitle>
|
</v-list-item-subtitle>
|
||||||
@ -113,40 +127,71 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 统计信息卡片 -->
|
<!-- 统计信息卡片 -->
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title>统计信息</v-card-title>
|
<v-card-title>统计信息</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-card variant="tonal" color="success">
|
<v-card
|
||||||
|
variant="tonal"
|
||||||
|
color="success"
|
||||||
|
>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<div class="text-h4">{{ stats.eventsReceived }}</div>
|
<div class="text-h4">
|
||||||
<div class="text-caption">接收事件</div>
|
{{ stats.eventsReceived }}
|
||||||
|
</div>
|
||||||
|
<div class="text-caption">
|
||||||
|
接收事件
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-card variant="tonal" color="primary">
|
<v-card
|
||||||
|
variant="tonal"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<div class="text-h4">{{ stats.eventsSent }}</div>
|
<div class="text-h4">
|
||||||
<div class="text-caption">发送事件</div>
|
{{ stats.eventsSent }}
|
||||||
|
</div>
|
||||||
|
<div class="text-caption">
|
||||||
|
发送事件
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-card variant="tonal" color="warning">
|
<v-card
|
||||||
|
variant="tonal"
|
||||||
|
color="warning"
|
||||||
|
>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<div class="text-h4">{{ stats.errors }}</div>
|
<div class="text-h4">
|
||||||
<div class="text-caption">错误次数</div>
|
{{ stats.errors }}
|
||||||
|
</div>
|
||||||
|
<div class="text-caption">
|
||||||
|
错误次数
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="6">
|
<v-col cols="6">
|
||||||
<v-card variant="tonal" color="info">
|
<v-card
|
||||||
|
variant="tonal"
|
||||||
|
color="info"
|
||||||
|
>
|
||||||
<v-card-text class="text-center">
|
<v-card-text class="text-center">
|
||||||
<div class="text-h4">{{ stats.reconnects }}</div>
|
<div class="text-h4">
|
||||||
<div class="text-caption">重连次数</div>
|
{{ stats.reconnects }}
|
||||||
|
</div>
|
||||||
|
<div class="text-caption">
|
||||||
|
重连次数
|
||||||
|
</div>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-col>
|
</v-col>
|
||||||
@ -175,14 +220,26 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 事件监控 -->
|
<!-- 事件监控 -->
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title>
|
<v-card-title>
|
||||||
事件监控
|
事件监控
|
||||||
<v-chip class="ml-2" size="small">{{ activeListeners.size }} 个监听器</v-chip>
|
<v-chip
|
||||||
|
class="ml-2"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
{{ activeListeners.size }} 个监听器
|
||||||
|
</v-chip>
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-list density="compact" max-height="300" style="overflow-y: auto">
|
<v-list
|
||||||
|
density="compact"
|
||||||
|
max-height="300"
|
||||||
|
style="overflow-y: auto"
|
||||||
|
>
|
||||||
<v-list-item v-if="activeListeners.size === 0">
|
<v-list-item v-if="activeListeners.size === 0">
|
||||||
<v-list-item-title class="text-center text-disabled">
|
<v-list-item-title class="text-center text-disabled">
|
||||||
暂无活动监听器
|
暂无活动监听器
|
||||||
@ -193,7 +250,9 @@
|
|||||||
:key="listener"
|
:key="listener"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<v-icon size="small">mdi-eye</v-icon>
|
<v-icon size="small">
|
||||||
|
mdi-eye
|
||||||
|
</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>{{ listener }}</v-list-item-title>
|
<v-list-item-title>{{ listener }}</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
@ -203,7 +262,10 @@
|
|||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<!-- 自定义事件发送 -->
|
<!-- 自定义事件发送 -->
|
||||||
<v-col cols="12" md="6">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="6"
|
||||||
|
>
|
||||||
<v-card border>
|
<v-card border>
|
||||||
<v-card-title>发送自定义事件</v-card-title>
|
<v-card-title>发送自定义事件</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
@ -272,9 +334,15 @@
|
|||||||
<span class="log-time">[{{ log.time }}]</span>
|
<span class="log-time">[{{ log.time }}]</span>
|
||||||
<span class="log-type">[{{ log.type.toUpperCase() }}]</span>
|
<span class="log-type">[{{ log.type.toUpperCase() }}]</span>
|
||||||
<span class="log-message">{{ log.message }}</span>
|
<span class="log-message">{{ log.message }}</span>
|
||||||
<pre v-if="log.data" class="log-data">{{ log.data }}</pre>
|
<pre
|
||||||
|
v-if="log.data"
|
||||||
|
class="log-data"
|
||||||
|
>{{ log.data }}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="logs.length === 0" class="text-center text-disabled pa-8">
|
<div
|
||||||
|
v-if="logs.length === 0"
|
||||||
|
class="text-center text-disabled pa-8"
|
||||||
|
>
|
||||||
暂无日志
|
暂无日志
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,7 +356,10 @@
|
|||||||
<v-card-title>连接诊断</v-card-title>
|
<v-card-title>连接诊断</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
block
|
block
|
||||||
color="info"
|
color="info"
|
||||||
@ -298,7 +369,10 @@
|
|||||||
测试连接
|
测试连接
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
block
|
block
|
||||||
color="success"
|
color="success"
|
||||||
@ -309,7 +383,10 @@
|
|||||||
测量延迟
|
测量延迟
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="4">
|
<v-col
|
||||||
|
cols="12"
|
||||||
|
md="4"
|
||||||
|
>
|
||||||
<v-btn
|
<v-btn
|
||||||
block
|
block
|
||||||
color="warning"
|
color="warning"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import {kvLocalProvider} from "./providers/kvLocalProvider";
|
import {kvLocalProvider} from "./providers/kvLocalProvider";
|
||||||
import {kvServerProvider} from "./providers/kvServerProvider";
|
import {kvServerProvider, getServerUrl, CLASSWORKS_CLOUD_SERVERS} from "./providers/kvServerProvider";
|
||||||
import {getSetting, setSetting} from "./settings";
|
import {getSetting, setSetting} from "./settings";
|
||||||
|
|
||||||
export const formatResponse = (data) => data;
|
export const formatResponse = (data) => data;
|
||||||
@ -176,6 +176,7 @@ export default {
|
|||||||
let serverUrl = getSetting("server.domain");
|
let serverUrl = getSetting("server.domain");
|
||||||
let siteKey = getSetting("server.siteKey");
|
let siteKey = getSetting("server.siteKey");
|
||||||
const machineId = getSetting("device.uuid");
|
const machineId = getSetting("device.uuid");
|
||||||
|
const provider = getSetting("server.provider");
|
||||||
let configured = false;
|
let configured = false;
|
||||||
|
|
||||||
// 检查云端配置是否为空或错误,如果是则使用默认配置
|
// 检查云端配置是否为空或错误,如果是则使用默认配置
|
||||||
@ -183,7 +184,7 @@ export default {
|
|||||||
if (autoConfigureCloud) {
|
if (autoConfigureCloud) {
|
||||||
// 使用classworksCloudDefaults配置
|
// 使用classworksCloudDefaults配置
|
||||||
const classworksCloudDefaults = {
|
const classworksCloudDefaults = {
|
||||||
"server.domain": import.meta.env.VITE_DEFAULT_KV_SERVER || "https://kv-service.houlang.cloud",
|
"server.domain": import.meta.env.VITE_DEFAULT_KV_SERVER || CLASSWORKS_CLOUD_SERVERS[0],
|
||||||
"server.siteKey": "",
|
"server.siteKey": "",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -205,6 +206,11 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果使用classworkscloud,使用当前激活的服务器URL
|
||||||
|
if (provider === "classworkscloud") {
|
||||||
|
serverUrl = getServerUrl();
|
||||||
|
}
|
||||||
|
|
||||||
let migrated = false;
|
let migrated = false;
|
||||||
|
|
||||||
// 如果需要迁移本地数据到云端
|
// 如果需要迁移本地数据到云端
|
||||||
|
|||||||
@ -2,6 +2,15 @@ import axios from "@/axios/axios";
|
|||||||
import {formatResponse, formatError} from "../dataProvider";
|
import {formatResponse, formatError} from "../dataProvider";
|
||||||
import {getSetting} from "../settings";
|
import {getSetting} from "../settings";
|
||||||
|
|
||||||
|
// Classworks云服务器地址列表(按优先级从上到下)
|
||||||
|
const CLASSWORKS_CLOUD_SERVERS = [
|
||||||
|
"https://kv-service.houlang.cloud",
|
||||||
|
"https://kv-service.wuyuan.dev"
|
||||||
|
];
|
||||||
|
|
||||||
|
// 当前正在使用的服务器索引
|
||||||
|
let currentServerIndex = 0;
|
||||||
|
|
||||||
// Helper function to get request headers with kvtoken
|
// Helper function to get request headers with kvtoken
|
||||||
const getHeaders = () => {
|
const getHeaders = () => {
|
||||||
const headers = {Accept: "application/json"};
|
const headers = {Accept: "application/json"};
|
||||||
@ -19,11 +28,68 @@ const getHeaders = () => {
|
|||||||
return headers;
|
return headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取服务器URL,支持Classworks云服务的自动故障转移
|
||||||
|
* @returns {string} 服务器URL
|
||||||
|
*/
|
||||||
|
const getServerUrl = () => {
|
||||||
|
const provider = getSetting("server.provider");
|
||||||
|
|
||||||
|
// 如果使用classworkscloud,使用服务器列表
|
||||||
|
if (provider === "classworkscloud") {
|
||||||
|
return CLASSWORKS_CLOUD_SERVERS[currentServerIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则使用用户配置的服务器域名
|
||||||
|
return getSetting("server.domain");
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试下一个服务器(仅对classworkscloud生效)
|
||||||
|
*/
|
||||||
|
const tryNextServer = () => {
|
||||||
|
const provider = getSetting("server.provider");
|
||||||
|
|
||||||
|
if (provider === "classworkscloud") {
|
||||||
|
currentServerIndex = (currentServerIndex + 1) % CLASSWORKS_CLOUD_SERVERS.length;
|
||||||
|
console.log(`切换到备用服务器: ${CLASSWORKS_CLOUD_SERVERS[currentServerIndex]}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带自动故障转移的请求包装器
|
||||||
|
* @param {Function} requestFn - 执行请求的函数
|
||||||
|
* @returns {Promise} 请求结果
|
||||||
|
*/
|
||||||
|
const requestWithFailover = async (requestFn) => {
|
||||||
|
const provider = getSetting("server.provider");
|
||||||
|
const maxRetries = provider === "classworkscloud" ? CLASSWORKS_CLOUD_SERVERS.length : 1;
|
||||||
|
|
||||||
|
let lastError = null;
|
||||||
|
|
||||||
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
||||||
|
try {
|
||||||
|
return await requestFn();
|
||||||
|
} catch (error) {
|
||||||
|
lastError = error;
|
||||||
|
|
||||||
|
// 只有在使用classworkscloud且还有其他服务器可尝试时才切换
|
||||||
|
if (provider === "classworkscloud" && attempt < maxRetries - 1) {
|
||||||
|
console.warn(`服务器请求失败,尝试备用服务器...`, error.message);
|
||||||
|
tryNextServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有服务器都失败后抛出最后一个错误
|
||||||
|
throw lastError;
|
||||||
|
};
|
||||||
|
|
||||||
export const kvServerProvider = {
|
export const kvServerProvider = {
|
||||||
async loadNamespaceInfo() {
|
async loadNamespaceInfo() {
|
||||||
try {
|
try {
|
||||||
// 使用 Classworks Cloud 或者用户配置的服务器域名
|
return await requestWithFailover(async () => {
|
||||||
const serverUrl = getSetting("server.domain");
|
const serverUrl = getServerUrl();
|
||||||
|
|
||||||
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
const res = await axios.get(`${serverUrl}/kv/_info`, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
@ -31,6 +97,7 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
// 直接返回新格式 API 数据,包含 device 和 account 信息
|
// 直接返回新格式 API 数据,包含 device 和 account 信息
|
||||||
return formatResponse(res.data);
|
return formatResponse(res.data);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("获取命名空间信息失败:", error);
|
console.error("获取命名空间信息失败:", error);
|
||||||
return formatError(
|
return formatError(
|
||||||
@ -42,13 +109,15 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async updateNamespaceInfo(data) {
|
async updateNamespaceInfo(data) {
|
||||||
try {
|
try {
|
||||||
const serverUrl = getSetting("server.domain");
|
return await requestWithFailover(async () => {
|
||||||
|
const serverUrl = getServerUrl();
|
||||||
|
|
||||||
const res = await axios.put(`${serverUrl}/kv/_info`, data, {
|
const res = await axios.put(`${serverUrl}/kv/_info`, data, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return formatError(
|
return formatError(
|
||||||
error.response?.data?.message || "更新命名空间信息失败",
|
error.response?.data?.message || "更新命名空间信息失败",
|
||||||
@ -59,13 +128,15 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async loadData(key) {
|
async loadData(key) {
|
||||||
try {
|
try {
|
||||||
const serverUrl = getSetting("server.domain");
|
return await requestWithFailover(async () => {
|
||||||
|
const serverUrl = getServerUrl();
|
||||||
|
|
||||||
const res = await axios.get(`${serverUrl}/kv/${key}`, {
|
const res = await axios.get(`${serverUrl}/kv/${key}`, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
|
|
||||||
return formatResponse(res.data);
|
return formatResponse(res.data);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response?.status === 404) {
|
if (error.response?.status === 404) {
|
||||||
return formatError("数据不存在", "NOT_FOUND");
|
return formatError("数据不存在", "NOT_FOUND");
|
||||||
@ -80,11 +151,13 @@ export const kvServerProvider = {
|
|||||||
|
|
||||||
async saveData(key, data) {
|
async saveData(key, data) {
|
||||||
try {
|
try {
|
||||||
const serverUrl = getSetting("server.domain");
|
return await requestWithFailover(async () => {
|
||||||
|
const serverUrl = getServerUrl();
|
||||||
await axios.post(`${serverUrl}/kv/${key}`, data, {
|
await axios.post(`${serverUrl}/kv/${key}`, data, {
|
||||||
headers: getHeaders(),
|
headers: getHeaders(),
|
||||||
});
|
});
|
||||||
return formatResponse(true);
|
return formatResponse(true);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return formatError(
|
return formatError(
|
||||||
@ -117,7 +190,8 @@ export const kvServerProvider = {
|
|||||||
*/
|
*/
|
||||||
async loadKeys(options = {}) {
|
async loadKeys(options = {}) {
|
||||||
try {
|
try {
|
||||||
const serverUrl = getSetting("server.domain");
|
return await requestWithFailover(async () => {
|
||||||
|
const serverUrl = getServerUrl();
|
||||||
|
|
||||||
// 设置默认参数
|
// 设置默认参数
|
||||||
const {
|
const {
|
||||||
@ -140,6 +214,7 @@ export const kvServerProvider = {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return formatResponse(res.data);
|
return formatResponse(res.data);
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.response?.status === 404) {
|
if (error.response?.status === 404) {
|
||||||
return formatError("命名空间不存在", "NOT_FOUND");
|
return formatError("命名空间不存在", "NOT_FOUND");
|
||||||
@ -158,3 +233,6 @@ export const kvServerProvider = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 导出服务器列表和URL获取函数供其他模块使用
|
||||||
|
export { CLASSWORKS_CLOUD_SERVERS, getServerUrl };
|
||||||
|
|||||||
@ -64,8 +64,14 @@ const SETTINGS_STORAGE_KEY = "Classworks_settings";
|
|||||||
|
|
||||||
|
|
||||||
// 新增: Classworks云端存储的默认设置
|
// 新增: Classworks云端存储的默认设置
|
||||||
|
// Classworks云服务器地址列表(按优先级从上到下)
|
||||||
|
const CLASSWORKS_CLOUD_SERVERS = [
|
||||||
|
"https://kv-service.houlang.cloud",
|
||||||
|
"https://kv-service.wuyuan.dev"
|
||||||
|
];
|
||||||
|
|
||||||
const classworksCloudDefaults = {
|
const classworksCloudDefaults = {
|
||||||
"server.domain": import.meta.env.VITE_DEFAULT_KV_SERVER || "https://kv-service.houlang.cloud",
|
"server.domain": import.meta.env.VITE_DEFAULT_KV_SERVER || CLASSWORKS_CLOUD_SERVERS[0],
|
||||||
//"server.domain": "http://localhost:3030",
|
//"server.domain": "http://localhost:3030",
|
||||||
"server.siteKey": "",
|
"server.siteKey": "",
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user