规范代码格式
This commit is contained in:
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<v-card border rounded="xl" hover>
|
||||
<v-card border hover rounded="xl">
|
||||
<v-card-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-information" size="large" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-information" size="large"/>
|
||||
</template>
|
||||
<v-card-title class="text-h6">关于</v-card-title>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text>
|
||||
<v-row>
|
||||
<v-col cols="12" md="8" class="mx-auto">
|
||||
<v-col class="mx-auto" cols="12" md="8">
|
||||
<div class="d-flex flex-column align-start">
|
||||
<v-avatar size="120" class="mb-4">
|
||||
<v-avatar class="mb-4" size="120">
|
||||
<v-img
|
||||
src="../../assets/cslogo.png"
|
||||
alt="Classworks"
|
||||
src="../../assets/cslogo.png"
|
||||
/>
|
||||
</v-avatar>
|
||||
|
||||
@@ -24,35 +24,35 @@
|
||||
<div class="d-flex gap-2 flex-wrap mb-6">
|
||||
<v-btn
|
||||
color="red"
|
||||
variant="tonal"
|
||||
href="https://github.com/ClassworksDev/Classworks/issues"
|
||||
target="_blank"
|
||||
prepend-icon="mdi-bug"
|
||||
target="_blank"
|
||||
variant="tonal"
|
||||
>
|
||||
报告问题
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
href="https://qm.qq.com/q/qNBX4ZZVeg"
|
||||
target="_blank"
|
||||
prepend-icon="mdi-qqchat"
|
||||
target="_blank"
|
||||
variant="tonal"
|
||||
>
|
||||
QQ 群
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
href="https://github.com/ClassworksDev/Classworks"
|
||||
target="_blank"
|
||||
prepend-icon="mdi-github"
|
||||
target="_blank"
|
||||
variant="text"
|
||||
>
|
||||
前端
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
href="https://github.com/ClassworksDev/ClassworksServer"
|
||||
target="_blank"
|
||||
prepend-icon="mdi-github"
|
||||
target="_blank"
|
||||
variant="text"
|
||||
>
|
||||
后端
|
||||
</v-btn>
|
||||
@@ -63,9 +63,9 @@
|
||||
<h3 class="text-h6 mb-2">备注与致谢</h3>
|
||||
<v-list class="mb-4 bg-transparent">
|
||||
<v-list-item
|
||||
append-icon="mdi-link"
|
||||
href="https://github.com/EnderWolf006/HomeworkBoard"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
>
|
||||
<v-list-item-title>
|
||||
本项目受到 HomeworkBoard 的启发而开发
|
||||
@@ -76,9 +76,9 @@
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
append-icon="mdi-link"
|
||||
href="https://hlyun.org"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
>
|
||||
<v-list-item-title>
|
||||
Classworks 由<strong>厚浪云</strong>提供
|
||||
@@ -88,9 +88,9 @@
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
append-icon="mdi-link"
|
||||
href="https://zerocat.houlangs.com"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
>
|
||||
<v-list-item-title>
|
||||
感谢 ZeroCat 社区的开发者们
|
||||
@@ -101,9 +101,9 @@
|
||||
</v-list-item>
|
||||
<v-divider class="ma-1"></v-divider>
|
||||
<v-list-item
|
||||
append-icon="mdi-link"
|
||||
href="https://github.com/HUSX100/IslandCaller"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
>
|
||||
<v-list-item-title>
|
||||
本项目与 IslandCaller 没有从属关系
|
||||
@@ -114,9 +114,9 @@
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
append-icon="mdi-link"
|
||||
href="https://classisland.tech"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
>
|
||||
<v-list-item-title>
|
||||
本项目与 ClassIsland 没有从属关系
|
||||
@@ -129,9 +129,9 @@
|
||||
</v-list>
|
||||
|
||||
<v-btn
|
||||
variant="text"
|
||||
class="mb-4"
|
||||
prepend-icon="mdi-package-variant"
|
||||
variant="text"
|
||||
@click="showDeps = true"
|
||||
>
|
||||
查看使用的第三方库
|
||||
@@ -139,11 +139,12 @@
|
||||
|
||||
<v-dialog
|
||||
v-model="showDeps"
|
||||
transition="dialog-bottom-transition"
|
||||
fullscreen
|
||||
transition="dialog-bottom-transition"
|
||||
>
|
||||
<v-card
|
||||
><v-toolbar>
|
||||
>
|
||||
<v-toolbar>
|
||||
<v-btn icon="mdi-close" @click="showDeps = false"></v-btn>
|
||||
<v-toolbar-title>使用的第三方库</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
@@ -154,8 +155,8 @@
|
||||
v-for="dep in Dependencies"
|
||||
:key="dep.name"
|
||||
:href="'https://www.npmjs.com/package/' + dep.name"
|
||||
target="_blank"
|
||||
append-icon="mdi-link"
|
||||
target="_blank"
|
||||
>
|
||||
<v-list-item-title>
|
||||
{{ dep.name }}
|
||||
@@ -180,7 +181,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted } from "vue";
|
||||
import {ref, onMounted} from "vue";
|
||||
import packageJson from "../../../package.json";
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<v-card :border="border" class="setting-group">
|
||||
<v-card-title v-if="title" class="d-flex align-center">
|
||||
<v-icon v-if="icon" :icon="icon" class="mr-2" />
|
||||
<v-icon v-if="icon" :icon="icon" class="mr-2"/>
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
|
||||
|
||||
<v-card-subtitle v-if="description">
|
||||
{{ description }}
|
||||
</v-card-subtitle>
|
||||
|
||||
|
||||
<v-card-text>
|
||||
<v-list>
|
||||
<slot>
|
||||
@@ -16,7 +16,7 @@
|
||||
</slot>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
|
||||
|
||||
<v-card-actions v-if="$slots.actions">
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
@@ -26,7 +26,7 @@
|
||||
<script>
|
||||
export default {
|
||||
name: 'SettingGroup',
|
||||
|
||||
|
||||
props: {
|
||||
/**
|
||||
* 设置组的标题
|
||||
@@ -35,7 +35,7 @@ export default {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 设置组的描述
|
||||
*/
|
||||
@@ -43,7 +43,7 @@ export default {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 设置组的图标
|
||||
*/
|
||||
@@ -51,7 +51,7 @@ export default {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 是否显示边框
|
||||
*/
|
||||
@@ -60,12 +60,12 @@ export default {
|
||||
default: false
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
methods: {
|
||||
onSettingUpdate(key, value) {
|
||||
this.$emit('update', key, value);
|
||||
},
|
||||
|
||||
|
||||
onSettingError(key) {
|
||||
this.$emit('error', key);
|
||||
}
|
||||
@@ -77,4 +77,4 @@ export default {
|
||||
.setting-group {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-list-item class="setting-item" :disabled="disabled">
|
||||
<v-list-item :disabled="disabled" class="setting-item">
|
||||
<template #prepend>
|
||||
<v-icon :icon="settingIcon" />
|
||||
<v-icon :icon="settingIcon"/>
|
||||
</template>
|
||||
|
||||
<v-list-item-title class="text-wrap">
|
||||
@@ -19,57 +19,57 @@
|
||||
<v-switch
|
||||
v-if="type === 'boolean'"
|
||||
v-model="localValue"
|
||||
:disabled="disabled"
|
||||
density="comfortable"
|
||||
hide-details
|
||||
:disabled="disabled"
|
||||
@update:model-value="updateSetting"
|
||||
/>
|
||||
|
||||
<v-select
|
||||
v-else-if="type === 'string' && hasOptions"
|
||||
v-model="localValue"
|
||||
:disabled="disabled"
|
||||
:items="selectOptions"
|
||||
bg-color="surface"
|
||||
class="setting-select"
|
||||
density="compact"
|
||||
hide-details
|
||||
:disabled="disabled"
|
||||
class="setting-select"
|
||||
variant="outlined"
|
||||
bg-color="surface"
|
||||
@update:model-value="updateSetting"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
variant="outlined"
|
||||
@update:model-value="updateSetting"
|
||||
/>
|
||||
|
||||
<div v-else-if="type === 'number'" class="d-flex align-center">
|
||||
<v-btn
|
||||
:disabled="disabled || localValue <= minValue"
|
||||
icon="mdi-minus"
|
||||
size="small"
|
||||
variant="text"
|
||||
:disabled="disabled || localValue <= minValue"
|
||||
@click="adjustValue(-stepValue)"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
v-model.number="localValue"
|
||||
type="number"
|
||||
:disabled="disabled"
|
||||
:max="maxValue"
|
||||
:min="minValue"
|
||||
:step="stepValue"
|
||||
bg-color="surface"
|
||||
class="mx-2 setting-number-field"
|
||||
density="compact"
|
||||
hide-details
|
||||
:min="minValue"
|
||||
:max="maxValue"
|
||||
:step="stepValue"
|
||||
:disabled="disabled"
|
||||
class="mx-2 setting-number-field"
|
||||
style="width: 80px"
|
||||
type="number"
|
||||
variant="outlined"
|
||||
bg-color="surface"
|
||||
@update:model-value="updateSetting"
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
:disabled="disabled || localValue >= maxValue"
|
||||
icon="mdi-plus"
|
||||
size="small"
|
||||
variant="text"
|
||||
:disabled="disabled || localValue >= maxValue"
|
||||
@click="adjustValue(stepValue)"
|
||||
/>
|
||||
</div>
|
||||
@@ -78,34 +78,34 @@
|
||||
<v-menu location="bottom">
|
||||
<template v-slot:activator="{ props }">
|
||||
<v-btn
|
||||
:disabled="disabled"
|
||||
class="ml-2"
|
||||
icon="mdi-dots-vertical"
|
||||
size="small"
|
||||
variant="text"
|
||||
v-bind="props"
|
||||
class="ml-2"
|
||||
:disabled="disabled"
|
||||
variant="text"
|
||||
/>
|
||||
</template>
|
||||
<v-list density="compact">
|
||||
<v-list-item @click="copySettingId">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-key" size="small" />
|
||||
<v-icon icon="mdi-key" size="small"/>
|
||||
</template>
|
||||
<v-list-item-title>复制设置ID</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="copySettingValue">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-content-copy" size="small" />
|
||||
<v-icon icon="mdi-content-copy" size="small"/>
|
||||
</template>
|
||||
<v-list-item-title>复制设置值</v-list-item-title>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider></v-divider>
|
||||
|
||||
<v-list-item @click="resetToDefault" :disabled="isDefaultValue">
|
||||
<v-list-item :disabled="isDefaultValue" @click="resetToDefault">
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-restore" size="small" />
|
||||
<v-icon icon="mdi-restore" size="small"/>
|
||||
</template>
|
||||
<v-list-item-title>重置为默认值</v-list-item-title>
|
||||
</v-list-item>
|
||||
@@ -119,12 +119,12 @@
|
||||
<div v-if="type === 'string' && !hasOptions" class="px-4 pb-2 pt-0">
|
||||
<v-text-field
|
||||
v-model="localValue"
|
||||
:disabled="disabled"
|
||||
bg-color="surface"
|
||||
class="setting-text-field mt-1"
|
||||
density="compact"
|
||||
hide-details
|
||||
:disabled="disabled"
|
||||
class="setting-text-field mt-1"
|
||||
variant="outlined"
|
||||
bg-color="surface"
|
||||
@update:model-value="updateSetting"
|
||||
/>
|
||||
</div>
|
||||
@@ -206,20 +206,20 @@ export default {
|
||||
showSnackbar: false,
|
||||
snackbarText: "",
|
||||
fontFamilies: [
|
||||
{ title: "Arial", value: "Arial, sans-serif" },
|
||||
{ title: "Calibri", value: "Calibri, sans-serif" },
|
||||
{ title: "Cambria", value: "Cambria, serif" },
|
||||
{ title: "Consolas", value: "Consolas, monospace" },
|
||||
{ title: "Courier New", value: "Courier New, monospace" },
|
||||
{ title: "Georgia", value: "Georgia, serif" },
|
||||
{ title: "Helvetica", value: "Helvetica, sans-serif" },
|
||||
{ title: "Segoe UI", value: "Segoe UI, sans-serif" },
|
||||
{ title: "Times New Roman", value: "Times New Roman, serif" },
|
||||
{ title: "Trebuchet MS", value: "Trebuchet MS, sans-serif" },
|
||||
{ title: "Verdana", value: "Verdana, sans-serif" },
|
||||
{ title: "Monospace", value: "monospace" },
|
||||
{ title: "Sans-serif", value: "sans-serif" },
|
||||
{ title: "Serif", value: "serif" },
|
||||
{title: "Arial", value: "Arial, sans-serif"},
|
||||
{title: "Calibri", value: "Calibri, sans-serif"},
|
||||
{title: "Cambria", value: "Cambria, serif"},
|
||||
{title: "Consolas", value: "Consolas, monospace"},
|
||||
{title: "Courier New", value: "Courier New, monospace"},
|
||||
{title: "Georgia", value: "Georgia, serif"},
|
||||
{title: "Helvetica", value: "Helvetica, sans-serif"},
|
||||
{title: "Segoe UI", value: "Segoe UI, sans-serif"},
|
||||
{title: "Times New Roman", value: "Times New Roman, serif"},
|
||||
{title: "Trebuchet MS", value: "Trebuchet MS, sans-serif"},
|
||||
{title: "Verdana", value: "Verdana, sans-serif"},
|
||||
{title: "Monospace", value: "monospace"},
|
||||
{title: "Sans-serif", value: "sans-serif"},
|
||||
{title: "Serif", value: "serif"},
|
||||
],
|
||||
// 设置项的显示名称映射
|
||||
displayValueMappings: {
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
<template>
|
||||
<div class="settings-explorer">
|
||||
|
||||
|
||||
<div >
|
||||
<v-text-field v-model="searchQuery" label="搜索设置" prepend-inner-icon="mdi-magnify" clearable variant="outlined"
|
||||
density="comfortable" class="mb-4" />
|
||||
|
||||
|
||||
<div>
|
||||
<v-text-field v-model="searchQuery" class="mb-4" clearable density="comfortable" label="搜索设置"
|
||||
prepend-inner-icon="mdi-magnify" variant="outlined"/>
|
||||
|
||||
|
||||
<v-list>
|
||||
<div v-for="setting in allSettings" :key="setting.key">
|
||||
<setting-item :key="setting.key" :setting-key="setting.key"
|
||||
:disabled="setting.requireDeveloper && !isDeveloperMode" @update="onSettingUpdate" @error="onSettingError" />
|
||||
<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>
|
||||
</v-list><v-card border>
|
||||
</v-list>
|
||||
<v-card border>
|
||||
<v-card-title class="text-subtitle-1">当前配置</v-card-title>
|
||||
<v-card-text>
|
||||
<pre class="settings-json">{{ formattedSettings }}</pre>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn @click="copySettingsToClipboard">
|
||||
<v-btn @click="copySettingsToClipboard">
|
||||
复制到剪贴板
|
||||
<v-icon right>mdi-content-copy</v-icon>
|
||||
</v-btn>
|
||||
@@ -32,7 +33,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getSetting, settingsDefinitions, exportSettingsAsKeyValue, watchSettings } from '@/utils/settings';
|
||||
import {getSetting, settingsDefinitions, exportSettingsAsKeyValue, watchSettings} from '@/utils/settings';
|
||||
import SettingItem from './SettingItem.vue';
|
||||
|
||||
export default {
|
||||
@@ -82,7 +83,7 @@ export default {
|
||||
created() {
|
||||
// 初始化当前设置
|
||||
this.updateCurrentSettings();
|
||||
|
||||
|
||||
// 监听设置变化
|
||||
this.unwatchFunction = watchSettings(() => {
|
||||
this.updateCurrentSettings();
|
||||
@@ -115,11 +116,11 @@ export default {
|
||||
navigator.clipboard.writeText(JSON.stringify(this.currentSettings))
|
||||
.then(() => {
|
||||
// 可以添加一个提示,表示复制成功
|
||||
this.$emit('message', { type: 'success', text: '设置已复制到剪贴板' });
|
||||
this.$emit('message', {type: 'success', text: '设置已复制到剪贴板'});
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('复制到剪贴板失败:', err);
|
||||
this.$emit('message', { type: 'error', text: '复制到剪贴板失败' });
|
||||
this.$emit('message', {type: 'error', text: '复制到剪贴板失败'});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -145,4 +146,4 @@ export default {
|
||||
.v-theme--dark .settings-json {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
<template>
|
||||
<v-card
|
||||
border
|
||||
:color="unsavedChanges ? 'warning-subtle' : undefined"
|
||||
:class="{ 'unsaved-changes': unsavedChanges }"
|
||||
:color="unsavedChanges ? 'warning-subtle' : undefined"
|
||||
border
|
||||
>
|
||||
<v-card-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-account-group" size="large" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-account-group" size="large"/>
|
||||
</template>
|
||||
<v-card-title class="text-h6">学生列表</v-card-title>
|
||||
<template #append>
|
||||
<unsaved-warning :show="unsavedChanges" message="有未保存的更改" />
|
||||
<unsaved-warning :show="unsavedChanges" message="有未保存的更改"/>
|
||||
<v-btn
|
||||
:disabled="modelValue.list.length === 0"
|
||||
class="mr-2"
|
||||
prepend-icon="mdi-sort-alphabetical-variant"
|
||||
variant="text"
|
||||
class="mr-2"
|
||||
@click="sortStudentsByPinyin"
|
||||
:disabled="modelValue.list.length === 0"
|
||||
>
|
||||
按姓名首字母排序
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:color="modelValue.advanced ? 'primary' : undefined"
|
||||
variant="text"
|
||||
prepend-icon="mdi-code-braces"
|
||||
variant="text"
|
||||
@click="toggleAdvanced"
|
||||
>
|
||||
{{ modelValue.advanced ? "返回基础编辑" : "高级编辑" }}
|
||||
@@ -34,12 +34,12 @@
|
||||
<v-card-text>
|
||||
<v-progress-linear
|
||||
v-if="loading"
|
||||
indeterminate
|
||||
color="primary"
|
||||
class="mb-4"
|
||||
color="primary"
|
||||
indeterminate
|
||||
/>
|
||||
|
||||
<v-alert v-if="error" type="error" variant="tonal" closable class="mb-4">
|
||||
<v-alert v-if="error" class="mb-4" closable type="error" variant="tonal">
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
|
||||
@@ -47,23 +47,23 @@
|
||||
<!-- 普通编辑模式 -->
|
||||
<div v-if="!modelValue.advanced">
|
||||
<v-row class="mb-6">
|
||||
<v-col cols="12" sm="6" md="4">
|
||||
<v-col cols="12" md="4" sm="6">
|
||||
<v-text-field
|
||||
v-model="newStudentName"
|
||||
class="mb-4"
|
||||
hide-details
|
||||
label="添加学生"
|
||||
placeholder="输入学生姓名后回车添加"
|
||||
prepend-inner-icon="mdi-account-plus"
|
||||
variant="outlined"
|
||||
hide-details
|
||||
class="mb-4"
|
||||
@keyup.enter="addStudent"
|
||||
>
|
||||
<template #append>
|
||||
<v-btn
|
||||
:disabled="!newStudentName.trim()"
|
||||
color="primary"
|
||||
icon="mdi-plus"
|
||||
variant="text"
|
||||
color="primary"
|
||||
:disabled="!newStudentName.trim()"
|
||||
@click="addStudent"
|
||||
/>
|
||||
</template>
|
||||
@@ -76,25 +76,25 @@
|
||||
v-for="(student, index) in modelValue.list"
|
||||
:key="index"
|
||||
cols="12"
|
||||
sm="6"
|
||||
md="4"
|
||||
lg="3"
|
||||
md="4"
|
||||
sm="6"
|
||||
>
|
||||
<v-hover v-slot="{ isHovering, props }">
|
||||
<v-card
|
||||
v-bind="props"
|
||||
:elevation="isMobile ? 1 : isHovering ? 4 : 1"
|
||||
class="student-card"
|
||||
border
|
||||
class="student-card"
|
||||
v-bind="props"
|
||||
>
|
||||
<v-card-text class="d-flex align-center pa-3">
|
||||
<v-menu location="bottom" :open-on-hover="!isMobile">
|
||||
<v-menu :open-on-hover="!isMobile" location="bottom">
|
||||
<template #activator="{ props: menuProps }">
|
||||
<v-btn
|
||||
variant="tonal"
|
||||
size="small"
|
||||
class="mr-3 font-weight-medium"
|
||||
size="small"
|
||||
v-bind="menuProps"
|
||||
variant="tonal"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</v-btn>
|
||||
@@ -102,23 +102,23 @@
|
||||
|
||||
<v-list density="compact" nav>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-arrow-up-bold"
|
||||
:disabled="index === 0"
|
||||
prepend-icon="mdi-arrow-up-bold"
|
||||
@click="moveStudent(index, 'top')"
|
||||
>
|
||||
置顶
|
||||
</v-list-item>
|
||||
<v-divider />
|
||||
<v-divider/>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-arrow-up"
|
||||
:disabled="index === 0"
|
||||
prepend-icon="mdi-arrow-up"
|
||||
@click="moveStudent(index, 'up')"
|
||||
>
|
||||
上移
|
||||
</v-list-item>
|
||||
<v-list-item
|
||||
prepend-icon="mdi-arrow-down"
|
||||
:disabled="index === modelValue.list.length - 1"
|
||||
prepend-icon="mdi-arrow-down"
|
||||
@click="moveStudent(index, 'down')"
|
||||
>
|
||||
下移
|
||||
@@ -129,13 +129,13 @@
|
||||
<v-text-field
|
||||
v-if="editState.index === index"
|
||||
v-model="editState.name"
|
||||
density="compact"
|
||||
variant="underlined"
|
||||
hide-details
|
||||
class="flex-grow-1"
|
||||
autofocus
|
||||
@keyup.enter="saveEdit"
|
||||
class="flex-grow-1"
|
||||
density="compact"
|
||||
hide-details
|
||||
variant="underlined"
|
||||
@blur="saveEdit"
|
||||
@keyup.enter="saveEdit"
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
@@ -146,21 +146,21 @@
|
||||
</span>
|
||||
|
||||
<div
|
||||
class="d-flex gap-1 action-buttons"
|
||||
:class="{ 'opacity-100': isHovering || isMobile }"
|
||||
class="d-flex gap-1 action-buttons"
|
||||
>
|
||||
<v-btn
|
||||
icon="mdi-pencil"
|
||||
variant="text"
|
||||
color="primary"
|
||||
icon="mdi-pencil"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="startEdit(index, student)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="removeStudent(index)"
|
||||
/>
|
||||
</div>
|
||||
@@ -175,36 +175,36 @@
|
||||
<div v-else class="pt-2">
|
||||
<v-textarea
|
||||
v-model="modelValue.text"
|
||||
label="批量编辑学生列表"
|
||||
placeholder="每行输入一个学生姓名"
|
||||
hint="使用文本编辑模式批量编辑学生名单,保存时会自动去除空行"
|
||||
label="批量编辑学生列表"
|
||||
persistent-hint
|
||||
variant="outlined"
|
||||
placeholder="每行输入一个学生姓名"
|
||||
rows="10"
|
||||
variant="outlined"
|
||||
@update:model-value="handleTextInput"
|
||||
/>
|
||||
</div>
|
||||
</v-expand-transition>
|
||||
|
||||
<v-row class="mt-6">
|
||||
<v-col cols="12" class="d-flex gap-2">
|
||||
<v-col class="d-flex gap-2" cols="12">
|
||||
<v-btn
|
||||
:disabled="loading"
|
||||
:loading="loading"
|
||||
color="primary"
|
||||
prepend-icon="mdi-content-save"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
@click="saveStudents"
|
||||
>
|
||||
保存名单
|
||||
</v-btn>
|
||||
<v-btn
|
||||
:disabled="loading"
|
||||
:loading="loading"
|
||||
color="error"
|
||||
variant="outlined"
|
||||
prepend-icon="mdi-refresh"
|
||||
size="large"
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
variant="outlined"
|
||||
@click="loadStudents"
|
||||
>
|
||||
重载名单
|
||||
@@ -218,9 +218,9 @@
|
||||
<script>
|
||||
import UnsavedWarning from "../common/UnsavedWarning.vue";
|
||||
import "@/styles/warnings.scss";
|
||||
import { pinyin } from "pinyin-pro";
|
||||
import {pinyin} from "pinyin-pro";
|
||||
import dataProvider from "@/utils/dataProvider";
|
||||
import { getSetting } from "@/utils/settings";
|
||||
import {getSetting} from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
name: "StudentListCard",
|
||||
@@ -289,7 +289,7 @@ export default {
|
||||
if (response.success != false && Array.isArray(response)) {
|
||||
this.modelValue.list = response.map((item, index) => {
|
||||
if (typeof item === 'string') {
|
||||
return { id: index + 1, name: item };
|
||||
return {id: index + 1, name: item};
|
||||
}
|
||||
return {
|
||||
id: item.id || index + 1,
|
||||
@@ -301,7 +301,7 @@ export default {
|
||||
this.modelValue.text = this.modelValue.list.map(s => s.name).join("\n");
|
||||
this.lastSavedData = JSON.parse(JSON.stringify(this.modelValue.list));
|
||||
this.unsavedChanges = false;
|
||||
return;
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
@@ -371,9 +371,9 @@ export default {
|
||||
const newList = lines.map(name => {
|
||||
name = name.trim();
|
||||
if (currentIds.has(name)) {
|
||||
return { id: currentIds.get(name), name };
|
||||
return {id: currentIds.get(name), name};
|
||||
}
|
||||
return { id: ++maxId, name };
|
||||
return {id: ++maxId, name};
|
||||
});
|
||||
|
||||
// Update the list
|
||||
@@ -384,7 +384,7 @@ export default {
|
||||
const name = this.newStudentName.trim();
|
||||
if (name && !this.modelValue.list.some(s => s.name === name)) {
|
||||
const maxId = Math.max(0, ...this.modelValue.list.map(s => s.id));
|
||||
this.modelValue.list.push({ id: maxId + 1, name });
|
||||
this.modelValue.list.push({id: maxId + 1, name});
|
||||
this.newStudentName = "";
|
||||
}
|
||||
},
|
||||
@@ -442,8 +442,8 @@ export default {
|
||||
|
||||
sortStudentsByPinyin() {
|
||||
const sorted = [...this.modelValue.list].sort((a, b) => {
|
||||
const pinyinA = pinyin(a.name, { toneType: "none" });
|
||||
const pinyinB = pinyin(b.name, { toneType: "none" });
|
||||
const pinyinA = pinyin(a.name, {toneType: "none"});
|
||||
const pinyinB = pinyin(b.name, {toneType: "none"});
|
||||
return pinyinA.localeCompare(pinyinB);
|
||||
});
|
||||
sorted.forEach((s, i) => s.id = i + 1);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<v-card class="my-4" :loading="loading" :disabled="!hasNamespaceInfo">
|
||||
<v-card :disabled="!hasNamespaceInfo" :loading="loading" class="my-4">
|
||||
<template #loader>
|
||||
<v-progress-linear v-if="loading" indeterminate color="primary" />
|
||||
<v-progress-linear v-if="loading" color="primary" indeterminate/>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -21,18 +21,18 @@
|
||||
class="mb-4"
|
||||
>
|
||||
<v-alert
|
||||
border
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
border
|
||||
>
|
||||
<v-alert-title>设备未绑定账号</v-alert-title>
|
||||
<div>当前设备尚未绑定账号,部分功能可能受限。请前往绑定账号以获得完整体验。</div>
|
||||
<v-btn
|
||||
class="mt-3"
|
||||
variant="outlined"
|
||||
:href="getBindAccountUrl()"
|
||||
append-icon="mdi-open-in-new"
|
||||
class="mt-3"
|
||||
target="_blank"
|
||||
variant="outlined"
|
||||
>
|
||||
前往绑定账号
|
||||
</v-btn>
|
||||
@@ -45,13 +45,13 @@
|
||||
class="d-flex align-center mb-4"
|
||||
>
|
||||
<v-card
|
||||
border
|
||||
hover
|
||||
class="w-100"
|
||||
variant="tonal"
|
||||
:prepend-avatar="namespaceInfo.account.avatarUrl"
|
||||
:title="namespaceInfo.account.name || '未命名用户'"
|
||||
:subtitle="'此设备由贵校管理 管理员账号 ID: ' + namespaceInfo.account.id"
|
||||
:title="namespaceInfo.account.name || '未命名用户'"
|
||||
border
|
||||
class="w-100"
|
||||
hover
|
||||
variant="tonal"
|
||||
>
|
||||
<v-card-text>
|
||||
此设备由贵校或贵单位管理,该管理员系此空间所有者,如有疑问请咨询他,对于恶意绑定、滥用行为请反馈。
|
||||
@@ -62,10 +62,10 @@
|
||||
<!-- 设备信息卡片 -->
|
||||
<v-card
|
||||
v-if="namespaceInfo.device"
|
||||
variant="tonal"
|
||||
class="mb-4"
|
||||
border
|
||||
class="mb-4"
|
||||
hover
|
||||
variant="tonal"
|
||||
>
|
||||
<v-card-title class="pb-1">
|
||||
设备信息
|
||||
@@ -74,8 +74,8 @@
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<div class="d-flex align-center">
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
size="small"
|
||||
>
|
||||
mdi-tag
|
||||
</v-icon>
|
||||
@@ -84,8 +84,8 @@
|
||||
</div>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
size="small"
|
||||
>
|
||||
mdi-identifier
|
||||
</v-icon>
|
||||
@@ -98,8 +98,8 @@
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
size="small"
|
||||
>
|
||||
mdi-uuid
|
||||
</v-icon>
|
||||
@@ -108,8 +108,8 @@
|
||||
</div>
|
||||
<div class="d-flex align-center">
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
size="small"
|
||||
>
|
||||
mdi-calendar
|
||||
</v-icon>
|
||||
@@ -121,8 +121,8 @@
|
||||
class="d-flex align-center"
|
||||
>
|
||||
<v-icon
|
||||
size="small"
|
||||
class="me-2"
|
||||
size="small"
|
||||
>
|
||||
mdi-calendar-clock
|
||||
</v-icon>
|
||||
@@ -134,13 +134,14 @@
|
||||
</v-card>
|
||||
|
||||
<v-card
|
||||
title="Classworks KV"
|
||||
subtitle="文档形键值数据库"
|
||||
border
|
||||
hover
|
||||
subtitle="文档形键值数据库"
|
||||
title="Classworks KV"
|
||||
>
|
||||
<v-card-text>
|
||||
Classworks KV 是厚浪云推出的文档形键值数据库,其是一个开放的云应用平台,为各种应用提供存储服务。此设备正在使用其服务,如果您希望管理设备信息,请前往 Classworks KV 的网站,如果您在服务推出前就在使用 Classworks,您的数据已被自动迁移。
|
||||
Classworks KV 是厚浪云推出的文档形键值数据库,其是一个开放的云应用平台,为各种应用提供存储服务。此设备正在使用其服务,如果您希望管理设备信息,请前往
|
||||
Classworks KV 的网站,如果您在服务推出前就在使用 Classworks,您的数据已被自动迁移。
|
||||
<br><br>
|
||||
Classworks KV 的全域管理员是
|
||||
<a
|
||||
@@ -153,8 +154,8 @@
|
||||
<v-card-actions>
|
||||
<v-btn
|
||||
:href="defaultAuthServer"
|
||||
class="text-none"
|
||||
append-icon="mdi-open-in-new"
|
||||
class="text-none"
|
||||
target="_blank"
|
||||
>
|
||||
前往 Classworks KV
|
||||
@@ -174,11 +175,11 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
:loading="loading"
|
||||
color="primary"
|
||||
variant="outlined"
|
||||
:loading="loading"
|
||||
@click="reloadInfo"
|
||||
>
|
||||
刷新设备信息
|
||||
@@ -202,9 +203,9 @@
|
||||
<v-card-title>确认重新初始化</v-card-title>
|
||||
<v-card-text>
|
||||
<v-alert
|
||||
class="mb-3"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
class="mb-3"
|
||||
>
|
||||
<v-alert-title>警告</v-alert-title>
|
||||
此操作将清除当前的云端存储配置(包括 Token),您需要重新进行授权。
|
||||
@@ -212,7 +213,7 @@
|
||||
<p>您确定要重新初始化云端存储吗?</p>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
variant="text"
|
||||
@click="showReinitDialog = false"
|
||||
@@ -232,8 +233,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { kvServerProvider } from "@/utils/providers/kvServerProvider";
|
||||
import { setSetting, getSetting } from "@/utils/settings";
|
||||
import {kvServerProvider} from "@/utils/providers/kvServerProvider";
|
||||
import {setSetting, getSetting} from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
name: "CloudNamespaceInfoCard",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<settings-card title="数据源设置" icon="mdi-database-cog">
|
||||
<settings-card icon="mdi-database-cog" title="数据源设置">
|
||||
<v-list>
|
||||
<!-- 服务器模式设置 -->
|
||||
<template
|
||||
@@ -10,7 +10,7 @@
|
||||
>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-lan-connect"/>
|
||||
</template>
|
||||
<v-list-item-title>检查服务器连接</v-list-item-title>
|
||||
<template #append>
|
||||
@@ -21,7 +21,8 @@
|
||||
>
|
||||
测试连接
|
||||
</v-btn>
|
||||
</template> </v-list-item
|
||||
</template>
|
||||
</v-list-item
|
||||
><!-- 数据迁移,仅对KV本地存储有效 -->
|
||||
</template>
|
||||
|
||||
@@ -29,11 +30,12 @@
|
||||
<template v-if="currentProvider === 'kv-local'">
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-database"/>
|
||||
</template>
|
||||
<v-list-item-title>清除数据库缓存</v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
>这将清除所有本地数据库中的数据</v-list-item-subtitle
|
||||
>这将清除所有本地数据库中的数据
|
||||
</v-list-item-subtitle
|
||||
>
|
||||
<template #append>
|
||||
<v-btn color="error" variant="tonal" @click="confirmClearIndexedDB">
|
||||
@@ -43,45 +45,48 @@
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-export" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-database-export"/>
|
||||
</template>
|
||||
<v-list-item-title>导出数据库</v-list-item-title>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" @click="exportData"> 导出 </v-btn>
|
||||
<v-btn variant="tonal" @click="exportData"> 导出</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-database-import" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-database-import"/>
|
||||
</template>
|
||||
<v-list-item-title>迁移旧数据</v-list-item-title>
|
||||
<v-list-item-subtitle
|
||||
>将旧的存储格式数据转移到新的KV存储</v-list-item-subtitle
|
||||
>将旧的存储格式数据转移到新的KV存储
|
||||
</v-list-item-subtitle
|
||||
>
|
||||
<template #append>
|
||||
<v-btn :loading="migrateLoading" variant="tonal" @click="migrateData">
|
||||
迁移
|
||||
</v-btn>
|
||||
</template> </v-list-item
|
||||
</template>
|
||||
</v-list-item
|
||||
><!-- 显示机器ID -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-identifier" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-identifier"/>
|
||||
</template>
|
||||
<v-list-item-title>本机唯一标识符</v-list-item-title>
|
||||
<v-list-item-subtitle v-if="machineId">{{
|
||||
machineId
|
||||
}}</v-list-item-subtitle>
|
||||
}}
|
||||
</v-list-item-subtitle>
|
||||
<v-list-item-subtitle v-else>正在加载...</v-list-item-subtitle>
|
||||
</v-list-item>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-lan-connect" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-lan-connect"/>
|
||||
</template>
|
||||
<v-list-item-title>查看本地缓存</v-list-item-title>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" to="/cachemanagement"> 查看 </v-btn>
|
||||
<v-btn to="/cachemanagement" variant="tonal"> 查看</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
@@ -94,10 +99,12 @@
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="grey" variant="text" @click="confirmDialog = false"
|
||||
>取消</v-btn
|
||||
>取消
|
||||
</v-btn
|
||||
>
|
||||
<v-btn color="error" variant="tonal" @click="handleConfirm"
|
||||
>确认</v-btn
|
||||
>确认
|
||||
</v-btn
|
||||
>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@@ -107,12 +114,12 @@
|
||||
|
||||
<script>
|
||||
import SettingsCard from "@/components/SettingsCard.vue";
|
||||
import { getSetting } from "@/utils/settings";
|
||||
import {getSetting} from "@/utils/settings";
|
||||
import axios from "axios";
|
||||
|
||||
export default {
|
||||
name: "DataProviderSettingsCard",
|
||||
components: { SettingsCard },
|
||||
components: {SettingsCard},
|
||||
|
||||
data() {
|
||||
return {
|
||||
@@ -156,7 +163,7 @@ export default {
|
||||
const siteKey = getSetting("server.siteKey");
|
||||
|
||||
// Prepare headers including site key if available
|
||||
const headers = { Accept: "application/json" };
|
||||
const headers = {Accept: "application/json"};
|
||||
if (siteKey) {
|
||||
headers["x-site-key"] = siteKey;
|
||||
}
|
||||
@@ -227,7 +234,7 @@ export default {
|
||||
async exportData() {
|
||||
try {
|
||||
const DBName = "ClassworksDB";
|
||||
const data = { indexedDB: {} };
|
||||
const data = {indexedDB: {}};
|
||||
|
||||
// 打开数据库
|
||||
const db = await new Promise((resolve, reject) => {
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
<template>
|
||||
<settings-card title="显示设置" icon="mdi-monitor" border>
|
||||
<v-list>
|
||||
<setting-item :setting-key="'display.emptySubjectDisplay'" />
|
||||
|
||||
<settings-card border icon="mdi-monitor" title="显示设置">
|
||||
<v-list>
|
||||
<setting-item :setting-key="'display.emptySubjectDisplay'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.dynamicSort'" />
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showRandomButton'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.dynamicSort'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showFullscreenButton'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.showRandomButton'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.cardHoverEffect'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.showFullscreenButton'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.enhancedTouchMode'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.cardHoverEffect'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showQuickTools'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.enhancedTouchMode'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showAntiScreenBurnCard'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.showQuickTools'"/>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'display.showExamScheduleButton'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.showAntiScreenBurnCard'"/>
|
||||
|
||||
</v-list>
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'display.showExamScheduleButton'"/>
|
||||
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import SettingItem from '@/components/settings/SettingItem.vue';
|
||||
|
||||
export default {
|
||||
name: 'DisplaySettingsCard',
|
||||
components: { SettingsCard, SettingItem },
|
||||
components: {SettingsCard, SettingItem},
|
||||
data() {
|
||||
|
||||
return {
|
||||
|
||||
};
|
||||
|
||||
return {};
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<settings-card
|
||||
border
|
||||
title="回声洞"
|
||||
icon="mdi-thought-bubble"
|
||||
title="回声洞"
|
||||
@click="handleClick"
|
||||
>
|
||||
<v-card-text>
|
||||
@@ -12,7 +12,7 @@
|
||||
<transition name="fade">
|
||||
<v-chip v-if="currentQuote?.contributor" class="contributor">
|
||||
<v-avatar start>
|
||||
<v-img :src="`https://github.com/${currentQuote.contributor}.png`" />
|
||||
<v-img :src="`https://github.com/${currentQuote.contributor}.png`"/>
|
||||
</v-avatar>
|
||||
{{ currentQuote.contributor }}
|
||||
</v-chip>
|
||||
@@ -31,13 +31,13 @@ const INITIAL_STATE = {
|
||||
};
|
||||
|
||||
const TYPEWRITER_CONFIG = {
|
||||
main: { delay: 50, deleteSpeed: 100 },
|
||||
source: { delay: 10, deleteSpeed: 10, cursor: "" }
|
||||
main: {delay: 50, deleteSpeed: 100},
|
||||
source: {delay: 10, deleteSpeed: 10, cursor: ""}
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "EchoChamberCard",
|
||||
components: { SettingsCard },
|
||||
components: {SettingsCard},
|
||||
data: () => ({
|
||||
typewriter: null,
|
||||
sourceWriter: null,
|
||||
@@ -79,7 +79,7 @@ export default {
|
||||
async copyToClipboard() {
|
||||
if (!this.currentQuote) return;
|
||||
|
||||
const { text, author, contributor, link } = this.currentQuote;
|
||||
const {text, author, contributor, link} = this.currentQuote;
|
||||
const parts = [
|
||||
text,
|
||||
author && `作者:${author}`,
|
||||
@@ -107,6 +107,11 @@ export default {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.fade-enter-active, .fade-leave-active { transition: opacity 0.3s ease; }
|
||||
.fade-enter-from, .fade-leave-to { opacity: 0; }
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
<template>
|
||||
<settings-card title="编辑设置" icon="mdi-cog">
|
||||
<settings-card icon="mdi-cog" title="编辑设置">
|
||||
<v-list>
|
||||
<setting-item :setting-key="'edit.autoSave'" />
|
||||
<setting-item :setting-key="'edit.autoSave'"/>
|
||||
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'edit.blockNonTodayAutoSave'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'edit.blockNonTodayAutoSave'"/>
|
||||
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'edit.confirmNonTodaySave'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'edit.confirmNonTodaySave'"/>
|
||||
|
||||
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item :setting-key="'edit.refreshBeforeEdit'" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item :setting-key="'edit.refreshBeforeEdit'"/>
|
||||
|
||||
</v-list>
|
||||
</settings-card>
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<settings-card
|
||||
title="作业模板配置"
|
||||
icon="mdi-book-edit"
|
||||
:loading="loading"
|
||||
border
|
||||
icon="mdi-book-edit"
|
||||
title="作业模板配置"
|
||||
>
|
||||
<!-- 顶部操作按钮 -->
|
||||
<v-alert
|
||||
v-if="error"
|
||||
class="mb-4"
|
||||
closable
|
||||
type="error"
|
||||
variant="tonal"
|
||||
closable
|
||||
class="mb-4"
|
||||
>
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
@@ -19,20 +19,20 @@
|
||||
<div class="d-flex justify-space-between align-center mb-6">
|
||||
<div>
|
||||
<v-btn
|
||||
color="primary"
|
||||
size="large"
|
||||
prepend-icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
@click="loadConfig"
|
||||
class="mr-2"
|
||||
color="primary"
|
||||
prepend-icon="mdi-refresh"
|
||||
size="large"
|
||||
@click="loadConfig"
|
||||
>
|
||||
重新加载配置
|
||||
</v-btn>
|
||||
<v-btn
|
||||
color="success"
|
||||
size="large"
|
||||
prepend-icon="mdi-content-save"
|
||||
:loading="loading"
|
||||
color="success"
|
||||
prepend-icon="mdi-content-save"
|
||||
size="large"
|
||||
@click="saveConfig"
|
||||
>
|
||||
保存所有更改
|
||||
@@ -49,15 +49,15 @@
|
||||
|
||||
<v-row>
|
||||
<v-col cols="12" md="6">
|
||||
<setting-group title="科目配置" icon="mdi-book" border>
|
||||
<setting-group border icon="mdi-book" title="科目配置">
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-text-field
|
||||
v-model="newSubject"
|
||||
append-inner-icon="mdi-plus"
|
||||
density="comfortable"
|
||||
label="添加新科目"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="addSubject"
|
||||
@keyup.enter="addSubject"
|
||||
/>
|
||||
@@ -70,32 +70,32 @@
|
||||
v-model="editedSubjects[subject]"
|
||||
:placeholder="subject"
|
||||
density="comfortable"
|
||||
variant="plain"
|
||||
hide-details
|
||||
variant="plain"
|
||||
@blur="updateSubject(subject)"
|
||||
/>
|
||||
<v-spacer />
|
||||
<v-spacer/>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="deleteSubject(subject)"
|
||||
/>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="newBookTypes[subject]"
|
||||
append-inner-icon="mdi-plus"
|
||||
class="mb-2"
|
||||
density="comfortable"
|
||||
label="添加作业本名称"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
class="mb-2"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="() => addBookType(subject)"
|
||||
@keyup.enter="() => addBookType(subject)"
|
||||
/>
|
||||
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list border density="compact" rounded>
|
||||
<v-list-item
|
||||
v-for="(books, bookType) in config.subjects[subject].books"
|
||||
:key="bookType"
|
||||
@@ -103,21 +103,21 @@
|
||||
@click="openSubjectBookDialog(subject, bookType, books)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-book-open-variant" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-book-open-variant"/>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<v-chip
|
||||
size="small"
|
||||
class="mr-2"
|
||||
color="info"
|
||||
size="small"
|
||||
>
|
||||
{{ books.length }}个部分
|
||||
</v-chip>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click.stop="() => deleteBookType(subject, bookType)"
|
||||
/>
|
||||
</template>
|
||||
@@ -131,22 +131,22 @@
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" md="6">
|
||||
<setting-group title="通用配置" icon="mdi-cog" border>
|
||||
<setting-group border icon="mdi-cog" title="通用配置">
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<v-text-field
|
||||
v-model="newCommonBook"
|
||||
append-inner-icon="mdi-plus"
|
||||
density="comfortable"
|
||||
label="添加作业本名称"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="addCommonBook"
|
||||
@keyup.enter="addCommonBook"
|
||||
/>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list border density="compact" rounded>
|
||||
<v-list-item
|
||||
v-for="(books, bookType) in config.commonSubject.books"
|
||||
:key="bookType"
|
||||
@@ -154,21 +154,21 @@
|
||||
@click="openSubjectBookDialog('common', bookType, books)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-book-multiple" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-book-multiple"/>
|
||||
</template>
|
||||
<template v-slot:append>
|
||||
<v-chip
|
||||
size="small"
|
||||
class="mr-2"
|
||||
color="info"
|
||||
size="small"
|
||||
>
|
||||
{{ books.length }}个部分
|
||||
</v-chip>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click.stop="() => deleteBookType('common', bookType)"
|
||||
/>
|
||||
</template>
|
||||
@@ -176,22 +176,22 @@
|
||||
</v-list>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<v-list-item>
|
||||
<v-text-field
|
||||
v-model="newAction"
|
||||
append-inner-icon="mdi-plus"
|
||||
density="comfortable"
|
||||
label="添加操作"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="addAction"
|
||||
@keyup.enter="addAction"
|
||||
/>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item>
|
||||
<v-list density="compact" border rounded>
|
||||
<v-list border density="compact" rounded>
|
||||
<v-list-item
|
||||
v-for="action in config.actions"
|
||||
:key="action"
|
||||
@@ -200,10 +200,10 @@
|
||||
>
|
||||
<template v-slot:append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click.stop="removeAction(action)"
|
||||
/>
|
||||
</template>
|
||||
@@ -229,41 +229,41 @@
|
||||
<v-text-field
|
||||
v-model="dialog.editedItem.name"
|
||||
:label="dialog.nameLabel"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:rules="[v => !!v || '名称不能为空']"
|
||||
density="comfortable"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" v-if="dialog.editedItem.type === 'subjectBook'">
|
||||
<v-col v-if="dialog.editedItem.type === 'subjectBook'" cols="12">
|
||||
<div class="text-subtitle-2 mb-2">所属科目</div>
|
||||
<v-chip color="primary">{{ dialog.editedItem.subject }}</v-chip>
|
||||
</v-col>
|
||||
|
||||
<v-col cols="12" v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)">
|
||||
<v-col v-if="['subjectBook', 'commonBook'].includes(dialog.editedItem.type)" cols="12">
|
||||
<v-card variant="outlined">
|
||||
<v-card-title class="text-subtitle-1 py-2">需完成部分</v-card-title>
|
||||
<v-card-text class="pt-0">
|
||||
<v-list density="compact" border rounded class="mb-2">
|
||||
<v-list border class="mb-2" density="compact" rounded>
|
||||
<v-list-item
|
||||
v-for="(task, index) in dialog.editedItem.tasks"
|
||||
:key="index"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon icon="mdi-checkbox-blank-circle-outline" size="small" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-checkbox-blank-circle-outline" size="small"/>
|
||||
</template>
|
||||
<v-text-field
|
||||
v-model="dialog.editedItem.tasks[index]"
|
||||
variant="plain"
|
||||
density="compact"
|
||||
hide-details
|
||||
variant="plain"
|
||||
/>
|
||||
<template v-slot:append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="removeTask(index)"
|
||||
/>
|
||||
</template>
|
||||
@@ -271,13 +271,13 @@
|
||||
</v-list>
|
||||
<v-text-field
|
||||
v-model="newTask"
|
||||
append-inner-icon="mdi-plus"
|
||||
class="mt-2"
|
||||
density="comfortable"
|
||||
label="添加需完成部分"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="addTask"
|
||||
@keyup.enter="addTask"
|
||||
class="mt-2"
|
||||
/>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@@ -318,7 +318,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { reactive } from 'vue';
|
||||
import {reactive} from 'vue';
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import SettingGroup from '@/components/settings/SettingGroup.vue';
|
||||
import dataProvider from "@/utils/dataProvider.js";
|
||||
@@ -466,7 +466,7 @@ export default {
|
||||
addSubject() {
|
||||
if (!this.newSubject) return;
|
||||
if (!this.config.subjects[this.newSubject]) {
|
||||
this.config.subjects[this.newSubject] = { books: {} };
|
||||
this.config.subjects[this.newSubject] = {books: {}};
|
||||
}
|
||||
this.newSubject = '';
|
||||
},
|
||||
@@ -627,7 +627,7 @@ export default {
|
||||
},
|
||||
|
||||
saveDialog() {
|
||||
const { type, name, subject, originalName, tasks } = this.dialog.editedItem;
|
||||
const {type, name, subject, originalName, tasks} = this.dialog.editedItem;
|
||||
|
||||
if (!name) {
|
||||
this.showMessage('名称不能为空', 'error');
|
||||
@@ -687,4 +687,4 @@ export default {
|
||||
.v-card-text {
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
<template>
|
||||
<settings-card title="KV数据库管理" icon="mdi-database-edit" :loading="loading">
|
||||
<settings-card :loading="loading" icon="mdi-database-edit" title="KV数据库管理">
|
||||
<v-list>
|
||||
<!-- 数据库连接状态 -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon :icon="connectionIcon" :color="connectionColor" class="mr-3" />
|
||||
<v-icon :color="connectionColor" :icon="connectionIcon" class="mr-3"/>
|
||||
</template>
|
||||
<v-list-item-title>数据库状态</v-list-item-title>
|
||||
<v-list-item-subtitle>{{ connectionStatus }}</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn variant="tonal" @click="refreshConnection" :loading="loading">
|
||||
<v-btn :loading="loading" variant="tonal" @click="refreshConnection">
|
||||
刷新
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<!-- 数据列表 -->
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-format-list-bulleted" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-format-list-bulleted"/>
|
||||
</template>
|
||||
<v-list-item-title>数据条目</v-list-item-title>
|
||||
<v-list-item-subtitle>共 {{ kvData.length }} 条记录</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn-group variant="tonal">
|
||||
<v-btn @click="loadKvData" :loading="loadingData">
|
||||
<v-btn :loading="loadingData" @click="loadKvData">
|
||||
加载数据
|
||||
</v-btn>
|
||||
<v-btn @click="createNewItem" :disabled="!isKvProvider">
|
||||
<v-icon icon="mdi-plus" class="mr-1" />
|
||||
<v-btn :disabled="!isKvProvider" @click="createNewItem">
|
||||
<v-icon class="mr-1" icon="mdi-plus"/>
|
||||
新建
|
||||
</v-btn>
|
||||
</v-btn-group>
|
||||
@@ -41,60 +41,60 @@
|
||||
<!-- 数据表格 -->
|
||||
<v-card v-if="kvData.length > 0" class="mt-4" variant="outlined">
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-table" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-table"/>
|
||||
KV数据列表
|
||||
<v-spacer />
|
||||
<v-spacer/>
|
||||
<v-text-field
|
||||
v-model="searchQuery"
|
||||
label="搜索键名"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
variant="outlined"
|
||||
clearable
|
||||
density="compact"
|
||||
hide-details
|
||||
clearable
|
||||
label="搜索键名"
|
||||
prepend-inner-icon="mdi-magnify"
|
||||
style="max-width: 300px;"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-card-title>
|
||||
|
||||
<v-data-table
|
||||
:headers="tableHeaders"
|
||||
:items="filteredKvData"
|
||||
:loading="loadingData"
|
||||
item-value="key"
|
||||
class="elevation-0"
|
||||
:items-per-page="10"
|
||||
:loading="loadingData"
|
||||
class="elevation-0"
|
||||
item-value="key"
|
||||
>
|
||||
<template #[`item.key`]="{ item }">
|
||||
<code class="text-primary">{{ item.key }}</code>
|
||||
</template>
|
||||
|
||||
<template #[`item.actions`]="{ item }">
|
||||
<v-btn-group variant="text" density="compact">
|
||||
<v-btn-group density="compact" variant="text">
|
||||
<v-btn
|
||||
icon="mdi-eye"
|
||||
size="small"
|
||||
@click="viewItem(item)"
|
||||
title="查看"
|
||||
@click="viewItem(item)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-pencil"
|
||||
size="small"
|
||||
@click="editItem(item)"
|
||||
title="编辑"
|
||||
@click="editItem(item)"
|
||||
/>
|
||||
<v-btn
|
||||
color="primary"
|
||||
icon="mdi-cloud-download"
|
||||
size="small"
|
||||
color="primary"
|
||||
@click="getCloudUrl(item)"
|
||||
title="获取云端地址"
|
||||
@click="getCloudUrl(item)"
|
||||
/>
|
||||
<v-btn
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
color="error"
|
||||
@click="confirmDelete(item)"
|
||||
title="删除"
|
||||
@click="confirmDelete(item)"
|
||||
/>
|
||||
</v-btn-group>
|
||||
</template>
|
||||
@@ -105,10 +105,10 @@
|
||||
<v-dialog v-model="viewDialog" max-width="800px">
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-eye" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-eye"/>
|
||||
查看数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="viewDialog = false" />
|
||||
<v-spacer/>
|
||||
<v-btn icon="mdi-close" variant="text" @click="viewDialog = false"/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="selectedItem">
|
||||
@@ -119,21 +119,21 @@
|
||||
<v-textarea
|
||||
v-if="selectedItem"
|
||||
:model-value="formatJsonData(selectedItem.value)"
|
||||
class="font-monospace"
|
||||
label="数据内容"
|
||||
variant="outlined"
|
||||
readonly
|
||||
rows="15"
|
||||
class="font-monospace"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="copyToClipboard(selectedItem?.value)" variant="tonal">
|
||||
<v-icon icon="mdi-content-copy" class="mr-1" />
|
||||
<v-spacer/>
|
||||
<v-btn variant="tonal" @click="copyToClipboard(selectedItem?.value)">
|
||||
<v-icon class="mr-1" icon="mdi-content-copy"/>
|
||||
复制数据
|
||||
</v-btn>
|
||||
<v-btn @click="viewDialog = false" variant="text">
|
||||
<v-btn variant="text" @click="viewDialog = false">
|
||||
关闭
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
@@ -144,10 +144,10 @@
|
||||
<v-dialog v-model="editDialog" max-width="800px">
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-pencil" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-pencil"/>
|
||||
编辑数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeEditDialog" />
|
||||
<v-spacer/>
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeEditDialog"/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="editingItem">
|
||||
@@ -157,26 +157,26 @@
|
||||
<v-card-text>
|
||||
<v-textarea
|
||||
v-model="editingData"
|
||||
label="数据内容 (JSON格式)"
|
||||
variant="outlined"
|
||||
rows="15"
|
||||
class="font-monospace"
|
||||
:error="!isValidJson"
|
||||
:error-messages="isValidJson ? [] : ['请输入有效的JSON格式']"
|
||||
class="font-monospace"
|
||||
label="数据内容 (JSON格式)"
|
||||
rows="15"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="closeEditDialog" variant="text">
|
||||
<v-spacer/>
|
||||
<v-btn variant="text" @click="closeEditDialog">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="saveEditedData"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="!isValidJson"
|
||||
:loading="savingData"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
@click="saveEditedData"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
@@ -188,46 +188,46 @@
|
||||
<v-dialog v-model="createDialog" max-width="800px">
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-plus" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-plus"/>
|
||||
新建数据
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeCreateDialog" />
|
||||
<v-spacer/>
|
||||
<v-btn icon="mdi-close" variant="text" @click="closeCreateDialog"/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<v-text-field
|
||||
v-model="newKey"
|
||||
label="键名"
|
||||
variant="outlined"
|
||||
class="mb-4"
|
||||
:error="!isValidKey"
|
||||
:error-messages="isValidKey ? [] : ['键名不能为空且不能与现有键重复']"
|
||||
class="mb-4"
|
||||
label="键名"
|
||||
placeholder="请输入键名,如:my-config"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
<v-textarea
|
||||
v-model="newData"
|
||||
label="数据内容 (JSON格式)"
|
||||
variant="outlined"
|
||||
rows="15"
|
||||
class="font-monospace"
|
||||
:error="!isValidNewJson"
|
||||
:error-messages="isValidNewJson ? [] : ['请输入有效的JSON格式']"
|
||||
class="font-monospace"
|
||||
label="数据内容 (JSON格式)"
|
||||
placeholder='请输入JSON数据,如:{"name": "value"}'
|
||||
rows="15"
|
||||
variant="outlined"
|
||||
/>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="closeCreateDialog" variant="text">
|
||||
<v-spacer/>
|
||||
<v-btn variant="text" @click="closeCreateDialog">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="saveNewData"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:disabled="!isValidKey || !isValidNewJson"
|
||||
:loading="savingData"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
@click="saveNewData"
|
||||
>
|
||||
创建
|
||||
</v-btn>
|
||||
@@ -239,10 +239,10 @@
|
||||
<v-dialog v-model="cloudUrlDialog" max-width="800px">
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center">
|
||||
<v-icon icon="mdi-cloud-download" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-cloud-download"/>
|
||||
获取云端访问地址
|
||||
<v-spacer />
|
||||
<v-btn icon="mdi-close" variant="text" @click="cloudUrlDialog = false" />
|
||||
<v-spacer/>
|
||||
<v-btn icon="mdi-close" variant="text" @click="cloudUrlDialog = false"/>
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle v-if="selectedCloudItem">
|
||||
@@ -250,19 +250,19 @@
|
||||
</v-card-subtitle>
|
||||
|
||||
<v-card-text>
|
||||
<v-alert v-if="cloudUrlError" type="error" variant="tonal" class="mb-4">
|
||||
<v-alert v-if="cloudUrlError" class="mb-4" type="error" variant="tonal">
|
||||
{{ cloudUrlError }}
|
||||
</v-alert>
|
||||
|
||||
<v-alert v-if="cloudUrlResult && cloudUrlResult.success" type="success" variant="tonal" class="mb-4">
|
||||
<v-alert v-if="cloudUrlResult && cloudUrlResult.success" class="mb-4" type="success" variant="tonal">
|
||||
<v-alert-title>云端地址获取成功</v-alert-title>
|
||||
<div class="mt-2">
|
||||
<div v-if="cloudUrlResult.migrated" class="mb-2">
|
||||
<v-icon icon="mdi-database-arrow-up" class="mr-1" color="success" />
|
||||
<v-icon class="mr-1" color="success" icon="mdi-database-arrow-up"/>
|
||||
数据已从本地迁移到云端
|
||||
</div>
|
||||
<div v-if="cloudUrlResult.configured" class="mb-2">
|
||||
<v-icon icon="mdi-cog" class="mr-1" color="info" />
|
||||
<v-icon class="mr-1" color="info" icon="mdi-cog"/>
|
||||
云端配置已自动设置
|
||||
</div>
|
||||
</div>
|
||||
@@ -271,39 +271,39 @@
|
||||
<v-text-field
|
||||
v-if="cloudUrlResult && cloudUrlResult.url"
|
||||
:model-value="cloudUrlResult.url"
|
||||
label="云端访问地址"
|
||||
variant="outlined"
|
||||
readonly
|
||||
class="font-monospace"
|
||||
append-inner-icon="mdi-content-copy"
|
||||
class="font-monospace"
|
||||
label="云端访问地址"
|
||||
readonly
|
||||
variant="outlined"
|
||||
@click:append-inner="copyCloudUrl"
|
||||
/>
|
||||
|
||||
<v-expansion-panels v-if="cloudUrlResult && cloudUrlResult.url" class="mt-4">
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-title>
|
||||
<v-icon icon="mdi-cog" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-cog"/>
|
||||
高级选项
|
||||
</v-expansion-panel-title>
|
||||
<v-expansion-panel-text>
|
||||
<v-checkbox
|
||||
v-model="cloudUrlOptions.migrateFromLocal"
|
||||
label="从本地迁移数据到云端"
|
||||
density="compact"
|
||||
label="从本地迁移数据到云端"
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="cloudUrlOptions.autoConfigureCloud"
|
||||
label="自动配置云端默认设置"
|
||||
density="compact"
|
||||
label="自动配置云端默认设置"
|
||||
/>
|
||||
<v-btn
|
||||
@click="refreshCloudUrl"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
:loading="gettingCloudUrl"
|
||||
class="mt-2"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
@click="refreshCloudUrl"
|
||||
>
|
||||
<v-icon icon="mdi-refresh" class="mr-1" />
|
||||
<v-icon class="mr-1" icon="mdi-refresh"/>
|
||||
重新获取
|
||||
</v-btn>
|
||||
</v-expansion-panel-text>
|
||||
@@ -312,17 +312,17 @@
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="cloudUrlDialog = false" variant="text">
|
||||
<v-spacer/>
|
||||
<v-btn variant="text" @click="cloudUrlDialog = false">
|
||||
关闭
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="cloudUrlResult && cloudUrlResult.url"
|
||||
@click="openCloudUrl"
|
||||
variant="tonal"
|
||||
color="primary"
|
||||
variant="tonal"
|
||||
@click="openCloudUrl"
|
||||
>
|
||||
<v-icon icon="mdi-open-in-new" class="mr-1" />
|
||||
<v-icon class="mr-1" icon="mdi-open-in-new"/>
|
||||
在新窗口打开
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
@@ -333,28 +333,28 @@
|
||||
<v-dialog v-model="deleteDialog" max-width="400px">
|
||||
<v-card>
|
||||
<v-card-title class="d-flex align-center text-error">
|
||||
<v-icon icon="mdi-alert" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-alert"/>
|
||||
确认删除
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
确定要删除键名为 <code>{{ itemToDelete?.key }}</code> 的数据吗?
|
||||
<br><br>
|
||||
<v-alert type="warning" variant="tonal" class="mt-2">
|
||||
<v-alert class="mt-2" type="warning" variant="tonal">
|
||||
此操作不可撤销,请谨慎操作!
|
||||
</v-alert>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions>
|
||||
<v-spacer />
|
||||
<v-btn @click="deleteDialog = false" variant="text">
|
||||
<v-spacer/>
|
||||
<v-btn variant="text" @click="deleteDialog = false">
|
||||
取消
|
||||
</v-btn>
|
||||
<v-btn
|
||||
@click="deleteItem"
|
||||
variant="tonal"
|
||||
color="error"
|
||||
:loading="deletingData"
|
||||
color="error"
|
||||
variant="tonal"
|
||||
@click="deleteItem"
|
||||
>
|
||||
删除
|
||||
</v-btn>
|
||||
@@ -367,8 +367,8 @@
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import dataProvider from '@/utils/dataProvider';
|
||||
import { getSetting } from '@/utils/settings';
|
||||
import { openDB } from 'idb';
|
||||
import {getSetting} from '@/utils/settings';
|
||||
import {openDB} from 'idb';
|
||||
|
||||
export default {
|
||||
name: 'KvDatabaseCard',
|
||||
@@ -414,8 +414,8 @@ export default {
|
||||
|
||||
// 表格头部
|
||||
tableHeaders: [
|
||||
{ title: '键名', key: 'key', sortable: true },
|
||||
{ title: '操作', key: 'actions', sortable: false, width: '120px' }
|
||||
{title: '键名', key: 'key', sortable: true},
|
||||
{title: '操作', key: 'actions', sortable: false, width: '120px'}
|
||||
]
|
||||
};
|
||||
},
|
||||
@@ -426,7 +426,7 @@ export default {
|
||||
},
|
||||
|
||||
isKvProvider() {
|
||||
return this.currentProvider === 'kv-local' || this.currentProvider === 'kv-server'||this.currentProvider === 'classworkscloud'
|
||||
return this.currentProvider === 'kv-local' || this.currentProvider === 'kv-server' || this.currentProvider === 'classworkscloud'
|
||||
},
|
||||
|
||||
connectionStatus() {
|
||||
@@ -537,15 +537,10 @@ export default {
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
async viewItem(item) {
|
||||
this.selectedItem = item;
|
||||
this.viewDialog = true;
|
||||
|
||||
|
||||
// 如果数据未加载,则加载数据
|
||||
if (!item.loaded || item.value === null) {
|
||||
await this.loadItemData(item);
|
||||
@@ -554,12 +549,12 @@ export default {
|
||||
|
||||
async editItem(item) {
|
||||
this.editingItem = item;
|
||||
|
||||
|
||||
// 如果数据未加载,则加载数据
|
||||
if (!item.loaded || item.value === null) {
|
||||
await this.loadItemData(item);
|
||||
}
|
||||
|
||||
|
||||
this.editingData = this.formatJsonData(item.value);
|
||||
this.editDialog = true;
|
||||
},
|
||||
@@ -716,22 +711,22 @@ export default {
|
||||
this.cloudUrlResult = null;
|
||||
this.cloudUrlError = null;
|
||||
this.cloudUrlDialog = true;
|
||||
|
||||
|
||||
await this.fetchCloudUrl();
|
||||
},
|
||||
|
||||
async fetchCloudUrl() {
|
||||
if (!this.selectedCloudItem) return;
|
||||
|
||||
|
||||
this.gettingCloudUrl = true;
|
||||
this.cloudUrlError = null;
|
||||
|
||||
|
||||
try {
|
||||
const result = await dataProvider.getKeyCloudUrl(
|
||||
this.selectedCloudItem.key,
|
||||
this.cloudUrlOptions
|
||||
);
|
||||
|
||||
|
||||
if (result.success) {
|
||||
this.cloudUrlResult = result;
|
||||
this.$message.success('云端地址获取成功');
|
||||
@@ -753,7 +748,7 @@ export default {
|
||||
|
||||
async copyCloudUrl() {
|
||||
if (!this.cloudUrlResult?.url) return;
|
||||
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(this.cloudUrlResult.url);
|
||||
this.$message.success('云端地址已复制到剪贴板');
|
||||
@@ -764,7 +759,7 @@ export default {
|
||||
|
||||
openCloudUrl() {
|
||||
if (!this.cloudUrlResult?.url) return;
|
||||
|
||||
|
||||
try {
|
||||
window.open(this.cloudUrlResult.url, '_blank');
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
<template>
|
||||
<settings-card title="编辑设置" icon="mdi-cog">
|
||||
<v-list>
|
||||
<setting-item setting-key="randomPicker.enabled" />
|
||||
<v-divider class="my-2" />
|
||||
<settings-card icon="mdi-cog" title="编辑设置">
|
||||
<v-list>
|
||||
<setting-item setting-key="randomPicker.enabled"/>
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<setting-item setting-key="randomPicker.mode" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="randomPicker.minNumber" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="randomPicker.maxNumber" />
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="randomPicker.defaultCount" />
|
||||
<setting-item setting-key="randomPicker.mode"/>
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item setting-key="randomPicker.minNumber"/>
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item setting-key="randomPicker.maxNumber"/>
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item setting-key="randomPicker.defaultCount"/>
|
||||
|
||||
|
||||
<v-divider class="my-2" />
|
||||
<setting-item setting-key="randomPicker.animation" />
|
||||
<v-divider class="my-2"/>
|
||||
<setting-item setting-key="randomPicker.animation"/>
|
||||
|
||||
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import SettingItem from '../SettingItem.vue';
|
||||
|
||||
</v-list>
|
||||
</settings-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import SettingItem from '../SettingItem.vue';
|
||||
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<template>
|
||||
<settings-card title="刷新设置" icon="mdi-refresh-circle">
|
||||
<settings-card icon="mdi-refresh-circle" title="刷新设置">
|
||||
<v-form>
|
||||
<v-list>
|
||||
<setting-item setting-key="refresh.auto" title="自动刷新" /> <v-divider class="my-2" />
|
||||
<setting-item setting-key="refresh.auto" title="自动刷新"/>
|
||||
<v-divider class="my-2"/>
|
||||
|
||||
<setting-item setting-key="refresh.interval" title="刷新间隔" />
|
||||
<setting-item setting-key="refresh.interval" title="刷新间隔"/>
|
||||
</v-list>
|
||||
|
||||
</v-form>
|
||||
@@ -14,15 +15,14 @@
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import SettingItem from '@/components/settings/SettingItem.vue';
|
||||
|
||||
export default {
|
||||
name: 'RefreshSettingsCard',
|
||||
components: { SettingsCard },
|
||||
components: {SettingsCard},
|
||||
data() {
|
||||
|
||||
|
||||
return {
|
||||
|
||||
};
|
||||
return {};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<settings-card
|
||||
title="数据源设置"
|
||||
icon="mdi-database"
|
||||
:loading="loading"
|
||||
icon="mdi-database"
|
||||
title="数据源设置"
|
||||
>
|
||||
<v-form>
|
||||
<!-- 使用双向绑定来替代 setting-key -->
|
||||
@@ -13,20 +13,20 @@
|
||||
{ title: 'KV本地存储', value: 'kv-local' },
|
||||
{ title: 'KV远程服务器', value: 'kv-server' }
|
||||
]"
|
||||
label="数据提供者"
|
||||
variant="outlined"
|
||||
class="mb-3"
|
||||
density="comfortable"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
label="数据提供者"
|
||||
prepend-icon="mdi-database"
|
||||
class="mb-3"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
<v-alert
|
||||
v-if="isKvProvider"
|
||||
class="my-2"
|
||||
type="info"
|
||||
variant="tonal"
|
||||
class="my-2"
|
||||
>
|
||||
<v-alert-title>KV 存储系统</v-alert-title>
|
||||
<p>KV存储系统使用本机唯一标识符(UUID)来区分不同设备的数据。</p>
|
||||
@@ -38,10 +38,10 @@
|
||||
|
||||
<v-alert
|
||||
v-if="isClassworksCloud"
|
||||
type="info"
|
||||
color="success"
|
||||
variant="tonal"
|
||||
class="my-2"
|
||||
color="success"
|
||||
type="info"
|
||||
variant="tonal"
|
||||
>
|
||||
<v-alert-title>Classworks云端存储</v-alert-title>
|
||||
<p>Classworks云端存储是官方提供的存储解决方案,自动配置了最优的访问设置。</p>
|
||||
@@ -56,17 +56,16 @@
|
||||
<div v-if="isClassworksCloud">
|
||||
<v-text-field
|
||||
v-model="serverSettings.kvToken"
|
||||
label="KV 授权令牌"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-shield-key"
|
||||
class="mb-2"
|
||||
density="comfortable"
|
||||
hint="令牌用于云端存储授权"
|
||||
label="KV 授权令牌"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-shield-key"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<cloud-namespace-info-card
|
||||
:visible="isClassworksCloud"
|
||||
class="mt-4"
|
||||
@@ -77,24 +76,24 @@
|
||||
<div v-else-if="currentProvider === 'kv-server'">
|
||||
<v-text-field
|
||||
v-model="serverSettings.domain"
|
||||
label="服务器域名"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-web"
|
||||
class="mb-2"
|
||||
density="comfortable"
|
||||
hint="例如: https://example.com (不需要路径)"
|
||||
label="服务器域名"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-web"
|
||||
variant="outlined"
|
||||
/>
|
||||
|
||||
<v-text-field
|
||||
v-model="serverSettings.kvToken"
|
||||
label="KV 授权令牌"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-shield-key"
|
||||
class="mb-2"
|
||||
density="comfortable"
|
||||
hint="令牌用于服务器验证"
|
||||
label="KV 授权令牌"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-shield-key"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -102,13 +101,13 @@
|
||||
<div v-else-if="currentProvider === 'kv-local'">
|
||||
<v-text-field
|
||||
v-model="serverSettings.classNumber"
|
||||
label="班级编号"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-account-group"
|
||||
class="mb-2"
|
||||
density="comfortable"
|
||||
hint="例如: 高三八班"
|
||||
label="班级编号"
|
||||
persistent-hint
|
||||
prepend-icon="mdi-account-group"
|
||||
variant="outlined"
|
||||
/>
|
||||
</div>
|
||||
</v-form>
|
||||
@@ -118,11 +117,11 @@
|
||||
<script>
|
||||
import SettingsCard from "@/components/SettingsCard.vue";
|
||||
import CloudNamespaceInfoCard from "./CloudNamespaceInfoCard.vue";
|
||||
import { getSetting, setSetting, watchSettings } from "@/utils/settings";
|
||||
import {getSetting, setSetting, watchSettings} from "@/utils/settings";
|
||||
|
||||
export default {
|
||||
name: "ServerSettingsCard",
|
||||
components: { SettingsCard, CloudNamespaceInfoCard },
|
||||
components: {SettingsCard, CloudNamespaceInfoCard},
|
||||
props: {
|
||||
loading: Boolean,
|
||||
},
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<settings-card
|
||||
title="科目管理"
|
||||
icon="mdi-book-multiple"
|
||||
:loading="loading"
|
||||
border
|
||||
icon="mdi-book-multiple"
|
||||
title="科目管理"
|
||||
>
|
||||
<v-alert
|
||||
v-if="error"
|
||||
class="mb-4"
|
||||
closable
|
||||
type="error"
|
||||
variant="tonal"
|
||||
closable
|
||||
class="mb-4"
|
||||
>
|
||||
{{ error }}
|
||||
</v-alert>
|
||||
@@ -18,32 +18,32 @@
|
||||
<div class="d-flex justify-space-between align-center mb-6">
|
||||
<div>
|
||||
<v-btn
|
||||
variant="text"
|
||||
color="primary"
|
||||
size="large"
|
||||
prepend-icon="mdi-refresh"
|
||||
:loading="loading"
|
||||
@click="loadConfig"
|
||||
class="mr-2"
|
||||
color="primary"
|
||||
prepend-icon="mdi-refresh"
|
||||
size="large"
|
||||
variant="text"
|
||||
@click="loadConfig"
|
||||
>
|
||||
重新加载
|
||||
</v-btn>
|
||||
|
||||
<v-btn
|
||||
color="success"
|
||||
size="large"
|
||||
prepend-icon="mdi-content-save"
|
||||
:loading="loading"
|
||||
color="success"
|
||||
prepend-icon="mdi-content-save"
|
||||
size="large"
|
||||
@click="saveConfig"
|
||||
>
|
||||
保存
|
||||
</v-btn>
|
||||
<v-btn
|
||||
variant="text"
|
||||
prepend-icon="mdi-restore"
|
||||
<v-btn
|
||||
:loading="loading"
|
||||
@click="resetToDefault"
|
||||
class="mr-2"
|
||||
prepend-icon="mdi-restore"
|
||||
variant="text"
|
||||
@click="resetToDefault"
|
||||
>
|
||||
重置为默认
|
||||
</v-btn>
|
||||
@@ -64,12 +64,12 @@
|
||||
<v-col cols="12" sm="6">
|
||||
<v-text-field
|
||||
v-model="newSubjectName"
|
||||
:rules="[v => !!v || '科目名称不能为空']"
|
||||
append-inner-icon="mdi-plus"
|
||||
density="comfortable"
|
||||
label="科目名称"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:rules="[v => !!v || '科目名称不能为空']"
|
||||
@keyup.enter="addSubject"
|
||||
append-inner-icon="mdi-plus"
|
||||
@click:append-inner="addSubject"
|
||||
/>
|
||||
</v-col>
|
||||
@@ -88,17 +88,17 @@
|
||||
<template v-slot:prepend>
|
||||
<div class="d-flex flex-column align-center mr-2">
|
||||
<v-btn
|
||||
icon="mdi-chevron-up"
|
||||
variant="text"
|
||||
size="small"
|
||||
:disabled="index === 0"
|
||||
icon="mdi-chevron-up"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="moveSubject(index, -1)"
|
||||
/>
|
||||
<v-btn
|
||||
icon="mdi-chevron-down"
|
||||
variant="text"
|
||||
size="small"
|
||||
:disabled="index === subjects.length - 1"
|
||||
icon="mdi-chevron-down"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="moveSubject(index, 1)"
|
||||
/>
|
||||
</div>
|
||||
@@ -107,19 +107,19 @@
|
||||
<v-list-item-title>
|
||||
<v-text-field
|
||||
v-model="subject.name"
|
||||
variant="plain"
|
||||
density="compact"
|
||||
hide-details
|
||||
variant="plain"
|
||||
@blur="updateSubject(subject)"
|
||||
/>
|
||||
</v-list-item-title>
|
||||
|
||||
<template v-slot:append>
|
||||
<v-btn
|
||||
icon="mdi-delete"
|
||||
variant="text"
|
||||
color="error"
|
||||
icon="mdi-delete"
|
||||
size="small"
|
||||
variant="text"
|
||||
@click="deleteSubject(subject)"
|
||||
/>
|
||||
</template>
|
||||
@@ -161,16 +161,16 @@ export default {
|
||||
snackbarText: '',
|
||||
snackbarColor: 'success',
|
||||
defaultSubjects: [
|
||||
{ name: '语文', order: 0 },
|
||||
{ name: '数学', order: 1 },
|
||||
{ name: '英语', order: 2 },
|
||||
{ name: '物理', order: 3 },
|
||||
{ name: '化学', order: 4 },
|
||||
{ name: '生物', order: 5 },
|
||||
{ name: '政治', order: 6 },
|
||||
{ name: '历史', order: 7 },
|
||||
{ name: '地理', order: 8 },
|
||||
{ name: '其他', order: 9 }
|
||||
{name: '语文', order: 0},
|
||||
{name: '数学', order: 1},
|
||||
{name: '英语', order: 2},
|
||||
{name: '物理', order: 3},
|
||||
{name: '化学', order: 4},
|
||||
{name: '生物', order: 5},
|
||||
{name: '政治', order: 6},
|
||||
{name: '历史', order: 7},
|
||||
{name: '地理', order: 8},
|
||||
{name: '其他', order: 9}
|
||||
]
|
||||
};
|
||||
},
|
||||
@@ -250,7 +250,7 @@ export default {
|
||||
updateSubject(subject) {
|
||||
const index = this.subjects.findIndex(s => s.order === subject.order);
|
||||
if (index > -1) {
|
||||
this.subjects[index] = { ...subject };
|
||||
this.subjects[index] = {...subject};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -291,7 +291,8 @@ export default {
|
||||
.v-list-item {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.v-list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
<template>
|
||||
<settings-card title="主题设置" icon="mdi-palette">
|
||||
<settings-card icon="mdi-palette" title="主题设置">
|
||||
<v-list>
|
||||
<v-list-item>
|
||||
<template #prepend>
|
||||
<v-icon icon="mdi-theme-light-dark" class="mr-3" />
|
||||
<v-icon class="mr-3" icon="mdi-theme-light-dark"/>
|
||||
</template>
|
||||
<v-list-item-title>主题模式</v-list-item-title>
|
||||
<v-list-item-subtitle>选择明亮或暗黑主题</v-list-item-subtitle>
|
||||
<template #append>
|
||||
<v-btn-toggle
|
||||
v-model="localTheme"
|
||||
density="comfortable"
|
||||
color="primary"
|
||||
density="comfortable"
|
||||
>
|
||||
<v-btn value="light">
|
||||
<v-icon icon="mdi-white-balance-sunny" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-white-balance-sunny"/>
|
||||
明亮
|
||||
</v-btn>
|
||||
<v-btn value="dark">
|
||||
<v-icon icon="mdi-moon-waning-crescent" class="mr-2" />
|
||||
<v-icon class="mr-2" icon="mdi-moon-waning-crescent"/>
|
||||
暗黑
|
||||
</v-btn>
|
||||
</v-btn-toggle>
|
||||
@@ -30,12 +30,12 @@
|
||||
|
||||
<script>
|
||||
import SettingsCard from '@/components/SettingsCard.vue';
|
||||
import { getSetting, setSetting } from '@/utils/settings';
|
||||
import { useTheme } from 'vuetify';
|
||||
import {getSetting, setSetting} from '@/utils/settings';
|
||||
import {useTheme} from 'vuetify';
|
||||
|
||||
export default {
|
||||
name: 'ThemeSettingsCard',
|
||||
components: { SettingsCard },
|
||||
components: {SettingsCard},
|
||||
|
||||
data() {
|
||||
return {
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
|
||||
setup() {
|
||||
const theme = useTheme();
|
||||
return { theme };
|
||||
return {theme};
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
||||
Reference in New Issue
Block a user